2 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3 * Henning Schild <hschild@os.inf.tu-dresden.de>
4 * economic rights: Technische Universität Dresden (Germany)
6 * This file is part of TUD:OS and distributed under the terms of the
7 * GNU General Public License 2.
8 * Please see the COPYING-GPL-2 file for details.
10 #include <l4/sys/factory.h>
11 #include <l4/sys/task.h>
12 #include <l4/sys/kdebug.h>
13 #include <l4/sys/vm.h>
14 #include <l4/sys/thread.h>
15 #include <l4/sys/vcpu.h>
17 #include <l4/sys/irq.h>
19 #include <l4/util/util.h>
20 #include <l4/util/cpu.h>
21 #include <l4/re/env.h>
22 #include <l4/re/c/util/cap_alloc.h>
23 #include <l4/vcpu/vcpu.h>
31 #define STACKSIZE (8<<10)
33 static char stack[STACKSIZE];
34 static char hdl_stack[STACKSIZE];
35 static unsigned long idt[32 * 2] __attribute__((aligned(4096)));
36 static unsigned long gdt[32 * 2] __attribute__((aligned(4096)));
39 void handle_vmexit(void);
40 l4_vcpu_state_t *vcpu;
41 l4_vm_svm_vmcb_t *vmcb_s;
43 static void init_vmcb(l4_vm_svm_vmcb_t *vmcb_s) {
45 vmcb_s->control_area.np_enable = 1;
46 vmcb_s->control_area.guest_asid_tlb_ctl = 1;
48 vmcb_s->state_save_area.es.selector = 0;
49 vmcb_s->state_save_area.es.attrib = 0;
50 vmcb_s->state_save_area.es.limit = 0;
51 vmcb_s->state_save_area.es.base = 0ULL;
53 // vmcb[256 + 0] = 0; // es; attrib sel
55 vmcb_s->state_save_area.cs.selector = 0x8;
56 vmcb_s->state_save_area.cs.attrib = 0xc9b;
57 vmcb_s->state_save_area.cs.limit = 0xffffffff;
58 vmcb_s->state_save_area.cs.base = 0ULL;
60 vmcb_s->state_save_area.ss.selector = 0x10;
61 vmcb_s->state_save_area.ss.attrib = 0xc93;
62 vmcb_s->state_save_area.ss.limit = 0xffffffff;
63 vmcb_s->state_save_area.ss.base = 0ULL;
65 vmcb_s->state_save_area.ds.selector = 0x23;
66 vmcb_s->state_save_area.ds.attrib = 0xcf3;
67 vmcb_s->state_save_area.ds.limit = 0xffffffff;
68 vmcb_s->state_save_area.ds.base = 0ULL;
70 vmcb_s->state_save_area.fs.selector = 0;
71 vmcb_s->state_save_area.fs.attrib = 0xcf3;
72 vmcb_s->state_save_area.fs.limit = 0xffffffff;
73 vmcb_s->state_save_area.fs.base = 0ULL;
75 vmcb_s->state_save_area.gs.selector = 0;
76 vmcb_s->state_save_area.gs.attrib = 0xcf3;
77 vmcb_s->state_save_area.gs.limit = 0xffffffff;
78 vmcb_s->state_save_area.gs.base = 0ULL;
80 vmcb_s->state_save_area.gdtr.selector = 0;
81 vmcb_s->state_save_area.gdtr.attrib = 0;
82 vmcb_s->state_save_area.gdtr.limit = 0x3f;
83 vmcb_s->state_save_area.gdtr.base = (unsigned long) gdt;
85 vmcb_s->state_save_area.ldtr.selector = 0;
86 vmcb_s->state_save_area.ldtr.attrib = 0;
87 vmcb_s->state_save_area.ldtr.limit = 0;
88 vmcb_s->state_save_area.ldtr.base = 0;
90 vmcb_s->state_save_area.idtr.selector = 0;
91 vmcb_s->state_save_area.idtr.attrib = 0;
92 vmcb_s->state_save_area.idtr.limit = 0xff;
93 vmcb_s->state_save_area.idtr.base = (unsigned long) idt;
95 vmcb_s->state_save_area.tr.selector = 0x28;
96 vmcb_s->state_save_area.tr.attrib = 0x8b;
97 vmcb_s->state_save_area.tr.limit = 0x67;
98 vmcb_s->state_save_area.tr.base = 0;
100 vmcb_s->state_save_area.g_pat = 0x7040600010406ULL;
103 static int check_svm(void) {
104 l4_umword_t ax, bx, cx, dx;
106 if (!l4util_cpu_has_cpuid())
109 l4util_cpu_cpuid(0x80000001, &ax, &bx, &cx, &dx);
112 printf("CPU does not support SVM.\n");
116 l4util_cpu_cpuid(0x8000000a, &ax, &bx, &cx, &dx);
118 printf("SVM revision: %lx\n", ax & 0xf);
119 printf("Number of ASIDs: %lx\n", bx);
124 static int check_svm_npt(void) {
125 l4_umword_t ax, bx, cx, dx;
127 l4util_cpu_cpuid(0x8000000a, &ax, &bx, &cx, &dx);
129 printf("NPT available: %s\n", dx & 1 ? "yes" : "no");
136 static int cnt_triggered, cnt_received;
138 static void handler(void) {
143 // exception and ipc handling here
145 printf("received interrupt %d | %d %d\n", (int)vcpu->i.label,
146 cnt_triggered, cnt_received);
151 void vm_resume(void) {
152 unsigned long long old_rip;
155 // if ((vmcb_s->state_save_area.rip >= marker)) {
156 // //printf("set tf for rip=%llx\n", vmcb_s->state_save_area.rip);
157 // vmcb_s->state_save_area.rflags |= 0x100; // set tf
160 vmcb_s->control_area.intercept_exceptions |= 0xa; // intercept #1 & #3
161 vmcb_s->control_area.intercept_exceptions |= 0xffffffff;
162 vmcb_s->control_area.intercept_instruction1 |= 0x20; // intercept int1
164 //vmcb_s->control_area.exitcode = 0x100 << i;
165 vmcb_s->control_area.exitcode = 0;
167 old_rip = vmcb_s->state_save_area.rip;
169 tag = l4_thread_vcpu_resume_commit(L4_INVALID_CAP,
170 l4_thread_vcpu_resume_start());
172 printf("vm-resume failed: %s (%ld)\n", l4sys_errtostr(l4_error(tag)),
175 // if l4_thread_vcpu_resume_commit returns without error
176 // tell the handler that a vmexit occurred
178 // and rewind the stack before we return into the handler
179 // simulating an upcall
187 : : "r"(vcpu->entry_sp), "r"(handler) );
191 void handle_vmexit(void) {
192 static unsigned int i = 0;
194 printf("iteration=%d, exit code=%llx", i,
195 vmcb_s->control_area.exitcode);
197 if (vmcb_s->control_area.exitcode == 0x43)
198 // int3 is treated as fault, not trap
199 vmcb_s->state_save_area.rip += 1;
201 if (vmcb_s->control_area.exitcode == 0x46) {
202 // if (vmcb_s->state_save_area.rip >= test_end)
204 vmcb_s->state_save_area.rip += 2;
207 if (vmcb_s->control_area.exitcode == 0x400) {
208 printf("host-level page fault; error code=%llx, gpa=%llx\n",
209 vmcb_s->control_area.exitinfo1, vmcb_s->control_area.exitinfo2);
212 if (vmcb_s->control_area.exitcode == 0x4e) {
213 printf("page fault; error code=%llx, pfa=%llx\n",
214 vmcb_s->control_area.exitinfo1, vmcb_s->control_area.exitinfo2);
217 if (vmcb_s->control_area.exitcode == 0x81) {
219 vmcb_s->state_save_area.rip += 3;
222 if (vmcb_s->control_area.exitcode == 0x4d) {
223 printf("cs=%08x attrib=%x, limit=%x, base=%llx\n",
224 vmcb_s->state_save_area.cs.selector,
225 vmcb_s->state_save_area.cs.attrib,
226 vmcb_s->state_save_area.cs.limit,
227 vmcb_s->state_save_area.cs.base);
228 printf("ss=%08x attrib=%x, limit=%x, base=%llx\n",
229 vmcb_s->state_save_area.ss.selector,
230 vmcb_s->state_save_area.ss.attrib,
231 vmcb_s->state_save_area.ss.limit,
232 vmcb_s->state_save_area.ss.base);
233 printf("np_enabled=%lld\n", vmcb_s->control_area.np_enable);
234 printf("cr0=%llx cr4=%llx\n", vmcb_s->state_save_area.cr0,
235 vmcb_s->state_save_area.cr4);
236 printf("interrupt_ctl=%llx\n", vmcb_s->control_area.interrupt_ctl);
237 printf("rip=%llx, rsp=%llx, cpl=%d\n", vmcb_s->state_save_area.rip,
238 vmcb_s->state_save_area.rsp, vmcb_s->state_save_area.cpl);
239 printf("exitinfo1=%llx\n", vmcb_s->control_area.exitinfo1);
243 static l4_vcpu_state_t *get_state_mem(l4_addr_t *extstate) {
247 static l4_addr_t ext_state;
250 *extstate = ext_state;
254 if ((r = l4vcpu_ext_alloc(&vcpu, &ext_state, L4_BASE_TASK_CAP,
256 printf("Adding state mem failed: %ld\n", r);
260 vcpu->state = L4_VCPU_F_FPU_ENABLED;
261 vcpu->saved_state = L4_VCPU_F_USER_MODE | L4_VCPU_F_FPU_ENABLED | L4_VCPU_F_IRQ;
263 vcpu->entry_ip = (l4_umword_t)handler;
264 l4_umword_t * stack = (l4_umword_t*)(hdl_stack + STACKSIZE);
267 vcpu->entry_sp = (l4_umword_t)stack;
270 tag = l4_thread_vcpu_control_ext(L4_INVALID_CAP, (l4_addr_t) vcpu);
272 printf("Could not enable ext vCPU\n");
277 *extstate = ext_state;
283 static void run_test(int np_available) {
286 l4_cap_idx_t vm_task = l4re_util_cap_alloc();
288 l4_umword_t ip; //, marker, test_end;
290 get_state_mem(&vmcx);
292 printf("run test, np_available=%d\n", np_available);
294 if (l4_is_invalid_cap(vm_task)) {
295 printf("No more caps.\n");
299 tag = l4_factory_create_vm(l4re_env()->factory, vm_task);
301 printf("Failed to create new task\n");
305 vmcb_s = (l4_vm_svm_vmcb_t *) vmcx;
307 vcpu->user_task = vm_task;
316 printf("clearing exit codes\n");
318 // asm volatile(" jmp 1f; \n"
330 // " movl %%eax, %%ecx \n"
331 // " addl %%edx, %%ecx \n"
335 // "1: movl $2b, %0 \n"
336 // " movl $3b, %1 \n"
337 // " movl $4b, %2 \n"
338 // : "=r" (ip), "=r" (marker), "=r" (test_end));
340 asm volatile(" jmp 1f; \n"
350 vmcb_s->state_save_area.cpl = 0;
351 vmcb_s->state_save_area.efer = 0x1000; // svme set
353 vmcb_s->state_save_area.cr4 = 0x690;
354 vmcb_s->state_save_area.cr3 = 0;
355 // PG[31] = 0, WP[16] = 1, NE[5] = 1, ET[4] = 1
356 // TS[3] = 1, MP[1] = 1, PE[0] = 1
357 vmcb_s->state_save_area.cr0 = 0x1003b;
360 vmcb_s->state_save_area.cr0 |= 0x80000000; // PG = 1
361 vmcb_s->control_area.np_enable &= ~1;
364 vmcb_s->state_save_area.dr7 = 0x300;
365 vmcb_s->state_save_area.dr6 = 0;
367 asm volatile("pushf \n"
371 vmcb_s->state_save_area.rflags = eflags;
372 vmcb_s->state_save_area.rip = ip;
373 vmcb_s->state_save_area.rsp = (l4_umword_t) stack + STACKSIZE;
376 for (ofs = 0; ofs < STACKSIZE; ofs += L4_PAGESIZE) {
378 unsigned char c = stack[ofs];
381 asm volatile("nop" : "=a"(dummy) : "0" (c));
383 tag = l4_task_map(vm_task, L4RE_THIS_TASK_CAP, l4_fpage(
384 (((l4_umword_t)(stack)) + ofs) & L4_PAGEMASK, L4_PAGESHIFT,
385 L4_FPAGE_RW), l4_map_control(((l4_umword_t) stack) + ofs, 0,
387 printf("msgtag raw=%08x, ofs=%08x\n", (unsigned) tag.raw, ofs);
390 tag = l4_task_map(vm_task, L4RE_THIS_TASK_CAP, l4_fpage(ip & L4_PAGEMASK,
391 L4_PAGESHIFT, L4_FPAGE_RW), l4_map_control(ip, 0, L4_MAP_ITEM_MAP));
393 printf("msgtag raw=%08lx, ip=%08lx\n", tag.raw, ip);
395 idt[26] = 0x80000; // #13 general protection fault
398 idt[28] = 0x80000; // #14 page fault
405 // stack segment 0x10
417 unsigned idt0 = (unsigned) idt;
418 tag = l4_task_map(vm_task, L4RE_THIS_TASK_CAP, l4_fpage(idt0 & L4_PAGEMASK,
419 L4_PAGESHIFT, L4_FPAGE_RW),
420 l4_map_control(idt0, 0, L4_MAP_ITEM_MAP));
421 printf("msgtag raw=%08x, idt=%08x\n", (unsigned) tag.raw, idt0);
423 unsigned gdt0 = (unsigned) gdt;
424 tag = l4_task_map(vm_task, L4RE_THIS_TASK_CAP, l4_fpage(gdt0 & L4_PAGEMASK,
425 L4_PAGESHIFT, L4_FPAGE_RW),
426 l4_map_control(gdt0, 0, L4_MAP_ITEM_MAP));
427 printf("msgtag raw=%08x, gdt=%08x\n", (unsigned) tag.raw, gdt0);
429 // printf("sizes vmcb=%x, control=%x, state=%x\n",
431 // sizeof(vmcb_s->control_area), sizeof(vmcb_s->sitate_save_area));
433 printf("start rip=%llx\n", vmcb_s->state_save_area.rip);
435 vmcb_s->state_save_area.rax = 8;
442 // printf("rip=%08llx, rax=%llx, edx=%lx, ecx=%lx\n",
443 // vmcb_s->state_save_area.rip,
444 // vmcb_s->state_save_area.rax,
445 // vcpu->r.dx, vcpu->r.cx);
447 // printf("run vm stop, status=%s\n", vcpu->r.cx == 9 ? "success" : "failure");
449 // l4_task_unmap(L4RE_THIS_TASK_CAP,
450 // l4_obj_fpage(vm_task, 0, L4_FPAGE_RWX),
451 // L4_FP_ALL_SPACES);
454 #include <l4/sys/ktrace.h>
455 l4_cap_idx_t timer_irq;
456 void * timer_thread(void * );
457 void * timer_thread(void * data) {
460 fiasco_tbuf_log("FIRST");
463 fiasco_tbuf_log("Trig");
466 l4_irq_trigger(timer_irq);
474 timer_irq = l4re_util_cap_alloc();
475 if (l4_error(l4_factory_create_irq(l4re_env()->factory, timer_irq)))
476 printf("irq creation failed\n");
478 if (l4_error(l4_irq_attach(timer_irq, 0x120, L4_INVALID_CAP)))
479 printf("irq attach failed\n");
481 printf("VM testing\n");
485 printf("No SVM CPU. Bye.\n");
489 l4_touch_rw(stack, sizeof(stack));
490 l4_touch_rw(hdl_stack, sizeof(hdl_stack));
492 pthread_t pthread_timer_thread;
494 pthread_create(&pthread_timer_thread, NULL, timer_thread, NULL);
498 if (!check_svm_npt())