palacios-lean:
(cd $(PALACIOS_BUILD_DIR) && make LEAN_AND_MEAN=1 world)
-kitten:
+kitten: palacios64
+ cp $(PALACIOS_BUILD_DIR)/libv3vee.a $(KITTEN_TOP_DIR)/palacios/
+ cp $(PALACIOS_BUILD_DIR)/../lib/xed/libxed32e.a $(KITTEN_TOP_DIR)/palacios/
+ cp $(PALACIOS_BUILD_DIR)/vm_kernel $(KITTEN_TOP_DIR)/palacios/
(cd $(KITTEN_TOP_DIR) && make)
kitten-full: palacios-full64
FDARGS = console=serial debug_mptable=1 init_argv="one two three" init_envp="one=1 two=2 three=3"
# Set this if you want an initrd included with the isoimage kernel
ifdef CONFIG_V3VEE
-FDINITRD = /opt/vmm-tools/isos/puppy.iso
+FDINITRD = /opt/vmm-tools/isos/finnix.iso
else
FDINITRD = init_task
endif
#!/bin/sh
exec /usr/local/qemu/bin/qemu-system-x86_64 \
+ -smp 1 \
-m 1024 \
- -nographic \
+ -serial file:./serial.out \
-cdrom ./arch/x86_64/boot/image.iso \
< /dev/null
palacios/vmm_queue.o \
palacios/vmm_host_events.o \
palacios/svm_lowlevel.o \
+ palacios/vmm_msr.o \
+ palacios/svm_msr.o \
# vmx.c vmcs_gen.c vmcs.c
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#ifndef __SVM_MSR_H__
+#define __SVM_MSR_H__
+
+
+#ifdef __V3VEE__
+
+#include <palacios/vmm.h>
+
+addr_t v3_init_svm_msr_map(struct guest_info * info);
+
+int v3_handle_msr_write(struct guest_info * info);
+
+int v3_handle_msr_read(struct guest_info * info);
+
+
+
+
+#endif // ! __V3VEE__
+
+#endif
#include <palacios/vmm_time.h>
#include <palacios/vmm_emulator.h>
#include <palacios/vmm_host_events.h>
-
+#include <palacios/vmm_msr.h>
struct v3_intr_state intr_state;
struct vmm_io_map io_map;
+
+ struct v3_msr_map msr_map;
// device_map
struct vmm_dev_mgr dev_mgr;
int v3_handle_cr3_write(struct guest_info * info);
int v3_handle_cr3_read(struct guest_info * info);
+int v3_handle_cr4_write(struct guest_info * info);
+int v3_handle_cr4_read(struct guest_info * info);
+
+
+int v3_handle_efer_write(uint_t msr, struct v3_msr src, void * priv_data);
+int v3_handle_efer_read(uint_t msr, struct v3_msr * dst, void * priv_data);
+
#endif // ! __V3VEE__
return 0xffff;
break;
case PROTECTED:
+ case PROTECTED_PAE:
return 0xffffffff;
case LONG:
case LONG_32_COMPAT:
break;*/
case PROTECTED:
+ case PROTECTED_PAE:
return addr + seg->base;
break;
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#ifndef __VMM_MSR_H__
+#define __VMM_MSR_H__
+
+
+#ifdef __V3VEE__
+
+#include <palacios/vmm_types.h>
+#include <palacios/vmm_list.h>
+
+struct guest_info;
+
+struct v3_msr {
+
+ union {
+ ullong_t value;
+
+ struct {
+ uint_t lo;
+ uint_t hi;
+ } ;
+
+ };
+};
+
+
+struct v3_msr_hook {
+ uint_t msr;
+
+ int (*read)(uint_t msr, struct v3_msr * dst, void * priv_data);
+ int (*write)(uint_t msr, struct v3_msr src, void * priv_data);
+
+ void * priv_data;
+
+ struct list_head link;
+};
+
+
+
+struct v3_msr_hook;
+
+struct v3_msr_map {
+ uint_t num_hooks;
+ struct list_head hook_list;
+};
+
+
+void v3_init_msr_map(struct guest_info * info);
+
+int v3_unhook_msr(struct guest_info * info, uint_t msr);
+
+int v3_hook_msr(struct guest_info * info, uint_t msr,
+ int (*read)(uint_t msr, struct v3_msr * dst, void * priv_data),
+ int (*write)(uint_t msr, struct v3_msr src, void * priv_data),
+ void * priv_data);
+
+
+struct v3_msr_hook * v3_get_msr_hook(struct guest_info * info, uint_t msr);
+
+void v3_print_msr_map(struct guest_info * info);
+
+
+
+#endif // ! __V3VEE__
+
+#endif
#define MAX_PTE32_ENTRIES 1024
#define MAX_PDE32_ENTRIES 1024
+#define MAX_PTE32PAE_ENTRIES 512
+#define MAX_PDE32PAE_ENTRIES 512
+#define MAX_PDPE32PAE_ENTRIES 4
+
#define MAX_PTE64_ENTRIES 512
#define MAX_PDE64_ENTRIES 512
#define MAX_PDPE64_ENTRIES 512
#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 */
+/* Deprecate these :*/
#define PD32_BASE_ADDR(x) (((uint_t)x) >> 12)
#define PT32_BASE_ADDR(x) (((uint_t)x) >> 12)
#define PD32_4MB_BASE_ADDR(x) (((uint_t)x) >> 22)
-
#define PML4E64_BASE_ADDR(x) (((ullong_t)x) >> 12)
#define PDPE64_BASE_ADDR(x) (((ullong_t)x) >> 12)
#define PDE64_BASE_ADDR(x) (((ullong_t)x) >> 12)
#define PTE64_BASE_ADDR(x) (((ullong_t)x) >> 12)
+/* 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 PDE32_4MB_T_ADDR(x) (((x).page_base_addr) << 22)
+
+/* Replace The above with these... */
+#define PAGE_BASE_ADDR(x) (((uint_t)x) >> 12)
+#define LARGE_PAGE_BASE_ADDR(x) (((uint_t)x) >> 22)
+#define BASE_TO_PAGE_ADDR(x) (((uint_t)x) << 12)
+#define LARGE_BASE_TO_PAGE_ADDR(x) (((uint_t)x) << 22)
+
+
#define PT32_PAGE_ADDR(x) (((uint_t)x) & 0xfffff000)
#define PT32_PAGE_OFFSET(x) (((uint_t)x) & 0xfff)
-/* 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 PDE32_4MB_T_ADDR(x) (((x).page_base_addr) << 22)
+
/* Page Table Flag Values */
#define PT32_HOOK 0x1
uint_t global_page : 1;
uint_t vmm_info : 3;
uint_t pt_base_addr : 20;
-} pde32_t;
+} __attribute__((packed)) pde32_t;
typedef struct pde32_4MB {
uint_t present : 1;
uint_t rsvd : 9;
uint_t page_base_addr : 10;
-} pde32_4MB_t;
+} __attribute__((packed)) pde32_4MB_t;
typedef struct pte32 {
uint_t present : 1;
uint_t global_page : 1;
uint_t vmm_info : 3;
uint_t page_base_addr : 20;
-} pte32_t;
+} __attribute__((packed)) pte32_t;
/* ***** */
/* 32 bit PAE PAGE STRUCTURES */
+typedef struct pdpe32pae {
+ uint_t present : 1;
+ uint_t rsvd : 2; // MBZ
+ uint_t write_through : 1;
+ uint_t cache_disable : 1;
+ uint_t accessed : 1;
+ uint_t avail : 1;
+ uint_t rsvd2 : 2; // MBZ
+ uint_t vmm_info : 3;
+ uint_t pd_base_addr : 24;
+ uint_t rsvd3 : 28; // MBZ
+} __attribute__((packed)) pdpe32pae_t;
+
+
+
+typedef struct pde32pae {
+ uint_t present : 1;
+ uint_t writable : 1;
+ uint_t user_page : 1;
+ uint_t write_through : 1;
+ uint_t cache_disable : 1;
+ uint_t accessed : 1;
+ uint_t avail : 1;
+ uint_t large_page : 1;
+ uint_t global_page : 1;
+ uint_t vmm_info : 3;
+ uint_t pt_base_addr : 24;
+ uint_t rsvd : 28;
+} __attribute__((packed)) pde32pae_t;
+
+typedef struct pde32pae_4MB {
+ uint_t present : 1;
+ uint_t writable : 1;
+ uint_t user_page : 1;
+ uint_t write_through : 1;
+ uint_t cache_disable : 1;
+ uint_t accessed : 1;
+ uint_t dirty : 1;
+ uint_t one : 1;
+ uint_t global_page : 1;
+ uint_t vmm_info : 3;
+ uint_t pat : 1;
+ uint_t rsvd : 9;
+ uint_t page_base_addr : 14;
+ uint_t rsvd2 : 28;
+
+} __attribute__((packed)) pde32pae_4MB_t;
+
+typedef struct pte32pae {
+ uint_t present : 1;
+ uint_t writable : 1;
+ uint_t user_page : 1;
+ uint_t write_through : 1;
+ uint_t cache_disable : 1;
+ uint_t accessed : 1;
+ uint_t dirty : 1;
+ uint_t pte_attr : 1;
+ uint_t global_page : 1;
+ uint_t vmm_info : 3;
+ uint_t page_base_addr : 24;
+ uint_t rsvd : 28;
+} __attribute__((packed)) pte32pae_t;
+
+
+
-//
-// Fill in
-//
/* ********** */
ullong_t pdp_base_addr : 40;
uint_t available : 11;
uint_t no_execute : 1;
-} pml4e64_t;
+} __attribute__((packed)) pml4e64_t;
typedef struct pdpe64 {
ullong_t pd_base_addr : 40;
uint_t available : 11;
uint_t no_execute : 1;
-} pdpe64_t;
+} __attribute__((packed)) pdpe64_t;
ullong_t pt_base_addr : 40;
uint_t available : 11;
uint_t no_execute : 1;
-} pde64_t;
+} __attribute__((packed)) pde64_t;
typedef struct pte64 {
uint_t present : 1;
ullong_t page_base_addr : 40;
uint_t available : 11;
uint_t no_execute : 1;
-} pte64_t;
+} __attribute__((packed)) pte64_t;
/* *************** */
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;
+} __attribute__((packed)) pf_error_t;
struct guest_info;
pde32_t * create_passthrough_pts_32(struct guest_info * guest_info);
+pdpe32pae_t * create_passthrough_pts_PAE32(struct guest_info * guest_info);
pml4e64_t * create_passthrough_pts_64(struct guest_info * info);
void PrintPD32(pde32_t * pde);
void PrintPTE32(addr_t virtual_address, pte32_t * pte);
void PrintPDE32(addr_t virtual_address, pde32_t * pde);
+
+void PrintDebugPageTables32PAE(pdpe32pae_t * pde);
+void PrintPTE32PAE(addr_t virtual_address, pte32pae_t * pte);
+void PrintPDE32PAE(addr_t virtual_address, pde32pae_t * pde);
void PrintPTE64(addr_t virtual_address, pte64_t * pte);
#endif // !__V3VEE__
#include <palacios/vmm_decoder.h>
#include <palacios/vmm_string.h>
#include <palacios/vmm_lowlevel.h>
+#include <palacios/svm_msr.h>
//ctrl_area->instrs.instrs.CR0 = 1;
ctrl_area->cr_reads.cr0 = 1;
ctrl_area->cr_writes.cr0 = 1;
+ ctrl_area->cr_reads.cr4 = 1;
+ ctrl_area->cr_writes.cr4 = 1;
/* Set up the efer to enable 64 bit page tables */
guest_state->efer |= EFER_MSR_svm_enable;
+ v3_hook_msr(vm_info, EFER_MSR,
+ &v3_handle_efer_read,
+ &v3_handle_efer_write,
+ vm_info);
+
guest_state->rflags = 0x00000002; // The reserved bit is always 1
ctrl_area->exceptions.nmi = 1;
*/
+
+
// Debug of boot on physical machines - 7/14/08
ctrl_area->instrs.NMI=1;
ctrl_area->instrs.SMI=1;
ctrl_area->instrs.PAUSE=1;
ctrl_area->instrs.shutdown_evts=1;
-
-
vm_info->vm_regs.rdx = 0x00000f00;
guest_state->cr0 = 0x60000010;
guest_state->dr6 = 0x00000000ffff0ff0LL;
guest_state->dr7 = 0x0000000000000400LL;
+
+
+
+
+
if (vm_info->io_map.num_ports > 0) {
struct vmm_io_hook * iter;
addr_t io_port_bitmap;
ctrl_area->instrs.IOIO_PROT = 1;
}
-
-
+
PrintDebug("Exiting on interrupts\n");
ctrl_area->guest_ctrl.V_INTR_MASKING = 1;
ctrl_area->TLB_CONTROL = 1;
-
guest_state->g_pat = 0x7040600070406ULL;
guest_state->cr0 |= 0x80000000;
}
+ if (vm_info->msr_map.num_hooks > 0) {
+ ctrl_area->MSRPM_BASE_PA = v3_init_svm_msr_map(vm_info);
+ ctrl_area->instrs.MSR_PROT = 1;
+
+ }
+
+
}
//PrintDebug("SVM Returned\n");
-#if PrintDebug
- {
- uint_t x = 0;
- PrintDebug("RSP=%p\n", (void *)&x);
- }
-#endif
-
v3_update_time(info, tmp_tsc - info->time_state.cached_host_tsc);
num_exits++;
v3_stgi();
- //PrintDebug("SVM Exit number %d\n", num_exits);
-
+ if (num_exits % 25 == 0) {
+ PrintDebug("SVM Exit number %d\n", num_exits);
+ }
if (v3_handle_svm_exit(info) != 0) {
-
+ vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
addr_t host_addr;
addr_t linear_addr = 0;
v3_print_segments(info);
v3_print_ctrl_regs(info);
v3_print_GPRs(info);
+
+
+
+ PrintDebug("SVM Exit Code: %p\n", (void *)(addr_t)guest_ctrl->exit_code);
+
+ PrintDebug("exit_info1 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info1));
+ PrintDebug("exit_info1 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
+
+ PrintDebug("exit_info2 low = 0x%.8x\n", *(uint_t*)&(guest_ctrl->exit_info2));
+ PrintDebug("exit_info2 high = 0x%.8x\n", *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
if (info->mem_mode == PHYSICAL_MEM) {
guest_pa_to_host_va(info, linear_addr, &host_addr);
#include <palacios/svm_wbinvd.h>
#include <palacios/vmm_intr.h>
#include <palacios/vmm_emulator.h>
-
+#include <palacios/svm_msr.h>
switch (exit_code) {
- case VMEXIT_IOIO: {
- struct svm_io_info * io_info = (struct svm_io_info *)&(guest_ctrl->exit_info1);
-
- if (io_info->type == 0) {
- if (io_info->str) {
- if (v3_handle_svm_io_outs(info) == -1 ) {
- return -1;
+ case VMEXIT_IOIO:
+ {
+ struct svm_io_info * io_info = (struct svm_io_info *)&(guest_ctrl->exit_info1);
+
+ if (io_info->type == 0) {
+ if (io_info->str) {
+ if (v3_handle_svm_io_outs(info) == -1 ) {
+ return -1;
+ }
+ } else {
+ if (v3_handle_svm_io_out(info) == -1) {
+ return -1;
+ }
}
} else {
- if (v3_handle_svm_io_out(info) == -1) {
- return -1;
+ if (io_info->str) {
+ if (v3_handle_svm_io_ins(info) == -1) {
+ return -1;
+ }
+ } else {
+ if (v3_handle_svm_io_in(info) == -1) {
+ return -1;
+ }
}
}
- } else {
- if (io_info->str) {
- if (v3_handle_svm_io_ins(info) == -1) {
+ break;
+ }
+ case VMEXIT_MSR:
+ {
+
+ if (guest_ctrl->exit_info1 == 0) {
+ if (v3_handle_msr_read(info) == -1) {
return -1;
}
- } else {
- if (v3_handle_svm_io_in(info) == -1) {
+ } else if (guest_ctrl->exit_info1 == 1) {
+ if (v3_handle_msr_write(info) == -1) {
return -1;
}
+ } else {
+ PrintError("Invalid MSR Operation\n");
+ return -1;
}
- }
- }
- break;
-
- case VMEXIT_CR0_WRITE: {
+ break;
+ }
+ case VMEXIT_CR0_WRITE:
+ {
#ifdef DEBUG_CTRL_REGS
- PrintDebug("CR0 Write\n");
+ PrintDebug("CR0 Write\n");
#endif
- if (v3_handle_cr0_write(info) == -1) {
- return -1;
+ if (v3_handle_cr0_write(info) == -1) {
+ return -1;
+ }
+ break;
+ }
+ case VMEXIT_CR0_READ:
+ {
+#ifdef DEBUG_CTRL_REGS
+ PrintDebug("CR0 Read\n");
+#endif
+ if (v3_handle_cr0_read(info) == -1) {
+ return -1;
+ }
+ break;
+ }
+ case VMEXIT_CR3_WRITE:
+ {
+#ifdef DEBUG_CTRL_REGS
+ PrintDebug("CR3 Write\n");
+#endif
+ if (v3_handle_cr3_write(info) == -1) {
+ return -1;
+ }
+ break;
}
- }
- break;
-
- case VMEXIT_CR0_READ: {
+ case VMEXIT_CR3_READ:
+ {
#ifdef DEBUG_CTRL_REGS
- PrintDebug("CR0 Read\n");
+ PrintDebug("CR3 Read\n");
#endif
- if (v3_handle_cr0_read(info) == -1) {
- return -1;
+ if (v3_handle_cr3_read(info) == -1) {
+ return -1;
+ }
+ break;
}
- }
- break;
-
- case VMEXIT_CR3_WRITE: {
+ case VMEXIT_CR4_WRITE:
+ {
#ifdef DEBUG_CTRL_REGS
- PrintDebug("CR3 Write\n");
+ PrintDebug("CR4 Write\n");
#endif
- if (v3_handle_cr3_write(info) == -1) {
- return -1;
- }
- }
- break;
-
- case VMEXIT_CR3_READ: {
+ if (v3_handle_cr4_write(info) == -1) {
+ return -1;
+ }
+ break;
+ }
+ case VMEXIT_CR4_READ:
+ {
#ifdef DEBUG_CTRL_REGS
- PrintDebug("CR3 Read\n");
+ PrintDebug("CR4 Read\n");
#endif
- if (v3_handle_cr3_read(info) == -1) {
- return -1;
+ if (v3_handle_cr4_read(info) == -1) {
+ return -1;
+ }
+ break;
}
- }
- break;
- case VMEXIT_EXCP14: {
- addr_t fault_addr = guest_ctrl->exit_info2;
- pf_error_t * error_code = (pf_error_t *)&(guest_ctrl->exit_info1);
+ case VMEXIT_EXCP14:
+ {
+ addr_t fault_addr = guest_ctrl->exit_info2;
+ pf_error_t * error_code = (pf_error_t *)&(guest_ctrl->exit_info1);
#ifdef DEBUG_SHADOW_PAGING
- PrintDebug("PageFault at %p (error=%d)\n",
- (void *)fault_addr, *(uint_t *)error_code);
+ PrintDebug("PageFault at %p (error=%d)\n",
+ (void *)fault_addr, *(uint_t *)error_code);
#endif
- if (info->shdw_pg_mode == SHADOW_PAGING) {
- if (v3_handle_shadow_pagefault(info, fault_addr, *error_code) == -1) {
+ if (info->shdw_pg_mode == SHADOW_PAGING) {
+ if (v3_handle_shadow_pagefault(info, fault_addr, *error_code) == -1) {
+ return -1;
+ }
+ } else {
+ PrintError("Page fault in un implemented paging mode\n");
return -1;
}
- } else {
- PrintError("Page fault in un implemented paging mode\n");
+ break;
+ }
+ case VMEXIT_NPF:
+ {
+ PrintError("Currently unhandled Nested Page Fault\n");
return -1;
- }
- }
- break;
-
- case VMEXIT_NPF: {
- PrintError("Currently unhandled Nested Page Fault\n");
- return -1;
-
- }
- break;
- case VMEXIT_INVLPG: {
- if (info->shdw_pg_mode == SHADOW_PAGING) {
+ break;
+ }
+ case VMEXIT_INVLPG:
+ {
+ if (info->shdw_pg_mode == SHADOW_PAGING) {
#ifdef DEBUG_SHADOW_PAGING
- PrintDebug("Invlpg\n");
+ PrintDebug("Invlpg\n");
#endif
- if (v3_handle_shadow_invlpg(info) == -1) {
- return -1;
+ if (v3_handle_shadow_invlpg(info) == -1) {
+ return -1;
+ }
}
- }
- /*
- (exit_code == VMEXIT_INVLPGA) ||
- */
-
- }
- break;
-
- case VMEXIT_INTR: {
-
- // handled by interrupt dispatch earlier
-
- }
- break;
-
- case VMEXIT_SMI: {
-
- // handle_svm_smi(info); // ignored for now
-
- }
- break;
-
- case VMEXIT_HLT: {
+ /*
+ (exit_code == VMEXIT_INVLPGA) ||
+ */
+ break;
+ }
+ case VMEXIT_INTR:
+ {
+ // handled by interrupt dispatch earlier
+ break;
+ }
+ case VMEXIT_SMI:
+ {
+ // handle_svm_smi(info); // ignored for now
+ break;
+ }
+ case VMEXIT_HLT:
+ {
#ifdef DEBUG_HALT
- PrintDebug("Guest halted\n");
+ PrintDebug("Guest halted\n");
#endif
- if (v3_handle_svm_halt(info) == -1) {
- return -1;
+ if (v3_handle_svm_halt(info) == -1) {
+ return -1;
+ }
+ break;
}
- }
- break;
-
case VMEXIT_PAUSE: {
//PrintDebug("Guest paused\n");
if (v3_handle_svm_pause(info) == -1) {
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/svm_msr.h>
+#include <palacios/vmm_msr.h>
+
+#include <palacios/vmm_list.h>
+
+
+#define PENTIUM_MSRS_START 0x00000000
+#define PENTIUM_MSRS_END 0x00001fff
+#define AMD_6_GEN_MSRS_START 0xc0000000
+#define AMD_6_GEN_MSRS_END 0xc0001fff
+#define AMD_7_8_GEN_MSRS_START 0xc0010000
+#define AMD_7_8_GEN_MSRS_END 0xc0011fff
+
+#define PENTIUM_MSRS_INDEX (0x0 * 4)
+#define AMD_6_GEN_MSRS_INDEX (0x800 * 4)
+#define AMD_7_8_GEN_MSRS_INDEX (0x1000 * 4)
+
+
+
+static int get_bitmap_index(uint_t msr) {
+ if ((msr >= PENTIUM_MSRS_START) &&
+ (msr <= PENTIUM_MSRS_END)) {
+ return (PENTIUM_MSRS_INDEX + (msr - PENTIUM_MSRS_START));
+ } else if ((msr >= AMD_6_GEN_MSRS_START) &&
+ (msr <= AMD_6_GEN_MSRS_END)) {
+ return (AMD_6_GEN_MSRS_INDEX + (msr - AMD_6_GEN_MSRS_START));
+ } else if ((msr >= AMD_7_8_GEN_MSRS_START) &&
+ (msr <= AMD_7_8_GEN_MSRS_END)) {
+ return (AMD_7_8_GEN_MSRS_INDEX + (msr - AMD_7_8_GEN_MSRS_START));
+ } else {
+ PrintError("MSR out of range (MSR=0x%x)\n", msr);
+ return -1;
+ }
+}
+
+
+
+addr_t v3_init_svm_msr_map(struct guest_info * info) {
+ uchar_t * msr_bitmap = (uchar_t*)V3_VAddr(V3_AllocPages(2));
+ struct v3_msr_map * msr_map = &(info->msr_map);
+ struct v3_msr_hook * hook = NULL;
+
+
+ memset(msr_bitmap, 0, PAGE_SIZE * 2);
+
+ list_for_each_entry(hook, &(msr_map->hook_list), link) {
+ int index = get_bitmap_index(hook->msr);
+ uint_t byte_offset = index / 4;
+ uint_t bit_offset = (index % 4) * 2;
+ uchar_t val = 0;
+ uchar_t mask = ~0x3;
+
+ if (hook->read) {
+ val |= 0x1;
+ }
+
+ if (hook->write) {
+ val |= 0x2;
+ }
+
+ val = val << bit_offset;
+ mask = mask << bit_offset;
+
+ *(msr_bitmap + byte_offset) &= mask;
+ *(msr_bitmap + byte_offset) |= val;
+ }
+
+ return (addr_t)V3_PAddr(msr_bitmap);
+}
+
+
+
+int v3_handle_msr_write(struct guest_info * info) {
+ uint_t msr_num = info->vm_regs.rcx;
+ struct v3_msr msr_val;
+ struct v3_msr_hook * hook = NULL;
+
+ hook = v3_get_msr_hook(info, msr_num);
+
+ if (!hook) {
+ PrintError("Hook for MSR write %d not found\n", msr_num);
+ return -1;
+ }
+
+ msr_val.value = 0;
+ msr_val.lo = info->vm_regs.rax;
+ msr_val.hi = info->vm_regs.rdx;
+
+ if (hook->write(msr_num, msr_val, hook->priv_data) == -1) {
+ PrintError("Error in MSR hook Write\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+int v3_handle_msr_read(struct guest_info * info) {
+ uint_t msr_num = info->vm_regs.rcx;
+ struct v3_msr msr_val;
+ struct v3_msr_hook * hook = NULL;
+
+ hook = v3_get_msr_hook(info, msr_num);
+
+ if (!hook) {
+ PrintError("Hook for MSR read %d not found\n", msr_num);
+ return -1;
+ }
+
+ msr_val.value = 0;
+
+ if (hook->read(msr_num, &msr_val, hook->priv_data) == -1) {
+ PrintError("Error in MSR hook Read\n");
+ return -1;
+ }
+
+ info->vm_regs.rax = msr_val.lo;
+ info->vm_regs.rdx = msr_val.hi;
+
+ return 0;
+}
} else if ((efer->lma == 1) && (cs->long_mode == 1)) {
return LONG;
} else {
+ return -1;
+ // What about LONG_16_COMPAT???
return LONG_32_COMPAT;
}
}
#include <palacios/vmm_config.h>
#include <palacios/vmm.h>
#include <palacios/vmm_debug.h>
+#include <palacios/vmm_msr.h>
#include <devices/serial.h>
v3_init_vmm_io_map(info);
+ v3_init_msr_map(info);
v3_init_interrupt_state(info);
v3_init_dev_mgr(info);
if (info->cpu_mode == LONG) {
// 64 bit registers
+ PrintError("Long mode currently not handled\n");
+ return -1;
} else {
// 32 bit registers
struct cr0_32 *real_cr0 = (struct cr0_32*)&(info->ctrl_regs.cr0);
} else if (cached == 0) {
addr_t shadow_pt;
- if( info->mem_mode == VIRTUAL_MEM )
- {
- PrintDebug("New CR3 is different - flushing shadow page table %p\n", shadow_cr3 );
-
- delete_page_tables_pde32((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
+ if(info->mem_mode == VIRTUAL_MEM) {
+ PrintDebug("New CR3 is different - flushing shadow page table %p\n", shadow_cr3 );
+ delete_page_tables_pde32((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
}
shadow_pt = v3_create_new_shadow_pt32();
return 0;
}
+
+int v3_handle_cr4_read(struct guest_info * info) {
+ PrintError("CR4 Read not handled\n");
+ return -1;
+}
+
+int v3_handle_cr4_write(struct guest_info * info) {
+ uchar_t instr[15];
+ int ret;
+ struct x86_instr dec_instr;
+
+ if (info->mem_mode == PHYSICAL_MEM) {
+ ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+ } else {
+ ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+ }
+
+ if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
+ PrintError("Could not decode instruction\n");
+ return -1;
+ }
+
+ if (v3_opcode_cmp(V3_OPCODE_MOV2CR, (const uchar_t *)(dec_instr.opcode)) != 0) {
+ PrintError("Invalid opcode in write to CR4\n");
+ return -1;
+ }
+
+ if ((info->cpu_mode == PROTECTED) || (info->cpu_mode == PROTECTED_PAE)) {
+ struct cr4_32 * new_cr4 = (struct cr4_32 *)(dec_instr.src_operand.operand);
+ struct cr4_32 * old_cr4 = (struct cr4_32 *)&(info->ctrl_regs.cr4);
+
+ PrintDebug("OperandVal = %x, length = %d\n", *(uint_t *)new_cr4, dec_instr.src_operand.size);
+ PrintDebug("Old CR4=%x\n", *(uint_t *)old_cr4);
+
+
+
+
+ if ((info->shdw_pg_mode == SHADOW_PAGING) &&
+ (v3_get_mem_mode(info) == PHYSICAL_MEM)) {
+
+ if ((old_cr4->pae == 0) && (new_cr4->pae == 1)) {
+ // Create Passthrough PAE pagetables
+ PrintDebug("Creating PAE passthrough tables\n");
+ info->ctrl_regs.cr3 = (addr_t)V3_PAddr(create_passthrough_pts_PAE32(info));
+ } else if ((old_cr4->pae == 1) && (new_cr4->pae == 0)) {
+ // Create passthrough standard 32bit pagetables
+ return -1;
+ }
+ }
+
+ *old_cr4 = *new_cr4;
+ PrintDebug("New CR4=%x\n", *(uint_t *)old_cr4);
+
+ } else {
+ return -1;
+ }
+
+ info->rip += dec_instr.instr_length;
+ return 0;
+}
+
+
+int v3_handle_efer_read(uint_t msr, struct v3_msr * dst, void * priv_data) {
+ PrintError("EFER Read not handled\n");
+ return -1;
+}
+
+
+int v3_handle_efer_write(uint_t msr, struct v3_msr src, void * priv_data) {
+ // struct guest_info * info = (struct guest_info *)(priv_data);
+ PrintError("EFER Write not handled (rax=%p, rdx=%p)\n",
+ (void *)(addr_t)(src.lo),
+ (void *)(addr_t)(src.hi));
+ return -1;
+}
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+#include <palacios/vmm_msr.h>
+#include <palacios/vmm.h>
+#include <palacios/vm_guest.h>
+
+
+void v3_init_msr_map(struct guest_info * info) {
+ struct v3_msr_map * msr_map = &(info->msr_map);
+
+ INIT_LIST_HEAD(&(msr_map->hook_list));
+ msr_map->num_hooks = 0;
+}
+
+
+int v3_hook_msr(struct guest_info * info, uint_t msr,
+ int (*read)(uint_t msr, struct v3_msr * dst, void * priv_data),
+ int (*write)(uint_t msr, struct v3_msr src, void * priv_data),
+ void * priv_data) {
+
+ struct v3_msr_map * msr_map = &(info->msr_map);
+ struct v3_msr_hook * hook = NULL;
+
+ hook = (struct v3_msr_hook *)V3_Malloc(sizeof(struct v3_msr_hook));
+ if (hook == NULL) {
+ PrintError("Could not allocate msr hook for MSR %d\n", msr);
+ return -1;
+ }
+
+ hook->read = read;
+ hook->write = write;
+ hook->msr = msr;
+ hook->priv_data = priv_data;
+
+ list_add(&(hook->link), &(msr_map->hook_list));
+
+ return 0;
+}
+
+
+int v3_unhook_msr(struct guest_info * info, uint_t msr) {
+ return -1;
+}
+
+
+
+struct v3_msr_hook * v3_get_msr_hook(struct guest_info * info, uint_t msr) {
+ struct v3_msr_map * msr_map = &(info->msr_map);
+ struct v3_msr_hook * hook = NULL;
+
+ list_for_each_entry(hook, &(msr_map->hook_list), link) {
+ if (hook->msr == msr) {
+ return hook;
+ }
+ }
+
+ return NULL;
+}
+
+
+void v3_print_msr_map(struct guest_info * info) {
+ struct v3_msr_map * msr_map = &(info->msr_map);
+ struct v3_msr_hook * hook = NULL;
+
+ list_for_each_entry(hook, &(msr_map->hook_list), link) {
+ PrintDebug("MSR HOOK (MSR=%d) (read=0x%p) (write=0x%p)\n",
+ hook->msr, hook->read, hook->write);
+ }
+}
}
+/* We generate a page table to correspond to a given memory layout
+ * pulling pages from the mem_list when necessary
+ * If there are any gaps in the layout, we add them as unmapped pages
+ */
+pdpe32pae_t * create_passthrough_pts_PAE32(struct guest_info * guest_info) {
+ addr_t current_page_addr = 0;
+ int i, j, k;
+ struct shadow_map * map = &(guest_info->mem_map);
+
+ pdpe32pae_t * pdpe = V3_VAddr(V3_AllocPages(1));
+ memset(pdpe, 0, PAGE_SIZE);
+
+ for (i = 0; i < MAX_PDPE32PAE_ENTRIES; i++) {
+ int pde_present = 0;
+ pde32pae_t * pde = V3_VAddr(V3_AllocPages(1));
+
+ for (j = 0; j < MAX_PDE32PAE_ENTRIES; j++) {
+
+
+ int pte_present = 0;
+ pte32pae_t * pte = V3_VAddr(V3_AllocPages(1));
+
+
+ for (k = 0; k < MAX_PTE32PAE_ENTRIES; k++) {
+ struct shadow_region * region = get_shadow_region_by_addr(map, current_page_addr);
+
+ if (!region ||
+ (region->host_type == HOST_REGION_HOOK) ||
+ (region->host_type == HOST_REGION_UNALLOCATED) ||
+ (region->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE) ||
+ (region->host_type == HOST_REGION_REMOTE) ||
+ (region->host_type == HOST_REGION_SWAPPED)) {
+ pte[k].present = 0;
+ pte[k].writable = 0;
+ pte[k].user_page = 0;
+ pte[k].write_through = 0;
+ pte[k].cache_disable = 0;
+ pte[k].accessed = 0;
+ pte[k].dirty = 0;
+ pte[k].pte_attr = 0;
+ pte[k].global_page = 0;
+ pte[k].vmm_info = 0;
+ pte[k].page_base_addr = 0;
+ pte[k].rsvd = 0;
+ } else {
+ addr_t host_addr;
+ pte[k].present = 1;
+ pte[k].writable = 1;
+ pte[k].user_page = 1;
+ pte[k].write_through = 0;
+ pte[k].cache_disable = 0;
+ pte[k].accessed = 0;
+ pte[k].dirty = 0;
+ pte[k].pte_attr = 0;
+ pte[k].global_page = 0;
+ pte[k].vmm_info = 0;
+
+ if (guest_pa_to_host_pa(guest_info, current_page_addr, &host_addr) == -1) {
+ // BIG ERROR
+ // PANIC
+ return NULL;
+ }
+
+ pte[k].page_base_addr = host_addr >> 12;
+ pte[k].rsvd = 0;
+
+ pte_present = 1;
+ }
+
+ current_page_addr += PAGE_SIZE;
+ }
+
+ if (pte_present == 0) {
+ V3_FreePage(V3_PAddr(pte));
+
+ pde[j].present = 0;
+ pde[j].writable = 0;
+ pde[j].user_page = 0;
+ pde[j].write_through = 0;
+ pde[j].cache_disable = 0;
+ pde[j].accessed = 0;
+ pde[j].avail = 0;
+ pde[j].large_page = 0;
+ pde[j].global_page = 0;
+ pde[j].vmm_info = 0;
+ pde[j].pt_base_addr = 0;
+ pde[j].rsvd = 0;
+ } else {
+ pde[j].present = 1;
+ pde[j].writable = 1;
+ pde[j].user_page = 1;
+ pde[j].write_through = 0;
+ pde[j].cache_disable = 0;
+ pde[j].accessed = 0;
+ pde[j].avail = 0;
+ pde[j].large_page = 0;
+ pde[j].global_page = 0;
+ pde[j].vmm_info = 0;
+ pde[j].pt_base_addr = PAGE_ALIGNED_ADDR((addr_t)V3_PAddr(pte));
+ pde[j].rsvd = 0;
+
+ pde_present = 1;
+ }
+
+ }
+
+ if (pde_present == 0) {
+ V3_FreePage(V3_PAddr(pde));
+
+ pdpe[i].present = 0;
+ pdpe[i].rsvd = 0;
+ pdpe[i].write_through = 0;
+ pdpe[i].cache_disable = 0;
+ pdpe[i].accessed = 0;
+ pdpe[i].avail = 0;
+ pdpe[i].rsvd2 = 0;
+ pdpe[i].vmm_info = 0;
+ pdpe[i].pd_base_addr = 0;
+ pdpe[i].rsvd3 = 0;
+ } else {
+ pdpe[i].present = 1;
+ pdpe[i].rsvd = 0;
+ pdpe[i].write_through = 0;
+ pdpe[i].cache_disable = 0;
+ pdpe[i].accessed = 0;
+ pdpe[i].avail = 0;
+ pdpe[i].rsvd2 = 0;
+ pdpe[i].vmm_info = 0;
+ pdpe[i].pd_base_addr = PAGE_ALIGNED_ADDR((addr_t)V3_PAddr(pde));
+ pdpe[i].rsvd3 = 0;
+ }
+
+ }
+
+
+ return pdpe;
+}
+
+
+
+
pml4e64_t * create_passthrough_pts_64(struct guest_info * info) {
}
+
+
+
+
void PrintPDE64(addr_t virtual_address, pde64_t * pde)
{
PrintDebug("PDE64 %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
+
+
void PrintDebugPageTables(pde32_t * pde)
{
int i;
}
}
+
+
+
+
+
+
+
+void PrintPDPE32PAE(addr_t virtual_address, pdpe32pae_t * pdpe)
+{
+ PrintDebug("PDPE %p -> %p : present=%x, wt=%x, cd=%x, accessed=%x, kernelInfo=%x\n",
+ (void *)virtual_address,
+ (void *)(addr_t) (pdpe->pd_base_addr << PAGE_POWER),
+ pdpe->present,
+ pdpe->write_through,
+ pdpe->cache_disable,
+ pdpe->accessed,
+ pdpe->vmm_info);
+}
+
+void PrintPDE32PAE(addr_t virtual_address, pde32pae_t * pde)
+{
+ PrintDebug("PDE %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
+ (void *)virtual_address,
+ (void *)(addr_t) (pde->pt_base_addr << PAGE_POWER),
+ pde->present,
+ pde->writable,
+ pde->user_page,
+ pde->write_through,
+ pde->cache_disable,
+ pde->accessed,
+ pde->large_page,
+ pde->global_page,
+ pde->vmm_info);
+}
+
+
+void PrintPTE32PAE(addr_t virtual_address, pte32pae_t * pte)
+{
+ PrintDebug("PTE %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, vmm_info=%x\n",
+ (void *)virtual_address,
+ (void*)(addr_t)(pte->page_base_addr << PAGE_POWER),
+ pte->present,
+ pte->writable,
+ pte->user_page,
+ pte->write_through,
+ pte->cache_disable,
+ pte->accessed,
+ pte->dirty,
+ pte->pte_attr,
+ pte->global_page,
+ pte->vmm_info);
+}
+
+
+
+
+
+
+void PrintDebugPageTables32PAE(pdpe32pae_t * pdpe)
+{
+ int i, j, k;
+ pde32pae_t * pde;
+ pte32pae_t * pte;
+ addr_t virtual_addr = 0;
+
+ PrintDebug("Dumping the pages starting with the pde page at %p\n", pdpe);
+
+ for (i = 0; (i < MAX_PDPE32PAE_ENTRIES); i++) {
+
+ if (pdpe[i].present) {
+ pde = (pde32pae_t *)V3_VAddr((void *)(addr_t)BASE_TO_PAGE_ADDR(pdpe[i].pd_base_addr));
+
+ PrintPDPE32PAE(virtual_addr, &(pdpe[i]));
+
+ for (j = 0; j < MAX_PDE32PAE_ENTRIES; j++) {
+
+ if (pde[j].present) {
+ pte = (pte32pae_t *)V3_VAddr((void *)(addr_t)BASE_TO_PAGE_ADDR(pde[j].pt_base_addr));
+
+ PrintPDE32PAE(virtual_addr, &(pde[j]));
+
+ for (k = 0; k < MAX_PTE32PAE_ENTRIES; k++) {
+ if (pte[k].present) {
+ PrintPTE32PAE(virtual_addr, &(pte[k]));
+ }
+
+ virtual_addr += PAGE_SIZE;
+ }
+ } else {
+ virtual_addr += PAGE_SIZE * MAX_PTE32PAE_ENTRIES;
+ }
+ }
+ } else {
+ virtual_addr += PAGE_SIZE * MAX_PDE32PAE_ENTRIES * MAX_PTE32PAE_ENTRIES;
+ }
+ }
+}
+
+