# Makefile for GeekOS kernel, userspace, and tools
# Copyright (c) 2004,2005 David H. Hovemeyer <daveho@cs.umd.edu>
-# $Revision: 1.30 $
+# $Revision: 1.31 $
# This is free software. You are permitted to use,
# redistribute, and modify it as specified in the file "COPYING".
CC_KERNEL_OPTS := -g -DGEEKOS -I$(PROJECT_ROOT)/include
# Flags used for VMM C source files
-CC_VMM_OPTS := -g -I$(PROJECT_ROOT)/include
+CC_VMM_OPTS := -g -I$(PROJECT_ROOT)/include -D__V3VEE__
# Flags used for VMM C ASM files
NASM_VMM_OPTS := -I$(PROJECT_ROOT)/src/palacios/ -f elf $(EXTRA_NASM_OPTS)
memory, registers, disassemble, etc. It's not a complete debugger,
thoough
--s waits for a gdb connection. This seems to only work for kgdb and linux kernels
+-S waits for a gdb connection. This seems to only work for kgdb and linux kernels
-serial stdio redirects COM1 to stdio
+-serial file:<file_name> writes COM1 to the given file
+MAKING an ISO image from a floppy image
+mkisofs -pad -b <floppy_image> -R -o <iso_output_image> <floppy_image>
+
+
+/usr/local/qemu/bin/qemu-system-x86_64 -serial file:serial.out -m 1024 -fda fd.img -cdrom guest_no_timer.iso
rombios:000f0000
-
+vgabios:000c0000
#ifndef __VM_GUEST_H
#define __VM_GUEST_H
+
+
+
#include <palacios/vmm_mem.h>
#include <palacios/vmm_types.h>
#include <palacios/vmm_io.h>
#include <palacios/vmm_dev_mgr.h>
#include <palacios/vmm_irq.h>
+
typedef ullong_t gpr_t;
/*
};
+
+
+
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;
#define __VMM_H
+#include <palacios/vm_guest.h>
+#include <palacios/vmm_mem.h>
+
+#ifdef __V3VEE__
+
//#include <palacios/vmm_types.h>
#include <palacios/vmm_string.h>
-#include <palacios/vmm_mem.h>
-//#include <palacios/vmm_paging.h>
-#include <palacios/vm_guest.h>
+//#include <palacios/vmm_paging.h>
/* utility definitions */
#define PrintDebug(fmt, args...) \
+#define V3_AllocPages(ptr, num_pages) \
+ do { \
+ extern struct vmm_os_hooks * os_hooks; \
+ if ((os_hooks) && (os_hooks)->allocate_pages) { \
+ ptr = (os_hooks)->allocate_pages(num_pages); \
+ } \
+ } while (0) \
+
+
-/* This clearly won't work, we need some way to get a return value out of it */
-#define VMMMalloc(type, var, size) \
+#define V3_Malloc(type, var, size) \
do { \
extern struct vmm_os_hooks * os_hooks; \
if ((os_hooks) && (os_hooks)->malloc) { \
// We need to check the hook structure at runtime to ensure its SAFE
-#define VMMFree(addr) \
+#define V3_Free(addr) \
do { \
extern struct vmm_os_hooks * os_hooks; \
if ((os_hooks) && (os_hooks)->free) { \
#define VMM_VMX_CPU 1
#define VMM_SVM_CPU 2
+#endif //!__V3VEE__
/* This will contain function pointers that provide OS services */
#define __VMM_MEM_H
+
#include <palacios/vmm_types.h>
+#define shadow_mem_type_t host_region_type_t
+
typedef struct shadow_region {
guest_region_type_t guest_type;
addr_t guest_start;
host_region_type_t lookup_shadow_map_addr(struct shadow_map * map, addr_t guest_addr, addr_t * host_addr);
+host_region_type_t get_shadow_addr_type(struct guest_info * info, addr_t guest_addr);
+addr_t get_shadow_addr(struct guest_info * info, addr_t guest_addr);
// Semantics:
// Adding a region that overlaps with an existing region results is undefined
switch is done by the hardware. On Intel VT, the switch is done
by the hardware as well, but we are responsible for manually updating
the host state in the vmcs before entering the guest.
-
-
*/
-
+#ifdef __V3VEE__
#define MAX_PTE32_ENTRIES 1024
#define MAX_PDE32_ENTRIES 1024
#define MAX_PDPE64_ENTRIES 512
#define MAX_PML4E64_ENTRIES 512
+
+/* Converts an address into a page table index */
#define PDE32_INDEX(x) ((((uint_t)x) >> 22) & 0x3ff)
#define PTE32_INDEX(x) ((((uint_t)x) >> 12) & 0x3ff)
+/* Gets the base address needed for a Page Table entry */
+#define PD32_BASE_ADDR(x) (((uint_t)x) >> 12)
+#define PT32_BASE_ADDR(x) (((uint_t)x) >> 12)
-#define PAGE_ALIGNED_ADDR(x) (((uint_t) (x)) >> 12)
+#define PT32_PAGE_ADDR(x) (((uint_t)x) & 0xfffff000)
+#define PT32_PAGE_OFFSET(x) (((uint_t)x) & 0xfff)
+#define PT32_PAGE_POWER 12
-#ifndef PAGE_ADDR
-#define PAGE_ADDR(x) (PAGE_ALIGNED_ADDR(x) << 12)
-#endif
+
+/* The following should be phased out */
#define PAGE_OFFSET(x) ((((uint_t)x) & 0xfff))
+#define PAGE_ALIGNED_ADDR(x) (((uint_t) (x)) >> 12)
+#define PAGE_ADDR(x) (PAGE_ALIGNED_ADDR(x) << 12)
+#define PAGE_POWER 12
+#define PAGE_SIZE 4096
+/* ** */
-#define PAGE_POWER 12
#define CR3_TO_PDE32(cr3) (((ulong_t)cr3) & 0xfffff000)
#define CR3_TO_PDPTRE(cr3) (((ulong_t)cr3) & 0xffffffe0)
-#define CR3_TO_PML4E64(cr3) (((ullong_t)cr3) & 0x000ffffffffff000)
+#define CR3_TO_PML4E64(cr3) (((ullong_t)cr3) & 0x000ffffffffff000LL)
+
+
+/* Accessor functions for the page table structures */
+#define PDE32_T_ADDR(x) ((x.pt_base_addr) << 12)
+#define PTE32_T_ADDR(x) ((x.page_base_addr) << 12)
#define VM_WRITE 1
#define VM_USER 2
#define VM_EXEC 0
+#endif
+
/* PDE 32 bit PAGE STRUCTURES */
typedef enum {NOT_PRESENT, PTE32, LARGE_PAGE} pde32_entry_type_t;
/* *************** */
+typedef struct pf_error_code {
+ uint_t present : 1; // if 0, fault due to page not present
+ uint_t write : 1; // if 1, faulting access was a write
+ uint_t user : 1; // if 1, faulting access was in user mode
+ uint_t rsvd_access : 1; // if 1, fault from reading a 1 from a reserved field (?)
+ uint_t ifetch : 1; // if 1, faulting access was an instr fetch (only with NX)
+ uint_t rsvd : 27;
+} pf_error_t;
typedef enum { PDE32 } paging_mode_t;
void PrintDebugPageTables(pde32_t * pde);
+#ifdef __V3VEE__
+
+
+void PrintPT32(addr_t starting_address, pte32_t * pte);
+void PrintPD32(pde32_t * pde);
+void PrintPTE32(addr_t virtual_address, pte32_t * pte);
+void PrintPDE32(addr_t virtual_address, pde32_t * pde);
+
+#endif // !__V3VEE__
+
#endif
#include <palacios/vmm_util.h>
-
-
-
#include <palacios/vmm_paging.h>
struct shadow_page_state {
// these two reflect the top-level page directory
// of the guest page table
paging_mode_t guest_mode;
- reg_ex_t guest_cr3; // points to guest's current page table
+ ullong_t guest_cr3; // points to guest's current page table
// Should this be here??
reg_ex_t guest_cr0;
// these two reflect the top-level page directory
- // the shadow page table
+ // of the shadow page table
paging_mode_t shadow_mode;
- reg_ex_t shadow_cr3;
+ ullong_t shadow_cr3;
};
int init_shadow_page_state(struct shadow_page_state * state);
-// This function will cause the shadow page table to be deleted
-// and rewritten to reflect the guest page table and the shadow map
-int wholesale_update_shadow_page_state(struct guest_info * guest_info);
+addr_t create_new_shadow_pt32(struct guest_info * info);
+addr_t setup_shadow_pt32(struct guest_info * info, addr_t virt_cr3);
+addr_t setup_shadow_pte32(struct guest_info * info, addr_t pt_host_addr);
+int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
+int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
#endif
struct vm_device * create_pic() {
struct pic_internal * state = NULL;
- VMMMalloc(struct pic_internal *, state, sizeof(struct pic_internal));
+ V3_Malloc(struct pic_internal *, state, sizeof(struct pic_internal));
struct vm_device *device = create_device("8259A", &dev_ops, state);
nvram_state->mem_state[NVRAM_REG_EXT_MEMORY_2ND_LOW]= 0x00;
// Set the extended memory beyond 16 MB to 128-16 MB
- nvram_state->mem_state[NVRAM_REG_AMI_BIG_MEMORY_HIGH]= 0x7;
+ // nvram_state->mem_state[NVRAM_REG_AMI_BIG_MEMORY_HIGH]= 0x7;
+ //nvram_state->mem_state[NVRAM_REG_AMI_BIG_MEMORY_LOW]= 0x00;
+
+ nvram_state->mem_state[NVRAM_REG_AMI_BIG_MEMORY_HIGH]= 0x00;
nvram_state->mem_state[NVRAM_REG_AMI_BIG_MEMORY_LOW]= 0x00;
struct vm_device * create_simple_pic() {
struct pic_internal * state = NULL;
- VMMMalloc(struct pic_internal *, state, sizeof(struct pic_internal));
+ V3_Malloc(struct pic_internal *, state, sizeof(struct pic_internal));
struct vm_device * pic_dev = create_device("Simple Pic", &dev_ops, state);
struct vm_device * create_timer() {
struct timer_state * timer = NULL;
- VMMMalloc(struct timer_state *, timer, sizeof(struct timer_state));
+ V3_Malloc(struct timer_state *, timer, sizeof(struct timer_state));
struct vm_device * dev = create_device("Timer", &dev_ops, timer);
return dev;
#include <geekos/serial.h>
#include <geekos/vm.h>
#include <geekos/screen.h>
-#include <palacios/vmm_dev_mgr.h>
+
#include <devices/nvram.h>
#include <devices/timer.h>
#include <devices/simple_pic.h>
#include <devices/8259a.h>
-#include <palacios/vmm_intr.h>
+#include <palacios/vmm_intr.h>
+#include <palacios/vmm_dev_mgr.h>
#define SPEAKER_PORT 0x61
-
+/* We need a configuration mechanism, so we can wrap this completely inside the VMM code,
+ * with no pollution into the HOST OS
+ */
int RunVMM(struct Boot_Info * bootInfo) {
os_hooks.hook_interrupt = &hook_irq_stub;
os_hooks.ack_irq = &ack_irq;
- // DumpGDT();
+
Init_VMM(&os_hooks, &vmm_ops);
+
+ /* MOVE THIS TO AN INIT GUEST ROUTINE */
init_shadow_map(&(vm_info.mem_map));
init_shadow_page_state(&(vm_info.shdw_pg_state));
vm_info.page_mode = SHADOW_PAGING;
init_interrupt_state(&vm_info);
dev_mgr_init(&(vm_info.dev_mgr));
+ /* ** */
if (0) {
void * region_start;
- PrintDebug("Guest Size: %lu\n", bootInfo->guest_size);
+ PrintBoth("Guest Size: %lu\n", bootInfo->guest_size);
struct guest_mem_layout * layout = (struct guest_mem_layout *)0x100000;
if (layout->magic != MAGIC_CODE) {
- PrintDebug("Layout Magic Mismatch (0x%x)\n", layout->magic);
+ PrintBoth("Layout Magic Mismatch (0x%x)\n", layout->magic);
}
- PrintDebug("%d layout regions\n", layout->num_regions);
+ PrintBoth("%d layout regions\n", layout->num_regions);
region_start = (void *)&(layout->regions[layout->num_regions]);
- PrintDebug("region start = 0x%x\n", region_start);
+ PrintBoth("region start = 0x%x\n", region_start);
for (i = 0; i < layout->num_regions; i++) {
struct layout_region * reg = &(layout->regions[i]);
uint_t num_pages = (reg->length / PAGE_SIZE) + ((reg->length % PAGE_SIZE) ? 1 : 0);
void * guest_mem = Allocate_VMM_Pages(num_pages);
- PrintDebug("Layout Region %d bytes\n", reg->length);
+ PrintBoth("Layout Region %d bytes\n", reg->length);
memcpy(guest_mem, region_start, reg->length);
SerialMemDump((unsigned char *)(guest_mem), 16);
add_shadow_region_passthrough(&vm_info, reg->final_addr, reg->final_addr + (num_pages * PAGE_SIZE), (addr_t)guest_mem);
- PrintDebug("Adding Shadow Region (0x%x-0x%x) -> 0x%x\n", reg->final_addr, reg->final_addr + (num_pages * PAGE_SIZE), guest_mem);
+ PrintBoth("Adding Shadow Region (0x%x-0x%x) -> 0x%x\n", reg->final_addr, reg->final_addr + (num_pages * PAGE_SIZE), guest_mem);
region_start += reg->length;
}
// TEMP
- add_shadow_region_passthrough(&vm_info, 0xc0000, 0xc8000, 0xc0000);
+ //add_shadow_region_passthrough(&vm_info, 0xc0000, 0xc8000, 0xc0000);
if (1) {
add_shadow_region_passthrough(&vm_info, 0xc7000, 0xc8000, (addr_t)Allocate_VMM_Pages(1));
if (add_shadow_region_passthrough(&vm_info, 0xc8000, 0xf0000, (addr_t)Allocate_VMM_Pages(40)) == -1) {
- PrintDebug("Error adding shadow region\n");
+ PrintBoth("Error adding shadow region\n");
}
} else {
add_shadow_region_passthrough(&vm_info, 0xc0000, 0xc8000, 0xc0000);
}
- add_shadow_region_passthrough(&vm_info, 0x100000, 0x2000000, (addr_t)Allocate_VMM_Pages(8192));
+ //add_shadow_region_passthrough(&vm_info, 0x100000, 0x2000000, (addr_t)Allocate_VMM_Pages(8192));
+ add_shadow_region_passthrough(&vm_info, 0x100000, 0x1000000, (addr_t)Allocate_VMM_Pages(4096));
print_shadow_map(&(vm_info.mem_map));
hook_io_port(&(vm_info.io_map), 0x61, &IO_Read, &IO_Write, NULL);
hook_io_port(&(vm_info.io_map), 0x05, &IO_Read, &IO_Write_to_Serial, NULL);
- /*
- hook_io_port(&(vm_info.io_map), 0x20, &IO_Read, &IO_Write_to_Serial, NULL);
- hook_io_port(&(vm_info.io_map), 0x21, &IO_Read, &IO_Write_to_Serial, NULL);
- hook_io_port(&(vm_info.io_map), 0xa0, &IO_Read, &IO_Write_to_Serial, NULL);
- hook_io_port(&(vm_info.io_map), 0xa1, &IO_Read, &IO_Write_to_Serial, NULL);
- */
+
hook_io_port(&(vm_info.io_map), 0x400, &IO_Read, &IO_Write_to_Serial, NULL);
hook_io_port(&(vm_info.io_map), 0x401, &IO_Read, &IO_Write_to_Serial, NULL);
hook_io_port(&(vm_info.io_map), 0x402, &IO_Read, &IO_BOCHS_debug, NULL);
hook_irq(&vm_info, 14);
hook_irq(&vm_info, 15);
+
vm_info.rip = 0xfff0;
vm_info.vm_regs.rsp = 0x0;
}
irq_map[irq] = info;
volatile void *foo = pic_intr_handler;
foo=0;
- // Install_IRQ(irq, pic_intr_handler);
- // Enable_IRQ(irq);
+ Disable_IRQ(irq);
+ Install_IRQ(irq, pic_intr_handler);
+ Enable_IRQ(irq);
return 0;
}
if (vm_info.page_mode == SHADOW_PAGING) {
PrintDebug("Creating initial shadow page table\n");
- vm_info.shdw_pg_state.shadow_cr3.e_reg.low |= ((addr_t)create_passthrough_pde32_pts(&vm_info) & ~0xfff);
+ vm_info.shdw_pg_state.shadow_cr3 |= ((addr_t)create_passthrough_pde32_pts(&vm_info) & ~0xfff);
PrintDebug("Created\n");
- guest_state->cr3 = vm_info.shdw_pg_state.shadow_cr3.r_reg;
+ guest_state->cr3 = vm_info.shdw_pg_state.shadow_cr3;
ctrl_area->cr_reads.cr3 = 1;
ctrl_area->cr_writes.cr3 = 1;
if (vm_info.page_mode == SHADOW_PAGING) {
PrintDebug("Creating initial shadow page table\n");
- vm_info.shdw_pg_state.shadow_cr3.e_reg.low |= ((addr_t)create_passthrough_pde32_pts(&vm_info) & ~0xfff);
+ vm_info.shdw_pg_state.shadow_cr3 |= ((addr_t)create_passthrough_pde32_pts(&vm_info) & ~0xfff);
PrintDebug("Created\n");
- guest_state->cr3 = vm_info.shdw_pg_state.shadow_cr3.r_reg;
+ guest_state->cr3 = vm_info.shdw_pg_state.shadow_cr3;
//PrintDebugPageTables((pde32_t*)(vm_info.shdw_pg_state.shadow_cr3.e_reg.low));
index++;
}
-
- /* CHECK IF MOV_TO_CR CAN TAKE MEMORY OPERANDS... */
if ((instr[index] == cr_access_byte) &&
(instr[index + 1] == mov_to_cr_byte)) {
struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
if (new_cr0->pg == 1){
+ struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
+
info->cpu_mode = PROTECTED_PG;
*shadow_cr0 = *new_cr0;
//
// Activate Shadow Paging
//
+ PrintDebug("Turning on paging in the guest\n");
+
+ guest_state->cr3 = *(addr_t*)shadow_cr3;
+
} else if (new_cr0->pe == 0) {
info->cpu_mode = REAL;
return 0;
}
+
+
+
+
+int handle_cr3_write(struct guest_info * info) {
+ vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
+
+
+ if ((info->cpu_mode == PROTECTED) || (info->cpu_mode == PROTECTED_PG)) {
+ int index = 0;
+ int ret;
+ char instr[15];
+
+ ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
+ if (ret != 15) {
+ PrintDebug("Could not read instruction (ret=%d)\n", ret);
+ return -1;
+ }
+
+ while (is_prefix_byte(instr[index])) {
+ index++;
+ }
+
+ if ((instr[index] == cr_access_byte) &&
+ (instr[index + 1] == mov_to_cr_byte)) {
+
+ addr_t first_operand;
+ addr_t second_operand;
+ struct cr3_32 * new_cr3;
+ // struct cr3_32 * real_cr3;
+ operand_type_t addr_type;
+
+ index += 2;
+
+ addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
+
+ if (addr_type != REG_OPERAND) {
+ /* Mov to CR3 can only be a 32 bit register */
+ return -1;
+ }
+
+ new_cr3 = (struct cr3_32 *)first_operand;
+
+ if (info->page_mode == SHADOW_PAGING) {
+ addr_t shadow_pt;
+ struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.shadow_cr3);
+ struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
+
+
+ *guest_cr3 = *new_cr3;
+
+ // Something like this
+ shadow_pt = create_new_shadow_pt32(info);
+ //shadow_pt = setup_shadow_pt32(info, CR3_TO_PDE32(*(addr_t *)new_cr3));
+
+ /* Copy Various flags */
+ *shadow_cr3 = *new_cr3;
+
+ shadow_cr3->pdt_base_addr = PD32_BASE_ADDR(shadow_pt);
+
+ if (info->cpu_mode == PROTECTED_PG) {
+ // If we aren't in paged mode then we have to preserve the identity mapped CR3
+ guest_state->cr3 = *(addr_t*)shadow_cr3;
+ }
+ }
+
+ info->rip += index;
+
+ } else {
+ PrintDebug("Unknown Instruction\n");
+ return -1;
+ }
+ } else {
+ PrintDebug("Invalid operating Mode\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+
+int handle_cr3_read(struct guest_info * info) {
+ vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
+
+ if ((info->cpu_mode == PROTECTED) || (info->cpu_mode == PROTECTED_PG)) {
+ int index = 0;
+ int ret;
+ char instr[15];
+
+ ret = read_guest_pa_memory(info, get_addr_linear(info, guest_state->rip, guest_state->cs.base), 15, instr);
+ if (ret != 15) {
+ PrintDebug("Could not read instruction (ret=%d)\n", ret);
+ return -1;
+ }
+
+ while (is_prefix_byte(instr[index])) {
+ index++;
+ }
+
+ if ((instr[index] == cr_access_byte) &&
+ (instr[index + 1] == mov_from_cr_byte)) {
+ addr_t first_operand;
+ addr_t second_operand;
+ struct cr3_32 * virt_cr3;
+ struct cr3_32 * real_cr3 = (struct cr3_32 *)&(guest_state->cr3);
+ operand_type_t addr_type;
+
+ index += 2;
+
+ addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
+
+ if (addr_type != REG_OPERAND) {
+ /* Mov to CR3 can only be a 32 bit register */
+ return -1;
+ }
+
+ virt_cr3 = (struct cr3_32 *)first_operand;
+
+ if (info->page_mode == SHADOW_PAGING) {
+ *virt_cr3 = *(struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
+ } else {
+ *virt_cr3 = *real_cr3;
+ }
+
+ info->rip += index;
+ } else {
+ PrintDebug("Unknown Instruction\n");
+ return -1;
+ }
+ } else {
+ PrintDebug("Invalid operating Mode\n");
+ return -1;
+ }
+
+ return 0;
+}
if (handle_cr0_read(info) == -1) {
return -1;
}
+ } else if (exit_code == VMEXIT_CR3_WRITE) {
+ PrintDebug("CR3 Write\n");
+ if (handle_cr3_write(info) == -1) {
+ return -1;
+ }
+ } else if (exit_code == VMEXIT_CR3_READ) {
+ PrintDebug("CR3 Read\n");
+
+ if (handle_cr3_read(info) == -1) {
+ return -1;
+ }
+
+ } else if (exit_code == VMEXIT_EXCP14) {
+ addr_t fault_addr = guest_ctrl->exit_info2;
+ pf_error_t * error_code = (pf_error_t *)&(guest_ctrl->exit_info1);
+
+ PrintDebug("PageFault at %x (error=%d)\n", fault_addr, *error_code);
+
+
+
+ if (handle_shadow_pagefault(info, fault_addr, *error_code) == -1) {
+ return -1;
+ }
/*
- } else if (( (exit_code == VMEXIT_CR3_READ) ||
- (exit_code == VMEXIT_CR3_WRITE) ||
- (exit_code == VMEXIT_INVLPG) ||
- (exit_code == VMEXIT_INVLPGA) ||
- (exit_code == VMEXIT_EXCP14)) &&
- (info->page_mode == SHADOW_PAGING)) {
- handle_shadow_paging(info);
+ } else if (( (exit_code == VMEXIT_CR3_READ) ||
+ (exit_code == VMEXIT_CR3_WRITE) ||
+ (exit_code == VMEXIT_INVLPG) ||
+ (exit_code == VMEXIT_INVLPGA) ||
+ (exit_code == VMEXIT_EXCP14)) &&
+ (info->page_mode == SHADOW_PAGING)) {
+ handle_shadow_paging(info);
*/
-
+
} else if (exit_code == VMEXIT_INTR) {
// handle_svm_intr(info);
struct vm_device * allocate_device() {
struct vm_device * dev = NULL;
- VMMMalloc(struct vm_device *, dev, sizeof(struct vm_device));
+ V3_Malloc(struct vm_device *, dev, sizeof(struct vm_device));
dev->ops = NULL;
memset(dev->name, 0, 32);
}
void free_device(struct vm_device * dev) {
- VMMFree(dev);
+ V3_Free(dev);
}
{
struct dev_mem_hook *hook;
- VMMMalloc(struct dev_mem_hook *, hook,sizeof(struct dev_mem_hook));
+ V3_Malloc(struct dev_mem_hook *, hook,sizeof(struct dev_mem_hook));
if (!hook) {
return -1;
//tmp_hook->read = io_hook->read;
//tmp_hook->write = io_hook->write;
- //VMMFree(io_hook);
+ //V3_Free(io_hook);
return -1;
} else {
io_hook->prev = tmp_hook;
io_hook->priv_data = priv_data;
if (add_io_hook(io_map, io_hook) != 0) {
- VMMFree(io_hook);
+ V3_Free(io_hook);
return -1;
}
void * private_data) {
struct vmm_irq_hook * hook = NULL;
- VMMMalloc(struct vmm_irq_hook *, hook, sizeof(struct vmm_irq_hook));
+ V3_Malloc(struct vmm_irq_hook *, hook, sizeof(struct vmm_irq_hook));
if (!hook) {
// big problems
hook->prev = NULL;
if (add_irq_hook(map, hook) != 0) {
- VMMFree(hook);
+ V3_Free(hook);
return -1;
}
while(cursor) {
tmp = cursor;
cursor = cursor->next;
- VMMFree(tmp);
+ V3_Free(tmp);
}
- VMMFree(map);
+ V3_Free(map);
}
}
+host_region_type_t get_shadow_addr_type(struct guest_info * info, addr_t guest_addr) {
+ shadow_region_t * reg = get_shadow_region_by_addr(&(info->mem_map), guest_addr);
+
+ if (!reg) {
+ return HOST_REGION_INVALID;
+ } else {
+ return reg->host_type;
+ }
+}
+
+addr_t get_shadow_addr(struct guest_info * info, addr_t guest_addr) {
+ shadow_region_t * reg = get_shadow_region_by_addr(&(info->mem_map), guest_addr);
+
+ if (!reg) {
+ return 0;
+ } else {
+ return (guest_addr - reg->guest_start) + reg->host_addr.phys_addr.host_start;
+ }
+}
+
host_region_type_t lookup_shadow_map_addr(struct shadow_map * map, addr_t guest_addr, addr_t * host_addr) {
shadow_region_t * reg = get_shadow_region_by_addr(map, guest_addr);
-void PrintPDE32(void * virtual_address, pde32_t * pde)
+void PrintPDE32(addr_t virtual_address, pde32_t * pde)
{
PrintDebug("PDE %p -> %p : present=%x, flags=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
virtual_address,
pde->vmm_info);
}
-void PrintPTE32(void * virtual_address, pte32_t * pte)
+void PrintPTE32(addr_t virtual_address, pte32_t * pte)
{
PrintDebug("PTE %p -> %p : present=%x, flags=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, vmm_info=%x\n",
virtual_address,
PrintDebug("Page Directory at %p:\n", pde);
for (i = 0; (i < MAX_PDE32_ENTRIES); i++) {
if ( pde[i].present) {
- PrintPDE32((void*)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), &(pde[i]));
+ PrintPDE32((addr_t)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), &(pde[i]));
}
}
}
-void PrintPT32(void * starting_address, pte32_t * pte)
+void PrintPT32(addr_t starting_address, pte32_t * pte)
{
int i;
for (i = 0; (i < MAX_PDE32_ENTRIES); i++) {
if (pde[i].present) {
- PrintPDE32((void *)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), &(pde[i]));
- PrintPT32((void *)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), (void *)(pde[i].pt_base_addr << PAGE_POWER));
+ PrintPDE32((addr_t)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), &(pde[i]));
+ PrintPT32((addr_t)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), (pte32_t *)(pde[i].pt_base_addr << PAGE_POWER));
}
}
}
#include <palacios/vmm_shadow_paging.h>
+
#include <palacios/vmm.h>
#include <palacios/vm_guest_mem.h>
state->guest_mode = PDE32;
state->shadow_mode = PDE32;
- state->guest_cr3.r_reg = 0;
- state->shadow_cr3.r_reg = 0;
+ state->guest_cr3 = 0;
+ state->shadow_cr3 = 0;
return 0;
}
-
-int wholesale_update_shadow_page_state(struct guest_info * guest_info) {
- unsigned i, j;
- pde32_t * guest_pde;
- pde32_t * shadow_pde;
+int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
+ if (info->cpu_mode == PROTECTED_PG) {
+ return handle_shadow_pagefault32(info, fault_addr, error_code);
+ } else {
+ return -1;
+ }
+}
- struct shadow_page_state * state = &(guest_info->shdw_pg_state);
+int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
+ pde32_t * guest_pde = NULL;
+ pde32_t * shadow_pde = (pde32_t *)CR3_TO_PDE32(info->shdw_pg_state.shadow_cr3);
+ addr_t guest_cr3 = CR3_TO_PDE32(info->shdw_pg_state.guest_cr3);
- // For now, we'll only work with PDE32
- if (state->guest_mode != PDE32) {
+ if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pde) == -1) {
return -1;
}
- shadow_pde = (pde32_t *)(CR3_TO_PDE32(state->shadow_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;
+ if (error_code.present == 0) {
+ // Faulted because page was not present...
+ if (shadow_pde[PDE32_INDEX(fault_addr)].present) {
+
+
+ } else {
+ return -1;
+ }
}
- // Delete the current page table
- delete_page_tables_pde32(shadow_pde);
+ // Checks:
+ // Shadow PDE
+ // Guest PDE
+ // Shadow PTE
+ // Guest PTE
+ // Mem Map
+
+ return -1;
+}
- shadow_pde = os_hooks->allocate_pages(1);
- state->shadow_cr3.e_reg.low = (addr_t)shadow_pde;
+addr_t create_new_shadow_pt32(struct guest_info * info) {
+ void * host_pde = 0;
- state->shadow_mode = PDE32;
+ V3_AllocPages(host_pde, 1);
+ memset(host_pde, 0, PAGE_SIZE);
+
+ return (addr_t)host_pde;
+}
- for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
- shadow_pde[i] = guest_pde[i];
- // The shadow can be identical to the guest if it's not present
- if (!shadow_pde[i].present) {
- continue;
- }
- if (shadow_pde[i].large_pages) {
- // large page - just map it through shadow map to generate its physical location
- addr_t guest_addr = PAGE_ADDR(shadow_pde[i].pt_base_addr);
- addr_t host_addr;
- shadow_region_t * ent;
- ent = get_shadow_region_by_addr(&(guest_info->mem_map), guest_addr);
-
- if (!ent) {
- // FIXME Panic here - guest is trying to map to physical memory
- // it does not own in any way!
- return -1;
+addr_t setup_shadow_pt32(struct guest_info * info, addr_t virt_cr3) {
+ addr_t cr3_guest_addr = CR3_TO_PDE32(virt_cr3);
+ pde32_t * guest_pde;
+ pde32_t * host_pde = NULL;
+ int i;
+
+ // Setup up guest_pde to point to the PageDir in host addr
+ if (guest_pa_to_host_va(info, cr3_guest_addr, (addr_t*)&guest_pde) == -1) {
+ return 0;
+ }
+
+ V3_AllocPages(host_pde, 1);
+ memset(host_pde, 0, PAGE_SIZE);
+
+ for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
+ if (guest_pde[i].present == 1) {
+ addr_t pt_host_addr;
+ addr_t host_pte;
+
+ if (guest_pa_to_host_va(info, PDE32_T_ADDR(guest_pde[i]), &pt_host_addr) == -1) {
+ return 0;
}
- // FIXME Bounds check here to see if it's trying to trick us
-
- switch (ent->host_type) {
- case HOST_REGION_PHYSICAL_MEMORY:
- // points into currently allocated physical memory, so we just
- // set up the shadow to point to the mapped location
- if (guest_pa_to_host_pa(guest_info, guest_addr, &host_addr)) {
- // Panic here
- return -1;
- }
-
- shadow_pde[i].pt_base_addr = PAGE_ALIGNED_ADDR(host_addr);
- // FIXME set vmm_info bits here
- break;
- case HOST_REGION_UNALLOCATED:
- // points to physical memory that is *allowed* but that we
- // have not yet allocated. We mark as not present and set a
- // bit to remind us to allocate it later
- shadow_pde[i].present = 0;
- // FIXME Set vminfo bits here so that we know that we will be
- // allocating it later
- break;
- case HOST_REGION_NOTHING:
- // points to physical memory that is NOT ALLOWED.
- // We will mark it as not present and set a bit to remind
- // us that it's bad later and insert a GPF then
- shadow_pde[i].present = 0;
- break;
- case HOST_REGION_MEMORY_MAPPED_DEVICE:
- case HOST_REGION_REMOTE:
- case HOST_REGION_SWAPPED:
- default:
- // Panic. Currently unhandled
- return -1;
- break;
+ if ((host_pte = setup_shadow_pte32(info, pt_host_addr)) == 0) {
+ return 0;
}
- } else {
- pte32_t * guest_pte;
- pte32_t * shadow_pte;
- addr_t guest_addr;
- addr_t guest_pte_host_addr;
- shadow_region_t * ent;
- // small page - set PDE and follow down to the child table
- shadow_pde[i] = guest_pde[i];
+ host_pde[i].present = 1;
+ host_pde[i].pt_base_addr = PD32_BASE_ADDR(host_pte);
- guest_addr = PAGE_ADDR(guest_pde[i].pt_base_addr);
+ //
+ // Set Page DIR flags
+ //
+ }
+ }
- // Allocate a new second level page table for the shadow
- shadow_pte = os_hooks->allocate_pages(1);
+ PrintDebugPageTables(host_pde);
- // make our first level page table in the shadow point to it
- shadow_pde[i].pt_base_addr = PAGE_ALIGNED_ADDR(shadow_pte);
-
- ent = get_shadow_region_by_addr(&(guest_info->mem_map), guest_addr);
-
+ return (addr_t)host_pde;
+}
- /* JRL: This is bad.... */
- // For now the guest Page Table must always be mapped to host physical memory
- /* If we swap out a page table or if it isn't present for some reason, this turns real ugly */
- if ((!ent) || (ent->host_type != HOST_REGION_PHYSICAL_MEMORY)) {
- // FIXME Panic here - guest is trying to map to physical memory
- // it does not own in any way!
- return -1;
- }
- // Address of the relevant second level page table in the guest
- if (guest_pa_to_host_pa(guest_info, guest_addr, &guest_pte_host_addr)) {
- // Panic here
- return -1;
- }
+addr_t setup_shadow_pte32(struct guest_info * info, addr_t pt_host_addr) {
+ pte32_t * guest_pte = (pte32_t *)pt_host_addr;
+ pte32_t * host_pte = NULL;
+ int i;
+ V3_AllocPages(host_pte, 1);
+ memset(host_pte, 0, PAGE_SIZE);
- // host_addr now contains the host physical address for the guest's 2nd level page table
- // Now we transform it to relevant virtual address
- guest_pte = os_hooks->paddr_to_vaddr((void *)guest_pte_host_addr);
+ for (i = 0; i < MAX_PTE32_ENTRIES; i++) {
+ if (guest_pte[i].present == 1) {
+ addr_t guest_pa = PTE32_T_ADDR(guest_pte[i]);
+ shadow_mem_type_t page_type;
+ addr_t host_pa = 0;
- // Now we walk through the second level guest page table
- // and clone it into the shadow
- for (j = 0; j < MAX_PTE32_ENTRIES; j++) {
- shadow_pte[j] = guest_pte[j];
+ page_type = get_shadow_addr_type(info, guest_pa);
- addr_t guest_addr = PAGE_ADDR(shadow_pte[j].page_base_addr);
+ if (page_type == HOST_REGION_PHYSICAL_MEMORY) {
+ host_pa = get_shadow_addr(info, guest_pa);
+ } else {
- shadow_region_t * ent;
-
- ent = get_shadow_region_by_addr(&(guest_info->mem_map), guest_addr);
-
- if (!ent) {
- // FIXME Panic here - guest is trying to map to physical memory
- // it does not own in any way!
- return -1;
- }
-
- switch (ent->host_type) {
- case HOST_REGION_PHYSICAL_MEMORY:
- {
- addr_t host_addr;
-
- // points into currently allocated physical memory, so we just
- // set up the shadow to point to the mapped location
- if (guest_pa_to_host_pa(guest_info, guest_addr, &host_addr)) {
- // Panic here
- return -1;
- }
-
- shadow_pte[j].page_base_addr = PAGE_ALIGNED_ADDR(host_addr);
- // FIXME set vmm_info bits here
- break;
- }
- case HOST_REGION_UNALLOCATED:
- // points to physical memory that is *allowed* but that we
- // have not yet allocated. We mark as not present and set a
- // bit to remind us to allocate it later
- shadow_pte[j].present = 0;
- // FIXME Set vminfo bits here so that we know that we will be
- // allocating it later
- break;
- case HOST_REGION_NOTHING:
- // points to physical memory that is NOT ALLOWED.
- // We will mark it as not present and set a bit to remind
- // us that it's bad later and insert a GPF then
- shadow_pte[j].present = 0;
- break;
- case HOST_REGION_MEMORY_MAPPED_DEVICE:
- case HOST_REGION_REMOTE:
- case HOST_REGION_SWAPPED:
- default:
- // Panic. Currently unhandled
- return -1;
- break;
- }
+ //
+ // Setup various memory types
+ //
}
+
+ host_pte[i].page_base_addr = PT32_BASE_ADDR(host_pa);
+ host_pte[i].present = 1;
}
}
- return 0;
+
+ return (addr_t)host_pte;
}
-
+