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>
15 #include <l4/util/util.h>
16 #include <l4/util/cpu.h>
17 #include <l4/re/env.h>
18 #include <l4/re/c/util/cap_alloc.h>
24 #define STACKSIZE (8<<10)
26 static char stack[STACKSIZE];
27 static unsigned long vmcb[1024] __attribute__((aligned(4096)));
28 static unsigned long idt[32 * 2] __attribute__((aligned(4096)));
29 static unsigned long gdt[32 * 2] __attribute__((aligned(4096)));
31 static void init_vmcb(struct l4_vm_svm_vmcb *vmcb_s)
34 vmcb_s->control_area.np_enable = 1;
35 vmcb_s->control_area.guest_asid_tlb_ctl = 1;
37 vmcb_s->state_save_area.es.selector = 0;
38 vmcb_s->state_save_area.es.attrib = 0;
39 vmcb_s->state_save_area.es.limit = 0;
40 vmcb_s->state_save_area.es.base = 0ULL;
43 // vmcb[256 + 0] = 0; // es; attrib sel
45 vmcb_s->state_save_area.cs.selector = 0x8;
46 vmcb_s->state_save_area.cs.attrib = 0xc9b;
47 vmcb_s->state_save_area.cs.limit = 0xffffffff;
48 vmcb_s->state_save_area.cs.base = 0ULL;
50 vmcb_s->state_save_area.ss.selector = 0x10;
51 vmcb_s->state_save_area.ss.attrib = 0xc93;
52 vmcb_s->state_save_area.ss.limit = 0xffffffff;
53 vmcb_s->state_save_area.ss.base = 0ULL;
56 vmcb_s->state_save_area.ds.selector = 0x23;
57 vmcb_s->state_save_area.ds.attrib = 0xcf3;
58 vmcb_s->state_save_area.ds.limit = 0xffffffff;
59 vmcb_s->state_save_area.ds.base = 0ULL;
61 vmcb_s->state_save_area.fs.selector = 0;
62 vmcb_s->state_save_area.fs.attrib = 0xcf3;
63 vmcb_s->state_save_area.fs.limit = 0xffffffff;
64 vmcb_s->state_save_area.fs.base = 0ULL;
66 vmcb_s->state_save_area.gs.selector = 0;
67 vmcb_s->state_save_area.gs.attrib = 0xcf3;
68 vmcb_s->state_save_area.gs.limit = 0xffffffff;
69 vmcb_s->state_save_area.gs.base = 0ULL;
71 vmcb_s->state_save_area.gdtr.selector = 0;
72 vmcb_s->state_save_area.gdtr.attrib = 0;
73 vmcb_s->state_save_area.gdtr.limit = 0x3f;
74 vmcb_s->state_save_area.gdtr.base = (unsigned long) gdt;
76 vmcb_s->state_save_area.ldtr.selector = 0;
77 vmcb_s->state_save_area.ldtr.attrib = 0;
78 vmcb_s->state_save_area.ldtr.limit = 0;
79 vmcb_s->state_save_area.ldtr.base = 0;
81 vmcb_s->state_save_area.idtr.selector = 0;
82 vmcb_s->state_save_area.idtr.attrib = 0;
83 vmcb_s->state_save_area.idtr.limit = 0xff;
84 vmcb_s->state_save_area.idtr.base = (unsigned long) idt;
86 vmcb_s->state_save_area.tr.selector = 0x28;
87 vmcb_s->state_save_area.tr.attrib = 0x8b;
88 vmcb_s->state_save_area.tr.limit = 0x67;
89 vmcb_s->state_save_area.tr.base = 0;
91 vmcb_s->state_save_area.g_pat = 0x7040600010406ULL;
94 static int check_svm(void)
96 l4_umword_t ax, bx, cx, dx;
98 if (!l4util_cpu_has_cpuid())
101 l4util_cpu_cpuid(0x80000001, &ax, &bx, &cx, &dx);
105 printf("CPU does not support SVM.\n");
109 l4util_cpu_cpuid(0x8000000a, &ax, &bx, &cx, &dx);
111 printf("SVM revision: %lx\n", ax & 0xf);
112 printf("Number of ASIDs: %lx\n", bx);
117 static int check_svm_npt(void)
119 l4_umword_t ax, bx, cx, dx;
121 l4util_cpu_cpuid(0x8000000a, &ax, &bx, &cx, &dx);
123 printf("NPT available: %s\n", dx & 1 ? "yes" : "no");
128 static void run_test(int np_available)
132 l4_cap_idx_t vm_task = l4re_util_cap_alloc();
134 unsigned long long exit_code[16];
135 l4_umword_t ip, marker, test_end;
137 printf("run test, np_available=%d\n", np_available);
139 if (l4_is_invalid_cap(vm_task))
141 printf("No more caps.\n");
145 tag = l4_factory_create_vm(l4re_env()->factory, vm_task);
148 printf("Failed to create new task\n");
152 struct l4_vm_svm_vmcb *vmcb_s = (struct l4_vm_svm_vmcb *) vmcb;
153 struct l4_vm_svm_gpregs gpregs =
166 printf("clearing exit codes\n");
168 for (i = 0; i < 16; i++)
169 exit_code[i] = 1 << i;
171 asm volatile(" jmp 1f; \n"
183 " movl %%eax, %%ecx \n"
184 " addl %%edx, %%ecx \n"
190 : "=r" (ip), "=r" (marker), "=r" (test_end));
195 vmcb_s->state_save_area.cpl = 0;
196 vmcb_s->state_save_area.efer = 0x1000; // svme set
198 vmcb_s->state_save_area.cr4 = 0x690;
199 vmcb_s->state_save_area.cr3 = 0;
200 // PG[31] = 0, WP[16] = 1, NE[5] = 1, ET[4] = 1
201 // TS[3] = 1, MP[1] = 1, PE[0] = 1
202 vmcb_s->state_save_area.cr0 = 0x1003b;
206 vmcb_s->state_save_area.cr0 |= 0x80000000; // PG = 1
207 vmcb_s->control_area.np_enable &= ~1;
210 vmcb_s->state_save_area.dr7 = 0x300;
211 vmcb_s->state_save_area.dr6 = 0;
213 asm volatile("pushf \n"
217 vmcb_s->state_save_area.rflags = eflags;
218 vmcb_s->state_save_area.rip = ip;
219 vmcb_s->state_save_area.rsp = (l4_umword_t)stack + STACKSIZE;
222 for (ofs = 0; ofs < STACKSIZE; ofs += L4_PAGESIZE)
225 unsigned char c = stack[ofs];
228 asm volatile("nop" : "=a"(dummy) : "0" (c));
230 tag = l4_task_map(vm_task, L4RE_THIS_TASK_CAP,
231 l4_fpage((((l4_umword_t)(stack)) + ofs) & L4_PAGEMASK,
232 L4_PAGESHIFT, L4_FPAGE_RW),
233 l4_map_control(((l4_umword_t)stack) + ofs, 0,
235 printf("msgtag raw=%08x, ofs=%08x\n", (unsigned) tag.raw, ofs);
238 tag = l4_task_map(vm_task, L4RE_THIS_TASK_CAP,
239 l4_fpage(ip & L4_PAGEMASK, L4_PAGESHIFT, L4_FPAGE_RW),
240 l4_map_control(ip, 0, L4_MAP_ITEM_MAP));
242 printf("msgtag raw=%08lx, ip=%08lx\n", tag.raw, ip);
244 idt[26] = 0x80000; // #13 general protection fault
247 idt[28] = 0x80000; // #14 page fault
254 // stack segment 0x10
266 unsigned idt0 = (unsigned) idt;
267 tag = l4_task_map(vm_task, L4RE_THIS_TASK_CAP,
268 l4_fpage(idt0 & L4_PAGEMASK, L4_PAGESHIFT, L4_FPAGE_RW),
269 l4_map_control(idt0, 0, L4_MAP_ITEM_MAP));
270 printf("msgtag raw=%08x, idt=%08x\n", (unsigned) tag.raw, idt0);
272 unsigned gdt0 = (unsigned) gdt;
273 tag = l4_task_map(vm_task, L4RE_THIS_TASK_CAP,
274 l4_fpage(gdt0 & L4_PAGEMASK, L4_PAGESHIFT, L4_FPAGE_RW),
275 l4_map_control(gdt0, 0, L4_MAP_ITEM_MAP));
276 printf("msgtag raw=%08x, gdt=%08x\n", (unsigned) tag.raw, gdt0);
279 // printf("sizes vmcb=%x, control=%x, state=%x\n",
281 // sizeof(vmcb_s->control_area), sizeof(vmcb_s->sitate_save_area));
283 printf("start rip=%llx\n", vmcb_s->state_save_area.rip);
285 vmcb_s->state_save_area.rax = 8;
287 for (i = 0; i < 16; i++)
289 unsigned long long old_rip;
291 if ((vmcb_s->state_save_area.rip >= marker))
293 //printf("set tf for rip=%llx\n", vmcb_s->state_save_area.rip);
294 vmcb_s->state_save_area.rflags |= 0x100; // set tf
297 vmcb_s->control_area.intercept_exceptions |= 0xa; // intercept #1 & #3
298 vmcb_s->control_area.intercept_exceptions |= 0xffffffff;
299 vmcb_s->control_area.intercept_instruction1 |= 0x20; // intercept int1
301 //vmcb_s->control_area.exitcode = 0x100 << i;
302 vmcb_s->control_area.exitcode = 0;
304 old_rip = vmcb_s->state_save_area.rip;
306 tag = l4_vm_run_svm(vm_task,l4_fpage((unsigned long)vmcb, 12, 0), &gpregs);
308 printf("vm-run failed: %s (%ld)\n",
309 l4sys_errtostr(l4_error(tag)), l4_error(tag));
311 printf("iteration=%d, exit code=%llx, rip=%llx -> %llx\n",
312 i, vmcb_s->control_area.exitcode,
313 old_rip, vmcb_s->state_save_area.rip);
314 //exit_code[i] = vmcb[28];
315 //exit_code[i] = vmcb_s->control_area.exitcode;
318 if (vmcb_s->control_area.exitcode == 0x43)
319 // int3 is treated as fault, not trap
320 vmcb_s->state_save_area.rip += 1;
322 if (vmcb_s->control_area.exitcode == 0x46)
324 if (vmcb_s->state_save_area.rip >= test_end)
326 vmcb_s->state_save_area.rip += 2;
329 if (vmcb_s->control_area.exitcode == 0x400)
331 printf("host-level page fault; error code=%llx, gpa=%llx\n",
332 vmcb_s->control_area.exitinfo1,
333 vmcb_s->control_area.exitinfo2);
336 if (vmcb_s->control_area.exitcode == 0x4e)
338 printf("page fault; error code=%llx, pfa=%llx\n",
339 vmcb_s->control_area.exitinfo1,
340 vmcb_s->control_area.exitinfo2);
343 if (vmcb_s->control_area.exitcode == 0x4d)
345 printf("cs=%08x attrib=%x, limit=%x, base=%llx\n",
346 vmcb_s->state_save_area.cs.selector,
347 vmcb_s->state_save_area.cs.attrib,
348 vmcb_s->state_save_area.cs.limit,
349 vmcb_s->state_save_area.cs.base);
350 printf("ss=%08x attrib=%x, limit=%x, base=%llx\n",
351 vmcb_s->state_save_area.ss.selector,
352 vmcb_s->state_save_area.ss.attrib,
353 vmcb_s->state_save_area.ss.limit,
354 vmcb_s->state_save_area.ss.base);
355 printf("np_enabled=%lld\n",
356 vmcb_s->control_area.np_enable);
357 printf("cr0=%llx cr4=%llx\n",
358 vmcb_s->state_save_area.cr0,
359 vmcb_s->state_save_area.cr4);
360 printf("interrupt_ctl=%llx\n",
361 vmcb_s->control_area.interrupt_ctl);
362 printf("rip=%llx, rsp=%llx, cpl=%d\n",
363 vmcb_s->state_save_area.rip,
364 vmcb_s->state_save_area.rsp,
365 vmcb_s->state_save_area.cpl);
366 printf("exitinfo1=%llx\n", vmcb_s->control_area.exitinfo1);
371 printf("rip=%08llx, rax=%llx, edx=%lx, ecx=%lx\n",
372 vmcb_s->state_save_area.rip,
373 vmcb_s->state_save_area.rax,
374 gpregs.edx, gpregs.ecx);
376 //for (j = 0; j < i; j++)
378 // printf("exit_code[%d] = %llx\n", j, exit_code[i]);
381 printf("run vm stop, status=%s\n", gpregs.ecx == 9 ? "success" : "failure");
383 l4_task_unmap(L4RE_THIS_TASK_CAP,
384 l4_obj_fpage(vm_task, 0, L4_FPAGE_RWX),
390 printf("VM testing\n");
394 printf("No SVM CPU. Bye.\n");
398 l4_touch_rw(stack, sizeof(stack));
402 if (!check_svm_npt())