cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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}