1/*
2** Copyright (c) 2011, Intel Corporation
3**
4** This software is licensed under the terms of the GNU General Public
5** License version 2, as published by the Free Software Foundation, and
6** may be copied, distributed, and modified under those terms.
7**
8** This program is distributed in the hope that it will be useful,
9** but WITHOUT ANY WARRANTY; without even the implied warranty of
10** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11** GNU General Public License for more details.
12*/
13
14#include "target-i386/hax-i386.h"
15
16/*
17 * return 0 upon success, -1 when the driver is not loaded,
18 * other negative value for other failures
19 */
20static int hax_open_device(hax_fd *fd)
21{
22    uint32_t errNum = 0;
23    HANDLE hDevice;
24
25    if (!fd)
26        return -2;
27
28    hDevice = CreateFile( "\\\\.\\HAX",
29      GENERIC_READ | GENERIC_WRITE,
30      0,
31      NULL,
32      CREATE_ALWAYS,
33      FILE_ATTRIBUTE_NORMAL,
34      NULL);
35
36    if (hDevice == INVALID_HANDLE_VALUE)
37    {
38        dprint("Failed to open the HAX device!\n");
39        errNum = GetLastError();
40        if (errNum == ERROR_FILE_NOT_FOUND)
41            return -1;
42        return -2;
43    }
44    *fd = hDevice;
45    dprint("device fd:%d\n", *fd);
46    return 0;
47}
48
49
50hax_fd hax_mod_open(void)
51{
52    int ret;
53    hax_fd fd = INVALID_HANDLE_VALUE;
54
55    ret = hax_open_device(&fd);
56    if (ret != 0) {
57        dprint("Open HAX device failed\n");
58        return INVALID_HANDLE_VALUE;
59    }
60
61    return fd;
62}
63
64int hax_populate_ram(uint64_t va, uint32_t size)
65{
66    int ret;
67    struct hax_alloc_ram_info info;
68    HANDLE hDeviceVM;
69    DWORD dSize = 0;
70
71    if (!hax_global.vm || !hax_global.vm->fd)
72    {
73        dprint("Allocate memory before vm create?\n");
74        return -EINVAL;
75    }
76
77    info.size = size;
78    info.va = va;
79
80    hDeviceVM = hax_global.vm->fd;
81
82    ret = DeviceIoControl(hDeviceVM,
83      HAX_VM_IOCTL_ALLOC_RAM,
84      &info, sizeof(info),
85      NULL, 0,
86      &dSize,
87      (LPOVERLAPPED) NULL);
88
89    if (!ret) {
90        dprint("HAX: Failed to allocate %x memory (address %llx)\n",
91               size, (unsigned long long)va);
92        return -1;
93    }
94
95    return 0;
96}
97
98
99int hax_set_phys_mem(hwaddr start_addr, ram_addr_t size, ram_addr_t phys_offset)
100{
101    struct hax_set_ram_info info, *pinfo = &info;
102    ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
103    HANDLE hDeviceVM;
104    DWORD dSize = 0;
105    int ret = 0;
106
107    /* We look for the  RAM and ROM only */
108    if (flags >= IO_MEM_UNASSIGNED)
109        return 0;
110
111    if ( (start_addr & ~TARGET_PAGE_MASK) || (size & ~TARGET_PAGE_MASK))
112    {
113        dprint(
114          "set_phys_mem %x %lx requires page aligned addr and size\n",
115          start_addr, size);
116        return -1;
117    }
118
119    info.pa_start = start_addr;
120    info.size = size;
121    info.va = (uint64_t)(uintptr_t)qemu_get_ram_ptr(phys_offset);
122    info.flags = (flags & IO_MEM_ROM) ? 1 : 0;
123
124    hDeviceVM = hax_global.vm->fd;
125
126    ret = DeviceIoControl(hDeviceVM,
127      HAX_VM_IOCTL_SET_RAM,
128      pinfo, sizeof(*pinfo),
129      NULL, 0,
130      &dSize,
131      (LPOVERLAPPED) NULL);
132
133    if (!ret)
134        return -EFAULT;
135    else
136        return 0;
137}
138
139int hax_capability(struct hax_state *hax, struct hax_capabilityinfo *cap)
140{
141    int ret;
142    HANDLE hDevice = hax->fd;   //handle to hax module
143    DWORD dSize = 0;
144    DWORD err = 0;
145
146    if (hax_invalid_fd(hDevice)) {
147        dprint("Invalid fd for hax device!\n");
148        return -ENODEV;
149    }
150
151    ret = DeviceIoControl(hDevice,
152      HAX_IOCTL_CAPABILITY,
153      NULL, 0,
154      cap, sizeof(*cap),
155      &dSize,
156      (LPOVERLAPPED) NULL);
157
158    if (!ret) {
159        err = GetLastError();
160        if (err == ERROR_INSUFFICIENT_BUFFER ||
161            err == ERROR_MORE_DATA)
162            dprint("hax capability is too long to hold.\n");
163        dprint("Failed to get Hax capability:%d\n", err);
164        return -EFAULT;
165    } else
166        return 0;
167}
168
169int hax_mod_version(struct hax_state *hax, struct hax_module_version *version)
170{
171    int ret;
172    HANDLE hDevice = hax->fd;   //handle to hax module
173    DWORD dSize = 0;
174    DWORD err = 0;
175
176    if (hax_invalid_fd(hDevice)) {
177        dprint("Invalid fd for hax device!\n");
178        return -ENODEV;
179    }
180
181    ret = DeviceIoControl(hDevice,
182      HAX_IOCTL_VERSION,
183      NULL, 0,
184      version, sizeof(*version),
185      &dSize,
186      (LPOVERLAPPED) NULL);
187
188    if (!ret) {
189        err = GetLastError();
190        if (err == ERROR_INSUFFICIENT_BUFFER ||
191            err == ERROR_MORE_DATA)
192            dprint("HAX module is too large.\n");
193        dprint("Failed to get Hax module version:%d\n", err);
194        return -EFAULT;
195    } else
196        return 0;
197}
198
199static char *hax_vm_devfs_string(int vm_id)
200{
201    char *name;
202
203    if (vm_id > MAX_VM_ID)
204    {
205        dprint("Too big VM id\n");
206        return NULL;
207    }
208
209    name = g_strdup("\\\\.\\hax_vmxx");
210    if (!name)
211        return NULL;
212    sprintf(name, "\\\\.\\hax_vm%02d", vm_id);
213
214    return name;
215}
216
217static char *hax_vcpu_devfs_string(int vm_id, int vcpu_id)
218{
219    char *name;
220
221    if (vm_id > MAX_VM_ID || vcpu_id > MAX_VCPU_ID)
222    {
223        dprint("Too big vm id %x or vcpu id %x\n", vm_id, vcpu_id);
224        return NULL;
225    }
226    name = g_strdup("\\\\.\\hax_vmxx_vcpuxx");
227    if (!name)
228        return NULL;
229    sprintf(name, "\\\\.\\hax_vm%02d_vcpu%02d", vm_id, vcpu_id);
230
231    return name;
232}
233
234int hax_host_create_vm(struct hax_state *hax, int *vmid)
235{
236    int ret;
237    int vm_id = 0;
238    DWORD dSize = 0;
239
240    if (hax_invalid_fd(hax->fd))
241        return -EINVAL;
242
243    if (hax->vm)
244        return 0;
245
246    ret = DeviceIoControl(hax->fd,
247      HAX_IOCTL_CREATE_VM,
248      NULL, 0,
249      &vm_id, sizeof(vm_id),
250      &dSize,
251      (LPOVERLAPPED) NULL);
252    if (!ret) {
253        dprint("error code:%d", GetLastError());
254        return -1;
255    }
256    *vmid = vm_id;
257    return 0;
258}
259
260hax_fd hax_host_open_vm(struct hax_state *hax, int vm_id)
261{
262    char *vm_name = NULL;
263    hax_fd hDeviceVM;
264
265    vm_name = hax_vm_devfs_string(vm_id);
266    if (!vm_name) {
267        dprint("Incorrect name\n");
268        return INVALID_HANDLE_VALUE;
269    }
270
271    hDeviceVM = CreateFile(vm_name,
272      GENERIC_READ | GENERIC_WRITE,
273      0,
274      NULL,
275      CREATE_ALWAYS,
276      FILE_ATTRIBUTE_NORMAL,
277      NULL);
278    if (hDeviceVM == INVALID_HANDLE_VALUE)
279        dprint("Open the vm devcie error:%s, ec:%d\n", vm_name, GetLastError());
280
281    g_free(vm_name);
282    return hDeviceVM;
283}
284
285int hax_notify_qemu_version(hax_fd vm_fd, struct hax_qemu_version *qversion)
286{
287    int ret;
288    DWORD dSize = 0;
289
290    if (hax_invalid_fd(vm_fd))
291        return -EINVAL;
292
293    ret = DeviceIoControl(vm_fd,
294      HAX_VM_IOCTL_NOTIFY_QEMU_VERSION,
295      qversion, sizeof(struct hax_qemu_version),
296      NULL, 0,
297      &dSize,
298      (LPOVERLAPPED) NULL);
299    if (!ret)
300    {
301        dprint("Failed to notify qemu API version\n");
302        return -1;
303    }
304
305    return 0;
306}
307
308int hax_host_create_vcpu(hax_fd vm_fd, int vcpuid)
309{
310    int ret;
311    DWORD dSize = 0;
312
313    ret = DeviceIoControl(vm_fd,
314      HAX_VM_IOCTL_VCPU_CREATE,
315      &vcpuid, sizeof(vcpuid),
316      NULL, 0,
317      &dSize,
318      (LPOVERLAPPED) NULL);
319    if (!ret)
320    {
321        dprint("Failed to create vcpu %x\n", vcpuid);
322        return -1;
323    }
324
325    return 0;
326}
327
328hax_fd hax_host_open_vcpu(int vmid, int vcpuid)
329{
330    char *devfs_path = NULL;
331    hax_fd hDeviceVCPU;
332
333    devfs_path = hax_vcpu_devfs_string(vmid, vcpuid);
334    if (!devfs_path)
335    {
336        dprint("Failed to get the devfs\n");
337        return INVALID_HANDLE_VALUE;
338    }
339
340    hDeviceVCPU = CreateFile( devfs_path,
341      GENERIC_READ | GENERIC_WRITE,
342      0,
343      NULL,
344      CREATE_ALWAYS,
345      FILE_ATTRIBUTE_NORMAL,
346      NULL);
347
348    if (hDeviceVCPU == INVALID_HANDLE_VALUE)
349        dprint("Failed to open the vcpu devfs\n");
350    g_free(devfs_path);
351    return hDeviceVCPU;
352}
353
354int hax_host_setup_vcpu_channel(struct hax_vcpu_state *vcpu)
355{
356    hax_fd hDeviceVCPU = vcpu->fd;
357    int ret;
358    struct hax_tunnel_info info;
359    DWORD dSize = 0;
360
361    ret = DeviceIoControl(hDeviceVCPU,
362      HAX_VCPU_IOCTL_SETUP_TUNNEL,
363      NULL, 0,
364      &info, sizeof(info),
365      &dSize,
366      (LPOVERLAPPED) NULL);
367    if (!ret)
368    {
369        dprint("Failed to setup the hax tunnel\n");
370        return -1;
371    }
372
373    if (!valid_hax_tunnel_size(info.size))
374    {
375        dprint("Invalid hax tunnel size %x\n", info.size);
376        ret = -EINVAL;
377        return ret;
378    }
379    vcpu->tunnel = (struct hax_tunnel *)(uintptr_t)(info.va);
380    vcpu->iobuf = (unsigned char *)(uintptr_t)(info.io_va);
381    return 0;
382}
383
384int hax_vcpu_run(struct hax_vcpu_state* vcpu)
385{
386    int ret;
387    HANDLE hDeviceVCPU = vcpu->fd;
388    DWORD dSize = 0;
389
390    ret = DeviceIoControl(hDeviceVCPU,
391      HAX_VCPU_IOCTL_RUN,
392      NULL, 0,
393      NULL, 0,
394      &dSize,
395      (LPOVERLAPPED) NULL);
396    if (!ret)
397        return -EFAULT;
398    else
399        return 0;
400}
401
402int hax_sync_fpu(CPUState *cpu, struct fx_layout *fl, int set)
403{
404    int ret;
405    hax_fd fd;
406    HANDLE hDeviceVCPU;
407    DWORD dSize = 0;
408
409    fd = hax_vcpu_get_fd(cpu);
410    if (hax_invalid_fd(fd))
411        return -1;
412
413    hDeviceVCPU = fd;
414
415    if (set)
416        ret = DeviceIoControl(hDeviceVCPU,
417          HAX_VCPU_IOCTL_SET_FPU,
418          fl, sizeof(*fl),
419          NULL, 0,
420          &dSize,
421          (LPOVERLAPPED) NULL);
422    else
423        ret = DeviceIoControl(hDeviceVCPU,
424          HAX_VCPU_IOCTL_GET_FPU,
425          NULL, 0,
426          fl, sizeof(*fl),
427          &dSize,
428          (LPOVERLAPPED) NULL);
429    if (!ret)
430        return -EFAULT;
431    else
432        return 0;
433}
434
435int hax_sync_msr(CPUState *cpu, struct hax_msr_data *msrs, int set)
436{
437    int ret;
438    hax_fd fd;
439    HANDLE hDeviceVCPU;
440    DWORD dSize = 0;
441
442    fd = hax_vcpu_get_fd(cpu);
443    if (hax_invalid_fd(fd))
444        return -1;
445    hDeviceVCPU = fd;
446
447    if (set)
448        ret = DeviceIoControl(hDeviceVCPU,
449          HAX_VCPU_IOCTL_SET_MSRS,
450          msrs, sizeof(*msrs),
451          msrs, sizeof(*msrs),
452          &dSize,
453          (LPOVERLAPPED) NULL);
454    else
455        ret = DeviceIoControl(hDeviceVCPU,
456          HAX_VCPU_IOCTL_GET_MSRS,
457          msrs, sizeof(*msrs),
458          msrs, sizeof(*msrs),
459          &dSize,
460          (LPOVERLAPPED) NULL);
461    if (!ret)
462        return -EFAULT;
463    else
464        return 0;
465}
466
467int hax_sync_vcpu_state(CPUState *cpu, struct vcpu_state_t *state, int set)
468{
469    int ret;
470    hax_fd fd;
471    HANDLE hDeviceVCPU;
472    DWORD dSize;
473
474    fd = hax_vcpu_get_fd(cpu);
475    if (hax_invalid_fd(fd))
476        return -1;
477
478    hDeviceVCPU = fd;
479
480    if (set)
481        ret = DeviceIoControl(hDeviceVCPU,
482          HAX_VCPU_SET_REGS,
483          state, sizeof(*state),
484          NULL, 0,
485          &dSize,
486          (LPOVERLAPPED) NULL);
487    else
488        ret = DeviceIoControl(hDeviceVCPU,
489          HAX_VCPU_GET_REGS,
490          NULL, 0,
491          state, sizeof(*state),
492          &dSize,
493          (LPOVERLAPPED) NULL);
494    if (!ret)
495        return -EFAULT;
496    else
497        return 0;
498}
499
500int hax_inject_interrupt(CPUState *cpu, int vector)
501{
502    int ret;
503    hax_fd fd;
504    HANDLE hDeviceVCPU;
505    DWORD dSize;
506
507    fd = hax_vcpu_get_fd(cpu);
508    if (hax_invalid_fd(fd))
509        return -1;
510
511    hDeviceVCPU = fd;
512
513    ret = DeviceIoControl(hDeviceVCPU,
514      HAX_VCPU_IOCTL_INTERRUPT,
515      &vector, sizeof(vector),
516      NULL, 0,
517      &dSize,
518      (LPOVERLAPPED) NULL);
519    if (!ret)
520        return -EFAULT;
521    else
522        return 0;
523}
524