@@ -7,9 +7,11 @@
#include <xen/lib.h>
#include <xen/sched.h>
+#include <asm/guest_access.h>
+
#include <public/arch-x86/xen.h>
-static int acpi_access_common(struct domain *d,
+static int acpi_access_common(struct domain *d, bool is_guest_access,
int dir, unsigned int port,
unsigned int bytes, uint32_t *val)
{
@@ -87,8 +89,13 @@ static int acpi_access_common(struct domain *d,
else
{
/* Guests do not write CPU map */
- if ( !mask_sts )
- return X86EMUL_UNHANDLEABLE;
+ if ( !is_guest_access && !mask_sts )
+ {
+ unsigned int first_byte = port - XEN_ACPI_CPU_MAP;
+
+ memcpy((uint8_t *)d->avail_vcpus + first_byte, val,
+ min(bytes, ((d->max_vcpus + 7) / 8) - first_byte));
+ }
else if ( mask_sts )
{
uint32_t v = *val;
@@ -97,14 +104,20 @@ static int acpi_access_common(struct domain *d,
switch ( port & 3 )
{
case 0:
- *sts &= ~(v & 0xff);
+ if ( is_guest_access )
+ *sts &= ~(v & 0xff);
+ else
+ *sts = (*sts & 0xff00) | (v & 0xff);
*sts &= *mask_sts;
if ( !--bytes )
break;
v >>= 8;
case 1:
- *sts &= ~((v & 0xff) << 8);
+ if ( is_guest_access )
+ *sts &= ~((v & 0xff) << 8);
+ else
+ *sts = ((v & 0xff) << 8) | (*sts & 0xff);
*sts &= *mask_sts;
if ( !--bytes )
break;
@@ -128,13 +141,47 @@ static int acpi_access_common(struct domain *d,
int hvm_acpi_domctl_access(struct domain *d, uint8_t rw, gas_t *gas,
XEN_GUEST_HANDLE_PARAM(uint8) arg)
{
- return -ENOSYS;
+ unsigned int port, tot_bytes, bytes;
+ unsigned int i;
+ uint32_t val;
+ uint8_t *ptr = (uint8_t *)&val;
+ int rc;
+
+ /*
+ * Only allow accesses to IO space. Accesses should be byte-aligned
+ * and integral number of bytes.
+ */
+ if ( gas->space_id != XEN_ACPI_SYSTEM_IO ||
+ gas->bit_width & 7 || gas->bit_offset & 7 )
+ return -EINVAL;
+
+ port = gas->address + (gas->bit_offset >> 3);
+ tot_bytes = gas->bit_width >> 3;
+
+ for ( i = 0; i < tot_bytes; i += sizeof(val) )
+ {
+ bytes = (tot_bytes - i > sizeof(val)) ? sizeof(val) : tot_bytes - i;
+
+ if ((rw == XEN_DOMCTL_ACPI_WRITE) &&
+ copy_from_guest_offset(ptr, arg, i, bytes))
+ return -EFAULT;
+
+ rc = acpi_access_common(d, false, rw, port + i, bytes, &val);
+ if ( rc )
+ return rc;
+
+ if ((rw == XEN_DOMCTL_ACPI_READ) &&
+ copy_to_guest_offset(arg, i, ptr, bytes))
+ return -EFAULT;
+ }
+
+ return 0;
}
static int acpi_guest_access(int dir, unsigned int port,
unsigned int bytes, uint32_t *val)
{
- return acpi_access_common(current->domain,
+ return acpi_access_common(current->domain, true,
(dir == IOREQ_READ) ?
XEN_DOMCTL_ACPI_READ: XEN_DOMCTL_ACPI_WRITE,
port, bytes, val);
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> --- Changes in v4: * New patch xen/arch/x86/hvm/acpi.c | 61 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 7 deletions(-)