--- /dev/null
+diff --git a/hw/acpi-wmi.h b/hw/acpi-wmi.h
+new file mode 100644
+index 0000000..af99c1c
+--- /dev/null
++++ b/hw/acpi-wmi.h
+@@ -0,0 +1,99 @@
++/******************************************************************************
++ * acpi-wmi.h
++ *
++ * Interface to /proc/misc/xen-acpi-wmi
++ *
++ * Copyright (c) 2009 Kamala Narasimhan
++ * Copyright (c) 2009 Citrix Systems, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++/* NOTE: This header is a duplicate of drivers/xen/acpi-wmi/acpi-wmi.h in our
++ * kernel repo. As we don't share headers between kernel and userspace, we have
++ * the same header in two places. It is important to keep the two headers in sync
++ * to avoid incompatibilities.
++ */
++
++#ifndef _XEN_WMI_ACPI
++#define _XEN_WMI_ACPI
++
++/*
++ * Userspace Interface
++ */
++
++#define XEN_WMI_DEVICE_NAME "xen-acpi-wmi"
++#define XEN_WMI_GUID_SIZE 16
++
++#define XEN_WMI_SUCCESS 0
++#define XEN_WMI_UNSUPPORTED_TYPE -1
++#define XEN_WMI_BUFFER_TOO_SMALL -11
++#define XEN_WMI_NOT_ENOUGH_MEMORY -12
++#define XEN_WMI_EFAULT -14
++#define XEN_WMI_INVALID_ARGUMENT -22
++#define XEN_WMI_ENOIOCTLCMD -515
++
++#define XEN_WMI_IOCTL_CALL_METHOD 100
++#define XEN_WMI_IOCTL_QUERY_OBJECT 101
++#define XEN_WMI_IOCTL_SET_OBJECT 102
++#define XEN_WMI_IOCTL_GET_EVENT_DATA 103
++
++typedef unsigned char byte;
++
++typedef struct xen_wmi_buffer {
++ size_t length;
++ void *pointer;
++ size_t *copied_length;
++} xen_wmi_buffer_t;
++
++typedef struct xen_wmi_obj_invocation_data {
++ byte guid[XEN_WMI_GUID_SIZE];
++ union {
++ struct {
++ ushort instance;
++ uint method_id;
++ xen_wmi_buffer_t in_buf;
++ xen_wmi_buffer_t out_buf;
++ } xen_wmi_method_arg;
++
++ struct {
++ ushort instance;
++ xen_wmi_buffer_t out_buf;
++ } xen_wmi_query_obj_arg;
++
++ struct {
++ ushort instance;
++ xen_wmi_buffer_t in_buf;
++ } xen_wmi_set_obj_arg;
++
++ struct {
++ ushort event_id;
++ xen_wmi_buffer_t out_buf;
++ } xen_wmi_event_data_arg;
++ } xen_wmi_arg;
++} xen_wmi_obj_invocation_data_t;
++
++#endif /* _XEN_WMI_ACPI */
++
+diff --git a/hw/pc.h b/hw/pc.h
+index e1ce52d..dbd691a 100644
+--- a/hw/pc.h
++++ b/hw/pc.h
+@@ -109,6 +109,8 @@ void acpi_ac_adapter_state_changed(void);
+ void acpi_power_button_pressed(void);
+ void acpi_lid_state_changed(void);
+
++void acpi_oem_event(void);
++
+ /* hpet.c */
+ extern int no_hpet;
+
+diff --git a/hw/piix4acpi.c b/hw/piix4acpi.c
+index d25f004..277f106 100644
+--- a/hw/piix4acpi.c
++++ b/hw/piix4acpi.c
+@@ -29,6 +29,7 @@
+ #include "sysemu.h"
+ #include "qemu-xen.h"
+ #include "battery_mgmt.h"
++#include "xen_acpi_wmi.h"
+
+ #include <xen/hvm/ioreq.h>
+ #include <xen/hvm/params.h>
+@@ -57,6 +58,7 @@
+ #define ACPI_AC_POWER_STATE_BIT 0x1c
+ #define ACPI_POWER_BUTTON_BIT 0x1
+ #define ACPI_LID_STATE_BIT 0x17
++#define ACPI_OEM_EVENT_BIT 0x18
+
+ typedef struct AcpiDeviceState AcpiDeviceState;
+ AcpiDeviceState *acpi_device_table;
+@@ -194,6 +196,7 @@ static void acpi_map(PCIDevice *pci_dev, int region_num,
+ register_ioport_read(addr + 4, 2, 2, acpiPm1Control_readw, d);
+
+ battery_mgmt_init(pci_dev);
++ xen_acpi_wmi_init(pci_dev);
+ }
+
+ static inline int test_bit(uint8_t *map, int bit)
+@@ -248,6 +251,19 @@ void acpi_lid_state_changed(void)
+ }
+ }
+
++void acpi_oem_event(void)
++{
++ GPEState *s = &gpe_state;
++
++ if ( !test_bit(&s->gpe0_sts[0], ACPI_OEM_EVENT_BIT) &&
++ test_bit(&s->gpe0_en[0], ACPI_OEM_EVENT_BIT) ) {
++ set_bit(&s->gpe0_sts[0], ACPI_OEM_EVENT_BIT);
++ s->sci_asserted = 1;
++ fprintf(logfile, "Raising oem event irq\n");
++ qemu_irq_raise(sci_irq);
++ }
++}
++
+ #ifdef CONFIG_PASSTHROUGH
+
+ static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
+diff --git a/hw/xen_acpi_wmi.c b/hw/xen_acpi_wmi.c
+new file mode 100644
+index 0000000..5d378d0
+--- /dev/null
++++ b/hw/xen_acpi_wmi.c
+@@ -0,0 +1,654 @@
++/*
++ * xen_acpi_wmi.c
++ *
++ * Copyright (c) 2009 Kamala Narasimhan
++ * Copyright (c) 2009 Citrix Systems, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/* Xen ACPI WMI implementation -
++ * OEMs expose their value add functionalites through firmware level WMI
++ * acpi objects. To support the underlying OEM value add within guest
++ * space, we expose a WMI psuedo device object at our vACPI layer. That
++ * vACPI layer relies on the below implementation to communication to the
++ * base firmware (through xen wmi module and linux acpi wmi wrapper
++ * driver) either it be to execute a WMI method or query or set
++ * data or recieve wmi event data.
++ */
++
++/* NOTE: As the vACPI layer is written to send request and take response in a
++ * synchronized way, there isn't a need to add synchronization logic here.
++ */
++
++#include "hw.h"
++#include "pc.h"
++#include "qemu-xen.h"
++#include "isa.h"
++#include "xen_acpi_wmi.h"
++
++#ifndef CONFIG_NO_XEN_ACPI_WMI
++
++#define XEN_WMI_DEFAULT_OUTPUT_BUFFER_SIZE 256
++
++static xen_acpi_wmi_cmd_info_t cmd_info;
++static int xen_wmi_device = -ENODEV;
++extern FILE *logfile;
++extern int domid;
++
++/* #define XEN_ACPI_WMI_DEBUG */
++/* #define XEN_ACPI_WMI_DEBUG_EXT */
++
++/*
++ * xen_acpi_wmi_set_guid
++ */
++void xen_acpi_wmi_set_guid(uint8_t val)
++{
++ if ( cmd_info.invocation_type == XEN_ACPI_WMI_UNDEFINED )
++ {
++ fprintf(logfile,
++ "XEN WMI: Unable to set guid with invalid invocation type!\n");
++ return;
++ }
++
++ if ( cmd_info.current_index >= XEN_WMI_GUID_SIZE )
++ {
++ fprintf(logfile, "XEN WMI: Guid array index out of range - %d!!!\n",
++ cmd_info.current_index);
++ cmd_info.invocation_type = XEN_ACPI_WMI_UNDEFINED;
++ return;
++ }
++
++ cmd_info.invocation_data.guid[cmd_info.current_index] = val;
++ cmd_info.current_index++;
++}
++
++/*
++ * xen_acpi_wmi_set_cmd_instance
++ */
++void xen_acpi_wmi_set_cmd_instance(uint32_t val)
++{
++ if ( cmd_info.invocation_type == XEN_ACPI_WMI_UNDEFINED )
++ {
++ fprintf(logfile,
++ "XEN WMI: Unable to set cmd instance with invalid invocation type!\n");
++ return;
++ }
++
++ switch( cmd_info.invocation_type )
++ {
++ case XEN_ACPI_WMI_EXEC_METHOD:
++ cmd_info.invocation_data.xen_wmi_arg.xen_wmi_method_arg.instance = val;
++ break;
++ case XEN_ACPI_WMI_QUERY_OBJECT:
++ cmd_info.invocation_data.xen_wmi_arg.xen_wmi_query_obj_arg.instance = val;
++ break;
++ case XEN_ACPI_WMI_SET_OBJECT:
++ cmd_info.invocation_data.xen_wmi_arg.xen_wmi_set_obj_arg.instance = val;
++ break;
++ default:
++ fprintf(logfile,
++ "Invalid attempt to set instance for current invocation type!\n");
++ break;
++ }
++}
++
++/*
++ * xen_acpi_wmi_set_method_id
++ */
++void xen_acpi_wmi_set_method_id(uint32_t val)
++{
++ if ( cmd_info.invocation_type != XEN_ACPI_WMI_EXEC_METHOD )
++ {
++ fprintf(logfile,
++ "Unable to set method id for the current invocation type!\n");
++ return;
++ }
++
++ cmd_info.invocation_data.xen_wmi_arg.xen_wmi_method_arg.method_id = val;
++}
++
++/*
++ * xen_acpi_wmi_get_input_buffer
++ */
++xen_wmi_buffer_t *xen_acpi_wmi_get_input_buffer(void)
++{
++ if ( cmd_info.invocation_type != XEN_ACPI_WMI_EXEC_METHOD &&
++ cmd_info.invocation_type != XEN_ACPI_WMI_SET_OBJECT )
++ return 0;
++
++ if ( cmd_info.invocation_type == XEN_ACPI_WMI_EXEC_METHOD )
++ return &cmd_info.invocation_data.xen_wmi_arg.xen_wmi_method_arg.in_buf;
++ else if ( cmd_info.invocation_type == XEN_ACPI_WMI_SET_OBJECT )
++ return &cmd_info.invocation_data.xen_wmi_arg.xen_wmi_set_obj_arg.in_buf;
++
++ return 0;
++}
++
++/*
++ * xen_acpi_wmi_set_buffer_size
++ * Guest vACPI layer passes to us the size of the input buffer it is
++ * about to transfer to ioemu and this method stores the passed in size
++ * apart from allocating a buffer with the provided size.
++ */
++void xen_acpi_wmi_set_in_buffer_size(uint32_t val)
++{
++ xen_wmi_buffer_t *buffer;
++
++ buffer = xen_acpi_wmi_get_input_buffer();
++ if ( buffer == NULL )
++ return;
++
++ cmd_info.current_index = 0;
++ buffer->length = val;
++ buffer->pointer = malloc(val);
++}
++
++/*
++ * xen_acpi_wmi_set_in_buffer
++ */
++void xen_acpi_wmi_set_in_buffer(uint8_t val)
++{
++ xen_wmi_buffer_t *buffer;
++
++ buffer = xen_acpi_wmi_get_input_buffer();
++ if ( buffer == NULL )
++ return;
++
++ if ( cmd_info.current_index >= buffer->length )
++ {
++ fprintf(logfile,
++ "XEN WMI: Cannot write beyond allocated input buffer size!!!\n");
++ return;
++ }
++
++ ((byte *)buffer->pointer)[cmd_info.current_index] = val;
++ cmd_info.current_index++;
++}
++
++/*
++ * xen_wmi_get_output_buffer
++ */
++xen_wmi_buffer_t *xen_acpi_wmi_get_output_buffer(void)
++{
++ if ( cmd_info.invocation_type != XEN_ACPI_WMI_EXEC_METHOD &&
++ cmd_info.invocation_type != XEN_ACPI_WMI_QUERY_OBJECT &&
++ cmd_info.invocation_type != XEN_ACPI_WMI_GET_EVENT_DATA )
++ {
++ fprintf(logfile,
++ "XEN WMI: Output buffer not available for current invocation type!\n");
++ return 0;
++ }
++
++ if ( cmd_info.invocation_type == XEN_ACPI_WMI_EXEC_METHOD )
++ return &cmd_info.invocation_data.xen_wmi_arg.xen_wmi_method_arg.out_buf;
++ else if ( cmd_info.invocation_type == XEN_ACPI_WMI_QUERY_OBJECT )
++ return &cmd_info.invocation_data.xen_wmi_arg.xen_wmi_query_obj_arg.out_buf;
++ else if ( cmd_info.invocation_type == XEN_ACPI_WMI_GET_EVENT_DATA )
++ return &cmd_info.invocation_data.xen_wmi_arg.xen_wmi_event_data_arg.out_buf;
++
++ return 0;
++}
++
++/*
++ * xen_acpi_wmi_allocate_output_buffer
++ */
++void xen_acpi_wmi_allocate_output_buffer(size_t length)
++{
++ xen_wmi_buffer_t *buffer;
++
++ buffer = xen_acpi_wmi_get_output_buffer();
++ if ( buffer == NULL )
++ return;
++
++ buffer->length = (length > 0) ? length : XEN_WMI_DEFAULT_OUTPUT_BUFFER_SIZE;
++ buffer->pointer = malloc(buffer->length);
++ memset(buffer->pointer, 0, buffer->length);
++
++ buffer->copied_length = malloc(sizeof(size_t));
++ memset(buffer->copied_length, 0, sizeof(size_t));
++}
++
++/*
++ * xen_acpi_wmi_reallocate_output_buffer
++ */
++int xen_acpi_wmi_reallocate_output_buffer()
++{
++ xen_wmi_buffer_t *buffer;
++
++ buffer = xen_acpi_wmi_get_output_buffer();
++ if ( buffer == NULL || buffer->copied_length == NULL || buffer->pointer == NULL )
++ return XEN_WMI_NOT_ENOUGH_MEMORY;
++
++ /* If required length is less than allocated length,
++ * we shouldn't have failed; no point in rellocating.
++ * @TODO: Rename copied_length to something more appropriate.
++ */
++ if ( *buffer->copied_length <= buffer->length )
++ return XEN_WMI_NOT_ENOUGH_MEMORY;
++
++ free(buffer->pointer);
++ buffer->pointer = malloc(*buffer->copied_length);
++ memset(buffer->pointer, 0, *buffer->copied_length);
++ buffer->length = *buffer->copied_length;
++ return XEN_WMI_SUCCESS;
++}
++
++/*
++ * xen_acpi_wmi_free_input_buffer
++ */
++void xen_acpi_wmi_free_input_buffer(void)
++{
++ xen_wmi_buffer_t *buffer;
++
++ buffer = xen_acpi_wmi_get_input_buffer();
++ if ( buffer == NULL )
++ return;
++
++ if ( buffer->length > 0 )
++ free(buffer->pointer);
++ buffer->length = 0;
++}
++
++#ifdef XEN_ACPI_WMI_DEBUG
++
++/*
++ * xen_acpi_wmi_print_input_buffer
++ */
++void xen_acpi_wmi_print_input_buffer(xen_wmi_buffer_t *in_buf)
++{
++ int count;
++
++ fprintf(logfile, "In buffer length - %d\n", in_buf->length);
++ fprintf(logfile, "In buffer: ");
++ for( count = 0; count < in_buf->length; count++ )
++ fprintf(logfile, " %d, ", ((byte *)in_buf->pointer)[count]);
++ fprintf(logfile, "\n");
++}
++
++/*
++ * xen_acpi_wmi_print_input_info
++ */
++void xen_acpi_wmi_print_input_info(void)
++{
++ int count;
++
++ fprintf(logfile, "Command invocation type - %d\n", cmd_info.invocation_type);
++ fprintf(logfile, "Invocation Data: \n");
++ fprintf(logfile, "Guid: ");
++
++ for (count=0; count < XEN_WMI_GUID_SIZE; count++)
++ fprintf(logfile,"%d ", cmd_info.invocation_data.guid[count]);
++
++ fprintf(logfile, "\n");
++
++ if ( cmd_info.invocation_type == XEN_ACPI_WMI_EXEC_METHOD )
++ {
++ fprintf(logfile,
++ "Instance id - %d\n",
++ cmd_info.invocation_data.xen_wmi_arg.xen_wmi_method_arg.instance);
++ fprintf(logfile,
++ "Method id - %d\n",
++ cmd_info.invocation_data.xen_wmi_arg.xen_wmi_method_arg.method_id);
++ xen_acpi_wmi_print_input_buffer(
++ &cmd_info.invocation_data.xen_wmi_arg.xen_wmi_method_arg.in_buf);
++ }
++ else if ( cmd_info.invocation_type == XEN_ACPI_WMI_QUERY_OBJECT )
++ {
++ fprintf(logfile,
++ "Instance id - %d\n",
++ cmd_info.invocation_data.xen_wmi_arg.xen_wmi_query_obj_arg.instance);
++ }
++ else if ( cmd_info.invocation_type == XEN_ACPI_WMI_SET_OBJECT )
++ {
++ fprintf(logfile,
++ "Instance id - %d\n",
++ cmd_info.invocation_data.xen_wmi_arg.xen_wmi_set_obj_arg.instance);
++ xen_acpi_wmi_print_input_buffer(
++ &cmd_info.invocation_data.xen_wmi_arg.xen_wmi_set_obj_arg.in_buf);
++ }
++ else if ( cmd_info.invocation_type == XEN_ACPI_WMI_GET_EVENT_DATA )
++ {
++ fprintf(logfile,
++ "Event id - %d\n",
++ cmd_info.invocation_data.xen_wmi_arg.xen_wmi_event_data_arg.event_id);
++ }
++}
++
++/*
++ * xen_acpi_wmi_print_output_buffer
++ */
++void xen_acpi_wmi_print_output_buffer(void)
++{
++ int count;
++ xen_wmi_buffer_t *buffer = xen_acpi_wmi_get_output_buffer();
++
++ if ( buffer == NULL || buffer->copied_length == NULL || *buffer->copied_length == 0 )
++ return;
++
++ fprintf(logfile, "XEN WMI: Output buffer size is - %d\n",
++ *buffer->copied_length);
++ fprintf(logfile, "XEN WMI output buffer is - ");
++ for (count=0; count < *buffer->copied_length; count++)
++ fprintf(logfile," %d, ", ((byte *)buffer->pointer)[count]);
++
++ fprintf(logfile, "\n");
++}
++
++#endif /* XEN_ACPI_WMI_DEBUG */
++
++/*
++ * xen_acpi_wmi_execute
++ */
++void xen_acpi_wmi_execute(void)
++{
++ int request, ret;
++
++ if ( cmd_info.invocation_type == XEN_ACPI_WMI_UNDEFINED )
++ {
++ fprintf(logfile,
++ "Unable to execute command for the given invocation type!\n");
++ return;
++ }
++
++ switch ( cmd_info.invocation_type )
++ {
++ case XEN_ACPI_WMI_EXEC_METHOD:
++ request = XEN_WMI_IOCTL_CALL_METHOD;
++ break;
++ case XEN_ACPI_WMI_QUERY_OBJECT:
++ request = XEN_WMI_IOCTL_QUERY_OBJECT;
++ break;
++ case XEN_ACPI_WMI_SET_OBJECT:
++ request = XEN_WMI_IOCTL_SET_OBJECT;
++ break;
++ case XEN_ACPI_WMI_GET_EVENT_DATA:
++ request = XEN_WMI_IOCTL_GET_EVENT_DATA;
++ break;
++ default:
++ fprintf(logfile,
++ "Unable to execute command for the given invocation type!\n");
++ return;
++ }
++
++ xen_acpi_wmi_allocate_output_buffer(0);
++#ifdef XEN_ACPI_WMI_DEBUG
++ fprintf(logfile, "XEN WMI Invoking ioctl - %d\n", cmd_info.invocation_type);
++ xen_acpi_wmi_print_input_info();
++#endif
++ ret = ioctl(xen_wmi_device, request, &cmd_info.invocation_data);
++ if ( ret == XEN_WMI_BUFFER_TOO_SMALL )
++ {
++ if ( xen_acpi_wmi_reallocate_output_buffer() == XEN_WMI_SUCCESS )
++ ret = ioctl(xen_wmi_device, request, &cmd_info.invocation_data);
++ }
++
++ if ( ret != XEN_WMI_SUCCESS )
++ fprintf(logfile, "Xen WMI ioctl failed with error - %d\n", ret);
++
++#ifdef XEN_ACPI_WMI_DEBUG
++ xen_acpi_wmi_print_output_buffer();
++#endif
++
++ xen_acpi_wmi_free_input_buffer();
++}
++
++/*
++ * xen_acpi_wmi_set_event_id
++ */
++void xen_acpi_wmi_set_event_id(uint8_t event_id)
++{
++ if ( cmd_info.invocation_type != XEN_ACPI_WMI_GET_EVENT_DATA )
++ {
++ fprintf(logfile,
++ "XEN WMI: Request to set event ID with incorrect invocation type!!!\n");
++ return;
++ }
++
++ cmd_info.invocation_data.xen_wmi_arg.xen_wmi_event_data_arg.event_id = event_id;
++}
++
++/*
++ * xen_acpi_wmi_cmd_port_read
++ */
++static uint32_t xen_acpi_wmi_cmd_port_read(void *opaque, uint32_t addr)
++{
++#ifdef XEN_ACPI_WMI_DEBUG_EXT
++ fprintf(logfile, "XEN WMI: In cmd port read - %d\n",
++ cmd_info.cmd_type);
++#endif
++ return cmd_info.cmd_type;
++}
++
++/*
++ * xen_acpi_wmi_cmd_port_write
++ */
++static void xen_acpi_wmi_cmd_port_write(void *opaque, uint32_t addr, uint32_t val)
++{
++#ifdef XEN_ACPI_WMI_DEBUG_EXT
++ fprintf(logfile, "XEN WMI: In cmd port write - %d\n", val);
++#endif
++ cmd_info.cmd_type = val;
++ if ( val < XEN_ACPI_WMI_CMD_INIT || val >= XEN_ACPI_WMI_CMD_UNDEFINED )
++ {
++ fprintf(logfile,"XEN WMI: Unknown xen acpi wmi command - %d\n", val);
++ cmd_info.invocation_type = XEN_ACPI_WMI_UNDEFINED;
++ cmd_info.current_index = 0;
++ return;
++ }
++
++ if ( val == XEN_ACPI_WMI_CMD_EXECUTE )
++ xen_acpi_wmi_execute();
++}
++
++/*
++ * xen_acpi_wmi_data_port_readb
++ */
++static uint32_t xen_acpi_wmi_data_port_readb(void *opaque, uint32_t addr)
++{
++ xen_wmi_buffer_t *buffer;
++ byte ret;
++
++ if ( cmd_info.cmd_type == XEN_ACPI_WMI_CMD_OUT_BUFFER )
++ {
++ buffer = xen_acpi_wmi_get_output_buffer();
++ if ( buffer == NULL || buffer->copied_length == NULL )
++ return 0x0;
++
++ if ( *buffer->copied_length == 0 )
++ return 0x0;
++
++ if ( cmd_info.current_index >= *buffer->copied_length )
++ {
++ fprintf(logfile,
++ "XEN WMI: Output buffer index overflow. Current - %d Max - %d\n",
++ cmd_info.current_index, *buffer->copied_length);
++ cmd_info.cmd_type = XEN_ACPI_WMI_CMD_UNDEFINED;
++ return 0x0;
++ }
++
++ ret = ((byte*)buffer->pointer)[cmd_info.current_index];
++ if ( cmd_info.current_index == buffer->length-1 )
++ {
++ /* @TODO: We expect that the firmware would read all of
++ * the output buffer before releasing it. This
++ * could result in a leak if the firmware chooses
++ * to ignore the return buffer. It might make sense to
++ * introduce a cleanup command. */
++ cmd_info.cmd_type = XEN_ACPI_WMI_CMD_UNDEFINED;
++ buffer->length = 0;
++ free(buffer->pointer);
++ buffer->pointer = NULL;
++ free(buffer->copied_length);
++ buffer->copied_length = NULL;
++ }
++
++#ifdef XEN_ACPI_WMI_DEBUG_EXT
++ fprintf(logfile, "XEN WMI: Data port read returned - %d\n", ret);
++#endif
++ cmd_info.current_index++;
++ return ret;
++ }
++
++ fprintf(logfile, "XEN WMI: Data port read byte. Shouldn't be here!!!\n");
++ return 0x0;
++}
++
++/*
++ * xen_acpi_wmi_data_port_writeb
++ */
++static void xen_acpi_wmi_data_port_writeb(void *opaque, uint32_t addr, uint32_t val)
++{
++#ifdef XEN_ACPI_WMI_DEBUG_EXT
++ fprintf(logfile, "XEN WMI: In data port write byte - %d\n", val);
++#endif
++
++ switch( cmd_info.cmd_type )
++ {
++ case XEN_ACPI_WMI_CMD_INIT:
++ cmd_info.invocation_type = val;
++ cmd_info.current_index = 0;
++ memset(&cmd_info.invocation_data, 0, sizeof(cmd_info.invocation_data));
++ break;
++ case XEN_ACPI_WMI_CMD_GUID:
++ xen_acpi_wmi_set_guid(val);
++ break;
++ case XEN_ACPI_WMI_CMD_IN_BUFFER:
++ xen_acpi_wmi_set_in_buffer(val);
++ break;
++ case XEN_ACPI_WMI_CMD_EVENT_ID:
++ xen_acpi_wmi_set_event_id(val);
++ break;
++ default:
++ fprintf(logfile,
++ "XEN WMI: Attempting to write to data(byte) port with incompatible cmd type %d\n",
++ cmd_info.cmd_type);
++ break;
++ }
++}
++
++/*
++ * xen_acpi_wmi_data_port_readl
++ */
++static uint32_t xen_acpi_wmi_data_port_readl(void *opaque, uint32_t addr)
++{
++ xen_wmi_buffer_t *buffer;
++
++ if ( cmd_info.cmd_type == XEN_ACPI_WMI_CMD_OUT_BUFFER_SIZE )
++ {
++ buffer = xen_acpi_wmi_get_output_buffer();
++ if ( buffer == NULL || buffer->copied_length == NULL )
++ return 0x0;
++
++ if (*buffer->copied_length == 0 )
++ return 0x0;
++
++ cmd_info.current_index = 0;
++#ifdef XEN_ACPI_WMI_DEBUG_EXT
++ fprintf(logfile, "XEN WMI: Output buffer length is - %d\n", *buffer->copied_length);
++#endif
++ return *buffer->copied_length;
++ }
++
++ fprintf(logfile, "XEN WMI: Data port read long. Shouldn't be here!!!\n");
++ return 0x0;
++}
++
++/*
++ * xen_acpi_wmi_data_port_writel
++ */
++static void xen_acpi_wmi_data_port_writel(void *opaque, uint32_t addr, uint32_t val)
++{
++#ifdef XEN_ACPI_WMI_DEBUG_EXT
++ fprintf(logfile, "XEN WMI: In data port write long - %d\n", val);
++#endif
++
++ switch( cmd_info.cmd_type )
++ {
++ case XEN_ACPI_WMI_CMD_OBJ_INSTANCE:
++ xen_acpi_wmi_set_cmd_instance(val);
++ break;
++ case XEN_ACPI_WMI_CMD_METHOD_ID:
++ xen_acpi_wmi_set_method_id(val);
++ break;
++ case XEN_ACPI_WMI_CMD_IN_BUFFER_SIZE:
++ xen_acpi_wmi_set_in_buffer_size(val);
++ break;
++ default:
++ fprintf(logfile,
++ "XEN WMI: Attempting to write to data(long) port with incompatible cmd type %d\n",
++ cmd_info.cmd_type);
++ break;
++ }
++}
++
++/*
++ * xen_acpi_wmi_init
++ */
++void xen_acpi_wmi_init(PCIDevice *device)
++{
++ char dev_name[64];
++ char *oem_buffer;
++
++ cmd_info.invocation_type = XEN_ACPI_WMI_UNDEFINED;
++ cmd_info.current_index = 0;
++
++ oem_buffer = xenstore_device_model_read(domid, "oem_features", NULL);
++ if ( oem_buffer == NULL )
++ {
++#ifdef XEN_ACPI_WMI_DEBUG
++ fprintf(logfile,"OEM value add disabled!\n");
++#endif
++ return;
++ }
++
++ sprintf(dev_name, "/dev/%s", XEN_WMI_DEVICE_NAME);
++ xen_wmi_device = open(dev_name, 0);
++ if ( xen_wmi_device < 0 )
++ {
++ fprintf(logfile,
++ "XEN WMI: Unable to open device - %s\n", XEN_WMI_DEVICE_NAME);
++ return;
++ }
++
++ register_ioport_read(XEN_ACPI_WMI_CMD_PORT, 1, 1, xen_acpi_wmi_cmd_port_read, device);
++ register_ioport_write(XEN_ACPI_WMI_CMD_PORT, 1, 1, xen_acpi_wmi_cmd_port_write, device);
++ register_ioport_read(XEN_ACPI_WMI_DATA_PORTB, 1, 1, xen_acpi_wmi_data_port_readb, device);
++ register_ioport_write(XEN_ACPI_WMI_DATA_PORTB, 1, 1, xen_acpi_wmi_data_port_writeb, device);
++ register_ioport_read(XEN_ACPI_WMI_DATA_PORTL, 4, 4, xen_acpi_wmi_data_port_readl, device);
++ register_ioport_write(XEN_ACPI_WMI_DATA_PORTL, 4, 4, xen_acpi_wmi_data_port_writel, device);
++
++ xenstore_register_for_oem_events();
++#ifdef XEN_ACPI_WMI_DEBUG
++ fprintf(logfile, "XEN WMI: XEN ACPI WMI registration succeeded!!!\n");
++#endif
++}
++
++/*
++ * xen_acpi_wmi_cleanup(void)
++ */
++void xen_acpi_wmi_cleanup(void)
++{
++ if ( xen_wmi_device > 0 )
++ close(xen_wmi_device);
++}
++
++#else
++
++void xen_acpi_wmi_init(PCIDevice *device) { }
++void xen_acpi_wmi_cleanup(void) { }
++
++#endif /* CONFIG_NO_XEN_ACPI_WMI */
++
+diff --git a/hw/xen_acpi_wmi.h b/hw/xen_acpi_wmi.h
+new file mode 100644
+index 0000000..91e4c00
+--- /dev/null
++++ b/hw/xen_acpi_wmi.h
+@@ -0,0 +1,66 @@
++/*
++ * xen_acpi_wmi.h
++ *
++ * Copyright (c) 2009 Kamala Narasimhan
++ * Copyright (c) 2009 Citrix Systems, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef _XEN_ACPI_WMI_H
++#define _XEN_ACPI_WMI_H
++
++#ifdef CONFIG_STUBDOM
++#define CONFIG_NO_XEN_ACPI_WMI
++#endif
++
++#include "acpi-wmi.h"
++
++#define XEN_ACPI_WMI_CMD_PORT 0x96
++#define XEN_ACPI_WMI_DATA_PORTB 0x98
++#define XEN_ACPI_WMI_DATA_PORTL 0x9A
++
++/* Values written to WMI command port */
++enum XEN_ACPI_WMI_COMMAND { XEN_ACPI_WMI_CMD_INIT = 100,
++ XEN_ACPI_WMI_CMD_GUID,
++ XEN_ACPI_WMI_CMD_OBJ_INSTANCE,
++ XEN_ACPI_WMI_CMD_METHOD_ID,
++ XEN_ACPI_WMI_CMD_IN_BUFFER,
++ XEN_ACPI_WMI_CMD_IN_BUFFER_SIZE,
++ XEN_ACPI_WMI_CMD_EXECUTE,
++ XEN_ACPI_WMI_CMD_OUT_BUFFER,
++ XEN_ACPI_WMI_CMD_OUT_BUFFER_SIZE,
++ XEN_ACPI_WMI_CMD_EVENT_ID,
++ XEN_ACPI_WMI_CMD_UNDEFINED };
++
++enum XEN_ACPI_WMI_OBJ_INVOCATION_TYPE { XEN_ACPI_WMI_EXEC_METHOD = 1,
++ XEN_ACPI_WMI_QUERY_OBJECT,
++ XEN_ACPI_WMI_SET_OBJECT,
++ XEN_ACPI_WMI_GET_EVENT_DATA,
++ XEN_ACPI_WMI_UNDEFINED };
++
++typedef struct xen_acpi_wmi_cmd_info {
++ enum XEN_ACPI_WMI_COMMAND cmd_type;
++ enum XEN_ACPI_WMI_OBJ_INVOCATION_TYPE invocation_type;
++ xen_wmi_obj_invocation_data_t invocation_data;
++ uint32_t current_index;
++} xen_acpi_wmi_cmd_info_t;
++
++void xen_acpi_wmi_init(PCIDevice *device);
++void xen_acpi_wmi_cleanup(void);
++
++#endif /* _XEN_ACPI_WMI_H */
++
++
+diff --git a/qemu-xen.h b/qemu-xen.h
+index 61c0f25..81a2e33 100644
+--- a/qemu-xen.h
++++ b/qemu-xen.h
+@@ -118,6 +118,7 @@ int xenstore_refresh_battery_status(void);
+ void xenstore_register_for_pm_events(void);
+ int xenstore_read_ac_adapter_state(void);
+ int xenstore_read_lid_state(void);
++void xenstore_register_for_oem_events(void);
+ int xenstore_pv_driver_build_blacklisted(uint16_t product_number,
+ uint32_t build_nr);
+
+diff --git a/xen-hooks.mak b/xen-hooks.mak
+index d52e99d..cdf7b59 100644
+--- a/xen-hooks.mak
++++ b/xen-hooks.mak
+@@ -35,6 +35,7 @@ OBJS += exec-dm.o
+ OBJS += pci_emulation.o
+ OBJS += helper2.o
+ OBJS += battery_mgmt.o
++OBJS += xen_acpi_wmi.o
+ OBJS += dom0_driver.o
+ OBJS += hid-linux.o
+ OBJS += intel.o
+diff --git a/xenstore.c b/xenstore.c
+index 3fa6115..5c33301 100644
+--- a/xenstore.c
++++ b/xenstore.c
+@@ -978,6 +978,11 @@ void xenstore_process_event(void *opaque)
+ goto out;
+ }
+
++ if (!strcmp(vec[XS_WATCH_TOKEN], "oemevt")) {
++ acpi_oem_event();
++ goto out;
++ }
++
+ if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
+ xenstore_process_logdirty_event();
+ goto out;
+@@ -1714,6 +1719,11 @@ void xenstore_register_for_pm_events(void)
+ xs_watch(xsh, "/pm/events/powerbuttonpressed", "pwrbuttonpressedevt");
+ }
+
++void xenstore_register_for_oem_events(void)
++{
++ xs_watch(xsh, "/oem/event", "oemevt");
++}
++
+ int xenstore_read_ac_adapter_state(void)
+ {
+ int ac_state = 1;
--- /dev/null
+diff --git a/hw/piix4acpi.c b/hw/piix4acpi.c
+index 3e7a7d6..5383032 100644
+--- a/hw/piix4acpi.c
++++ b/hw/piix4acpi.c
+@@ -198,6 +198,7 @@ static void acpi_map(PCIDevice *pci_dev, int region_num,
+
+ battery_mgmt_init(pci_dev);
+ xen_acpi_wmi_init(pci_dev);
++ thermal_mgmt_init(pci_dev);
+ }
+
+ static inline int test_bit(uint8_t *map, int bit)
+diff --git a/hw/thermal_mgmt.c b/hw/thermal_mgmt.c
+new file mode 100644
+index 0000000..649b622
+--- /dev/null
++++ b/hw/thermal_mgmt.c
+@@ -0,0 +1,79 @@
++/*
++ * thermal_mgmt.c
++ *
++ * Copyright (c) 2009 Kamala Narasimhan
++ * Copyright (c) 2009 Citrix Systems, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/* Implementation Notes: Following provides a minimal thermal zone implementation for
++ * HVM guest. The vACPI layer exposes a single thermal zone with critical and current
++ * temperature objects which when invoked relies on the below to return back the critical
++ * and current temperature provided by the underlying firmware.
++ */
++
++#include "hw.h"
++#include "pc.h"
++#include "qemu-xen.h"
++#include "isa.h"
++#include "thermal_mgmt.h"
++
++#ifndef CONFIG_NO_THERMAL_MGMT
++
++/* #define THERMAL_MGMT_DBG */
++
++extern FILE *logfile;
++
++static uint32_t thermal_port_1_readw(void *opaque, uint32_t addr)
++{
++ int current_temp;
++
++ xenstore_refresh_thermal_info();
++ current_temp = xenstore_read_current_temperature();
++#ifdef THERMAL_MGMT_DBG
++ fprintf(logfile, "Current temperature - %d\n", current_temp);
++#endif
++ return current_temp;
++}
++
++static uint32_t thermal_port_2_readw(void *opaque, uint32_t addr)
++{
++ int critical_temp;
++
++ xenstore_refresh_thermal_info();
++ critical_temp = xenstore_read_critical_temperature();
++#ifdef THERMAL_MGMT_DBG
++ fprintf(logfile, "Critical trip point temperature - %d\n", critical_temp);
++#endif
++ return critical_temp;
++}
++
++void thermal_mgmt_init(PCIDevice *device)
++{
++#ifdef THERMAL_MGMT_DBG
++ fprintf(logfile, "In thermal management init\n");
++#endif
++
++ register_ioport_read(THERMAL_PORT_1, 1, 2, thermal_port_1_readw, device);
++ register_ioport_read(THERMAL_PORT_2, 1, 2, thermal_port_2_readw, device);
++}
++
++#else
++
++void thermal_mgmt_init(PCIDevice *device) { }
++
++#endif
++
+diff --git a/hw/thermal_mgmt.h b/hw/thermal_mgmt.h
+new file mode 100644
+index 0000000..d83273b
+--- /dev/null
++++ b/hw/thermal_mgmt.h
+@@ -0,0 +1,35 @@
++/*
++ * thermal_mgmt.h
++ *
++ * Copyright (c) 2009 Kamala Narasimhan
++ * Copyright (c) 2009 Citrix Systems, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef _THERMAL_MGMT_H
++#define _THERMAL_MGMT_H
++
++#ifdef CONFIG_STUBDOM
++#define CONFIG_NO_THERMAL_MGMT
++#endif
++
++#define THERMAL_PORT_1 0x90
++#define THERMAL_PORT_2 0x92
++
++void thermal_mgmt_init(PCIDevice *device);
++
++#endif
++
+diff --git a/qemu-xen.h b/qemu-xen.h
+index 81a2e33..1410d4f 100644
+--- a/qemu-xen.h
++++ b/qemu-xen.h
+@@ -115,9 +115,12 @@ char *xenstore_vm_read(int domid, const char *key, unsigned int *len);
+ char *xenstore_device_model_read(int domid, const char *key, unsigned int *len);
+ char *xenstore_read_battery_data(int battery_status);
+ int xenstore_refresh_battery_status(void);
++int xenstore_refresh_thermal_info(void);
+ void xenstore_register_for_pm_events(void);
+ int xenstore_read_ac_adapter_state(void);
+ int xenstore_read_lid_state(void);
++int xenstore_read_current_temperature(void);
++int xenstore_read_critical_temperature(void);
+ void xenstore_register_for_oem_events(void);
+ int xenstore_pv_driver_build_blacklisted(uint16_t product_number,
+ uint32_t build_nr);
+diff --git a/xen-hooks.mak b/xen-hooks.mak
+index cdf7b59..55dd477 100644
+--- a/xen-hooks.mak
++++ b/xen-hooks.mak
+@@ -36,6 +36,7 @@ OBJS += pci_emulation.o
+ OBJS += helper2.o
+ OBJS += battery_mgmt.o
+ OBJS += xen_acpi_wmi.o
++OBJS += thermal_mgmt.o
+ OBJS += dom0_driver.o
+ OBJS += hid-linux.o
+ OBJS += intel.o
+diff --git a/xenstore.c b/xenstore.c
+index 9e5d904..690b78e 100644
+--- a/xenstore.c
++++ b/xenstore.c
+@@ -1379,6 +1379,20 @@ static char *xenstore_extended_power_mgmt_read(const char *key, unsigned int *le
+ return value;
+ }
+
++int xenstore_extended_power_mgmt_read_int(char *key, int default_value)
++{
++ int value = default_value;
++ char *buffer;
++
++ buffer = xenstore_extended_power_mgmt_read(key, NULL);
++ if ( buffer == NULL )
++ return value;
++
++ value = strtoull(buffer, NULL, 10);
++ free(buffer);
++ return value;
++}
++
+ static int xenstore_extended_power_mgmt_write(const char *key, const char *value)
+ {
+ int ret;
+@@ -1431,6 +1445,11 @@ int xenstore_refresh_battery_status(void)
+ return xenstore_extended_power_mgmt_event_trigger("refreshbatterystatus", "1");
+ }
+
++int xenstore_refresh_thermal_info(void)
++{
++ return xenstore_extended_power_mgmt_event_trigger("refreshthermalinfo", "1");
++}
++
+ /*
+ * Create a store entry for a device (e.g., monitor, serial/parallel lines).
+ * The entry is <domain-path><storeString>/tty and the value is the name
+@@ -1731,28 +1750,21 @@ void xenstore_register_for_oem_events(void)
+
+ int xenstore_read_ac_adapter_state(void)
+ {
+- int ac_state = 1;
+- char *buffer;
+-
+- buffer = xenstore_extended_power_mgmt_read("ac_adapter", NULL);
+- if ( buffer == NULL )
+- return ac_state;
+-
+- ac_state = strtoull(buffer, NULL, 10);
+- free(buffer);
+- return ac_state;
++ return xenstore_extended_power_mgmt_read_int("ac_adapter", 1);
+ }
+
+ int xenstore_read_lid_state(void)
+ {
+- int lid_state = 1;
+- char * buffer;
++ return xenstore_extended_power_mgmt_read_int("lid_state", 1);
++}
+
+- buffer = xenstore_extended_power_mgmt_read("lid_state", NULL);
+- if ( buffer == NULL )
+- return lid_state;
++int xenstore_read_current_temperature(void)
++{
++ return xenstore_extended_power_mgmt_read_int("current_temperature", 0);
++}
+
+- lid_state = strtoull(buffer, NULL, 10);
+- free(buffer);
+- return lid_state;
++int xenstore_read_critical_temperature(void)
++{
++ return xenstore_extended_power_mgmt_read_int("critical_temperature", 100);
+ }
++