]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/examples/sys/vmtest/main.c
update
[l4.git] / l4 / pkg / examples / sys / vmtest / main.c
1 /*
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)
5  *
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.
9  */
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>
16
17 #include <l4/sys/irq.h>
18
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>
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include <pthread.h>
30
31 #define STACKSIZE (8<<10)
32
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)));
37
38 void vm_resume(void);
39 void handle_vmexit(void);
40 l4_vcpu_state_t *vcpu;
41 l4_vm_svm_vmcb_t *vmcb_s;
42
43 static void init_vmcb(l4_vm_svm_vmcb_t *vmcb_s) {
44
45     vmcb_s->control_area.np_enable = 1;
46     vmcb_s->control_area.guest_asid_tlb_ctl = 1;
47
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;
52
53     //  vmcb[256 +  0] = 0;        // es; attrib sel
54
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;
59
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;
64
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;
69
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;
74
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;
79
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;
84
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;
89
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;
94
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;
99
100     vmcb_s->state_save_area.g_pat = 0x7040600010406ULL;
101 }
102
103 static int check_svm(void) {
104     l4_umword_t ax, bx, cx, dx;
105
106     if (!l4util_cpu_has_cpuid())
107         return 1;
108
109     l4util_cpu_cpuid(0x80000001, &ax, &bx, &cx, &dx);
110
111     if (!(cx & 4)) {
112         printf("CPU does not support SVM.\n");
113         return 1;
114     }
115
116     l4util_cpu_cpuid(0x8000000a, &ax, &bx, &cx, &dx);
117
118     printf("SVM revision: %lx\n", ax & 0xf);
119     printf("Number of ASIDs: %lx\n", bx);
120
121     return 0;
122 }
123
124 static int check_svm_npt(void) {
125     l4_umword_t ax, bx, cx, dx;
126
127     l4util_cpu_cpuid(0x8000000a, &ax, &bx, &cx, &dx);
128
129     printf("NPT available: %s\n", dx & 1 ? "yes" : "no");
130
131     return (!(dx & 1));
132 }
133
134 int vmexit = 0;
135
136 static int cnt_triggered, cnt_received;
137
138 static void handler(void) {
139     //if(vmexit){
140         //vmexit = 0;
141         //handle_vmexit();
142     //} else {
143         // exception and ipc handling here
144     cnt_received++;
145     printf("received interrupt %d | %d %d\n", (int)vcpu->i.label,
146            cnt_triggered, cnt_received);
147     //}
148     vm_resume();
149 }
150
151 void vm_resume(void) {
152     unsigned long long old_rip;
153     l4_msgtag_t tag;
154
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
158 //    }
159
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
163
164     //vmcb_s->control_area.exitcode = 0x100 << i;
165     vmcb_s->control_area.exitcode = 0;
166
167     old_rip = vmcb_s->state_save_area.rip;
168
169     tag = l4_thread_vcpu_resume_commit(L4_INVALID_CAP,
170             l4_thread_vcpu_resume_start());
171     if (l4_error(tag))
172         printf("vm-resume failed: %s (%ld)\n", l4sys_errtostr(l4_error(tag)),
173                 l4_error(tag));
174
175     // if l4_thread_vcpu_resume_commit returns without error
176     // tell the handler that a vmexit occurred
177     vmexit = 1;
178     // and rewind the stack before we return into the handler
179     // simulating an upcall
180     handle_vmexit();
181     vm_resume();
182 #if 0
183     asm volatile (
184             "movl %0, %%esp\n"
185             "pushl %1\n"
186             "ret\n"
187             : : "r"(vcpu->entry_sp), "r"(handler) );
188 #endif
189 }
190
191 void handle_vmexit(void) {
192     static unsigned int i = 0;
193     ++i;
194     printf("iteration=%d, exit code=%llx", i,
195             vmcb_s->control_area.exitcode);
196
197     if (vmcb_s->control_area.exitcode == 0x43)
198         // int3 is treated as fault, not trap
199         vmcb_s->state_save_area.rip += 1;
200
201     if (vmcb_s->control_area.exitcode == 0x46) {
202 //        if (vmcb_s->state_save_area.rip >= test_end)
203 //            break;
204         vmcb_s->state_save_area.rip += 2;
205     }
206
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);
210     }
211
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);
215     }
216
217     if (vmcb_s->control_area.exitcode == 0x81) {
218         printf("VMMCALL\n");
219         vmcb_s->state_save_area.rip += 3;
220     }
221
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);
240     }
241 }
242
243 static l4_vcpu_state_t *get_state_mem(l4_addr_t *extstate) {
244     static int done;
245     long r;
246     l4_msgtag_t tag;
247     static l4_addr_t ext_state;
248
249     if (done) {
250         *extstate = ext_state;
251         return vcpu;
252     }
253
254     if ((r = l4vcpu_ext_alloc(&vcpu, &ext_state, L4_BASE_TASK_CAP,
255             l4re_env()->rm))) {
256         printf("Adding state mem failed: %ld\n", r);
257         exit(1);
258     }
259
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;
262
263     vcpu->entry_ip = (l4_umword_t)handler;
264     l4_umword_t * stack = (l4_umword_t*)(hdl_stack + STACKSIZE);
265     --stack;
266     *stack = 0;
267     vcpu->entry_sp = (l4_umword_t)stack;
268
269
270     tag = l4_thread_vcpu_control_ext(L4_INVALID_CAP, (l4_addr_t) vcpu);
271     if (l4_error(tag)) {
272         printf("Could not enable ext vCPU\n");
273         exit(1);
274     }
275
276     done = 1;
277     *extstate = ext_state;
278
279     return vcpu;
280 }
281
282
283 static void run_test(int np_available) {
284     l4_umword_t eflags;
285     l4_msgtag_t tag;
286     l4_cap_idx_t vm_task = l4re_util_cap_alloc();
287 //    int i;
288     l4_umword_t ip; //, marker, test_end;
289     l4_addr_t vmcx;
290     get_state_mem(&vmcx);
291
292     printf("run test, np_available=%d\n", np_available);
293
294     if (l4_is_invalid_cap(vm_task)) {
295         printf("No more caps.\n");
296         return;
297     }
298
299     tag = l4_factory_create_vm(l4re_env()->factory, vm_task);
300     if (l4_error(tag)) {
301         printf("Failed to create new task\n");
302         exit(1);
303     }
304
305     vmcb_s = (l4_vm_svm_vmcb_t *) vmcx;
306
307     vcpu->user_task = vm_task;
308
309     vcpu->r.dx = 1;
310     vcpu->r.cx = 2;
311     vcpu->r.bx = 3;
312     vcpu->r.bp = 4;
313     vcpu->r.si = 5;
314     vcpu->r.di = 6;
315
316     printf("clearing exit codes\n");
317
318     //  asm volatile("    jmp 1f;           \n"
319     //               "2:  nop               \n"
320     //               "    nop               \n"
321     //               "    ud2               \n"
322     //               "    int3              \n"
323     //               "3:  nop               \n"
324     //               "    nop               \n"
325     //               "    int3              \n"
326     //               //"3:  nop               \n"
327     //               //"    int3              \n"
328     //               "    nop               \n"
329     //               "    nop               \n"
330     //               "    movl %%eax, %%ecx \n"
331     //               "    addl %%edx, %%ecx \n"
332     //               "    vmmcall           \n"
333     //               "4:                    \n"
334     //               "    ud2               \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));
339
340     asm volatile("    jmp 1f;           \n"
341             "2:  nop               \n"
342             "    nop               \n"
343             "    nop               \n"
344             "    jmp 2b            \n"
345             "1:  movl $2b, %0      \n"
346             : "=r" (ip));
347
348     init_vmcb(vmcb_s);
349
350     vmcb_s->state_save_area.cpl = 0;
351     vmcb_s->state_save_area.efer = 0x1000; // svme set
352
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;
358
359     if (!np_available) {
360         vmcb_s->state_save_area.cr0 |= 0x80000000; // PG = 1
361         vmcb_s->control_area.np_enable &= ~1;
362     }
363
364     vmcb_s->state_save_area.dr7 = 0x300;
365     vmcb_s->state_save_area.dr6 = 0;
366
367     asm volatile("pushf     \n"
368             "popl %0   \n"
369             : "=r" (eflags));
370
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;
374
375     unsigned ofs;
376     for (ofs = 0; ofs < STACKSIZE; ofs += L4_PAGESIZE) {
377         stack[ofs] = 0;
378         unsigned char c = stack[ofs];
379         unsigned dummy;
380
381         asm volatile("nop" : "=a"(dummy) : "0" (c));
382
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,
386                 L4_MAP_ITEM_MAP));
387         printf("msgtag raw=%08x, ofs=%08x\n", (unsigned) tag.raw, ofs);
388     }
389
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));
392
393     printf("msgtag raw=%08lx, ip=%08lx\n", tag.raw, ip);
394
395     idt[26] = 0x80000; // #13 general protection fault
396     idt[27] = 0x8e00;
397
398     idt[28] = 0x80000; // #14 page fault
399     idt[29] = 0x8e00;
400
401     // code segment 0x08
402     gdt[2] = 0xffff;
403     gdt[3] = 0xcf9b00;
404
405     // stack segment 0x10
406     gdt[4] = 0xffff;
407     gdt[5] = 0xcf9300;
408
409     // data segment 0x20
410     gdt[8] = 0xffff;
411     gdt[9] = 0xcff300;
412
413     // tss 0x28
414     gdt[10] = 0x67;
415     gdt[11] = 0x8b00;
416
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);
422
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);
428
429     //  printf("sizes vmcb=%x, control=%x,  state=%x\n",
430     //         sizeof(*vmcb_s),
431     //         sizeof(vmcb_s->control_area), sizeof(vmcb_s->sitate_save_area));
432
433     printf("start rip=%llx\n", vmcb_s->state_save_area.rip);
434
435     vmcb_s->state_save_area.rax = 8;
436
437     vm_resume();
438
439 }
440
441
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);
446 //
447 //  printf("run vm stop, status=%s\n", vcpu->r.cx == 9 ? "success" : "failure");
448 //
449 //  l4_task_unmap(L4RE_THIS_TASK_CAP,
450 //                l4_obj_fpage(vm_task, 0, L4_FPAGE_RWX),
451 //                L4_FP_ALL_SPACES);
452 //}
453
454 #include <l4/sys/ktrace.h>
455 l4_cap_idx_t timer_irq;
456 void * timer_thread(void * );
457 void * timer_thread(void * data) {
458     (void)data;
459     l4_sleep(1000);
460     fiasco_tbuf_log("FIRST");
461     while(1){
462         l4_sleep(200);
463         fiasco_tbuf_log("Trig");
464         printf("trigger\n");
465         cnt_triggered++;
466         l4_irq_trigger(timer_irq);
467     }
468 }
469
470 #include <unistd.h>
471
472 int main(void)
473 {
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");
477
478     if (l4_error(l4_irq_attach(timer_irq, 0x120, L4_INVALID_CAP)))
479         printf("irq attach failed\n");
480
481     printf("VM testing\n");
482
483     if (check_svm())
484       {
485         printf("No SVM CPU. Bye.\n");
486         return 1;
487       }
488
489     l4_touch_rw(stack, sizeof(stack));
490     l4_touch_rw(hdl_stack, sizeof(hdl_stack));
491
492     pthread_t pthread_timer_thread;
493
494     pthread_create(&pthread_timer_thread, NULL, timer_thread, NULL);
495
496     run_test(0);
497
498     if (!check_svm_npt())
499         run_test(1);
500
501     return 0;
502 }