/* ** 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 = INVALID_HANDLE_VALUE; ret = hax_open_device(&fd); if (ret != 0) { dprint("Open HAX device failed\n"); return INVALID_HANDLE_VALUE; } 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("HAX: Failed to allocate %x memory (address %llx)\n", size, (unsigned long long)va); return -1; } return 0; } int hax_set_phys_mem(hwaddr 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)(uintptr_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_capability(struct hax_state *hax, struct hax_capabilityinfo *cap) { 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_CAPABILITY, NULL, 0, cap, sizeof(*cap), &dSize, (LPOVERLAPPED) NULL); if (!ret) { err = GetLastError(); if (err == ERROR_INSUFFICIENT_BUFFER || err == ERROR_MORE_DATA) dprint("hax capability is too long to hold.\n"); dprint("Failed to get Hax capability:%d\n", err); 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 = g_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 = g_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 *vmid) { int ret; int vm_id = 0; 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; } *vmid = vm_id; 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()); g_free(vm_name); return hDeviceVM; } int hax_notify_qemu_version(hax_fd vm_fd, struct hax_qemu_version *qversion) { int ret; DWORD dSize = 0; if (hax_invalid_fd(vm_fd)) return -EINVAL; ret = DeviceIoControl(vm_fd, HAX_VM_IOCTL_NOTIFY_QEMU_VERSION, qversion, sizeof(struct hax_qemu_version), NULL, 0, &dSize, (LPOVERLAPPED) NULL); if (!ret) { dprint("Failed to notify qemu API version\n"); return -1; } return 0; } 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"); g_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 *)(uintptr_t)(info.va); vcpu->iobuf = (unsigned char *)(uintptr_t)(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 *cpu, struct fx_layout *fl, int set) { int ret; hax_fd fd; HANDLE hDeviceVCPU; DWORD dSize = 0; fd = hax_vcpu_get_fd(cpu); 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 *cpu, struct hax_msr_data *msrs, int set) { int ret; hax_fd fd; HANDLE hDeviceVCPU; DWORD dSize = 0; fd = hax_vcpu_get_fd(cpu); 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 *cpu, struct vcpu_state_t *state, int set) { int ret; hax_fd fd; HANDLE hDeviceVCPU; DWORD dSize; fd = hax_vcpu_get_fd(cpu); 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 *cpu, int vector) { int ret; hax_fd fd; HANDLE hDeviceVCPU; DWORD dSize; fd = hax_vcpu_get_fd(cpu); 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; }