diff mbox

[v5,05/13] pvh/acpi: Handle ACPI accesses for PVH guests

Message ID 1481930319-4796-6-git-send-email-boris.ostrovsky@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Boris Ostrovsky Dec. 16, 2016, 11:18 p.m. UTC
Subsequent domctl access to ACPI registers and VCPU map will use the
same code. We create acpi_[cpumap_]access_common() routines in anticipation
of these changes.

Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
---
Changes in v5:
* Code movement due to changes in patch 4
* Added fallthough switch statemnt comments
* Free d->avail_vcpus

 xen/arch/x86/hvm/acpi.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++-
 xen/common/domain.c     |   1 +
 xen/common/domctl.c     |   5 ++
 xen/include/xen/sched.h |   3 ++
 4 files changed, 134 insertions(+), 2 deletions(-)

Comments

Jan Beulich Dec. 20, 2016, 11:50 a.m. UTC | #1
>>> On 17.12.16 at 00:18, <boris.ostrovsky@oracle.com> wrote:
> +static int acpi_cpumap_access_common(struct domain *d,
> +                                     int dir, unsigned int port,
> +                                     unsigned int bytes, uint32_t *val)
> +{
> +    unsigned int first_byte = port - XEN_ACPI_CPU_MAP;
> +
> +    BUILD_BUG_ON(XEN_ACPI_CPU_MAP + XEN_ACPI_CPU_MAP_LEN
> +                 >= ACPI_GPE0_BLK_ADDRESS_V1);

Just > afaict.

> +
> +    if ( dir == XEN_DOMCTL_ACPI_READ )
> +    {
> +        uint32_t mask = (bytes < 4) ? ~0U << (bytes * 8) : 0;
> +
> +        /*
> +         * Clear bits that we are about to read to in case we
> +         * copy fewer than @bytes.
> +         */
> +        *val &= mask;
> +
> +        if ( ((d->max_vcpus + 7) / 8) > first_byte )
> +            memcpy(val, (uint8_t *)d->avail_vcpus + first_byte,
> +                   min(bytes, ((d->max_vcpus + 7) / 8) - first_byte));
> +    }
> +    else
> +        /* Guests do not write CPU map */
> +        return X86EMUL_UNHANDLEABLE;

Perhaps make this an early bail, reducing overall indentation?

> +static int acpi_access_common(struct domain *d,
> +                              int dir, unsigned int port,
> +                              unsigned int bytes, uint32_t *val)
> +{
> +    uint16_t *sts = NULL, *en = NULL;
> +    const uint16_t *mask_sts = NULL, *mask_en = NULL;
> +    static const uint16_t pm1a_sts_mask = ACPI_BITMASK_GLOBAL_LOCK_STATUS;
> +    static const uint16_t pm1a_en_mask = ACPI_BITMASK_GLOBAL_LOCK_ENABLE;
> +    static const uint16_t gpe0_sts_mask = 1U << XEN_ACPI_GPE0_CPUHP_BIT;
> +    static const uint16_t gpe0_en_mask = 1U << XEN_ACPI_GPE0_CPUHP_BIT;
> +
> +    ASSERT(!has_acpi_dm_ff(d));
> +
> +    switch ( port )
> +    {
> +    case ACPI_PM1A_EVT_BLK_ADDRESS_V1 ...
> +        ACPI_PM1A_EVT_BLK_ADDRESS_V1 +
> +        sizeof(d->arch.hvm_domain.acpi.pm1a_sts) +
> +        sizeof(d->arch.hvm_domain.acpi.pm1a_en):
> +
> +        sts = &d->arch.hvm_domain.acpi.pm1a_sts;
> +        en = &d->arch.hvm_domain.acpi.pm1a_en;
> +        mask_sts = &pm1a_sts_mask;
> +        mask_en = &pm1a_en_mask;
> +        break;
> +
> +    case ACPI_GPE0_BLK_ADDRESS_V1 ...
> +        ACPI_GPE0_BLK_ADDRESS_V1 +
> +        sizeof(d->arch.hvm_domain.acpi.gpe0_sts) +
> +        sizeof(d->arch.hvm_domain.acpi.gpe0_en):
> +
> +        sts = &d->arch.hvm_domain.acpi.gpe0_sts;
> +        en = &d->arch.hvm_domain.acpi.gpe0_en;
> +        mask_sts = &gpe0_sts_mask;
> +        mask_en = &gpe0_en_mask;
> +        break;
> +
> +    default:
> +        return X86EMUL_UNHANDLEABLE;
> +    }
> +
> +    if ( dir == XEN_DOMCTL_ACPI_READ )
> +    {
> +        uint32_t mask = (bytes < 4) ? ~0U << (bytes * 8) : 0;
> +        uint32_t data = (((uint32_t)*en) << 16) | *sts;

There's one pair of pointless parentheses around the cast
expression here.

> +
> +        data >>= 8 * (port & 3);
> +        *val = (*val & mask) | (data & ~mask);
> +    }
> +    else
> +    {
> +        uint32_t v = *val;
> +
> +        /* Status register is write-1-to-clear by guests */
> +        switch ( port & 3 )
> +        {
> +        case 0:
> +            *sts &= ~(v & 0xff);
> +            *sts &= *mask_sts;

I can understand the first &=, but why would a read have this second
(side) effect? I could see some sort of need for such only when you
were setting any flags.

> +            if ( !--bytes )
> +                break;
> +            v >>= 8;
> +            /* fallthrough */
> +        case 1:
> +            *sts &= ~((v & 0xff) << 8);
> +            *sts &= *mask_sts;
> +            if ( !--bytes )
> +                break;
> +            v >>= 8;
> +            /* fallthrough */
> +        case 2:
> +            *en = ((*en & 0xff00) | (v & 0xff)) & *mask_en;
> +            if ( !--bytes )
> +                break;
> +            v >>= 8;
> +            /* fallthrough */
> +        case 3:
> +            *en = (((v & 0xff) << 8) | (*en & 0xff)) & *mask_en;
> +            break;
> +        }
> +    }
> +
> +    return X86EMUL_OKAY;
> +}
> +
> +
>  int hvm_acpi_domctl_access(struct domain *d, uint8_t rw,

No double blank lines please.

> @@ -18,13 +135,19 @@ int hvm_acpi_domctl_access(struct domain *d, uint8_t rw,
>  static int acpi_guest_access(int dir, unsigned int port,
>                               unsigned int bytes, uint32_t *val)
>  {
> -    return X86EMUL_UNHANDLEABLE;
> +    return  acpi_access_common(current->domain,
> +                               (dir == IOREQ_READ) ?
> +                               XEN_DOMCTL_ACPI_READ: XEN_DOMCTL_ACPI_WRITE,
> +                               port, bytes, val);
>  }

I don't think this one is meant to be used by the domctl, so I don't see
why you need a helper here. That would also eliminate the seemingly
unnecessary use of XEN_DOMCTL_* here (I think you already had said
this was an oversight in an earlier reply).

Jan
Boris Ostrovsky Dec. 20, 2016, 2:35 p.m. UTC | #2
On 12/20/2016 06:50 AM, Jan Beulich wrote:
>
>> +
>> +    if ( dir == XEN_DOMCTL_ACPI_READ )
>> +    {
>> +        uint32_t mask = (bytes < 4) ? ~0U << (bytes * 8) : 0;
>> +        uint32_t data = (((uint32_t)*en) << 16) | *sts;
> There's one pair of pointless parentheses around the cast
> expression here.
>
>> +
>> +        data >>= 8 * (port & 3);
>> +        *val = (*val & mask) | (data & ~mask);
>> +    }
>> +    else
>> +    {
>> +        uint32_t v = *val;
>> +
>> +        /* Status register is write-1-to-clear by guests */
>> +        switch ( port & 3 )
>> +        {
>> +        case 0:
>> +            *sts &= ~(v & 0xff);
>> +            *sts &= *mask_sts;
> I can understand the first &=, but why would a read have this second
> (side) effect? I could see some sort of need for such only when you
> were setting any flags.

This is a write, not a read.

>
>> @@ -18,13 +135,19 @@ int hvm_acpi_domctl_access(struct domain *d, uint8_t rw,
>>  static int acpi_guest_access(int dir, unsigned int port,
>>                               unsigned int bytes, uint32_t *val)
>>  {
>> -    return X86EMUL_UNHANDLEABLE;
>> +    return  acpi_access_common(current->domain,
>> +                               (dir == IOREQ_READ) ?
>> +                               XEN_DOMCTL_ACPI_READ: XEN_DOMCTL_ACPI_WRITE,
>> +                               port, bytes, val);
>>  }
> I don't think this one is meant to be used by the domctl, so I don't see
> why you need a helper here. That would also eliminate the seemingly
> unnecessary use of XEN_DOMCTL_* here (I think you already had said
> this was an oversight in an earlier reply).

Yes, XEN_DOMCTL_*is out of place here but I'd prefer to keep the helper
to isolate the sense of 'dir' as is used by portio handling
infrastructure (i.e. IOREQ_READ/WRITE) from how it is defined in the
acpi code here. Especially if, as mentioned in another thread, I use
bool is_write in common routines.


-boris
Jan Beulich Dec. 20, 2016, 2:47 p.m. UTC | #3
>>> On 20.12.16 at 15:35, <boris.ostrovsky@oracle.com> wrote:
> On 12/20/2016 06:50 AM, Jan Beulich wrote:
>>> +    else
>>> +    {
>>> +        uint32_t v = *val;
>>> +
>>> +        /* Status register is write-1-to-clear by guests */
>>> +        switch ( port & 3 )
>>> +        {
>>> +        case 0:
>>> +            *sts &= ~(v & 0xff);
>>> +            *sts &= *mask_sts;
>> I can understand the first &=, but why would a read have this second
>> (side) effect? I could see some sort of need for such only when you
>> were setting any flags.
> 
> This is a write, not a read.

Oh, right. But the question remains about that unexpected side
effect.

>>> @@ -18,13 +135,19 @@ int hvm_acpi_domctl_access(struct domain *d, uint8_t rw,
>>>  static int acpi_guest_access(int dir, unsigned int port,
>>>                               unsigned int bytes, uint32_t *val)
>>>  {
>>> -    return X86EMUL_UNHANDLEABLE;
>>> +    return  acpi_access_common(current->domain,
>>> +                               (dir == IOREQ_READ) ?
>>> +                               XEN_DOMCTL_ACPI_READ: XEN_DOMCTL_ACPI_WRITE,
>>> +                               port, bytes, val);
>>>  }
>> I don't think this one is meant to be used by the domctl, so I don't see
>> why you need a helper here. That would also eliminate the seemingly
>> unnecessary use of XEN_DOMCTL_* here (I think you already had said
>> this was an oversight in an earlier reply).
> 
> Yes, XEN_DOMCTL_*is out of place here but I'd prefer to keep the helper
> to isolate the sense of 'dir' as is used by portio handling
> infrastructure (i.e. IOREQ_READ/WRITE) from how it is defined in the
> acpi code here. Especially if, as mentioned in another thread, I use
> bool is_write in common routines.

Well, if the helper is needed for the domctl, then this is at least
acceptable (albeit personally I'd prefer the domctl handler to
do the translation, using the IOREQ_* values internally. If the
helper is not needed for domctl, then XEN_DOMCTL_* shouldn't
be passed here.

Jan
Boris Ostrovsky Dec. 20, 2016, 3:29 p.m. UTC | #4
On 12/20/2016 09:47 AM, Jan Beulich wrote:
>>>> On 20.12.16 at 15:35, <boris.ostrovsky@oracle.com> wrote:
>> On 12/20/2016 06:50 AM, Jan Beulich wrote:
>>>> +    else
>>>> +    {
>>>> +        uint32_t v = *val;
>>>> +
>>>> +        /* Status register is write-1-to-clear by guests */
>>>> +        switch ( port & 3 )
>>>> +        {
>>>> +        case 0:
>>>> +            *sts &= ~(v & 0xff);
>>>> +            *sts &= *mask_sts;
>>> I can understand the first &=, but why would a read have this second
>>> (side) effect? I could see some sort of need for such only when you
>>> were setting any flags.
>> This is a write, not a read.
> Oh, right. But the question remains about that unexpected side
> effect.

It indeed doesn't do anything for the case of guest access. It is
guarding against setting unauthorized bits by domctl (introduced by the
next patch). And I can move it into that case.

However, as discussed in the thread about 06/13 patch, we may currently
not need to provide domctl access to anything but VCPU map. So the
question is whether domctl interface to GPE0/PM1a is needed at all. I
think it's a useful interface with very little extra code required and
the toolstack can use it, for example, to inject events into guests. But
I don't have a specific use case.

-boris
Jan Beulich Dec. 20, 2016, 3:41 p.m. UTC | #5
>>> On 20.12.16 at 16:29, <boris.ostrovsky@oracle.com> wrote:
> On 12/20/2016 09:47 AM, Jan Beulich wrote:
>>>>> On 20.12.16 at 15:35, <boris.ostrovsky@oracle.com> wrote:
>>> On 12/20/2016 06:50 AM, Jan Beulich wrote:
>>>>> +    else
>>>>> +    {
>>>>> +        uint32_t v = *val;
>>>>> +
>>>>> +        /* Status register is write-1-to-clear by guests */
>>>>> +        switch ( port & 3 )
>>>>> +        {
>>>>> +        case 0:
>>>>> +            *sts &= ~(v & 0xff);
>>>>> +            *sts &= *mask_sts;
>>>> I can understand the first &=, but why would a read have this second
>>>> (side) effect? I could see some sort of need for such only when you
>>>> were setting any flags.
>>> This is a write, not a read.
>> Oh, right. But the question remains about that unexpected side
>> effect.
> 
> It indeed doesn't do anything for the case of guest access. It is
> guarding against setting unauthorized bits by domctl (introduced by the
> next patch). And I can move it into that case.
> 
> However, as discussed in the thread about 06/13 patch, we may currently
> not need to provide domctl access to anything but VCPU map. So the
> question is whether domctl interface to GPE0/PM1a is needed at all. I
> think it's a useful interface with very little extra code required and
> the toolstack can use it, for example, to inject events into guests. But
> I don't have a specific use case.

To be honest, I'd keep out anything we don't really need.

Jan
Andrew Cooper Dec. 20, 2016, 4:46 p.m. UTC | #6
On 20/12/2016 15:41, Jan Beulich wrote:
>>>> On 20.12.16 at 16:29, <boris.ostrovsky@oracle.com> wrote:
>> On 12/20/2016 09:47 AM, Jan Beulich wrote:
>>>>>> On 20.12.16 at 15:35, <boris.ostrovsky@oracle.com> wrote:
>>>> On 12/20/2016 06:50 AM, Jan Beulich wrote:
>>>>>> +    else
>>>>>> +    {
>>>>>> +        uint32_t v = *val;
>>>>>> +
>>>>>> +        /* Status register is write-1-to-clear by guests */
>>>>>> +        switch ( port & 3 )
>>>>>> +        {
>>>>>> +        case 0:
>>>>>> +            *sts &= ~(v & 0xff);
>>>>>> +            *sts &= *mask_sts;
>>>>> I can understand the first &=, but why would a read have this second
>>>>> (side) effect? I could see some sort of need for such only when you
>>>>> were setting any flags.
>>>> This is a write, not a read.
>>> Oh, right. But the question remains about that unexpected side
>>> effect.
>> It indeed doesn't do anything for the case of guest access. It is
>> guarding against setting unauthorized bits by domctl (introduced by the
>> next patch). And I can move it into that case.
>>
>> However, as discussed in the thread about 06/13 patch, we may currently
>> not need to provide domctl access to anything but VCPU map. So the
>> question is whether domctl interface to GPE0/PM1a is needed at all. I
>> think it's a useful interface with very little extra code required and
>> the toolstack can use it, for example, to inject events into guests. But
>> I don't have a specific use case.
> To be honest, I'd keep out anything we don't really need.

I have two specific use-cases.  1) DIMM Hotplug, and 2) Windows
tablet/desktop mode switch, both of which I think will just require a
toolstack entity to be able to raise an SCI.

However, I am happy for you to ignore these case for now (as they
haven't yet been fully designed and thought through), on the assumption
that if we do need to add anything, it will happily sit alongside the
VCPU code.

~Andrew
Boris Ostrovsky Dec. 20, 2016, 4:51 p.m. UTC | #7
On 12/20/2016 11:46 AM, Andrew Cooper wrote:
> On 20/12/2016 15:41, Jan Beulich wrote:
>>>>> On 20.12.16 at 16:29, <boris.ostrovsky@oracle.com> wrote:
>>> On 12/20/2016 09:47 AM, Jan Beulich wrote:
>>>>>>> On 20.12.16 at 15:35, <boris.ostrovsky@oracle.com> wrote:
>>>>> On 12/20/2016 06:50 AM, Jan Beulich wrote:
>>>>>>> +    else
>>>>>>> +    {
>>>>>>> +        uint32_t v = *val;
>>>>>>> +
>>>>>>> +        /* Status register is write-1-to-clear by guests */
>>>>>>> +        switch ( port & 3 )
>>>>>>> +        {
>>>>>>> +        case 0:
>>>>>>> +            *sts &= ~(v & 0xff);
>>>>>>> +            *sts &= *mask_sts;
>>>>>> I can understand the first &=, but why would a read have this second
>>>>>> (side) effect? I could see some sort of need for such only when you
>>>>>> were setting any flags.
>>>>> This is a write, not a read.
>>>> Oh, right. But the question remains about that unexpected side
>>>> effect.
>>> It indeed doesn't do anything for the case of guest access. It is
>>> guarding against setting unauthorized bits by domctl (introduced by the
>>> next patch). And I can move it into that case.
>>>
>>> However, as discussed in the thread about 06/13 patch, we may currently
>>> not need to provide domctl access to anything but VCPU map. So the
>>> question is whether domctl interface to GPE0/PM1a is needed at all. I
>>> think it's a useful interface with very little extra code required and
>>> the toolstack can use it, for example, to inject events into guests. But
>>> I don't have a specific use case.
>> To be honest, I'd keep out anything we don't really need.
> I have two specific use-cases.  1) DIMM Hotplug, and 2) Windows
> tablet/desktop mode switch, both of which I think will just require a
> toolstack entity to be able to raise an SCI.

And I just found these two: XEN_DOMCTL_SENDTRIGGER_POWER and
XEN_DOMCTL_SENDTRIGGER_POWER.

When we switch HVM to new interface these can be re-implemented on top
of ACPI access.

-boris

>
> However, I am happy for you to ignore these case for now (as they
> haven't yet been fully designed and thought through), on the assumption
> that if we do need to add anything, it will happily sit alongside the
> VCPU code.
>
> ~Andrew
diff mbox

Patch

diff --git a/xen/arch/x86/hvm/acpi.c b/xen/arch/x86/hvm/acpi.c
index 9b2885e..b2299a4 100644
--- a/xen/arch/x86/hvm/acpi.c
+++ b/xen/arch/x86/hvm/acpi.c
@@ -2,12 +2,129 @@ 
  *
  * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
  */
+#include <xen/acpi.h>
 #include <xen/errno.h>
 #include <xen/lib.h>
 #include <xen/sched.h>
 
 #include <public/arch-x86/xen.h>
 
+static int acpi_cpumap_access_common(struct domain *d,
+                                     int dir, unsigned int port,
+                                     unsigned int bytes, uint32_t *val)
+{
+    unsigned int first_byte = port - XEN_ACPI_CPU_MAP;
+
+    BUILD_BUG_ON(XEN_ACPI_CPU_MAP + XEN_ACPI_CPU_MAP_LEN
+                 >= ACPI_GPE0_BLK_ADDRESS_V1);
+
+    if ( dir == XEN_DOMCTL_ACPI_READ )
+    {
+        uint32_t mask = (bytes < 4) ? ~0U << (bytes * 8) : 0;
+
+        /*
+         * Clear bits that we are about to read to in case we
+         * copy fewer than @bytes.
+         */
+        *val &= mask;
+
+        if ( ((d->max_vcpus + 7) / 8) > first_byte )
+            memcpy(val, (uint8_t *)d->avail_vcpus + first_byte,
+                   min(bytes, ((d->max_vcpus + 7) / 8) - first_byte));
+    }
+    else
+        /* Guests do not write CPU map */
+        return X86EMUL_UNHANDLEABLE;
+
+    return X86EMUL_OKAY;
+}
+
+static int acpi_access_common(struct domain *d,
+                              int dir, unsigned int port,
+                              unsigned int bytes, uint32_t *val)
+{
+    uint16_t *sts = NULL, *en = NULL;
+    const uint16_t *mask_sts = NULL, *mask_en = NULL;
+    static const uint16_t pm1a_sts_mask = ACPI_BITMASK_GLOBAL_LOCK_STATUS;
+    static const uint16_t pm1a_en_mask = ACPI_BITMASK_GLOBAL_LOCK_ENABLE;
+    static const uint16_t gpe0_sts_mask = 1U << XEN_ACPI_GPE0_CPUHP_BIT;
+    static const uint16_t gpe0_en_mask = 1U << XEN_ACPI_GPE0_CPUHP_BIT;
+
+    ASSERT(!has_acpi_dm_ff(d));
+
+    switch ( port )
+    {
+    case ACPI_PM1A_EVT_BLK_ADDRESS_V1 ...
+        ACPI_PM1A_EVT_BLK_ADDRESS_V1 +
+        sizeof(d->arch.hvm_domain.acpi.pm1a_sts) +
+        sizeof(d->arch.hvm_domain.acpi.pm1a_en):
+
+        sts = &d->arch.hvm_domain.acpi.pm1a_sts;
+        en = &d->arch.hvm_domain.acpi.pm1a_en;
+        mask_sts = &pm1a_sts_mask;
+        mask_en = &pm1a_en_mask;
+        break;
+
+    case ACPI_GPE0_BLK_ADDRESS_V1 ...
+        ACPI_GPE0_BLK_ADDRESS_V1 +
+        sizeof(d->arch.hvm_domain.acpi.gpe0_sts) +
+        sizeof(d->arch.hvm_domain.acpi.gpe0_en):
+
+        sts = &d->arch.hvm_domain.acpi.gpe0_sts;
+        en = &d->arch.hvm_domain.acpi.gpe0_en;
+        mask_sts = &gpe0_sts_mask;
+        mask_en = &gpe0_en_mask;
+        break;
+
+    default:
+        return X86EMUL_UNHANDLEABLE;
+    }
+
+    if ( dir == XEN_DOMCTL_ACPI_READ )
+    {
+        uint32_t mask = (bytes < 4) ? ~0U << (bytes * 8) : 0;
+        uint32_t data = (((uint32_t)*en) << 16) | *sts;
+
+        data >>= 8 * (port & 3);
+        *val = (*val & mask) | (data & ~mask);
+    }
+    else
+    {
+        uint32_t v = *val;
+
+        /* Status register is write-1-to-clear by guests */
+        switch ( port & 3 )
+        {
+        case 0:
+            *sts &= ~(v & 0xff);
+            *sts &= *mask_sts;
+            if ( !--bytes )
+                break;
+            v >>= 8;
+            /* fallthrough */
+        case 1:
+            *sts &= ~((v & 0xff) << 8);
+            *sts &= *mask_sts;
+            if ( !--bytes )
+                break;
+            v >>= 8;
+            /* fallthrough */
+        case 2:
+            *en = ((*en & 0xff00) | (v & 0xff)) & *mask_en;
+            if ( !--bytes )
+                break;
+            v >>= 8;
+            /* fallthrough */
+        case 3:
+            *en = (((v & 0xff) << 8) | (*en & 0xff)) & *mask_en;
+            break;
+        }
+    }
+
+    return X86EMUL_OKAY;
+}
+
+
 int hvm_acpi_domctl_access(struct domain *d, uint8_t rw,
                            const xen_acpi_access_t *access,
                            XEN_GUEST_HANDLE_PARAM(void) arg)
@@ -18,13 +135,19 @@  int hvm_acpi_domctl_access(struct domain *d, uint8_t rw,
 static int acpi_guest_access(int dir, unsigned int port,
                              unsigned int bytes, uint32_t *val)
 {
-    return X86EMUL_UNHANDLEABLE;
+    return  acpi_access_common(current->domain,
+                               (dir == IOREQ_READ) ?
+                               XEN_DOMCTL_ACPI_READ: XEN_DOMCTL_ACPI_WRITE,
+                               port, bytes, val);
 }
 
 static int acpi_cpumap_guest_access(int dir, unsigned int port,
                                     unsigned int bytes, uint32_t *val)
 {
-    return X86EMUL_UNHANDLEABLE;
+    return  acpi_cpumap_access_common(current->domain,
+                                      (dir == IOREQ_READ) ?
+                                      XEN_DOMCTL_ACPI_READ: XEN_DOMCTL_ACPI_WRITE,
+                                      port, bytes, val);
 }
 
 void hvm_acpi_init(struct domain *d)
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 3abaca9..cb8df09 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -847,6 +847,7 @@  static void complete_domain_destroy(struct rcu_head *head)
     xsm_free_security_domain(d);
     free_cpumask_var(d->domain_dirty_cpumask);
     xfree(d->vcpu);
+    xfree(d->avail_vcpus);
     free_domain_struct(d);
 
     send_global_virq(VIRQ_DOM_EXC);
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index b0ee961..0a08b83 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -651,6 +651,11 @@  long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
                 goto maxvcpu_out;
         }
 
+        d->avail_vcpus = xzalloc_array(unsigned long,
+                                       BITS_TO_LONGS(d->max_vcpus));
+        if ( !d->avail_vcpus )
+            goto maxvcpu_out;
+
         ret = 0;
 
     maxvcpu_out:
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 063efe6..bee190f 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -315,6 +315,9 @@  struct domain
     unsigned int     max_vcpus;
     struct vcpu    **vcpu;
 
+    /* Bitmap of available VCPUs. */
+    unsigned long   *avail_vcpus;
+
     shared_info_t   *shared_info;     /* shared data area */
 
     spinlock_t       domain_lock;