VMM: Added header for virtio_lguest_console functions
[akaros.git] / user / vmm / decode.c
index afcefb6..39910d6 100644 (file)
@@ -6,12 +6,12 @@
  * Akarosn is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, version 2 of the License.
- * 
+ *
  * Akaros is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * Lesser GNU General Public License for more details.
- * 
+ *
  * See COPYING.LESSER for details on the GNU Lesser General Public License.
  * See COPYING for details on the GNU General Public License.
  */
@@ -36,6 +36,7 @@
 #include <vmm/virtio_mmio.h>
 #include <vmm/virtio_ids.h>
 #include <vmm/virtio_config.h>
+#include <ros/arch/trapframe.h>
 
 int debug_decode = 0;
 #define DPRINTF(fmt, ...) \
@@ -50,10 +51,10 @@ static char *modrmreg[] = {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi
 // The ugly messiness of the SIB and all that are not yet needed. Maybe they
 // never will be.
 
-// Target size -- 1, 2, 4, or 8 bytes. We have yet to see 64 bytes. 
+// Target size -- 1, 2, 4, or 8 bytes. We have yet to see 64 bytes.
 // TODO: if we ever see it, test the prefix. Since this only supports the low 1M,
 // that's not likely.
-static int target(void *insn, int *store) 
+static int target(void *insn, int *store)
 {
        *store = 0;
        int s = -1;
@@ -78,10 +79,22 @@ static int target(void *insn, int *store)
                break;
        case 0x89:
        case 0x8b:
-               s = 2;
+               // TODO: To really know, for sure, that this is 32 bit, we'd likely have
+               //       to check the segment descriptor for the guest's current code
+               //       segment in it's GDT. The D flag (bit 22) determines whether the
+               //       instruction is using 32 or 16-bit operand size. I'm just going
+               //       to assume the flag is set (meaning 32 bit operands) for now, in
+               //       order to make virtio work. But really we should check if we
+               //       want to know for sure. Note that this hack (changing the below
+               //       line) only applies to mov instructions.
+               //
+               //       And I think there's also a prefix you can use to switch the
+               //       instruction to 16-bit addressing
+               //       (address-size override prefix?)
+               s = 4;
                break;
        case 0x81:
-               s = 4;  
+               s = 4;
                break;
        case 0x0f:
        switch(*word) {
@@ -136,9 +149,9 @@ static int insize(void *rip)
        int rm = kva[1] & 7;
 
        switch(kva[0]) {
-       default: 
+       default:
                fprintf(stderr, "BUG! %s got 0x%x\n", __func__, kva[0]);
-       case 0x0f: 
+       case 0x0f:
                break;
        case 0x81:
                advance = 6 + extra;
@@ -149,13 +162,13 @@ static int insize(void *rip)
        case 0x89:
        case 0x8b:
                switch (mod) {
-               case 0: 
+               case 0:
                        advance = 2 + (rm == 4) + extra;
                        break;
                case 1:
                        advance = 3 + (rm == 4) + extra;
                        break;
-               case 2: 
+               case 2:
                        advance = 6 + (rm == 4) + extra;
                        break;
                case 3:
@@ -174,23 +187,25 @@ static int insize(void *rip)
 // address (gpa) the decode is far simpler because we only need to find the register, how many bytes
 // to move, and how big the instruction is. I thought about bringing in emulate.c from kvm from xen,
 // but it has way more stuff than we need.
-// gpa is a pointer to the gpa. 
+// gpa is a pointer to the gpa.
 // int is the reg index which we can use for printing info.
 // regp points to the register in hw_trapframe from which
 // to load or store a result.
-int decode(struct vmctl *v, uint64_t *gpa, uint8_t *destreg, uint64_t **regp, int *store, int *size, int *advance)
+int decode(struct guest_thread *vm_thread, uint64_t *gpa, uint8_t *destreg,
+           uint64_t **regp, int *store, int *size, int *advance)
 {
+       struct vm_trapframe *vm_tf = &(vm_thread->uthread.u_ctx.tf.vm_tf);
 
-       DPRINTF("v is %p\n", v);
+       DPRINTF("v is %p\n", vm_tf);
 
-       // Duh, which way did he go George? Which way did he go? 
+       // Duh, which way did he go George? Which way did he go?
        // First hit on Google gets you there!
        // This is the guest physical address of the access.
        // This is nice, because if we ever go with more complete
        // instruction decode, knowing this gpa reduces our work:
        // we don't have to find the source address in registers,
        // only the register holding or receiving the value.
-       *gpa = v->gpa;
+       *gpa = vm_tf->tf_guest_pa;
        DPRINTF("gpa is %p\n", *gpa);
 
        // To find out what to do, we have to look at
@@ -199,7 +214,7 @@ int decode(struct vmctl *v, uint64_t *gpa, uint8_t *destreg, uint64_t **regp, in
        // we take a shortcut for now: read the low 30 bits and use
        // that as the kernel PA, or our VA, and see what's
        // there. Hokey. Works.
-       uint8_t *kva = (void *)(v->regs.tf_rip & 0x3fffffff);
+       uint8_t *kva = (void *)(vm_tf->tf_rip & 0x3fffffff);
        DPRINTF("kva is %p\n", kva);
 
        // fail fast. If we can't get the size we're done.
@@ -211,7 +226,7 @@ int decode(struct vmctl *v, uint64_t *gpa, uint8_t *destreg, uint64_t **regp, in
 
        uint16_t ins = *(uint16_t *)(kva + (kva[0] == 0x44));
        DPRINTF("ins is %04x\n", ins);
-               
+
        *destreg = (ins>>11) & 7;
        *destreg += 8*(kva[0] == 0x44);
        // Our primitive approach wins big here.
@@ -220,69 +235,53 @@ int decode(struct vmctl *v, uint64_t *gpa, uint8_t *destreg, uint64_t **regp, in
        // All we need to know is which destination or source register it is.
        switch (*destreg) {
        case 0:
-               *regp = &v->regs.tf_rax;
+               *regp = &vm_tf->tf_rax;
                break;
        case 1:
-               *regp = &v->regs.tf_rcx;
+               *regp = &vm_tf->tf_rcx;
                break;
        case 2:
-               *regp = &v->regs.tf_rdx;
+               *regp = &vm_tf->tf_rdx;
                break;
        case 3:
-               *regp = &v->regs.tf_rbx;
+               *regp = &vm_tf->tf_rbx;
                break;
        case 4:
-               *regp = &v->regs.tf_rsp; // uh, right.
+               *regp = &vm_tf->tf_rsp; // uh, right.
                break;
        case 5:
-               *regp = &v->regs.tf_rbp;
+               *regp = &vm_tf->tf_rbp;
                break;
        case 6:
-               *regp = &v->regs.tf_rsi;
+               *regp = &vm_tf->tf_rsi;
                break;
        case 7:
-               *regp = &v->regs.tf_rdi;
+               *regp = &vm_tf->tf_rdi;
                break;
        case 8:
-               *regp = &v->regs.tf_r8;
+               *regp = &vm_tf->tf_r8;
                break;
        case 9:
-               *regp = &v->regs.tf_r9;
+               *regp = &vm_tf->tf_r9;
                break;
        case 10:
-               *regp = &v->regs.tf_r10;
+               *regp = &vm_tf->tf_r10;
                break;
        case 11:
-               *regp = &v->regs.tf_r11;
+               *regp = &vm_tf->tf_r11;
                break;
        case 12:
-               *regp = &v->regs.tf_r12;
+               *regp = &vm_tf->tf_r12;
                break;
        case 13:
-               *regp = &v->regs.tf_r13;
+               *regp = &vm_tf->tf_r13;
                break;
        case 14:
-               *regp = &v->regs.tf_r14;
+               *regp = &vm_tf->tf_r14;
                break;
        case 15:
-               *regp = &v->regs.tf_r15;
+               *regp = &vm_tf->tf_r15;
                break;
        }
        return 0;
 }
-
-#if 0
-// stupid emulator since what we need is so limited.
-int emu(struct vmctl *v, uint64_t gpa, uint8_t destreg, uint64_t *regp, int store, int size, int advance)
-{
-       uint8_t *kva = f->regs.tf_rip;
-
-       if (
-       switch(kva[0]) {
-
-                               val = *(uint64_t*) (lowmem + gpa); 
-                               printf("val %p ", val);
-                               memcpy(regp, &val, size);
-
-}
-#endif