// Second opcode byte
static const uchar_t lmsw_byte = 0x01;
+static const uchar_t lmsw_reg_byte = 0x6;
static const uchar_t smsw_byte = 0x01;
+static const uchar_t smsw_reg_byte = 0x4;
static const uchar_t clts_byte = 0x06;
static const uchar_t mov_to_cr_byte = 0x22;
static const uchar_t mov_from_cr_byte = 0x20;
#include <geekos/vmm_mem.h>
#include <geekos/ktypes.h>
#include <geekos/vmm_io.h>
-//#include <geekos/vmm_paging.h>
-
-
+#include <geekos/vmm_shadow_paging.h>
-struct guest_info;
+typedef ullong_t gpr_t;
-#include <geekos/vmm_shadow_paging.h>
+/*
+ struct guest_gprs {
+ addr_t rax;
+ addr_t rbx;
+ addr_t rcx;
+ addr_t rdx;
+ addr_t rsi;
+ addr_t rdi;
+ addr_t rbp;
+ };
+*/
struct guest_gprs {
- ullong_t rbx;
- ullong_t rcx;
- ullong_t rdx;
- ullong_t rsi;
- ullong_t rdi;
- ullong_t rbp;
-
+ gpr_t rdi;
+ gpr_t rsi;
+ gpr_t rbp;
+ gpr_t rsp;
+ gpr_t rbx;
+ gpr_t rdx;
+ gpr_t rcx;
+ gpr_t rax;
};
+struct shadow_page_state;
+
+
typedef enum {SHADOW_PAGING, NESTED_PAGING} vm_page_mode_t;
typedef enum {REAL, PROTECTED, PROTECTED_PG, PROTECTED_PAE, PROTECTED_PAE_PG, LONG, LONG_PG} vm_cpu_mode_t;
struct guest_info {
ullong_t rip;
- ullong_t rsp;
+
shadow_map_t mem_map;
vm_page_mode_t page_mode;
- struct shadow_page_state shdw_pg_state;
+ struct shadow_page_state shdw_pg_state;
// nested_paging_t nested_page_state;
int read_guest_va_memory(struct guest_info * guest_info, addr_t guest_va, int count, char * dest);
int read_guest_pa_memory(struct guest_info * guest_info, addr_t guest_pa, int count, char * dest);
-
+int write_guest_pa_memory(struct guest_info * guest_info, addr_t guest_pa, int count, char * src);
+// TODO int write_guest_va_memory(struct guest_info * guest_info, addr_t guest_va, int count, char * src);
#ifndef __VMM_EMULATE_H
#define __VMM_EMULATE_H
+#include <geekos/vm_guest.h>
-/* JRL: Most of this was taken from the Xen sources...
+/*
+ * This is where we do the hideous X86 instruction parsing among other things
+ * We can parse out the instruction prefixes, as well as decode the operands
+ *
+ * Before we begin I'd just like to say a few words to those that made this possible...
+ *
+ *
+ * _____
+ * || ||
+ * |\___/|
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * _____|<--->|_____
+ * ___/ | | \
+ * / | | | | \
+ * | | | | | |
+ * | | | | | |
+ * | | |
+ * | | |
+ * | Fuck You Intel! /
+ * | /
+ * \ /
+ * \ /
+ * | |
+ * | |
+ *
+ * That is all.
+ *
+ */
+
+
+/* JRL: Some of this was taken from the Xen sources...
*
*/
+#define PACKED __attribute__((packed))
+
+#define MODRM_MOD(x) ((x >> 6) & 0x3)
+#define MODRM_REG(x) ((x >> 3) & 0x7)
+#define MODRM_RM(x) (x & 0x07)
+
+struct modrm_byte {
+ uint_t rm : 3 PACKED;
+ uint_t reg : 3 PACKED;
+ uint_t mod : 2 PACKED;
+};
+
+
+struct sib_byte {
+ uint_t base : 3 PACKED;
+ uint_t index : 3 PACKED;
+ uint_t scale : 2 PACKED;
+};
+
+
#define MAKE_INSTR(nm, ...) static const uchar_t OPCODE_##nm[] = { __VA_ARGS__ }
}
}
+typedef enum {INVALID_ADDR_TYPE, REG, DISP0, DISP8, DISP16, DISP32} modrm_addr_type_t;
+typedef enum {INVALID_REG_SIZE, REG64, REG32, REG16, REG8} reg_size_t;
+typedef enum {INVALID_OPERAND_TYPE, REG_TO_REG, REG_TO_MEM, MEM_TO_REG} operand_type_t;
+
+struct guest_gprs;
+
+
+static inline int decode_operands16(struct guest_gprs * gprs,
+ char * modrm_instr,
+ addr_t * first_operand,
+ addr_t * second_operand,
+ reg_size_t reg_size) {
+
+ struct modrm_byte * modrm = (struct modrm_byte*)modrm_instr;
+ addr_t base_addr = 0;
+ modrm_addr_type_t mod_type = 0;
+
+ PrintDebug("ModRM mod=%d\n", modrm->mod);
+
+ if (modrm->mod == 3) {
+ mod_type = REG;
+
+ PrintDebug("first operand = Register (RM=%d)\n",modrm->rm);
+
+ switch (modrm->rm) {
+ case 0:
+ PrintDebug("EAX Operand\n");
+ *first_operand = (addr_t)&(gprs->rax);
+ break;
+ case 1:
+ *first_operand = (addr_t)&(gprs->rcx);
+ break;
+ case 2:
+ *first_operand = (addr_t)&(gprs->rdx);
+ break;
+ case 3:
+ *first_operand = (addr_t)&(gprs->rbx);
+ break;
+ case 4:
+ if (reg_size == REG8) {
+ *first_operand = (addr_t)(&(gprs->rax) + 1);
+ } else {
+ *first_operand = (addr_t)&(gprs->rsp);
+ }
+ break;
+ case 5:
+ if (reg_size == REG8) {
+ *first_operand = (addr_t)(&(gprs->rcx) + 1);
+ } else {
+ *first_operand = (addr_t)&(gprs->rbp);
+ }
+ break;
+ case 6:
+ if (reg_size == REG8) {
+ *first_operand = (addr_t)(&(gprs->rdx) + 1);
+ } else {
+ *first_operand = (addr_t)&(gprs->rsi);
+ }
+ break;
+ case 7:
+ if (reg_size == REG8) {
+ *first_operand = (addr_t)(&(gprs->rbx) + 1);
+ } else {
+ *first_operand = (addr_t)&(gprs->rdi);
+ }
+ break;
+ }
+
+ } else {
+ if (modrm->mod == 0) {
+ mod_type = DISP0;
+ } else if (modrm->mod == 1) {
+ mod_type = DISP8;
+ } else if (modrm->mod == 2) {
+ mod_type = DISP16;
+ }
+
+ switch (modrm->rm) {
+ case 0:
+ base_addr = gprs->rbx + gprs->rsi;
+ case 1:
+ base_addr = gprs->rbx + gprs->rdi;
+ case 2:
+ base_addr = gprs->rbp + gprs->rsi;
+ case 3:
+ base_addr = gprs->rbp + gprs->rdi;
+ case 4:
+ base_addr = gprs->rsi;
+ case 5:
+ base_addr = gprs->rdi;
+ case 6:
+ if (modrm->mod == 0) {
+ base_addr = 0;
+ mod_type = DISP16;
+ } else {
+ base_addr = gprs->rbp;
+ }
+ case 7:
+ base_addr = gprs->rbx;
+ }
+
+ if (mod_type == DISP8) {
+ base_addr += (uchar_t)*(modrm_instr + 1);
+ } else if (mod_type == DISP16) {
+ base_addr += (ushort_t)*(modrm_instr + 1);
+ }
+
+
+ *first_operand = base_addr;
+ }
+
+
+
+ switch (modrm->reg) {
+ case 0:
+ *second_operand = (addr_t)&(gprs->rax);
+ break;
+ case 1:
+ *second_operand = (addr_t)&(gprs->rcx);
+ break;
+ case 2:
+ *second_operand = (addr_t)&(gprs->rdx);
+ break;
+ case 3:
+ *second_operand = (addr_t)&(gprs->rbx);
+ break;
+ case 4:
+ if (reg_size == REG8) {
+ *second_operand = (addr_t)&(gprs->rax) + 1;
+ } else {
+ *second_operand = (addr_t)&(gprs->rsp);
+ }
+ break;
+ case 5:
+ if (reg_size == REG8) {
+ *second_operand = (addr_t)&(gprs->rcx) + 1;
+ } else {
+ *second_operand = (addr_t)&(gprs->rbp);
+ }
+ break;
+ case 6:
+ if (reg_size == REG8) {
+ *second_operand = (addr_t)&(gprs->rdx) + 1;
+ } else {
+ *second_operand = (addr_t)&(gprs->rsi);
+ }
+ break;
+ case 7:
+ if (reg_size == REG8) {
+ *second_operand = (addr_t)&(gprs->rbx) + 1;
+ } else {
+ *second_operand = (addr_t)&(gprs->rdi);
+ }
+ break;
+ }
+
+ return 0;
+
+}
-
-#include <geekos/vm_guest.h>
+struct guest_info;
pde32_t * create_passthrough_pde32_pts(struct guest_info * guest_info);
#define __VMM_SHADOW_PAGING_H
-#include <geekos/vmm_paging.h>
#include <geekos/vmm_util.h>
+
+#include <geekos/vmm_paging.h>
+
struct shadow_page_state {
// these two reflect the top-level page directory
-
-
-#include <geekos/vm_guest.h>
struct guest_info;
+
int init_shadow_page_state(struct shadow_page_state * state);
// This function will cause the shadow page table to be deleted
* Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
* Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
* Copyright (c) 2004, Iulian Neamtiu <neamtiu@cs.umd.edu>
- * $Revision: 1.25 $
+ * $Revision: 1.26 $
*
* This is free software. You are permitted to use,
* redistribute, and modify it as specified in the file "COPYING".
vm_info.rip = rip;
rsp = (addr_t)Alloc_Page();
- vm_info.rsp = (rsp +4092 );// - 0x2000;
+ vm_info.vm_regs.rsp = (rsp +4092 );// - 0x2000;
} else {
vm_info.cs.limit=0xffff;
*/
vm_info.rip = 0xfff0;
- vm_info.rsp = 0x0;
+ vm_info.vm_regs.rsp = 0x0;
}
- PrintBoth("Initializing Guest (eip=0x%.8x) (esp=0x%.8x)\n", (uint_t)vm_info.rip,(uint_t)vm_info.rsp);
+ PrintBoth("Initializing Guest (eip=0x%.8x) (esp=0x%.8x)\n", (uint_t)vm_info.rip,(uint_t)vm_info.vm_regs.rsp);
(vmm_ops).init_guest(&vm_info);
PrintBoth("Starting Guest\n");
(vmm_ops).start_guest(&vm_info);
PrintDebug("Initializing VMCB (addr=%x)\n", info->vmm_data);
Init_VMCB((vmcb_t*)(info->vmm_data), *info);
-
- info->vm_regs.rbx = 0;
- info->vm_regs.rcx = 0;
- info->vm_regs.rdx = 0;
- info->vm_regs.rsi = 0;
+ info->rip = 0;
+
info->vm_regs.rdi = 0;
+ info->vm_regs.rsi = 0;
info->vm_regs.rbp = 0;
-
+ info->vm_regs.rsp = 0;
+ info->vm_regs.rbx = 0;
+ info->vm_regs.rdx = 0;
+ info->vm_regs.rcx = 0;
+ info->vm_regs.rax = 0;
+
return 0;
}
//PrintDebugVMCB((vmcb_t*)(info->vmm_data));
while (1) {
-
+ PrintDebug("SVM Launch Args (vmcb=%x), (info=%x), (vm_regs=%x)\n", info->vmm_data, &(info->vm_regs));
safe_svm_launch((vmcb_t*)(info->vmm_data), &(info->vm_regs));
//launch_svm((vmcb_t*)(info->vmm_data));
PrintDebug("SVM Returned\n");
if (handle_svm_exit(info) != 0) {
+ // handle exit code....
break;
}
}
uint_t i;
- guest_state->rsp = vm_info.rsp;
+ guest_state->rsp = vm_info.vm_regs.rsp;
guest_state->rip = vm_info.rip;
uint_t i;
- guest_state->rsp = vm_info.rsp;
+ guest_state->rsp = vm_info.vm_regs.rsp;
guest_state->rip = vm_info.rip;
uint_t i = 0;
- guest_state->rsp = vm_info.rsp;
+ guest_state->rsp = vm_info.vm_regs.rsp;
guest_state->rip = vm_info.rip;
#include <geekos/vmm.h>
#include <geekos/vmcb.h>
#include <geekos/vmm_emulate.h>
-
+#include <geekos/vm_guest_mem.h>
int handle_cr0_write(struct guest_info * info, ullong_t * new_cr0) {
- vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
+ //vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
char instr[15];
int index = 0;
while (is_prefix_byte(instr[index])) {
+ PrintDebug("instr(%d): 0x%x\n", index, instr[index]);
index++;
}
-
+ PrintDebug("instr(%d): 0x%x\n", index, instr[index]);
+ PrintDebug("instr(%d): 0x%x\n", index+1, instr[index + 1]);
+
if ((instr[index] == cr_access_byte) &&
- (instr[index + 1] == lmsw_byte)) {
+ (instr[index + 1] == lmsw_byte) &&
+ (MODRM_REG(instr[index + 2]) == lmsw_reg_byte)) {
+
+ addr_t first_operand;
+ addr_t second_operand;
+
// LMSW
// decode mod/RM
+ index += 2;
+
+
+ if (decode_operands16(&(info->vm_regs), instr + index, &first_operand, &second_operand, REG16) != 0) {
+ // error... don't know what to do
+ return -1;
+ }
+
+ PrintDebug("FirstOperand addr: %x, RAX addr: %x\n", first_operand, &(info->vm_regs.rax));
+
+
+
} else if ((instr[index] == cr_access_byte) &&
(instr[index + 1] == clts_byte)) {
#include <geekos/vmm.h>
#include <geekos/svm_ctrl_regs.h>
+extern struct vmm_os_hooks * os_hooks;
+
int handle_svm_exit(struct guest_info * info) {
vmcb_ctrl_t * guest_ctrl = 0;
// Update the high level state
info->rip = guest_state->rip;
- info->rsp = guest_state->rsp;
+ info->vm_regs.rsp = guest_state->rsp;
+ info->vm_regs.rax = guest_state->rax;
+ info->vm_regs.rsp = guest_state->rsp;
- PrintDebug("SVM Returned: (Exit Code=%x) (VMCB=%x)\n",&(guest_ctrl->exit_code), info->vmm_data);
+ PrintDebug("SVM Returned: (Exit Code=%x) (VMCB=%x)\n", &(guest_ctrl->exit_code), info->vmm_data);
PrintDebug("RIP: %x\n", guest_state->rip);
exit_code = guest_ctrl->exit_code;
- // PrintDebugVMCB((vmcb_t*)(info->vmm_data));
+ // PrintDebugVMCB((vmcb_t*)(info->vmm_data));
PrintDebug("SVM Returned: Exit Code: %x\n",exit_code);
PrintDebug("io_info1 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info1));
PrintDebug("io_info1 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
// Update the low level state
+ guest_state->rax = info->vm_regs.rax;
guest_state->rip = info->rip;
- guest_state->rsp = info->rsp;
+ guest_state->rsp = info->vm_regs.rsp;
return 0;
}
%include "defs.asm"
%include "symbol.asm"
+SVM_ERROR equ 0xFFFFFFFF
+SVM_SUCCESS equ 0x00000000
EXPORT DisableInts
EXPORT safe_svm_launch
+
+
;; These need to be kept similar with the svm return values in svm.h
SVM_HANDLER_SUCCESS equ 0x00
SVM_HANDLER_ERROR equ 0x1
; Save and restore registers needed by SVM
%macro Save_SVM_Registers 1
- mov [%1], ebx
- mov [%1 + 8], ecx
- mov [%1 + 16], edx
- mov [%1 + 24], esi
- mov [%1 + 32], edi
- mov [%1 + 40], ebp
+ push eax
+ mov eax, dword %1
+ mov [eax], edi
+ mov [eax + 8], esi
+ mov [eax + 16], ebp
+ mov [eax + 24], dword 0 ;; esp
+ mov [eax + 32], ebx
+ mov [eax + 40], edx
+ mov [eax + 48], ecx
+
+ push ebx
+ mov ebx, [esp + 4]
+ mov [eax + 56], ebx ;; eax
+ pop ebx
+
+ pop eax
%endmacro
%macro Restore_SVM_Registers 1
- mov ebx, [%1]
- mov ecx, [%1 + 8]
- mov edx, [%1 + 16]
- mov esi, [%1 + 24]
- mov edi, [%1 + 32]
- mov ebp, [%1 + 40]
+ push eax
+ mov eax, dword %1
+ mov edi, [eax]
+ mov esi, [eax + 8]
+ mov ebp, [eax + 16]
+;; mov esp, [eax + 24]
+ mov ebx, [eax + 32]
+ mov edx, [eax + 40]
+ mov ecx, [eax + 48]
+;; mov eax, [eax + 56]
+ pop eax
%endmacro
%macro vmrun 0
push ebp
mov ebp, esp
pushf
- pusha ;; Save Host state
+ pusha ;; Save Host state
- push dword [ebp + 12] ;; pointer to the guest GPR save area
- push dword [ebp + 8] ;; pointer to the VMCB pointer
+ push dword [ebp + 12] ;; pointer to the guest GPR save area
+ push dword [ebp + 8] ;; pointer to the VMCB pointer
- mov eax, [esp + 4] ;; mov guest GPR pointer to eax
+;; mov eax, [esp + 4] ;; mov guest GPR pointer to eax
- Restore_SVM_Registers eax ;; Restore Guest GPR state
- pop eax ;; pop VMCB pointer into eax
+ Restore_SVM_Registers [esp + 4] ;; Restore Guest GPR state
+ pop eax ;; pop VMCB pointer into eax
vmload
vmrun
vmsave
- pop eax ;; pop Guest GPR pointer into eax
- Save_SVM_Registers eax ;; save guest GPRs
-
- popa ;; Restore Host state
+;; pop eax ;; pop Guest GPR pointer into eax
+ Save_SVM_Registers [esp] ;; save guest GPRs
+
+ add esp, 4 ;; skip past the gpr ptr
+
+ popa ;; Restore Host state
popf
pop ebp
ret
-;;align 8
-;;safe_svm_launch:
-;; push ebp
-;; mov ebp, esp
-;; pushf
-;; pusha
-;;
-;.vmm_loop:
-; mov eax, [ebp + 8]
-; vmrun
-; Save_SVM_Registers
-;
-; call handle_svm_exit
-;
-; mov [ebp + 12], eax
-;
-; and eax, eax
-;
-; Restore_SVM_Registers
-;
-; jz .vmm_loop
-;
-; popa
-; popf
-; pop ebp
-; ret
-
-
%endif
*/
int read_guest_va_memory(struct guest_info * guest_info, addr_t guest_va, int count, char * dest) {
addr_t cursor = guest_va;
+ int bytes_read = 0;
while (count > 0) {
int dist_to_pg_edge = (PAGE_OFFSET(cursor) + PAGE_SIZE) - cursor;
return -1;
}
- memcpy(dest, (void*)cursor, bytes_to_copy);
-
+ memcpy(dest + bytes_read, (void*)host_addr, bytes_to_copy);
+
+ bytes_read += bytes_to_copy;
count -= bytes_to_copy;
cursor += bytes_to_copy;
}
*/
int read_guest_pa_memory(struct guest_info * guest_info, addr_t guest_pa, int count, char * dest) {
addr_t cursor = guest_pa;
+ int bytes_read = 0;
while (count > 0) {
int dist_to_pg_edge = (PAGE_OFFSET(cursor) + PAGE_SIZE) - cursor;
return -1;
}
- memcpy(dest, (void*)cursor, bytes_to_copy);
+ memcpy(dest + bytes_read, (void*)host_addr, bytes_to_copy);
+
+ bytes_read += bytes_to_copy;
+ count -= bytes_to_copy;
+ cursor += bytes_to_copy;
+ }
+
+ return 0;
+}
+
+
+
+/* This is a straight address conversion + copy,
+ * except for the tiny little issue of crossing page boundries.....
+ */
+int write_guest_pa_memory(struct guest_info * guest_info, addr_t guest_pa, int count, char * src) {
+ addr_t cursor = guest_pa;
+ int bytes_written = 0;
+
+ while (count > 0) {
+ int dist_to_pg_edge = (PAGE_OFFSET(cursor) + PAGE_SIZE) - cursor;
+ int bytes_to_copy = (dist_to_pg_edge > count) ? count : dist_to_pg_edge;
+ addr_t host_addr;
+
+ if (guest_pa_to_host_va(guest_info, cursor, &host_addr) != 0) {
+ return -1;
+ }
+
+ memcpy((void*)host_addr, src + bytes_written, bytes_to_copy);
+
+ bytes_written += bytes_to_copy;
count -= bytes_to_copy;
cursor += bytes_to_copy;
}
}
shadow_pde = (pde32_t *)(CR3_TO_PDE32(state->shadow_cr3.e_reg.low));
- guest_pde = (pde32_t *)(host_pa_to_host_va((void*)CR3_TO_PDE32(state->guest_cr3.e_reg.low)));
+
+ if (host_pa_to_host_va(CR3_TO_PDE32(state->guest_cr3.e_reg.low), (addr_t*)&guest_pde) != 0) {
+ return -1;
+ }
// Delete the current page table
delete_page_tables_pde32(shadow_pde);