hax-windows.c (12483B)
1/* 2 * QEMU HAXM support 3 * 4 * Copyright (c) 2011 Intel Corporation 5 * Written by: 6 * Jiang Yunhong<yunhong.jiang@intel.com> 7 * 8 * This work is licensed under the terms of the GNU GPL, version 2 or later. 9 * See the COPYING file in the top-level directory. 10 * 11 */ 12 13#include "qemu/osdep.h" 14#include "cpu.h" 15#include "hax-accel-ops.h" 16 17/* 18 * return 0 when success, -1 when driver not loaded, 19 * other negative value for other failure 20 */ 21static int hax_open_device(hax_fd *fd) 22{ 23 uint32_t errNum = 0; 24 HANDLE hDevice; 25 26 if (!fd) { 27 return -2; 28 } 29 30 hDevice = CreateFile("\\\\.\\HAX", 31 GENERIC_READ | GENERIC_WRITE, 32 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 33 34 if (hDevice == INVALID_HANDLE_VALUE) { 35 fprintf(stderr, "Failed to open the HAX device!\n"); 36 errNum = GetLastError(); 37 if (errNum == ERROR_FILE_NOT_FOUND) { 38 return -1; 39 } 40 return -2; 41 } 42 *fd = hDevice; 43 return 0; 44} 45 46/* hax_fd hax_mod_open */ 47 hax_fd hax_mod_open(void) 48{ 49 int ret; 50 hax_fd fd = NULL; 51 52 ret = hax_open_device(&fd); 53 if (ret != 0) { 54 fprintf(stderr, "Open HAX device failed\n"); 55 } 56 57 return fd; 58} 59 60int hax_populate_ram(uint64_t va, uint64_t size) 61{ 62 int ret; 63 HANDLE hDeviceVM; 64 DWORD dSize = 0; 65 66 if (!hax_global.vm || !hax_global.vm->fd) { 67 fprintf(stderr, "Allocate memory before vm create?\n"); 68 return -EINVAL; 69 } 70 71 hDeviceVM = hax_global.vm->fd; 72 if (hax_global.supports_64bit_ramblock) { 73 struct hax_ramblock_info ramblock = { 74 .start_va = va, 75 .size = size, 76 .reserved = 0 77 }; 78 79 ret = DeviceIoControl(hDeviceVM, 80 HAX_VM_IOCTL_ADD_RAMBLOCK, 81 &ramblock, sizeof(ramblock), NULL, 0, &dSize, 82 (LPOVERLAPPED) NULL); 83 } else { 84 struct hax_alloc_ram_info info = { 85 .size = (uint32_t) size, 86 .pad = 0, 87 .va = va 88 }; 89 90 ret = DeviceIoControl(hDeviceVM, 91 HAX_VM_IOCTL_ALLOC_RAM, 92 &info, sizeof(info), NULL, 0, &dSize, 93 (LPOVERLAPPED) NULL); 94 } 95 96 if (!ret) { 97 fprintf(stderr, "Failed to register RAM block: va=0x%" PRIx64 98 ", size=0x%" PRIx64 ", method=%s\n", va, size, 99 hax_global.supports_64bit_ramblock ? "new" : "legacy"); 100 return ret; 101 } 102 103 return 0; 104} 105 106int hax_set_ram(uint64_t start_pa, uint32_t size, uint64_t host_va, int flags) 107{ 108 struct hax_set_ram_info info; 109 HANDLE hDeviceVM = hax_global.vm->fd; 110 DWORD dSize = 0; 111 int ret; 112 113 info.pa_start = start_pa; 114 info.size = size; 115 info.va = host_va; 116 info.flags = (uint8_t) flags; 117 118 ret = DeviceIoControl(hDeviceVM, HAX_VM_IOCTL_SET_RAM, 119 &info, sizeof(info), NULL, 0, &dSize, 120 (LPOVERLAPPED) NULL); 121 122 if (!ret) { 123 return -EFAULT; 124 } else { 125 return 0; 126 } 127} 128 129int hax_capability(struct hax_state *hax, struct hax_capabilityinfo *cap) 130{ 131 int ret; 132 HANDLE hDevice = hax->fd; /* handle to hax module */ 133 DWORD dSize = 0; 134 DWORD err = 0; 135 136 if (hax_invalid_fd(hDevice)) { 137 fprintf(stderr, "Invalid fd for hax device!\n"); 138 return -ENODEV; 139 } 140 141 ret = DeviceIoControl(hDevice, HAX_IOCTL_CAPABILITY, NULL, 0, cap, 142 sizeof(*cap), &dSize, (LPOVERLAPPED) NULL); 143 144 if (!ret) { 145 err = GetLastError(); 146 if (err == ERROR_INSUFFICIENT_BUFFER || err == ERROR_MORE_DATA) { 147 fprintf(stderr, "hax capability is too long to hold.\n"); 148 } 149 fprintf(stderr, "Failed to get Hax capability:%luu\n", err); 150 return -EFAULT; 151 } else { 152 return 0; 153 } 154} 155 156int hax_mod_version(struct hax_state *hax, struct hax_module_version *version) 157{ 158 int ret; 159 HANDLE hDevice = hax->fd; /* handle to hax module */ 160 DWORD dSize = 0; 161 DWORD err = 0; 162 163 if (hax_invalid_fd(hDevice)) { 164 fprintf(stderr, "Invalid fd for hax device!\n"); 165 return -ENODEV; 166 } 167 168 ret = DeviceIoControl(hDevice, 169 HAX_IOCTL_VERSION, 170 NULL, 0, 171 version, sizeof(*version), &dSize, 172 (LPOVERLAPPED) NULL); 173 174 if (!ret) { 175 err = GetLastError(); 176 if (err == ERROR_INSUFFICIENT_BUFFER || err == ERROR_MORE_DATA) { 177 fprintf(stderr, "hax module verion is too long to hold.\n"); 178 } 179 fprintf(stderr, "Failed to get Hax module version:%lu\n", err); 180 return -EFAULT; 181 } else { 182 return 0; 183 } 184} 185 186static char *hax_vm_devfs_string(int vm_id) 187{ 188 return g_strdup_printf("\\\\.\\hax_vm%02d", vm_id); 189} 190 191static char *hax_vcpu_devfs_string(int vm_id, int vcpu_id) 192{ 193 return g_strdup_printf("\\\\.\\hax_vm%02d_vcpu%02d", vm_id, vcpu_id); 194} 195 196int hax_host_create_vm(struct hax_state *hax, int *vmid) 197{ 198 int ret; 199 int vm_id = 0; 200 DWORD dSize = 0; 201 202 if (hax_invalid_fd(hax->fd)) { 203 return -EINVAL; 204 } 205 206 if (hax->vm) { 207 return 0; 208 } 209 210 ret = DeviceIoControl(hax->fd, 211 HAX_IOCTL_CREATE_VM, 212 NULL, 0, &vm_id, sizeof(vm_id), &dSize, 213 (LPOVERLAPPED) NULL); 214 if (!ret) { 215 fprintf(stderr, "Failed to create VM. Error code: %lu\n", 216 GetLastError()); 217 return -1; 218 } 219 *vmid = vm_id; 220 return 0; 221} 222 223hax_fd hax_host_open_vm(struct hax_state *hax, int vm_id) 224{ 225 char *vm_name = NULL; 226 hax_fd hDeviceVM; 227 228 vm_name = hax_vm_devfs_string(vm_id); 229 if (!vm_name) { 230 fprintf(stderr, "Failed to open VM. VM name is null\n"); 231 return INVALID_HANDLE_VALUE; 232 } 233 234 hDeviceVM = CreateFile(vm_name, 235 GENERIC_READ | GENERIC_WRITE, 236 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 237 if (hDeviceVM == INVALID_HANDLE_VALUE) { 238 fprintf(stderr, "Open the vm device error:%s, ec:%lu\n", 239 vm_name, GetLastError()); 240 } 241 242 g_free(vm_name); 243 return hDeviceVM; 244} 245 246int hax_notify_qemu_version(hax_fd vm_fd, struct hax_qemu_version *qversion) 247{ 248 int ret; 249 DWORD dSize = 0; 250 if (hax_invalid_fd(vm_fd)) { 251 return -EINVAL; 252 } 253 ret = DeviceIoControl(vm_fd, 254 HAX_VM_IOCTL_NOTIFY_QEMU_VERSION, 255 qversion, sizeof(struct hax_qemu_version), 256 NULL, 0, &dSize, (LPOVERLAPPED) NULL); 257 if (!ret) { 258 fprintf(stderr, "Failed to notify qemu API version\n"); 259 return -1; 260 } 261 return 0; 262} 263 264int hax_host_create_vcpu(hax_fd vm_fd, int vcpuid) 265{ 266 int ret; 267 DWORD dSize = 0; 268 269 ret = DeviceIoControl(vm_fd, 270 HAX_VM_IOCTL_VCPU_CREATE, 271 &vcpuid, sizeof(vcpuid), NULL, 0, &dSize, 272 (LPOVERLAPPED) NULL); 273 if (!ret) { 274 fprintf(stderr, "Failed to create vcpu %x\n", vcpuid); 275 return -1; 276 } 277 278 return 0; 279} 280 281hax_fd hax_host_open_vcpu(int vmid, int vcpuid) 282{ 283 char *devfs_path = NULL; 284 hax_fd hDeviceVCPU; 285 286 devfs_path = hax_vcpu_devfs_string(vmid, vcpuid); 287 if (!devfs_path) { 288 fprintf(stderr, "Failed to get the devfs\n"); 289 return INVALID_HANDLE_VALUE; 290 } 291 292 hDeviceVCPU = CreateFile(devfs_path, 293 GENERIC_READ | GENERIC_WRITE, 294 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 295 NULL); 296 297 if (hDeviceVCPU == INVALID_HANDLE_VALUE) { 298 fprintf(stderr, "Failed to open the vcpu devfs\n"); 299 } 300 g_free(devfs_path); 301 return hDeviceVCPU; 302} 303 304int hax_host_setup_vcpu_channel(struct hax_vcpu_state *vcpu) 305{ 306 hax_fd hDeviceVCPU = vcpu->fd; 307 int ret; 308 struct hax_tunnel_info info; 309 DWORD dSize = 0; 310 311 ret = DeviceIoControl(hDeviceVCPU, 312 HAX_VCPU_IOCTL_SETUP_TUNNEL, 313 NULL, 0, &info, sizeof(info), &dSize, 314 (LPOVERLAPPED) NULL); 315 if (!ret) { 316 fprintf(stderr, "Failed to setup the hax tunnel\n"); 317 return -1; 318 } 319 320 if (!valid_hax_tunnel_size(info.size)) { 321 fprintf(stderr, "Invalid hax tunnel size %x\n", info.size); 322 ret = -EINVAL; 323 return ret; 324 } 325 vcpu->tunnel = (struct hax_tunnel *) (intptr_t) (info.va); 326 vcpu->iobuf = (unsigned char *) (intptr_t) (info.io_va); 327 return 0; 328} 329 330int hax_vcpu_run(struct hax_vcpu_state *vcpu) 331{ 332 int ret; 333 HANDLE hDeviceVCPU = vcpu->fd; 334 DWORD dSize = 0; 335 336 ret = DeviceIoControl(hDeviceVCPU, 337 HAX_VCPU_IOCTL_RUN, 338 NULL, 0, NULL, 0, &dSize, (LPOVERLAPPED) NULL); 339 if (!ret) { 340 return -EFAULT; 341 } else { 342 return 0; 343 } 344} 345 346int hax_sync_fpu(CPUArchState *env, struct fx_layout *fl, int set) 347{ 348 int ret; 349 hax_fd fd; 350 HANDLE hDeviceVCPU; 351 DWORD dSize = 0; 352 353 fd = hax_vcpu_get_fd(env); 354 if (hax_invalid_fd(fd)) { 355 return -1; 356 } 357 358 hDeviceVCPU = fd; 359 360 if (set) { 361 ret = DeviceIoControl(hDeviceVCPU, 362 HAX_VCPU_IOCTL_SET_FPU, 363 fl, sizeof(*fl), NULL, 0, &dSize, 364 (LPOVERLAPPED) NULL); 365 } else { 366 ret = DeviceIoControl(hDeviceVCPU, 367 HAX_VCPU_IOCTL_GET_FPU, 368 NULL, 0, fl, sizeof(*fl), &dSize, 369 (LPOVERLAPPED) NULL); 370 } 371 if (!ret) { 372 return -EFAULT; 373 } else { 374 return 0; 375 } 376} 377 378int hax_sync_msr(CPUArchState *env, struct hax_msr_data *msrs, int set) 379{ 380 int ret; 381 hax_fd fd; 382 HANDLE hDeviceVCPU; 383 DWORD dSize = 0; 384 385 fd = hax_vcpu_get_fd(env); 386 if (hax_invalid_fd(fd)) { 387 return -1; 388 } 389 hDeviceVCPU = fd; 390 391 if (set) { 392 ret = DeviceIoControl(hDeviceVCPU, 393 HAX_VCPU_IOCTL_SET_MSRS, 394 msrs, sizeof(*msrs), 395 msrs, sizeof(*msrs), &dSize, (LPOVERLAPPED) NULL); 396 } else { 397 ret = DeviceIoControl(hDeviceVCPU, 398 HAX_VCPU_IOCTL_GET_MSRS, 399 msrs, sizeof(*msrs), 400 msrs, sizeof(*msrs), &dSize, (LPOVERLAPPED) NULL); 401 } 402 if (!ret) { 403 return -EFAULT; 404 } else { 405 return 0; 406 } 407} 408 409int hax_sync_vcpu_state(CPUArchState *env, struct vcpu_state_t *state, int set) 410{ 411 int ret; 412 hax_fd fd; 413 HANDLE hDeviceVCPU; 414 DWORD dSize; 415 416 fd = hax_vcpu_get_fd(env); 417 if (hax_invalid_fd(fd)) { 418 return -1; 419 } 420 421 hDeviceVCPU = fd; 422 423 if (set) { 424 ret = DeviceIoControl(hDeviceVCPU, 425 HAX_VCPU_SET_REGS, 426 state, sizeof(*state), 427 NULL, 0, &dSize, (LPOVERLAPPED) NULL); 428 } else { 429 ret = DeviceIoControl(hDeviceVCPU, 430 HAX_VCPU_GET_REGS, 431 NULL, 0, 432 state, sizeof(*state), &dSize, 433 (LPOVERLAPPED) NULL); 434 } 435 if (!ret) { 436 return -EFAULT; 437 } else { 438 return 0; 439 } 440} 441 442int hax_inject_interrupt(CPUArchState *env, int vector) 443{ 444 int ret; 445 hax_fd fd; 446 HANDLE hDeviceVCPU; 447 DWORD dSize; 448 449 fd = hax_vcpu_get_fd(env); 450 if (hax_invalid_fd(fd)) { 451 return -1; 452 } 453 454 hDeviceVCPU = fd; 455 456 ret = DeviceIoControl(hDeviceVCPU, 457 HAX_VCPU_IOCTL_INTERRUPT, 458 &vector, sizeof(vector), NULL, 0, &dSize, 459 (LPOVERLAPPED) NULL); 460 if (!ret) { 461 return -EFAULT; 462 } else { 463 return 0; 464 } 465} 466 467static void CALLBACK dummy_apc_func(ULONG_PTR unused) 468{ 469} 470 471void hax_kick_vcpu_thread(CPUState *cpu) 472{ 473 /* 474 * FIXME: race condition with the exit_request check in 475 * hax_vcpu_hax_exec 476 */ 477 cpu->exit_request = 1; 478 if (!qemu_cpu_is_self(cpu)) { 479 if (!QueueUserAPC(dummy_apc_func, cpu->hThread, 0)) { 480 fprintf(stderr, "%s: QueueUserAPC failed with error %lu\n", 481 __func__, GetLastError()); 482 exit(1); 483 } 484 } 485}