blob: c41a874cb00b9dcd5e2b5262081cd5305b9b37c7 [file] [log] [blame]
Jun Nakajimae4a3c782011-12-17 19:22:12 -08001/*
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/*
15 * HAX common code for both Windows and Darwin
16 * Some portion of code from KVM is used in this file.
17 */
18
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +010019#include "hw/hw.h"
Jun Nakajimae4a3c782011-12-17 19:22:12 -080020#include "target-i386/hax-i386.h"
21
22#define HAX_EMUL_ONE 0x1
23#define HAX_EMUL_REAL 0x2
24#define HAX_EMUL_HLT 0x4
25#define HAX_EMUL_EXITLOOP 0x5
26
27#define HAX_EMULATE_STATE_MMIO 0x1
28#define HAX_EMULATE_STATE_REAL 0x2
29#define HAX_EMULATE_STATE_NONE 0x3
30#define HAX_EMULATE_STATE_INITIAL 0x4
31
32struct hax_state hax_global;
33
34int hax_support = -1;
35
36/* Called after hax_init */
37int hax_enabled()
38{
39 return (!hax_disabled && hax_support);
40}
41
42/* Currently non-PG modes are emulated by QEMU */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +010043int hax_vcpu_emulation_mode(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -080044{
45 return !(env->cr[0] & CR0_PG_MASK);
46}
47
David 'Digit' Turnere2678e12014-01-16 15:56:43 +010048static int hax_prepare_emulation(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -080049{
50 /* Flush all emulation states */
51 tlb_flush(env, 1);
52 tb_flush(env);
53 /* Sync the vcpu state from hax kernel module */
54 hax_vcpu_sync_state(env, 0);
55 return 0;
56}
57
58/*
59 * Check whether to break the translation block loop
60 * Break tbloop after one MMIO emulation, or after finish emulation mode
61 */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +010062static int hax_stop_tbloop(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -080063{
64 switch (env->hax_vcpu->emulation_state)
65 {
66 case HAX_EMULATE_STATE_MMIO:
67 return 1;
68 case HAX_EMULATE_STATE_INITIAL:
69 case HAX_EMULATE_STATE_REAL:
70 if (!hax_vcpu_emulation_mode(env))
71 return 1;
72 break;
73 default:
74 dprint("Invalid emulation state in hax_sto_tbloop state %x\n",
75 env->hax_vcpu->emulation_state);
76 break;
77 }
78
79 return 0;
80}
81
David 'Digit' Turnere2678e12014-01-16 15:56:43 +010082int hax_stop_emulation(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -080083{
84 if (hax_stop_tbloop(env))
85 {
86 env->hax_vcpu->emulation_state = HAX_EMULATE_STATE_NONE;
87 /*
88 * QEMU emulation changes vcpu state,
89 * Sync the vcpu state to HAX kernel module
90 */
91 hax_vcpu_sync_state(env, 1);
92 return 1;
93 }
94
95 return 0;
96}
97
David 'Digit' Turnere2678e12014-01-16 15:56:43 +010098int hax_stop_translate(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -080099{
100 struct hax_vcpu_state *vstate;
101
102 vstate = env->hax_vcpu;
103 assert(vstate->emulation_state);
104 if (vstate->emulation_state == HAX_EMULATE_STATE_MMIO )
105 return 1;
106
107 return 0;
108}
109
110int valid_hax_tunnel_size(uint16_t size)
111{
112 return size >= sizeof(struct hax_tunnel);
113}
114
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100115hax_fd hax_vcpu_get_fd(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800116{
117 struct hax_vcpu_state *vcpu = env->hax_vcpu;
118 if (!vcpu)
119 return HAX_INVALID_FD;
120 return vcpu->fd;
121}
122
123/* Current version */
Jiang, Yunhongfba19d92012-04-01 10:01:33 +0800124uint32_t hax_cur_version = 0x2;
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800125/* Least HAX kernel version */
126uint32_t hax_lest_version = 0x1;
127
Jiang, Yunhong4a5a0ef2012-02-23 06:31:12 +0800128static int hax_get_capability(struct hax_state *hax)
129{
130 int ret;
131 struct hax_capabilityinfo capinfo, *cap = &capinfo;
132
133 ret = hax_capability(hax, cap);
134 if (ret)
135 return -ENOSYS;
136
137 if ( ((cap->wstatus & HAX_CAP_WORKSTATUS_MASK) ==
138 HAX_CAP_STATUS_NOTWORKING ))
139 {
140 if (cap->winfo & HAX_CAP_FAILREASON_VT)
141 dprint("VT feature is not enabled, HAXM not working.\n");
142 else if (cap->winfo & HAX_CAP_FAILREASON_NX)
143 dprint("NX feature is not enabled, HAXM not working.\n");
144 return -ENXIO;
145 }
146
147 if (cap->wstatus & HAX_CAP_MEMQUOTA)
148 {
149 if (cap->mem_quota < hax->mem_quota)
150 {
151 dprint("The memory needed by this VM exceeds the driver limit.\n");
152 return -ENOSPC;
153 }
154 }
155
156 return 0;
157}
158
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800159static int hax_version_support(struct hax_state *hax)
160{
161 int ret;
162 struct hax_module_version version;
163
164 ret = hax_mod_version(hax, &version);
165 if (ret < 0)
166 return 0;
167
168 if ( (hax_lest_version > version.cur_version) ||
169 (hax_cur_version < version.compat_version) )
170 return 0;
171
172 return 1;
173}
174
175int hax_vcpu_create(int id)
176{
177 struct hax_vcpu_state *vcpu = NULL;
178 int ret;
179
180 if (!hax_global.vm)
181 {
182 dprint("vcpu %x created failed, vm is null\n", id);
183 return -1;
184 }
185
186 if (hax_global.vm->vcpus[id])
187 {
188 dprint("vcpu %x allocated already\n", id);
189 return 0;
190 }
191
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100192 vcpu = g_malloc(sizeof(struct hax_vcpu_state));
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800193 if (!vcpu)
194 {
195 dprint("Failed to alloc vcpu state\n");
196 return -ENOMEM;
197 }
198
199 memset(vcpu, 0, sizeof(struct hax_vcpu_state));
200
201 ret = hax_host_create_vcpu(hax_global.vm->fd, id);
202 if (ret)
203 {
204 dprint("Failed to create vcpu %x\n", id);
205 goto error;
206 }
207
208 vcpu->fd = hax_host_open_vcpu(hax_global.vm->id, id);
209 if (hax_invalid_fd(vcpu->fd))
210 {
211 dprint("Failed to open the vcpu\n");
212 ret = -ENODEV;
213 goto error;
214 }
215
216 hax_global.vm->vcpus[id] = vcpu;
217
218 ret = hax_host_setup_vcpu_channel(vcpu);
219 if (ret)
220 {
221 dprint("Invalid HAX tunnel size \n");
222 ret = -EINVAL;
223 goto error;
224 }
225 return 0;
226
227error:
228 /* vcpu and tunnel will be closed automatically */
229 if (vcpu && !hax_invalid_fd(vcpu->fd))
230 hax_close_fd(vcpu->fd);
231
232 hax_global.vm->vcpus[id] = NULL;
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100233 g_free(vcpu);
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800234 return -1;
235}
236
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100237int hax_vcpu_destroy(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800238{
239 struct hax_vcpu_state *vcpu = env->hax_vcpu;
240
241 if (!hax_global.vm)
242 {
243 dprint("vcpu %x destroy failed, vm is null\n", vcpu->vcpu_id);
244 return -1;
245 }
246
247 if (!vcpu)
248 return 0;
249
250 /*
251 * 1. The hax_tunnel is also destroyed at vcpu_destroy
252 * 2. hax_close_fd will require the HAX kernel module to free vcpu
253 */
254 hax_close_fd(vcpu->fd);
255 hax_global.vm->vcpus[vcpu->vcpu_id] = NULL;
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100256 g_free(vcpu);
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800257 return 0;
258}
259
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100260int hax_init_vcpu(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800261{
262 int ret;
263
264 ret = hax_vcpu_create(env->cpu_index);
265 if (ret < 0)
266 {
267 dprint("Failed to create HAX vcpu\n");
268 exit(-1);
269 }
270
271 env->hax_vcpu = hax_global.vm->vcpus[env->cpu_index];
272 env->hax_vcpu->emulation_state = HAX_EMULATE_STATE_INITIAL;
273
274 return ret;
275}
276
277struct hax_vm *hax_vm_create(struct hax_state *hax)
278{
279 struct hax_vm *vm;
280 int vm_id = 0, ret;
281 char *vm_name = NULL;
282
283 if (hax_invalid_fd(hax->fd))
284 return NULL;
285
286 if (hax->vm)
287 return hax->vm;
288
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100289 vm = g_malloc(sizeof(struct hax_vm));
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800290 if (!vm)
291 return NULL;
292 memset(vm, 0, sizeof(struct hax_vm));
Jiang, Yunhong1d1280d2012-02-23 05:21:15 +0800293 ret = hax_host_create_vm(hax, &vm_id);
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800294 if (ret) {
295 dprint("Failed to create vm %x\n", ret);
296 goto error;
297 }
298 vm->id = vm_id;
299 vm->fd = hax_host_open_vm(hax, vm_id);
300 if (hax_invalid_fd(vm->fd))
301 {
302 dprint("Open vm device error:%s\n", vm_name);
303 goto error;
304 }
305
306 hax->vm = vm;
307 return vm;
308
309error:
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100310 g_free(vm);
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800311 hax->vm = NULL;
312 return NULL;
313}
314
315int hax_vm_destroy(struct hax_vm *vm)
316{
317 int i;
318
319 for (i = 0; i < HAX_MAX_VCPU; i++)
320 if (vm->vcpus[i])
321 {
322 dprint("VCPU should be cleaned before vm clean\n");
323 return -1;
324 }
325 hax_close_fd(vm->fd);
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100326 g_free(vm);
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800327 hax_global.vm = NULL;
328 return 0;
329}
330
Jiang, Yunhong4a5a0ef2012-02-23 06:31:12 +0800331int hax_set_ramsize(uint64_t ramsize)
332{
333 struct hax_state *hax = &hax_global;
334
335 memset(hax, 0, sizeof(struct hax_state));
336 hax->mem_quota = ram_size;
337
338 return 0;
339}
340
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800341int hax_init(int smp_cpus)
342{
343 struct hax_state *hax = NULL;
Jiang, Yunhong8a539ea2012-03-23 13:47:38 +0800344 struct hax_qemu_version qversion;
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800345 int ret;
346
347 hax_support = 0;
348
349 hax = &hax_global;
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800350
351 hax->fd = hax_mod_open();
352 if (hax_invalid_fd(hax->fd))
353 {
354 hax->fd = 0;
355 ret = -ENODEV;
356 goto error;
357 }
358
Jiang, Yunhong4a5a0ef2012-02-23 06:31:12 +0800359 ret = hax_get_capability(hax);
360 /* In case HAXM have no such capability support */
361 if (ret && (ret != -ENOSYS))
362 {
363 ret = -EINVAL;
364 goto error;
365 }
366
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800367 if (!hax_version_support(hax))
368 {
369 dprint("Incompatible HAX version. Qemu current version %x ", hax_cur_version );
370 dprint("requires least HAX version %x\n", hax_lest_version);
371 ret = -EINVAL;
372 goto error;
373 }
374
375 hax->vm = hax_vm_create(hax);
376 if (!hax->vm)
377 {
378 dprint("Failed to create HAX VM\n");
379 ret = -EINVAL;
380 goto error;
381 }
382
Jiang, Yunhong8a539ea2012-03-23 13:47:38 +0800383 qversion.cur_version = hax_cur_version;
384 qversion.least_version = hax_lest_version;
385 hax_notify_qemu_version(hax->vm->fd, &qversion);
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800386 hax_support = 1;
387 qemu_register_reset( hax_reset_vcpu_state, 0, NULL);
388
389 return 0;
390error:
391 if (hax->vm)
392 hax_vm_destroy(hax->vm);
393 if (hax->fd)
394 hax_mod_close(hax);
395
396 return ret;
397}
398
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100399int hax_handle_fastmmio(CPUX86State *env, struct hax_fastmmio *hft)
Jiang, Yunhongfba19d92012-04-01 10:01:33 +0800400{
401 uint64_t buf = 0;
402
403 /*
404 * With fast MMIO, QEMU need not sync vCPU state with HAXM
405 * driver because it will only invoke MMIO handler
406 * However, some MMIO operations utilize virtual address like qemu_pipe
407 * Thus we need to sync the CR0, CR3 and CR4 so that QEMU
408 * can translate the guest virtual address to guest physical
409 * address
410 */
411 env->cr[0] = hft->_cr0;
412 env->cr[2] = hft->_cr2;
413 env->cr[3] = hft->_cr3;
414 env->cr[4] = hft->_cr4;
415
416 buf = hft->value;
417 cpu_physical_memory_rw(hft->gpa, &buf, hft->size, hft->direction);
418 if (hft->direction == 0)
419 hft->value = buf;
420
421 return 0;
422}
423
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100424int hax_handle_io(CPUX86State *env, uint32_t df, uint16_t port, int direction,
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800425 int size, int count, void *buffer)
426{
427 uint8_t *ptr;
428 int i;
429
430 if (!df)
431 ptr = (uint8_t *)buffer;
432 else
433 ptr = buffer + size * count - size;
434 for (i = 0; i < count; i++)
435 {
436 if (direction == HAX_EXIT_IO_IN) {
437 switch (size) {
438 case 1:
439 stb_p(ptr, cpu_inb(port));
440 break;
441 case 2:
442 stw_p(ptr, cpu_inw(port));
443 break;
444 case 4:
445 stl_p(ptr, cpu_inl(port));
446 break;
447 }
448 } else {
449 switch (size) {
450 case 1:
451 cpu_outb(port, ldub_p(ptr));
452 break;
453 case 2:
454 cpu_outw(port, lduw_p(ptr));
455 break;
456 case 4:
457 cpu_outl(port, ldl_p(ptr));
458 break;
459 }
460 }
461 if (!df)
462 ptr += size;
463 else
464 ptr -= size;
465 }
466
467 return 0;
468}
469
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100470static int hax_vcpu_interrupt(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800471{
472 struct hax_vcpu_state *vcpu = env->hax_vcpu;
473 struct hax_tunnel *ht = vcpu->tunnel;
474
475 /*
476 * Try to inject an interrupt if the guest can accept it
477 * Unlike KVM, the HAX kernel module checks the eflags, instead.
478 */
479 if (ht->ready_for_interrupt_injection &&
480 (env->interrupt_request & CPU_INTERRUPT_HARD))
481 {
482 int irq;
483
484 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
485 irq = cpu_get_pic_interrupt(env);
486 if (irq >= 0) {
487 hax_inject_interrupt(env, irq);
488 }
489 }
490
David 'Digit' Turnerc0052462014-02-25 18:39:29 +0100491 /*
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800492 * If we have an interrupt pending but the guest is not ready to
493 * receive it, request an interrupt window exit. This will cause
494 * a return to userspace as soon as the guest is ready to receive
495 * an interrupt.
496 */
497 if ((env->interrupt_request & CPU_INTERRUPT_HARD))
498 ht->request_interrupt_window = 1;
499 else
500 ht->request_interrupt_window = 0;
501 return 0;
502}
503
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100504void hax_raise_event(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800505{
506 struct hax_vcpu_state *vcpu = env->hax_vcpu;
507
508 if (!vcpu)
509 return;
510 vcpu->tunnel->user_event_pending = 1;
511}
512
513/*
514 * Request the HAX kernel module to run the CPU for us until one of
515 * the following occurs:
516 * 1. Guest crashes or is shut down
517 * 2. We need QEMU's emulation like when the guest executes a MMIO
518 * instruction or guest enters emulation mode (non-PG mode)
519 * 3. Guest executes HLT
520 * 4. Qemu has Signal/event pending
521 * 5. An unknown VMX-exit happens
522 */
523extern void qemu_system_reset_request(void);
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100524static int hax_vcpu_hax_exec(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800525{
526 int ret = 0;
527 struct hax_vcpu_state *vcpu = env->hax_vcpu;
528 struct hax_tunnel *ht = vcpu->tunnel;
529
530 if (hax_vcpu_emulation_mode(env))
531 {
532 dprint("Trying to vcpu execute at eip:%lx\n", env->eip);
533 return HAX_EMUL_EXITLOOP;
534 }
535
536 do {
537 int hax_ret;
538
539 if (env->exit_request) {
540 ret = HAX_EMUL_EXITLOOP ;
541 break;
542 }
543
544 hax_vcpu_interrupt(env);
545
546 hax_ret = hax_vcpu_run(vcpu);
547
548 /* Simply continue the vcpu_run if system call interrupted */
549 if (hax_ret == -EINTR || hax_ret == -EAGAIN) {
550 dprint("io window interrupted\n");
551 continue;
552 }
553
554 if (hax_ret < 0)
555 {
556 dprint("vcpu run failed for vcpu %x\n", vcpu->vcpu_id);
557 abort();
558 }
559 switch (ht->_exit_status)
560 {
561 case HAX_EXIT_IO:
562 {
563 ret = hax_handle_io(env, ht->pio._df, ht->pio._port,
564 ht->pio._direction,
565 ht->pio._size, ht->pio._count, vcpu->iobuf);
566 }
567 break;
568 case HAX_EXIT_MMIO:
569 ret = HAX_EMUL_ONE;
570 break;
Jiang, Yunhongfba19d92012-04-01 10:01:33 +0800571 case HAX_EXIT_FAST_MMIO:
572 ret = hax_handle_fastmmio(env,
573 (struct hax_fastmmio *)vcpu->iobuf);
574 break;
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800575 case HAX_EXIT_REAL:
576 ret = HAX_EMUL_REAL;
577 break;
578 /* Guest state changed, currently only for shutdown */
579 case HAX_EXIT_STATECHANGE:
580 dprint("VCPU shutdown request\n");
581 qemu_system_reset_request();
582 hax_prepare_emulation(env);
583 cpu_dump_state(env, stderr, fprintf, 0);
584 ret = HAX_EMUL_EXITLOOP;
585 break;
586 case HAX_EXIT_UNKNOWN_VMEXIT:
587 dprint("Unknown VMX exit %x from guest\n", ht->_exit_reason);
588 qemu_system_reset_request();
589 hax_prepare_emulation(env);
590 cpu_dump_state(env, stderr, fprintf, 0);
591 ret = HAX_EMUL_EXITLOOP;
592 break;
593 case HAX_EXIT_HLT:
594 if (!(env->interrupt_request & CPU_INTERRUPT_HARD) &&
595 !(env->interrupt_request & CPU_INTERRUPT_NMI)) {
596 /* hlt instruction with interrupt disabled is shutdown */
597 env->eflags |= IF_MASK;
598 env->halted = 1;
599 env->exception_index = EXCP_HLT;
600 ret = HAX_EMUL_HLT;
601 }
602 break;
603 /* these situation will continue to hax module */
604 case HAX_EXIT_INTERRUPT:
605 case HAX_EXIT_PAUSED:
606 break;
607 default:
608 dprint("Unknow exit %x from hax\n", ht->_exit_status);
609 qemu_system_reset_request();
610 hax_prepare_emulation(env);
611 cpu_dump_state(env, stderr, fprintf, 0);
612 ret = HAX_EMUL_EXITLOOP;
613 break;
614 }
615 }while (!ret);
616
617 if (env->exit_request) {
618 env->exit_request = 0;
619 env->exception_index = EXCP_INTERRUPT;
620 }
621 return ret;
622}
623
624/*
625 * return 1 when need to emulate, 0 when need to exit loop
626 */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100627int hax_vcpu_exec(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800628{
629 int next = 0, ret = 0;
630 struct hax_vcpu_state *vcpu;
631
632 if (env->hax_vcpu->emulation_state != HAX_EMULATE_STATE_NONE)
633 return 1;
634
635 vcpu = env->hax_vcpu;
636 next = hax_vcpu_hax_exec(env);
637 switch (next)
638 {
639 case HAX_EMUL_ONE:
640 ret = 1;
641 env->hax_vcpu->emulation_state = HAX_EMULATE_STATE_MMIO;
642 hax_prepare_emulation(env);
643 break;
644 case HAX_EMUL_REAL:
645 ret = 1;
646 env->hax_vcpu->emulation_state =
647 HAX_EMULATE_STATE_REAL;
648 hax_prepare_emulation(env);
649 break;
650 case HAX_EMUL_HLT:
651 case HAX_EMUL_EXITLOOP:
652 break;
653 default:
654 dprint("Unknown hax vcpu exec return %x\n", next);
655 abort();
656 }
657
658 return ret;
659}
660
661#define HAX_RAM_INFO_ROM 0x1
662
663static void set_v8086_seg(struct segment_desc_t *lhs, const SegmentCache *rhs)
664{
665 memset(lhs, 0, sizeof(struct segment_desc_t ));
666 lhs->selector = rhs->selector;
667 lhs->base = rhs->base;
668 lhs->limit = rhs->limit;
669 lhs->type = 3;
670 lhs->present = 1;
671 lhs->dpl = 3;
672 lhs->operand_size = 0;
673 lhs->desc = 1;
674 lhs->long_mode = 0;
675 lhs->granularity = 0;
676 lhs->available = 0;
677}
678
679static void get_seg(SegmentCache *lhs, const struct segment_desc_t *rhs)
680{
681 lhs->selector = rhs->selector;
682 lhs->base = rhs->base;
683 lhs->limit = rhs->limit;
684 lhs->flags =
685 (rhs->type << DESC_TYPE_SHIFT)
686 | (rhs->present * DESC_P_MASK)
687 | (rhs->dpl << DESC_DPL_SHIFT)
688 | (rhs->operand_size << DESC_B_SHIFT)
689 | (rhs->desc * DESC_S_MASK)
690 | (rhs->long_mode << DESC_L_SHIFT)
691 | (rhs->granularity * DESC_G_MASK)
692 | (rhs->available * DESC_AVL_MASK);
693}
694
695static void set_seg(struct segment_desc_t *lhs, const SegmentCache *rhs)
696{
697 unsigned flags = rhs->flags;
698
699 memset(lhs, 0, sizeof(struct segment_desc_t));
700 lhs->selector = rhs->selector;
701 lhs->base = rhs->base;
702 lhs->limit = rhs->limit;
703 lhs->type = (flags >> DESC_TYPE_SHIFT) & 15;
704 lhs->present = (flags & DESC_P_MASK) != 0;
705 lhs->dpl = rhs->selector & 3;
706 lhs->operand_size = (flags >> DESC_B_SHIFT) & 1;
707 lhs->desc = (flags & DESC_S_MASK) != 0;
708 lhs->long_mode = (flags >> DESC_L_SHIFT) & 1;
709 lhs->granularity = (flags & DESC_G_MASK) != 0;
710 lhs->available = (flags & DESC_AVL_MASK) != 0;
711}
712
713static void hax_getput_reg(uint64_t *hax_reg, target_ulong *qemu_reg, int set)
714{
715 target_ulong reg = *hax_reg;
716
717 if (set)
718 *hax_reg = *qemu_reg;
719 else
720 *qemu_reg = reg;
721}
722
723/* The sregs has been synced with HAX kernel already before this call */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100724static int hax_get_segments(CPUX86State *env, struct vcpu_state_t *sregs)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800725{
726 get_seg(&env->segs[R_CS], &sregs->_cs);
727 get_seg(&env->segs[R_DS], &sregs->_ds);
728 get_seg(&env->segs[R_ES], &sregs->_es);
729 get_seg(&env->segs[R_FS], &sregs->_fs);
730 get_seg(&env->segs[R_GS], &sregs->_gs);
731 get_seg(&env->segs[R_SS], &sregs->_ss);
732
733 get_seg(&env->tr, &sregs->_tr);
734 get_seg(&env->ldt, &sregs->_ldt);
735 env->idt.limit = sregs->_idt.limit;
736 env->idt.base = sregs->_idt.base;
737 env->gdt.limit = sregs->_gdt.limit;
738 env->gdt.base = sregs->_gdt.base;
739 return 0;
740}
741
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100742static int hax_set_segments(CPUX86State *env, struct vcpu_state_t *sregs)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800743{
744 if ((env->eflags & VM_MASK)) {
745 set_v8086_seg(&sregs->_cs, &env->segs[R_CS]);
746 set_v8086_seg(&sregs->_ds, &env->segs[R_DS]);
747 set_v8086_seg(&sregs->_es, &env->segs[R_ES]);
748 set_v8086_seg(&sregs->_fs, &env->segs[R_FS]);
749 set_v8086_seg(&sregs->_gs, &env->segs[R_GS]);
750 set_v8086_seg(&sregs->_ss, &env->segs[R_SS]);
751 } else {
752 set_seg(&sregs->_cs, &env->segs[R_CS]);
753 set_seg(&sregs->_ds, &env->segs[R_DS]);
754 set_seg(&sregs->_es, &env->segs[R_ES]);
755 set_seg(&sregs->_fs, &env->segs[R_FS]);
756 set_seg(&sregs->_gs, &env->segs[R_GS]);
757 set_seg(&sregs->_ss, &env->segs[R_SS]);
758
759 if (env->cr[0] & CR0_PE_MASK) {
760 /* force ss cpl to cs cpl */
761 sregs->_ss.selector = (sregs->_ss.selector & ~3) |
762 (sregs->_cs.selector & 3);
763 sregs->_ss.dpl = sregs->_ss.selector & 3;
764 }
765 }
766
767 set_seg(&sregs->_tr, &env->tr);
768 set_seg(&sregs->_ldt, &env->ldt);
769 sregs->_idt.limit = env->idt.limit;
770 sregs->_idt.base = env->idt.base;
771 sregs->_gdt.limit = env->gdt.limit;
772 sregs->_gdt.base = env->gdt.base;
773 return 0;
774}
775
776/*
777 * After get the state from the kernel module, some
778 * qemu emulator state need be updated also
779 */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100780static int hax_setup_qemu_emulator(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800781{
782
783#define HFLAG_COPY_MASK ~( \
784 HF_CPL_MASK | HF_PE_MASK | HF_MP_MASK | HF_EM_MASK | \
785 HF_TS_MASK | HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK | \
786 HF_OSFXSR_MASK | HF_LMA_MASK | HF_CS32_MASK | \
787 HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)
788
789 uint32_t hflags;
790
791 hflags = (env->segs[R_CS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
792 hflags |= (env->cr[0] & CR0_PE_MASK) << (HF_PE_SHIFT - CR0_PE_SHIFT);
793 hflags |= (env->cr[0] << (HF_MP_SHIFT - CR0_MP_SHIFT)) &
794 (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK);
795 hflags |= (env->eflags & (HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK));
796 hflags |= (env->cr[4] & CR4_OSFXSR_MASK) <<
797 (HF_OSFXSR_SHIFT - CR4_OSFXSR_SHIFT);
798
799 if (env->efer & MSR_EFER_LMA) {
800 hflags |= HF_LMA_MASK;
801 }
802
803 if ((hflags & HF_LMA_MASK) && (env->segs[R_CS].flags & DESC_L_MASK)) {
804 hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK;
805 } else {
806 hflags |= (env->segs[R_CS].flags & DESC_B_MASK) >>
807 (DESC_B_SHIFT - HF_CS32_SHIFT);
808 hflags |= (env->segs[R_SS].flags & DESC_B_MASK) >>
809 (DESC_B_SHIFT - HF_SS32_SHIFT);
810 if (!(env->cr[0] & CR0_PE_MASK) ||
811 (env->eflags & VM_MASK) ||
812 !(hflags & HF_CS32_MASK)) {
813 hflags |= HF_ADDSEG_MASK;
814 } else {
815 hflags |= ((env->segs[R_DS].base |
816 env->segs[R_ES].base |
817 env->segs[R_SS].base) != 0) <<
818 HF_ADDSEG_SHIFT;
819 }
820 }
821 env->hflags = (env->hflags & HFLAG_COPY_MASK) | hflags;
822 return 0;
823}
824
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100825static int hax_sync_vcpu_register(CPUX86State *env, int set)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800826{
827 struct vcpu_state_t regs;
828 int ret;
829 memset(&regs, 0, sizeof(struct vcpu_state_t));
830
831 if (!set)
832 {
833 ret = hax_sync_vcpu_state(env, &regs, 0);
834 if (ret < 0)
835 return -1;
836 }
837
838 /*generic register */
839 hax_getput_reg(&regs._rax, &env->regs[R_EAX], set);
840 hax_getput_reg(&regs._rbx, &env->regs[R_EBX], set);
841 hax_getput_reg(&regs._rcx, &env->regs[R_ECX], set);
842 hax_getput_reg(&regs._rdx, &env->regs[R_EDX], set);
843 hax_getput_reg(&regs._rsi, &env->regs[R_ESI], set);
844 hax_getput_reg(&regs._rdi, &env->regs[R_EDI], set);
845 hax_getput_reg(&regs._rsp, &env->regs[R_ESP], set);
846 hax_getput_reg(&regs._rbp, &env->regs[R_EBP], set);
847
848 hax_getput_reg(&regs._rflags, &env->eflags, set);
849 hax_getput_reg(&regs._rip, &env->eip, set);
850
851 if (set)
852 {
853
854 regs._cr0 = env->cr[0];
855 regs._cr2 = env->cr[2];
856 regs._cr3 = env->cr[3];
857 regs._cr4 = env->cr[4];
858 hax_set_segments(env, &regs);
859 }
860 else
861 {
862 env->cr[0] = regs._cr0;
863 env->cr[2] = regs._cr2;
864 env->cr[3] = regs._cr3;
865 env->cr[4] = regs._cr4;
866 hax_get_segments(env, &regs);
867 }
868
869 if (set)
870 {
871 ret = hax_sync_vcpu_state(env, &regs, 1);
872 if (ret < 0)
873 return -1;
874 }
875 if (!set)
876 hax_setup_qemu_emulator(env);
877 return 0;
878}
879
880static void hax_msr_entry_set(struct vmx_msr *item,
881 uint32_t index, uint64_t value)
882{
883 item->entry = index;
884 item->value = value;
885}
886
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100887static int hax_get_msrs(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800888{
889 struct hax_msr_data md;
890 struct vmx_msr *msrs = md.entries;
891 int ret, i, n;
892
893 n = 0;
894 msrs[n++].entry = MSR_IA32_SYSENTER_CS;
895 msrs[n++].entry = MSR_IA32_SYSENTER_ESP;
896 msrs[n++].entry = MSR_IA32_SYSENTER_EIP;
897 msrs[n++].entry = MSR_IA32_TSC;
898 md.nr_msr = n;
899 ret = hax_sync_msr(env, &md, 0);
900 if (ret < 0)
901 return ret;
902
903 for (i = 0; i < md.done; i++) {
904 switch (msrs[i].entry) {
905 case MSR_IA32_SYSENTER_CS:
906 env->sysenter_cs = msrs[i].value;
907 break;
908 case MSR_IA32_SYSENTER_ESP:
909 env->sysenter_esp = msrs[i].value;
910 break;
911 case MSR_IA32_SYSENTER_EIP:
912 env->sysenter_eip = msrs[i].value;
913 break;
914 case MSR_IA32_TSC:
915 env->tsc = msrs[i].value;
916 break;
917 }
918 }
919
920 return 0;
921}
922
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100923static int hax_set_msrs(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800924{
925 struct hax_msr_data md;
926 struct vmx_msr *msrs;
927 msrs = md.entries;
928 int n = 0;
929
930 memset(&md, 0, sizeof(struct hax_msr_data));
931 hax_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_CS, env->sysenter_cs);
932 hax_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_ESP, env->sysenter_esp);
933 hax_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_EIP, env->sysenter_eip);
934 hax_msr_entry_set(&msrs[n++], MSR_IA32_TSC, env->tsc);
935 md.nr_msr = n;
936 md.done = 0;
937
938 return hax_sync_msr(env, &md, 1);
939
940}
941
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100942static int hax_get_fpu(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800943{
944 struct fx_layout fpu;
945 int i, ret;
946
947 ret = hax_sync_fpu(env, &fpu, 0);
948 if (ret < 0)
949 return ret;
950
951 env->fpstt = (fpu.fsw >> 11) & 7;
952 env->fpus = fpu.fsw;
953 env->fpuc = fpu.fcw;
954 for (i = 0; i < 8; ++i)
955 env->fptags[i] = !((fpu.ftw >> i) & 1);
956 memcpy(env->fpregs, fpu.st_mm, sizeof(env->fpregs));
957
958 memcpy(env->xmm_regs, fpu.mmx_1, sizeof(fpu.mmx_1));
959 memcpy((XMMReg *)(env->xmm_regs) + 8, fpu.mmx_2, sizeof(fpu.mmx_2));
960 env->mxcsr = fpu.mxcsr;
961
962 return 0;
963}
964
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100965static int hax_set_fpu(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800966{
967 struct fx_layout fpu;
968 int i;
969
970 memset(&fpu, 0, sizeof(fpu));
971 fpu.fsw = env->fpus & ~(7 << 11);
972 fpu.fsw |= (env->fpstt & 7) << 11;
973 fpu.fcw = env->fpuc;
974
975 for (i = 0; i < 8; ++i)
976 fpu.ftw |= (!env->fptags[i]) << i;
977
978 memcpy(fpu.st_mm, env->fpregs, sizeof (env->fpregs));
979 memcpy(fpu.mmx_1, env->xmm_regs, sizeof (fpu.mmx_1));
980 memcpy(fpu.mmx_2, (XMMReg *)(env->xmm_regs) + 8, sizeof (fpu.mmx_2));
981
982 fpu.mxcsr = env->mxcsr;
983
984 return hax_sync_fpu(env, &fpu, 1);
985}
986
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100987int hax_arch_get_registers(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -0800988{
989 int ret;
990
991 ret = hax_sync_vcpu_register(env, 0);
992 if (ret < 0)
993 return ret;
994
995 ret = hax_get_fpu(env);
996 if (ret < 0)
997 return ret;
998
999 ret = hax_get_msrs(env);
1000 if (ret < 0)
1001 return ret;
1002
1003 return 0;
1004}
1005
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001006static int hax_arch_set_registers(CPUX86State *env)
Jun Nakajimae4a3c782011-12-17 19:22:12 -08001007{
1008 int ret;
1009 ret = hax_sync_vcpu_register(env, 1);
1010
1011 if (ret < 0)
1012 {
1013 dprint("Failed to sync vcpu reg\n");
1014 return ret;
1015 }
1016 ret = hax_set_fpu(env);
1017 if (ret < 0)
1018 {
1019 dprint("FPU failed\n");
1020 return ret;
1021 }
1022 ret = hax_set_msrs(env);
1023 if (ret < 0)
1024 {
1025 dprint("MSR failed\n");
1026 return ret;
1027 }
1028
1029 return 0;
1030}
1031
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001032void hax_vcpu_sync_state(CPUX86State *env, int modified)
Jun Nakajimae4a3c782011-12-17 19:22:12 -08001033{
1034 if (hax_enabled()) {
1035 if (modified)
1036 hax_arch_set_registers(env);
1037 else
1038 hax_arch_get_registers(env);
1039 }
1040}
1041
1042/*
1043 * This is simpler than the one for KVM because we don't support
1044 * direct I/O device assignment at this point.
1045 */
1046int hax_sync_vcpus(void)
1047{
1048 if (hax_enabled())
1049 {
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001050 CPUX86State *env;
Jun Nakajimae4a3c782011-12-17 19:22:12 -08001051
1052 env = first_cpu;
1053 if (!env)
1054 return 0;
1055
1056 for (; env != NULL; env = env->next_cpu) {
1057 int ret;
1058
1059 ret = hax_arch_set_registers(env);
1060 if (ret < 0)
1061 {
1062 dprint("Failed to sync HAX vcpu context\n");
1063 exit(1);
1064 }
1065 }
1066 }
1067
1068 return 0;
1069}
1070
1071void hax_reset_vcpu_state(void *opaque)
1072{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001073 CPUX86State *env;
Jun Nakajimae4a3c782011-12-17 19:22:12 -08001074 for (env = first_cpu; env != NULL; env = env->next_cpu)
1075 {
1076 if (env->hax_vcpu)
1077 {
1078 env->hax_vcpu->emulation_state = HAX_EMULATE_STATE_INITIAL;
1079 env->hax_vcpu->tunnel->user_event_pending = 0;
1080 env->hax_vcpu->tunnel->ready_for_interrupt_injection = 0;
1081 }
1082 }
1083}