-typedef enum {SHADOW_PAGING, NESTED_PAGING} v3_paging_mode_t;
-typedef enum {VM_RUNNING, VM_STOPPED, VM_SUSPENDED, VM_ERROR, VM_EMULATING} v3_vm_operating_mode_t;
-
-
-typedef enum {REAL, /*UNREAL,*/ PROTECTED, PROTECTED_PAE, LONG, LONG_32_COMPAT, LONG_16_COMPAT} v3_vm_cpu_mode_t;
-typedef enum {PHYSICAL_MEM, VIRTUAL_MEM} v3_vm_mem_mode_t;
-
struct guest_info {
uint_t mp : 1;
uint_t em : 1;
uint_t ts : 1;
-};
+} __attribute__((packed));
struct cr0_32 {
uint_t nw : 1;
uint_t cd : 1;
uint_t pg : 1;
-};
+} __attribute__((packed));
struct cr0_64 {
uint_t pg : 1;
uint_t rsvd4; // MBZ
-};
+} __attribute__((packed));
struct cr2_32 {
uint_t pf_vaddr;
-};
+} __attribute__((packed));
struct cr2_64 {
ullong_t pf_vaddr;
-};
+} __attribute__((packed));
struct cr3_32 {
uint_t pcd : 1;
uint_t rsvd2 : 7;
uint_t pdt_base_addr : 20;
-};
+} __attribute__((packed));
struct cr3_32_PAE {
uint_t pwt : 1;
uint_t pcd : 1;
uint_t pdpt_base_addr : 27;
-};
+} __attribute__((packed));
struct cr3_64 {
uint_t rsvd2 : 7;
ullong_t pml4t_base_addr : 40;
uint_t rsvd3 : 12;
-};
+} __attribute__((packed));
struct cr4_32 {
uint_t osf_xsr : 1;
uint_t osx : 1;
uint_t rsvd1 : 21;
-};
+} __attribute__((packed));
struct cr4_64 {
uint_t vme : 1;
uint_t osx : 1;
uint_t rsvd1 : 21;
uint_t rsvd2 : 32;
-};
+} __attribute__((packed));
uint_t ffxsr : 1;
uint_t rsvd4 : 12; // MBZ
uint_t rsvd5 : 32; // MBZ
-};
+} __attribute__((packed));
struct rflags {
uint_t id : 1; // ID flag
uint_t rsvd5 : 10; // Read as 0
uint_t rsvd6 : 32; // Read as 0
-};
+} __attribute__((packed));
#include <palacios/vmm_types.h>
#include <palacios/vmm_util.h>
+
/*
In the following, when we say "page table", we mean the whole 2 or 4 layer
#define PTE32_INDEX(x) ((((uint_t)x) >> 12) & 0x3ff)
+#define PDPE32PAE_INDEX(x) ((((uint_t)x) >> 30) & 0x3)
+#define PDE32PAE_INDEX(x) ((((uint_t)x) >> 21) & 0x1ff)
+#define PTE32PAE_INDEX(x) ((((uint_t)x) >> 12) & 0x1ff)
+
+#define PML4E64_INDEX(x) ((((ullong_t)x) >> 39) & 0x1ff)
+#define PDPE64_INDEX(x) ((((ullong_t)x) >> 30) & 0x1ff)
+#define PDE64_INDEX(x) ((((ullong_t)x) >> 21) & 0x1ff)
+#define PTE64_INDEX(x) ((((ullong_t)x) >> 12) & 0x1ff)
+
+
/* Gets the base address needed for a Page Table entry */
/* Deprecate these :*/
#define PD32_BASE_ADDR(x) (((uint_t)x) >> 12)
-#define CR3_TO_PDE32(cr3) (V3_VAddr((void *)(((ulong_t)cr3) & 0xfffff000)))
+#define CR3_TO_PDE32(cr3) ((pde32_t *)V3_VAddr((void *)(((ulong_t)cr3) & 0xfffff000)))
#define CR3_TO_PDPTRE(cr3) (V3_VAddr((void *)(((ulong_t)cr3) & 0xffffffe0)))
-#define CR3_TO_PML4E64(cr3) (V3_VAddr((void *)(((ullong_t)cr3) & 0x000ffffffffff000LL)))
+#define CR3_TO_PML4E64(cr3) ((pml4e64_t *)V3_VAddr((void *)(((ullong_t)cr3) & 0x000ffffffffff000LL)))
-void delete_page_tables_pde32(pde32_t * pde);
-
+void delete_page_tables_32(pde32_t * pde);
+void delete_page_tables_32PAE(pdpe32pae_t * pdpe);
+void delete_page_tables_64(pml4e64_t * pml4);
pde32_entry_type_t pde32_lookup(pde32_t * pd, addr_t addr, addr_t * entry);
int pte32_lookup(pte32_t * pte, addr_t addr, addr_t * entry);
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);
+pdpe32pae_t * create_passthrough_pts_32PAE(struct guest_info * guest_info);
pml4e64_t * create_passthrough_pts_64(struct guest_info * info);
+//#include <palacios/vm_guest.h>
void PrintDebugPageTables(pde32_t * pde);
+void PrintPageTree(v3_vm_cpu_mode_t cpu_mode, addr_t virtual_addr, addr_t cr3);
+void PrintPageTree_64(addr_t virtual_addr, pml4e64_t * pml);
void PrintPT32(addr_t starting_address, pte32_t * pte);
int v3_init_shadow_page_state(struct guest_info * info);
-addr_t v3_create_new_shadow_pt32();
+addr_t v3_create_new_shadow_pt();
int v3_handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
int v3_handle_shadow_invlpg(struct guest_info * info);
#ifdef __V3VEE__
#include <palacios/vmm_stddef.h>
+typedef enum {SHADOW_PAGING, NESTED_PAGING} v3_paging_mode_t;
+typedef enum {VM_RUNNING, VM_STOPPED, VM_SUSPENDED, VM_ERROR, VM_EMULATING} v3_vm_operating_mode_t;
+
+
+typedef enum {REAL, /*UNREAL,*/ PROTECTED, PROTECTED_PAE, LONG, LONG_32_COMPAT, LONG_16_COMPAT} v3_vm_cpu_mode_t;
+typedef enum {PHYSICAL_MEM, VIRTUAL_MEM} v3_vm_mem_mode_t;
+
+
+
+
typedef signed char schar_t;
typedef unsigned char uchar_t;
guest_state->efer |= EFER_MSR_svm_enable;
v3_hook_msr(vm_info, EFER_MSR,
- &v3_handle_efer_read,
+ NULL, /*&v3_handle_efer_read,*/
&v3_handle_efer_write,
vm_info);
if (vm_info->msr_map.num_hooks > 0) {
+ PrintDebug("Hooking %d msrs\n", vm_info->msr_map.num_hooks);
ctrl_area->MSRPM_BASE_PA = v3_init_svm_msr_map(vm_info);
ctrl_area->instrs.MSR_PROT = 1;
if (cr0->pe == 0) {
return REAL;
- } else if ((cr4->pae == 0) && (efer->lma == 0)) {
+ } else if ((cr4->pae == 0) && (efer->lme == 0)) {
return PROTECTED;
- } else if (efer->lma == 0) {
+ } else if (efer->lme == 0) {
return PROTECTED_PAE;
- } else if ((efer->lma == 1) && (cs->long_mode == 1)) {
+ } else if ((efer->lme == 1) && (cs->long_mode == 1)) {
return LONG;
} else {
- return -1;
// What about LONG_16_COMPAT???
return LONG_32_COMPAT;
}
if (info->cpu_mode == LONG) {
// 64 bit registers
+ // Set efer.lma = 1
+
PrintError("Long mode currently not handled\n");
return -1;
} else {
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));
+ delete_page_tables_32((pde32_t *)CR3_TO_PDE32(*(uint_t*)shadow_cr3));
}
- shadow_pt = v3_create_new_shadow_pt32();
+ shadow_pt = v3_create_new_shadow_pt();
shadow_cr3->pdt_base_addr = (addr_t)V3_PAddr((void *)(addr_t)PD32_BASE_ADDR(shadow_pt));
PrintDebug( "Created new shadow page table %p\n", (void *)(addr_t)shadow_cr3->pdt_base_addr );
(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));
+
+ // Delete the old 32 bit direct map page tables
+ delete_page_tables_32((pde32_t *)V3_VAddr((void *)(info->direct_map_pt)));
+
+ // create 32 bit PAE direct map page table
+ info->direct_map_pt = (addr_t)V3_PAddr(create_passthrough_pts_32PAE(info));
+
+ // reset cr3 to new page tables
+ info->ctrl_regs.cr3 = *(addr_t*)&(info->direct_map_pt);
+
} else if ((old_cr4->pae == 1) && (new_cr4->pae == 0)) {
// Create passthrough standard 32bit pagetables
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;
+ struct guest_info * info = (struct guest_info *)(priv_data);
+ struct efer_64 * new_efer = (struct efer_64 *)&(src.value);
+ struct efer_64 * old_efer = (struct efer_64 *)&(info->ctrl_regs.efer);
+
+ PrintDebug("Old EFER=%p\n", (void *)*(addr_t*)(old_efer));
+
+ if ((info->shdw_pg_mode == SHADOW_PAGING) &&
+ (v3_get_mem_mode(info) == PHYSICAL_MEM)) {
+
+ if ((old_efer->lme == 0) && (new_efer->lme == 1)) {
+ PrintDebug("Transition to longmode\n");
+ PrintDebug("Creating Passthrough 64 bit page tables\n");
+
+ // Delete the old 32 bit direct map page tables
+ /*
+ * JRL BUG?
+ * Will these page tables always be in PAE format??
+ */
+ PrintDebug("Deleting old PAE Page tables\n");
+ PrintError("JRL BUG?: Will the old page tables always be in PAE format??\n");
+ delete_page_tables_32PAE((pdpe32pae_t *)V3_VAddr((void *)(info->direct_map_pt)));
+
+ // create 64 bit direct map page table
+ info->direct_map_pt = (addr_t)V3_PAddr(create_passthrough_pts_64(info));
+
+ // reset cr3 to new page tables
+ info->ctrl_regs.cr3 = *(addr_t*)&(info->direct_map_pt);
+
+
+ // Does this mean we will have to fully virtualize a shadow EFER??
+ new_efer->lma = 1;
+
+ } else if ((old_efer->lme == 1) && (new_efer->lme == 0)) {
+ // transition out of long mode
+ return -1;
+ }
+
+ *old_efer = *new_efer;
+ PrintDebug("New EFER=%p\n", (void *)*(addr_t *)(old_efer));
+ } else {
+ return -1;
+ }
+
+ info->rip += 2; // WRMSR/RDMSR are two byte operands
+
+ return 0;
}
hook->msr = msr;
hook->priv_data = priv_data;
+ msr_map->num_hooks++;
+
list_add(&(hook->link), &(msr_map->hook_list));
return 0;
-void delete_page_tables_pde32(pde32_t * pde) {
- int i;//, j;
+void delete_page_tables_32(pde32_t * pde) {
+ int i;
if (pde == NULL) {
return;
PrintDebug("PTE base addr %x \n", pde[i].pt_base_addr);
pte32_t * pte = (pte32_t *)((addr_t)(uint_t)(pde[i].pt_base_addr << PAGE_POWER));
- /*
- for (j = 0; (j < MAX_PTE32_ENTRIES); j++) {
- if ((pte[j].present)) {
- os_hooks->free_page((void *)(pte[j].page_base_addr << PAGE_POWER));
- }
- }
- */
PrintDebug("Deleting PTE %d (%p)\n", i, pte);
V3_FreePage(pte);
}
V3_FreePage(V3_PAddr(pde));
}
+void delete_page_tables_32PAE(pdpe32pae_t * pdpe) {
+ PrintError("Unimplemented function\n");
+}
+
+void delete_page_tables_64(pml4e64_t * pml4) {
+ PrintError("Unimplemented function\n");
+}
+
* 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) {
+pdpe32pae_t * create_passthrough_pts_32PAE(struct guest_info * guest_info) {
addr_t current_page_addr = 0;
int i, j, k;
struct shadow_map * map = &(guest_info->mem_map);
int pdpe_present = 0;
pdpe64_t * pdpe = V3_VAddr(V3_AllocPages(1));
- for (j = 0; j < 1; j++) {
+ for (j = 0; j < 20; j++) {
int pde_present = 0;
pde64_t * pde = V3_VAddr(V3_AllocPages(1));
+
+
+
void PrintPDE32(addr_t virtual_address, pde32_t * pde)
{
PrintDebug("PDE %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
-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 *)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->reserved,
- pde->large_page,
- 0,//pde->global_page,
- pde->vmm_info);
-}
-
-
-void PrintPTE64(addr_t virtual_address, pte64_t * pte)
-{
- PrintDebug("PTE64 %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 PrintPML4e64(addr_t virtual_address, pml4e64_t * pml)
+{
+ PrintDebug("PML4e64 %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, reserved=%x, kernelInfo=%x\n",
+ (void *)virtual_address,
+ (void *)(addr_t) (BASE_TO_PAGE_ADDR(pml->pdp_base_addr)),
+ pml->present,
+ pml->writable,
+ pml->user_page,
+ pml->write_through,
+ pml->cache_disable,
+ pml->accessed,
+ pml->reserved,
+ pml->vmm_info);
+}
+
+void PrintPDPE64(addr_t virtual_address, pdpe64_t * pdpe)
+{
+ PrintDebug("PDPE64 %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
+ (void *)virtual_address,
+ (void *)(addr_t) (BASE_TO_PAGE_ADDR(pdpe->pd_base_addr)),
+ pdpe->present,
+ pdpe->writable,
+ pdpe->user_page,
+ pdpe->write_through,
+ pdpe->cache_disable,
+ pdpe->accessed,
+ pdpe->reserved,
+ pdpe->large_page,
+ 0,//pdpe->global_page,
+ pdpe->vmm_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 *)virtual_address,
+ (void *)(addr_t) (BASE_TO_PAGE_ADDR(pde->pt_base_addr)),
+ pde->present,
+ pde->writable,
+ pde->user_page,
+ pde->write_through,
+ pde->cache_disable,
+ pde->accessed,
+ pde->reserved,
+ pde->large_page,
+ 0,//pde->global_page,
+ pde->vmm_info);
+}
+
+
+void PrintPTE64(addr_t virtual_address, pte64_t * pte)
+{
+ PrintDebug("PTE64 %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)(BASE_TO_PAGE_ADDR(pte->page_base_addr)),
+ 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 PrintPageTree_64(addr_t virtual_addr, pml4e64_t * pml) {
+ uint_t pml4_index = PML4E64_INDEX(virtual_addr);
+ uint_t pdpe_index = PDPE64_INDEX(virtual_addr);
+ uint_t pde_index = PDE64_INDEX(virtual_addr);
+ uint_t pte_index = PTE64_INDEX(virtual_addr);
+
+ PrintPML4e64(virtual_addr, &(pml[pml4_index]));
+ if (pml[pml4_index].present) {
+ pdpe64_t * pdpe = (pdpe64_t *)V3_VAddr((void *)(addr_t)BASE_TO_PAGE_ADDR(pml[pml4_index].pdp_base_addr));
+ PrintPDPE64(virtual_addr, &(pdpe[pdpe_index]));
+
+ if (pdpe[pdpe_index].present) {
+ pde64_t * pde = (pde64_t *)V3_VAddr((void *)(addr_t)BASE_TO_PAGE_ADDR(pdpe[pdpe_index].pd_base_addr));
+ PrintPDE64(virtual_addr, &(pde[pde_index]));
+
+ if (pde[pde_index].present) {
+ pte64_t * pte = (pte64_t *)V3_VAddr((void *)(addr_t)BASE_TO_PAGE_ADDR(pde[pde_index].pt_base_addr));
+ PrintPTE64(virtual_addr, &(pte[pte_index]));
+ }
+
+ }
+
+ }
+
+}
+
+
+
+
+void PrintPageTree(v3_vm_cpu_mode_t cpu_mode, addr_t virtual_addr, addr_t cr3) {
+ switch (cpu_mode) {
+ case LONG:
+ case LONG_32_COMPAT:
+ case LONG_16_COMPAT:
+ PrintPageTree_64(virtual_addr, CR3_TO_PML4E64(cr3));
+ break;
+ default:
+ PrintError("Unsupported CPU MODE %d\n", cpu_mode);
+ break;
+ }
+}
if (info->mem_mode == PHYSICAL_MEM) {
// If paging is not turned on we need to handle the special cases
+
+#ifdef DEBUG_SHADOW_PAGING
+ PrintPageTree(info->cpu_mode, fault_addr, info->ctrl_regs.cr3);
+#endif
+
return handle_special_page_fault(info, fault_addr, fault_addr, error_code);
} else if (info->mem_mode == VIRTUAL_MEM) {
}
}
-addr_t v3_create_new_shadow_pt32() {
+addr_t v3_create_new_shadow_pt() {
void * host_pde = 0;
host_pde = V3_VAddr(V3_AllocPages(1));
if (shadow_pde_access == PT_ENTRY_NOT_PRESENT)
{
- pte32_t * shadow_pt = (pte32_t *)v3_create_new_shadow_pt32();
+ pte32_t * shadow_pt = (pte32_t *)v3_create_new_shadow_pt();
shadow_pde->present = 1;
shadow_pde->user_page = guest_pde->user_page;