aboutsummaryrefslogtreecommitdiffstats
path: root/target-i386/hax-windows.c
diff options
context:
space:
mode:
authorJun Nakajima <jun.nakajima@intel.com>2011-12-17 19:22:12 -0800
committerJiang, Yunhong <yunhong.jiang@intel.com>2012-01-17 06:15:11 +0800
commite4a3c7801e0075a49674c79972394ad962b338f2 (patch)
treec8f2463b26574e3b07cd1d5fa1b02820575d34e1 /target-i386/hax-windows.c
parenta381ef07088ce479610129e37bfef42538f397da (diff)
downloadexternal_qemu-e4a3c7801e0075a49674c79972394ad962b338f2.zip
external_qemu-e4a3c7801e0075a49674c79972394ad962b338f2.tar.gz
external_qemu-e4a3c7801e0075a49674c79972394ad962b338f2.tar.bz2
New files to add HAX support
QEMU emulator interacts with the HAX kernel module. A HAX (Hardware-based Accelerated eXecution) kernel module is required to use HAX support. Most guest instructions run in VMX non-root (i.e. in hardware) mode and achieve near-native (relative to the host) performance. QEMU still emulates PIO/MMIO instructions and non-PG (paging) mode operations. HAX is supported only on Mac OS X and Windows hosts when Intel VT is present. Change-Id: I8dd52a35e315437dc568f555742bb8ab7e9d8ab2 Signed-off-by: Zhang, Xiantao <xiantao.zhang@intel.com> Signed-off-by: Xin, Xiaohui <xiaohui.xin@intel.com> Signed-off-by: Jiang Yunhong <yunhong.jiang@intel.com> Signed-off-by: Nakajima, Jun <jun.nakajima@intel.com>
Diffstat (limited to 'target-i386/hax-windows.c')
-rw-r--r--target-i386/hax-windows.c466
1 files changed, 466 insertions, 0 deletions
diff --git a/target-i386/hax-windows.c b/target-i386/hax-windows.c
new file mode 100644
index 0000000..683a227
--- /dev/null
+++ b/target-i386/hax-windows.c
@@ -0,0 +1,466 @@
+/*
+** Copyright (c) 2011, Intel Corporation
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+#include "target-i386/hax-i386.h"
+
+/*
+ * return 0 upon success, -1 when the driver is not loaded,
+ * other negative value for other failures
+ */
+static int hax_open_device(hax_fd *fd)
+{
+ uint32_t errNum = 0;
+ HANDLE hDevice;
+
+ if (!fd)
+ return -2;
+
+ hDevice = CreateFile( "\\\\.\\HAX",
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hDevice == INVALID_HANDLE_VALUE)
+ {
+ dprint("Failed to open the HAX device!\n");
+ errNum = GetLastError();
+ if (errNum == ERROR_FILE_NOT_FOUND)
+ return -1;
+ return -2;
+ }
+ *fd = hDevice;
+ dprint("device fd:%d\n", *fd);
+ return 0;
+}
+
+
+hax_fd hax_mod_open(void)
+{
+ int ret;
+ hax_fd fd;
+
+ ret = hax_open_device(&fd);
+ if (ret != 0)
+ dprint("Open HAX device failed\n");
+
+ return fd;
+}
+
+int hax_populate_ram(uint64_t va, uint32_t size)
+{
+ int ret;
+ struct hax_alloc_ram_info info;
+ HANDLE hDeviceVM;
+ DWORD dSize = 0;
+
+ if (!hax_global.vm || !hax_global.vm->fd)
+ {
+ dprint("Allocate memory before vm create?\n");
+ return -EINVAL;
+ }
+
+ info.size = size;
+ info.va = va;
+
+ hDeviceVM = hax_global.vm->fd;
+
+ ret = DeviceIoControl(hDeviceVM,
+ HAX_VM_IOCTL_ALLOC_RAM,
+ &info, sizeof(info),
+ NULL, 0,
+ &dSize,
+ (LPOVERLAPPED) NULL);
+
+ if (!ret) {
+ dprint("Failed to allocate %x memory\n", size);
+ return ret;
+ }
+
+ return 0;
+}
+
+
+int hax_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, ram_addr_t phys_offset)
+{
+ struct hax_set_ram_info info, *pinfo = &info;
+ ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
+ HANDLE hDeviceVM;
+ DWORD dSize = 0;
+ int ret = 0;
+
+ /* We look for the RAM and ROM only */
+ if (flags >= IO_MEM_UNASSIGNED)
+ return 0;
+
+ if ( (start_addr & ~TARGET_PAGE_MASK) || (size & ~TARGET_PAGE_MASK))
+ {
+ dprint(
+ "set_phys_mem %x %lx requires page aligned addr and size\n",
+ start_addr, size);
+ return -1;
+ }
+
+ info.pa_start = start_addr;
+ info.size = size;
+ info.va = (uint64_t)qemu_get_ram_ptr(phys_offset);
+ info.flags = (flags & IO_MEM_ROM) ? 1 : 0;
+
+ hDeviceVM = hax_global.vm->fd;
+
+ ret = DeviceIoControl(hDeviceVM,
+ HAX_VM_IOCTL_SET_RAM,
+ pinfo, sizeof(*pinfo),
+ NULL, 0,
+ &dSize,
+ (LPOVERLAPPED) NULL);
+
+ if (!ret)
+ return -EFAULT;
+ else
+ return 0;
+}
+
+int hax_mod_version(struct hax_state *hax, struct hax_module_version *version)
+{
+ int ret;
+ HANDLE hDevice = hax->fd; //handle to hax module
+ DWORD dSize = 0;
+ DWORD err = 0;
+
+ if (hax_invalid_fd(hDevice)) {
+ dprint("Invalid fd for hax device!\n");
+ return -ENODEV;
+ }
+
+ ret = DeviceIoControl(hDevice,
+ HAX_IOCTL_VERSION,
+ NULL, 0,
+ version, sizeof(*version),
+ &dSize,
+ (LPOVERLAPPED) NULL);
+
+ if (!ret) {
+ err = GetLastError();
+ if (err == ERROR_INSUFFICIENT_BUFFER ||
+ err == ERROR_MORE_DATA)
+ dprint("HAX module is too large.\n");
+ dprint("Failed to get Hax module version:%d\n", err);
+ return -EFAULT;
+ } else
+ return 0;
+}
+
+static char *hax_vm_devfs_string(int vm_id)
+{
+ char *name;
+
+ if (vm_id > MAX_VM_ID)
+ {
+ dprint("Too big VM id\n");
+ return NULL;
+ }
+
+ name = qemu_strdup("\\\\.\\hax_vmxx");
+ if (!name)
+ return NULL;
+ sprintf(name, "\\\\.\\hax_vm%02d", vm_id);
+
+ return name;
+}
+
+static char *hax_vcpu_devfs_string(int vm_id, int vcpu_id)
+{
+ char *name;
+
+ if (vm_id > MAX_VM_ID || vcpu_id > MAX_VCPU_ID)
+ {
+ dprint("Too big vm id %x or vcpu id %x\n", vm_id, vcpu_id);
+ return NULL;
+ }
+ name = qemu_strdup("\\\\.\\hax_vmxx_vcpuxx");
+ if (!name)
+ return NULL;
+ sprintf(name, "\\\\.\\hax_vm%02d_vcpu%02d", vm_id, vcpu_id);
+
+ return name;
+}
+
+int hax_host_create_vm(struct hax_state *hax, int vm_id)
+{
+ int ret;
+ DWORD dSize = 0;
+
+ if (hax_invalid_fd(hax->fd))
+ return -EINVAL;
+
+ if (hax->vm)
+ return 0;
+
+ ret = DeviceIoControl(hax->fd,
+ HAX_IOCTL_CREATE_VM,
+ NULL, 0,
+ &vm_id, sizeof(vm_id),
+ &dSize,
+ (LPOVERLAPPED) NULL);
+ if (!ret) {
+ dprint("error code:%d", GetLastError());
+ return -1;
+ }
+
+ return 0;
+}
+
+hax_fd hax_host_open_vm(struct hax_state *hax, int vm_id)
+{
+ char *vm_name = NULL;
+ hax_fd hDeviceVM;
+
+ vm_name = hax_vm_devfs_string(vm_id);
+ if (!vm_name) {
+ dprint("Incorrect name\n");
+ return INVALID_HANDLE_VALUE;
+ }
+
+ hDeviceVM = CreateFile(vm_name,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hDeviceVM == INVALID_HANDLE_VALUE)
+ dprint("Open the vm devcie error:%s, ec:%d\n", vm_name, GetLastError());
+
+ qemu_free(vm_name);
+ return hDeviceVM;
+}
+
+int hax_host_create_vcpu(hax_fd vm_fd, int vcpuid)
+{
+ int ret;
+ DWORD dSize = 0;
+
+ ret = DeviceIoControl(vm_fd,
+ HAX_VM_IOCTL_VCPU_CREATE,
+ &vcpuid, sizeof(vcpuid),
+ NULL, 0,
+ &dSize,
+ (LPOVERLAPPED) NULL);
+ if (!ret)
+ {
+ dprint("Failed to create vcpu %x\n", vcpuid);
+ return -1;
+ }
+
+ return 0;
+}
+
+hax_fd hax_host_open_vcpu(int vmid, int vcpuid)
+{
+ char *devfs_path = NULL;
+ hax_fd hDeviceVCPU;
+
+ devfs_path = hax_vcpu_devfs_string(vmid, vcpuid);
+ if (!devfs_path)
+ {
+ dprint("Failed to get the devfs\n");
+ return INVALID_HANDLE_VALUE;
+ }
+
+ hDeviceVCPU = CreateFile( devfs_path,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hDeviceVCPU == INVALID_HANDLE_VALUE)
+ dprint("Failed to open the vcpu devfs\n");
+ qemu_free(devfs_path);
+ return hDeviceVCPU;
+}
+
+int hax_host_setup_vcpu_channel(struct hax_vcpu_state *vcpu)
+{
+ hax_fd hDeviceVCPU = vcpu->fd;
+ int ret;
+ struct hax_tunnel_info info;
+ DWORD dSize = 0;
+
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_IOCTL_SETUP_TUNNEL,
+ NULL, 0,
+ &info, sizeof(info),
+ &dSize,
+ (LPOVERLAPPED) NULL);
+ if (!ret)
+ {
+ dprint("Failed to setup the hax tunnel\n");
+ return -1;
+ }
+
+ if (!valid_hax_tunnel_size(info.size))
+ {
+ dprint("Invalid hax tunnel size %x\n", info.size);
+ ret = -EINVAL;
+ return ret;
+ }
+ vcpu->tunnel = (struct hax_tunnel *)(info.va);
+ vcpu->iobuf = (unsigned char *)(info.io_va);
+ return 0;
+}
+
+int hax_vcpu_run(struct hax_vcpu_state* vcpu)
+{
+ int ret;
+ HANDLE hDeviceVCPU = vcpu->fd;
+ DWORD dSize = 0;
+
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_IOCTL_RUN,
+ NULL, 0,
+ NULL, 0,
+ &dSize,
+ (LPOVERLAPPED) NULL);
+ if (!ret)
+ return -EFAULT;
+ else
+ return 0;
+}
+
+int hax_sync_fpu(CPUState *env, struct fx_layout *fl, int set)
+{
+ int ret;
+ hax_fd fd;
+ HANDLE hDeviceVCPU;
+ DWORD dSize = 0;
+
+ fd = hax_vcpu_get_fd(env);
+ if (hax_invalid_fd(fd))
+ return -1;
+
+ hDeviceVCPU = fd;
+
+ if (set)
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_IOCTL_SET_FPU,
+ fl, sizeof(*fl),
+ NULL, 0,
+ &dSize,
+ (LPOVERLAPPED) NULL);
+ else
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_IOCTL_GET_FPU,
+ NULL, 0,
+ fl, sizeof(*fl),
+ &dSize,
+ (LPOVERLAPPED) NULL);
+ if (!ret)
+ return -EFAULT;
+ else
+ return 0;
+}
+
+int hax_sync_msr(CPUState *env, struct hax_msr_data *msrs, int set)
+{
+ int ret;
+ hax_fd fd;
+ HANDLE hDeviceVCPU;
+ DWORD dSize = 0;
+
+ fd = hax_vcpu_get_fd(env);
+ if (hax_invalid_fd(fd))
+ return -1;
+ hDeviceVCPU = fd;
+
+ if (set)
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_IOCTL_SET_MSRS,
+ msrs, sizeof(*msrs),
+ msrs, sizeof(*msrs),
+ &dSize,
+ (LPOVERLAPPED) NULL);
+ else
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_IOCTL_GET_MSRS,
+ msrs, sizeof(*msrs),
+ msrs, sizeof(*msrs),
+ &dSize,
+ (LPOVERLAPPED) NULL);
+ if (!ret)
+ return -EFAULT;
+ else
+ return 0;
+}
+
+int hax_sync_vcpu_state(CPUState *env, struct vcpu_state_t *state, int set)
+{
+ int ret;
+ hax_fd fd;
+ HANDLE hDeviceVCPU;
+ DWORD dSize;
+
+ fd = hax_vcpu_get_fd(env);
+ if (hax_invalid_fd(fd))
+ return -1;
+
+ hDeviceVCPU = fd;
+
+ if (set)
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_SET_REGS,
+ state, sizeof(*state),
+ NULL, 0,
+ &dSize,
+ (LPOVERLAPPED) NULL);
+ else
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_GET_REGS,
+ NULL, 0,
+ state, sizeof(*state),
+ &dSize,
+ (LPOVERLAPPED) NULL);
+ if (!ret)
+ return -EFAULT;
+ else
+ return 0;
+}
+
+int hax_inject_interrupt(CPUState *env, int vector)
+{
+ int ret;
+ hax_fd fd;
+ HANDLE hDeviceVCPU;
+ DWORD dSize;
+
+ fd = hax_vcpu_get_fd(env);
+ if (hax_invalid_fd(fd))
+ return -1;
+
+ hDeviceVCPU = fd;
+
+ ret = DeviceIoControl(hDeviceVCPU,
+ HAX_VCPU_IOCTL_INTERRUPT,
+ &vector, sizeof(vector),
+ NULL, 0,
+ &dSize,
+ (LPOVERLAPPED) NULL);
+ if (!ret)
+ return -EFAULT;
+ else
+ return 0;
+}