Major cleanups.
[akaros.git] / user / vmm / decode.c
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * This file is part of Akaros.
5  *
6  * Akarosn is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, version 2 of the License.
9  * 
10  * Akaros is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * Lesser GNU General Public License for more details.
14  * 
15  * See COPYING.LESSER for details on the GNU Lesser General Public License.
16  * See COPYING for details on the GNU General Public License.
17  */
18
19 #include <stdio.h>
20 #include <sys/types.h>
21 #include <pthread.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <parlib/arch/arch.h>
25 #include <parlib/ros_debug.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/uio.h>
31 #include <stdint.h>
32 #include <err.h>
33 #include <sys/mman.h>
34 #include <vmm/vmm.h>
35 #include <vmm/virtio.h>
36 #include <vmm/virtio_mmio.h>
37 #include <vmm/virtio_ids.h>
38 #include <vmm/virtio_config.h>
39
40 int debug_decode = 0;
41 #define DPRINTF(fmt, ...) \
42         if (debug_decode) { printf("decode: " fmt , ## __VA_ARGS__); }
43
44 static char *modrmreg[] = {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"};
45
46 char *regname(uint8_t reg)
47 {
48         return modrmreg[reg];
49 }
50
51 // This is a very limited function. It's only here to manage virtio-mmio and acpi root
52 // pointer loads. I am hoping it won't grow with time. The intent is that we enter it with
53 // and EPT fault from a region that is deliberately left unbacked by any memory. We return
54 // enough info to let you emulate the operation if you want.
55 // gpa is a pointer to the gpa. 
56 // int is the reg index which we can use for printing info.
57 // regp points to the register in hw_trapframe from which
58 // to load or store a result.
59 int decode(struct vmctl *v, uint64_t *gpa, uint8_t *destreg, uint64_t **regp, int *store)
60 {
61         int advance = 3; /* how much to move the IP forward at the end. 3 is a good default. */
62         //DPRINTF("v is %p\n", v);
63
64         // Duh, which way did he go George? Which way did he go? 
65         // First hit on Google gets you there!
66         // This is the guest physical address of the access.
67         // This is nice, because if we ever go with more complete
68         // instruction decode, knowing this gpa reduces our work:
69         // we don't have to find the source address in registers,
70         // only the register holding or receiving the value.
71         *gpa = v->gpa;
72         //DPRINTF("gpa is %p\n", *gpa);
73
74         // To find out what to do, we have to look at
75         // RIP. Technically, we should read RIP, walk the page tables
76         // to find the PA, and read that. But we're in the kernel, so
77         // we take a shortcut for now: read the low 30 bits and use
78         // that as the kernel PA, or our VA, and see what's
79         // there. Hokey. Works.
80         uint8_t *kva = (void *)(v->regs.tf_rip & 0x3fffffff);
81         //DPRINTF("kva is %p\n", kva);
82
83         // If this gets any longer we'll have to make a smarter loop. I'm betting it
84         // won't
85         if ((kva[0] != 0x8b) && (kva[0] != 0x89) && (kva[0] != 0x0f || kva[1] != 0xb7)) {
86                 fprintf(stderr, "%s: can't handle instruction 0x%x\n", kva[0]);
87                 return -1;
88         }
89
90         uint16_t ins = *(uint16_t *)kva;
91         //DPRINTF("ins is %04x\n", ins);
92         
93         *store = (kva[0] == 0x8b) ? 0 : 1;
94
95         if (kva[0] != 0x0f) {
96                 /* the dreaded mod/rm byte. */
97                 int mod = kva[1]>>6;
98                 switch (mod) {
99                 case 0: 
100                 case 3:
101                         advance = 2;
102                         break;
103                 case 1:
104                         advance = 3;
105                         break;
106                 case 2: 
107                         advance = 6;
108                         break;
109                 }
110         }
111
112         *destreg = (ins>>11) & 7;
113         // Our primitive approach wins big here.
114         // We don't have to decode the register or the offset used
115         // in the computation; that was done by the CPU and is the gpa.
116         // All we need to know is which destination or source register it is.
117         switch (*destreg) {
118         case 0:
119                 *regp = &v->regs.tf_rax;
120                 break;
121         case 1:
122                 *regp = &v->regs.tf_rcx;
123                 break;
124         case 2:
125                 *regp = &v->regs.tf_rdx;
126                 break;
127         case 3:
128                 *regp = &v->regs.tf_rbx;
129                 break;
130         case 4:
131                 *regp = &v->regs.tf_rsp; // uh, right.
132                 break;
133         case 5:
134                 *regp = &v->regs.tf_rbp;
135                 break;
136         case 6:
137                 *regp = &v->regs.tf_rsi;
138                 break;
139         case 7:
140                 *regp = &v->regs.tf_rdi;
141                 break;
142         }
143         v->regs.tf_rip += advance;
144         DPRINTF("Advance rip by %d bytes to %p\n", advance, v->regs.tf_rip);
145         return 0;
146 }
147