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