]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/examples/sys/vmtest/main.c
87327f8a407211125021a0e639d2dd19539a3da4
[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
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>
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23
24 #define STACKSIZE (8<<10)
25
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)));
30
31 static void init_vmcb(struct l4_vm_svm_vmcb *vmcb_s)
32 {
33
34   vmcb_s->control_area.np_enable = 1;
35   vmcb_s->control_area.guest_asid_tlb_ctl = 1;
36
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;
41
42
43 //  vmcb[256 +  0] = 0;        // es; attrib sel
44
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;
49
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;
54
55
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;
60
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;
65
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;
70
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;
75
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;
80
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;
85
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;
90
91   vmcb_s->state_save_area.g_pat = 0x7040600010406ULL;
92 }
93
94 static int check_svm(void)
95 {
96   l4_umword_t ax, bx, cx, dx;
97
98   if (!l4util_cpu_has_cpuid())
99     return 1;
100
101   l4util_cpu_cpuid(0x80000001, &ax, &bx, &cx, &dx);
102
103   if (!(cx & 4))
104     {
105       printf("CPU does not support SVM.\n");
106       return 1;
107     }
108
109   l4util_cpu_cpuid(0x8000000a, &ax, &bx, &cx, &dx);
110
111   printf("SVM revision: %lx\n", ax & 0xf);
112   printf("Number of ASIDs: %lx\n", bx);
113
114   return 0;
115 }
116
117 static int check_svm_npt(void)
118 {
119   l4_umword_t ax, bx, cx, dx;
120
121   l4util_cpu_cpuid(0x8000000a, &ax, &bx, &cx, &dx);
122
123   printf("NPT available: %s\n", dx & 1 ? "yes" : "no");
124
125   return (!(dx & 1));
126 }
127
128 static void run_test(int np_available)
129 {
130   l4_umword_t eflags;
131   l4_msgtag_t tag;
132   l4_cap_idx_t vm_task = l4re_util_cap_alloc();
133   int i;
134   unsigned long long exit_code[16];
135   l4_umword_t ip, marker, test_end;
136
137   printf("run test, np_available=%d\n", np_available);
138
139   if (l4_is_invalid_cap(vm_task))
140     {
141       printf("No more caps.\n");
142       return;
143     }
144
145   tag = l4_factory_create_vm(l4re_env()->factory, vm_task);
146   if (l4_error(tag))
147     {
148       printf("Failed to create new task\n");
149       exit(1);
150     }
151
152   struct l4_vm_svm_vmcb *vmcb_s = (struct l4_vm_svm_vmcb *) vmcb;
153   struct l4_vm_svm_gpregs gpregs =
154     { .edx = 1,
155       .ecx = 2,
156       .ebx = 3,
157       .ebp = 4,
158       .esi = 5,
159       .edi = 6,
160       .dr0 = 0,
161       .dr1 = 0,
162       .dr2 = 0,
163       .dr3 = 0
164     };
165
166   printf("clearing exit codes\n");
167
168   for (i = 0; i < 16; i++)
169     exit_code[i] = 1 << i;
170
171   asm volatile("    jmp 1f;           \n"
172                "2:  nop               \n"
173                "    nop               \n"
174                "    ud2               \n"
175                "    int3              \n"
176                "3:  nop               \n"
177                "    nop               \n"
178                "    int3              \n"
179                //"3:  nop               \n"
180                //"    int3              \n"
181                "    nop               \n"
182                "    nop               \n"
183                "    movl %%eax, %%ecx \n"
184                "    addl %%edx, %%ecx \n"
185                "4:                    \n"
186                "    ud2               \n"
187                "1:  movl $2b, %0      \n"
188                "    movl $3b, %1      \n"
189                "    movl $4b, %2      \n"
190                : "=r" (ip), "=r" (marker), "=r" (test_end));
191
192
193   init_vmcb(vmcb_s);
194
195   vmcb_s->state_save_area.cpl = 0;
196   vmcb_s->state_save_area.efer = 0x1000; // svme set
197
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; 
203
204   if (!np_available)
205     {
206       vmcb_s->state_save_area.cr0    |= 0x80000000;  // PG = 1
207       vmcb_s->control_area.np_enable &= ~1;
208     }
209
210   vmcb_s->state_save_area.dr7 = 0x300;
211   vmcb_s->state_save_area.dr6 = 0;
212
213   asm volatile("pushf     \n"
214                "popl %0   \n"
215                : "=r" (eflags));
216
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;
220
221   unsigned ofs;
222   for (ofs = 0; ofs < STACKSIZE; ofs += L4_PAGESIZE)
223     {
224       stack[ofs] = 0;
225       unsigned char c = stack[ofs];
226       unsigned dummy;
227
228       asm volatile("nop" : "=a"(dummy) : "0" (c));
229
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,
234                                        L4_MAP_ITEM_MAP));
235       printf("msgtag raw=%08x, ofs=%08x\n", (unsigned) tag.raw, ofs);
236     }
237
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));
241
242   printf("msgtag raw=%08lx, ip=%08lx\n", tag.raw, ip);
243
244   idt[26] = 0x80000; // #13 general protection fault
245   idt[27] = 0x8e00;
246
247   idt[28] = 0x80000; // #14 page fault
248   idt[29] = 0x8e00;
249
250   // code segment 0x08
251   gdt[2] = 0xffff;
252   gdt[3] = 0xcf9b00;
253
254   // stack segment 0x10
255   gdt[4] = 0xffff;
256   gdt[5] = 0xcf9300;
257
258   // data segment 0x20
259   gdt[8] = 0xffff;
260   gdt[9] = 0xcff300;
261
262   // tss 0x28
263   gdt[10] = 0x67;
264   gdt[11] = 0x8b00;
265
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);
271
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);
277
278
279 //  printf("sizes vmcb=%x, control=%x,  state=%x\n",
280 //         sizeof(*vmcb_s),
281 //         sizeof(vmcb_s->control_area), sizeof(vmcb_s->sitate_save_area));
282
283   printf("start rip=%llx\n", vmcb_s->state_save_area.rip);
284
285   vmcb_s->state_save_area.rax = 8;
286
287   for (i = 0; i < 16; i++)
288     {
289       unsigned long long old_rip;
290
291       if ((vmcb_s->state_save_area.rip >= marker))
292         {
293           //printf("set tf for rip=%llx\n", vmcb_s->state_save_area.rip);
294           vmcb_s->state_save_area.rflags |= 0x100; // set tf
295         }
296
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
300
301       //vmcb_s->control_area.exitcode = 0x100 << i;
302       vmcb_s->control_area.exitcode = 0;
303
304       old_rip = vmcb_s->state_save_area.rip;
305
306       tag = l4_vm_run_svm(vm_task,l4_fpage((unsigned long)vmcb, 12, 0), &gpregs);
307       if (l4_error(tag))
308         printf("vm-run failed: %s (%ld)\n",
309                l4sys_errtostr(l4_error(tag)), l4_error(tag));
310
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;
316
317
318       if (vmcb_s->control_area.exitcode == 0x43)
319         // int3 is treated as fault, not trap
320         vmcb_s->state_save_area.rip += 1;
321
322       if (vmcb_s->control_area.exitcode == 0x46)
323         {
324           if (vmcb_s->state_save_area.rip >= test_end)
325             break;
326           vmcb_s->state_save_area.rip += 2;
327         }
328
329       if (vmcb_s->control_area.exitcode == 0x400)
330         {
331           printf("host-level page fault; error code=%llx, gpa=%llx\n",
332                  vmcb_s->control_area.exitinfo1,
333                  vmcb_s->control_area.exitinfo2);
334         }
335
336       if (vmcb_s->control_area.exitcode == 0x4e)
337         {
338           printf("page fault; error code=%llx, pfa=%llx\n",
339                  vmcb_s->control_area.exitinfo1,
340                  vmcb_s->control_area.exitinfo2);
341         }
342
343       if (vmcb_s->control_area.exitcode == 0x4d)
344         {
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);
367           break;
368         }
369   }
370
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);
375
376   //for (j = 0; j < i; j++)
377   //  {
378   //    printf("exit_code[%d] = %llx\n", j, exit_code[i]);
379   //  }
380
381   printf("run vm stop, status=%s\n", gpregs.ecx == 9 ? "success" : "failure");
382
383   l4_task_unmap(L4RE_THIS_TASK_CAP,
384                 l4_obj_fpage(vm_task, 0, L4_FPAGE_RWX),
385                 L4_FP_ALL_SPACES);
386 }
387
388 int main(void)
389 {
390   printf("VM testing\n");
391
392   if (check_svm())
393     {
394       printf("No SVM CPU. Bye.\n");
395       return 1;
396     }
397
398   l4_touch_rw(stack, sizeof(stack));
399
400   run_test(0);
401
402   if (!check_svm_npt())
403     run_test(1);
404
405   return 0;
406 }