Add page table walk for guest va to pa translation
[akaros.git] / user / vmm / vmx.c
1 #include <stdio.h>
2 #include <pthread.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <fcntl.h>
6 #include <parlib/arch/arch.h>
7 #include <parlib/ros_debug.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <dirent.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ros/syscall.h>
14 #include <sys/mman.h>
15 #include <vmm/coreboot_tables.h>
16 #include <ros/common.h>
17 #include <vmm/vmm.h>
18 #include <vmm/virtio.h>
19 #include <vmm/virtio_mmio.h>
20 #include <vmm/virtio_ids.h>
21 #include <ros/arch/vmx.h>
22 #include <vmm/sched.h>
23 #include <ros/arch/mmu.h>
24 #include <ros/arch/trapframe.h>
25
26 char *vmxexit[] = {
27         VMX_EXIT_REASONS
28 };
29
30 void showstatus(FILE *f, struct guest_thread *vm_thread)
31 {
32         struct vm_trapframe *vm_tf = &(vm_thread->uthread.u_ctx.tf.vm_tf);
33         int shutdown = vm_tf->tf_exit_reason;
34         char *when = shutdown & VMX_EXIT_REASONS_FAILED_VMENTRY ? "entry" : "exit";
35         shutdown &= ~VMX_EXIT_REASONS_FAILED_VMENTRY;
36         char *reason = "UNKNOWN";
37         if (shutdown < COUNT_OF(vmxexit) && vmxexit[shutdown])
38                 reason = vmxexit[shutdown];
39         fprintf(f, "Shutdown: core %d, %s due to %s(0x%x); ret code 0x%x\n",
40                 vm_tf->tf_guest_pcoreid, when, reason, shutdown,
41                         vm_tf->tf_exit_reason);
42         fprintf(f, "  gva %p gpa %p cr3 %p\n", (void *)vm_tf->tf_guest_va,
43                 (void *)vm_tf->tf_guest_pa, (void *)vm_tf->tf_cr3);
44
45         fprintf(f, "  rax  0x%016lx\n",           vm_tf->tf_rax);
46         fprintf(f, "  rbx  0x%016lx\n",           vm_tf->tf_rbx);
47         fprintf(f, "  rcx  0x%016lx\n",           vm_tf->tf_rcx);
48         fprintf(f, "  rdx  0x%016lx\n",           vm_tf->tf_rdx);
49         fprintf(f, "  rbp  0x%016lx\n",           vm_tf->tf_rbp);
50         fprintf(f, "  rsi  0x%016lx\n",           vm_tf->tf_rsi);
51         fprintf(f, "  rdi  0x%016lx\n",           vm_tf->tf_rdi);
52         fprintf(f, "  r8   0x%016lx\n",           vm_tf->tf_r8);
53         fprintf(f, "  r9   0x%016lx\n",           vm_tf->tf_r9);
54         fprintf(f, "  r10  0x%016lx\n",           vm_tf->tf_r10);
55         fprintf(f, "  r11  0x%016lx\n",           vm_tf->tf_r11);
56         fprintf(f, "  r12  0x%016lx\n",           vm_tf->tf_r12);
57         fprintf(f, "  r13  0x%016lx\n",           vm_tf->tf_r13);
58         fprintf(f, "  r14  0x%016lx\n",           vm_tf->tf_r14);
59         fprintf(f, "  r15  0x%016lx\n",           vm_tf->tf_r15);
60 }
61
62 /* Convert a kernel guest virtual address to physical address.
63  * Assumes that the guest VA is in the high negative address space.
64  * TODO: Takes the vm_thread argument so that we can walk the page tables
65  * instead of just coercing the pointer. Therefore, this is not in vmm.h
66  * since it may get complex. */
67 int gvatogpa(struct guest_thread *vm_thread, uint64_t va, uint64_t *pa)
68 {
69         assert(vm_thread != NULL);
70         struct vm_trapframe *vm_tf = gth_to_vmtf(vm_thread);
71         uint64_t *ptptr = (uint64_t *)vm_tf->tf_cr3;
72         uint64_t entry;
73
74         for (int shift = PML4_SHIFT; shift >= PML1_SHIFT; shift -= BITS_PER_PML) {
75                 entry = ptptr[PMLx(va, shift)];
76
77                 if (!PAGE_PRESENT(entry))
78                         return -1;
79                 if ((entry & PTE_PS) != 0) {
80                         uint64_t bitmask = ((1 << shift) - 1);
81
82                         *pa = (((uint64_t)va & bitmask) | (entry & ~bitmask));
83                         return 0;
84                 }
85                 ptptr = (uint64_t *)PG_ADDR(entry);
86         }
87         *pa = ((uint64_t)va & 0xfff) | (uint64_t)ptptr;
88         return 0;
89 }
90
91 /* Get the RIP as a physical address. */
92 int rippa(struct guest_thread *vm_thread, uint64_t *pa)
93 {
94         assert(vm_thread != NULL);
95         return gvatogpa(vm_thread, gth_to_vmtf(vm_thread)->tf_rip, pa);
96 }