From: Jack Lange Date: Tue, 3 Feb 2009 20:45:02 +0000 (-0600) Subject: revamped the INVLPG handler X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=42fa79cec8ed9c44392a71c6253edab3abcb900e revamped the INVLPG handler --- diff --git a/palacios/include/palacios/vmm_decoder.h b/palacios/include/palacios/vmm_decoder.h index 0ae0109..6aa0833 100644 --- a/palacios/include/palacios/vmm_decoder.h +++ b/palacios/include/palacios/vmm_decoder.h @@ -28,6 +28,7 @@ typedef enum { V3_INVALID_OP, V3_OP_MOVCR2, V3_OP_MOV2CR, V3_OP_SMSW, V3_OP_LMSW, V3_OP_CLTS, + V3_OP_INVLPG, V3_OP_ADC, V3_OP_ADD, V3_OP_AND, V3_OP_OR, V3_OP_XOR, V3_OP_SUB, V3_OP_INC, V3_OP_DEC, V3_OP_NEG, V3_OP_MOV, V3_OP_NOT, V3_OP_XCHG, V3_OP_SETB, V3_OP_SETBE, V3_OP_SETL, V3_OP_SETLE, V3_OP_SETNB, diff --git a/palacios/include/palacios/vmm_paging.h b/palacios/include/palacios/vmm_paging.h index e7f68f1..7535a3e 100644 --- a/palacios/include/palacios/vmm_paging.h +++ b/palacios/include/palacios/vmm_paging.h @@ -129,23 +129,7 @@ typedef enum {PAGE_4KB, PAGE_2MB, PAGE_4MB, PAGE_1GB, /* 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) ((x) >> 12) #define PAGE_BASE_ADDR_4KB(x) ((x) >> 12) #define PAGE_BASE_ADDR_2MB(x) ((x) >> 21) @@ -159,21 +143,7 @@ typedef enum {PAGE_4KB, PAGE_2MB, PAGE_4MB, PAGE_1GB, #define BASE_TO_PAGE_ADDR_1GB(x) (((addr_t)x) << 30) /* *** */ -/* Deprecated */ -/* - #define PT32_PAGE_OFFSET(x) (((uint_t)x) & 0xfff) - #define PD32_4MB_PAGE_OFFSET(x) (((uint_t)x) & 0x003fffff) - - #define PT32_PAGE_ADDR(x) (((uint_t)x) & 0xfffff000) - #define PD32_4MB_PAGE_ADDR(x) (((uint_t)x) & 0xffc00000) - - #define PT32_PAGE_POWER 12 - #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 -*/ -/* use these instead */ + #define PAGE_OFFSET(x) ((x) & 0xfff) #define PAGE_OFFSET_4KB(x) ((x) & 0xfff) #define PAGE_OFFSET_2MB(x) ((x) & 0x1fffff) diff --git a/palacios/include/palacios/vmm_shadow_paging.h b/palacios/include/palacios/vmm_shadow_paging.h index 1b63e8b..da9c76d 100644 --- a/palacios/include/palacios/vmm_shadow_paging.h +++ b/palacios/include/palacios/vmm_shadow_paging.h @@ -61,15 +61,6 @@ int v3_handle_shadow_invlpg(struct guest_info * info); int v3_activate_shadow_pt(struct guest_info * info); int v3_activate_passthrough_pt(struct guest_info * info); -/* TODO: Change to static functions - * External visibility not needed - */ -addr_t v3_create_new_shadow_pt(); -int v3_replace_shdw_page32(struct guest_info * info, addr_t location, pte32_t * new_page, pte32_t * old_page); -/* *** */ - - -int v3_replace_shdw_page(struct guest_info * info, addr_t location, void * new_page, void * old_page); #endif // ! __V3VEE__ diff --git a/palacios/src/palacios/vmm_shadow_paging.c b/palacios/src/palacios/vmm_shadow_paging.c index 6a0b3be..0f98acf 100644 --- a/palacios/src/palacios/vmm_shadow_paging.c +++ b/palacios/src/palacios/vmm_shadow_paging.c @@ -99,16 +99,13 @@ int v3_init_shadow_page_state(struct guest_info * info) { state->guest_cr0 = 0; state->cached_ptes = NULL; - + state->cached_cr3 = 0; + return 0; } - - - - // Reads the guest CR3 register // creates new shadow page tables // updates the shadow CR3 register to point to the new pts @@ -148,12 +145,6 @@ int v3_handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_e if (info->mem_mode == PHYSICAL_MEM) { // If paging is not turned on we need to handle the special cases - -#ifdef DEBUG_SHADOW_PAGING - PrintHostPageTree(info->cpu_mode, fault_addr, info->ctrl_regs.cr3); - PrintGuestPageTree(info, fault_addr, info->shdw_pg_state.guest_cr3); -#endif - return handle_special_page_fault(info, fault_addr, fault_addr, error_code); } else if (info->mem_mode == VIRTUAL_MEM) { @@ -238,97 +229,58 @@ static int is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shado +int v3_handle_shadow_invlpg(struct guest_info * info) { + uchar_t instr[15]; + struct x86_instr dec_instr; + int ret = 0; + addr_t vaddr = 0; - -/* Currently Does not work with Segmentation!!! */ -int v3_handle_shadow_invlpg(struct guest_info * info) -{ if (info->mem_mode != VIRTUAL_MEM) { // Paging must be turned on... // should handle with some sort of fault I think PrintError("ERROR: INVLPG called in non paged mode\n"); return -1; } - - - if (info->cpu_mode != PROTECTED) { - PrintError("Unsupported CPU mode (mode=%s)\n", v3_cpu_mode_to_str(info->cpu_mode)); - return -1; + + 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); } - - uchar_t instr[15]; - int index = 0; - - int ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr); - if (ret != 15) { - PrintError("Could not read instruction 0x%p (ret=%d)\n", (void *)(addr_t)(info->rip), ret); + + if (ret == -1) { + PrintError("Could not read instruction into buffer\n"); return -1; } - - - /* Can INVLPG work with Segments?? */ - while (is_prefix_byte(instr[index])) { - index++; - } - - - if( (instr[index + 0] != (uchar_t) 0x0f) || - (instr[index + 1] != (uchar_t) 0x01) ) { - PrintError("invalid Instruction Opcode\n"); - PrintTraceMemDump(instr, 15); + + if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) { + PrintError("Decoding Error\n"); return -1; } - addr_t first_operand; - addr_t second_operand; - addr_t guest_cr3 = CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3); - - pde32_t * guest_pd = NULL; - - if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) { - PrintError("Invalid Guest PDE Address: 0x%p\n", (void *)guest_cr3); + if ((dec_instr.op_type != V3_OP_INVLPG) || + (dec_instr.num_operands != 1) || + (dec_instr.dst_operand.type != MEM_OPERAND)) { + PrintError("Decoder Error: Not a valid INVLPG instruction...\n"); return -1; } - - index += 2; - v3_operand_type_t addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32); - - if (addr_type != MEM_OPERAND) { - PrintError("Invalid Operand type\n"); + vaddr = dec_instr.dst_operand.operand; + + info->rip += dec_instr.instr_length; + + switch (info->cpu_mode) { + case PROTECTED: + return handle_shadow_invlpg_32(info, vaddr); + case PROTECTED_PAE: + return handle_shadow_invlpg_32pae(info, vaddr); + case LONG: + case LONG_32_COMPAT: + case LONG_16_COMPAT: + return handle_shadow_invlpg_64(info, vaddr); + default: + PrintError("Invalid CPU mode: %d\n", info->cpu_mode); return -1; } - - pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32_VA(info->ctrl_regs.cr3); - pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(first_operand)]; - pde32_t * guest_pde; - - //PrintDebug("PDE Index=%d\n", PDE32_INDEX(first_operand)); - //PrintDebug("FirstOperand = %x\n", first_operand); - - PrintDebug("Invalidating page for %p\n", (void *)first_operand); - - guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(first_operand)]); - - if (guest_pde->large_page == 1) { - shadow_pde->present = 0; - PrintDebug("Invalidating Large Page\n"); - } else - if (shadow_pde->present == 1) { - pte32_t * shadow_pt = (pte32_t *)(addr_t)BASE_TO_PAGE_ADDR(shadow_pde->pt_base_addr); - pte32_t * shadow_pte = (pte32_t *) V3_VAddr( (void*) &shadow_pt[PTE32_INDEX(first_operand)] ); - -#ifdef DEBUG_SHADOW_PAGING - PrintDebug("Setting not present\n"); - PrintPTEntry(PAGE_PT32, first_operand, shadow_pte); -#endif - - shadow_pte->present = 0; - } - - info->rip += index; - - return 0; } - diff --git a/palacios/src/palacios/vmm_shadow_paging_32.h b/palacios/src/palacios/vmm_shadow_paging_32.h index 7e0106a..b43a5a6 100644 --- a/palacios/src/palacios/vmm_shadow_paging_32.h +++ b/palacios/src/palacios/vmm_shadow_paging_32.h @@ -495,3 +495,37 @@ static int handle_shadow_pte32_fault(struct guest_info * info, PrintDebug("Returning end of function\n"); return 0; } + + + +/* If we start to optimize we should look up the guest pages in the cache... */ +static int handle_shadow_invlpg_32(struct guest_info * info, addr_t vaddr) { + pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32_VA(info->ctrl_regs.cr3); + pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(vaddr)]; + + addr_t guest_cr3 = CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3); + pde32_t * guest_pd = NULL; + pde32_t * guest_pde; + + if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) { + PrintError("Invalid Guest PDE Address: 0x%p\n", (void *)guest_cr3); + return -1; + } + + guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(vaddr)]); + + if (guest_pde->large_page == 1) { + shadow_pde->present = 0; + PrintDebug("Invalidating Large Page\n"); + } else if (shadow_pde->present == 1) { + pte32_t * shadow_pt = (pte32_t *)(addr_t)BASE_TO_PAGE_ADDR_4KB(shadow_pde->pt_base_addr); + pte32_t * shadow_pte = (pte32_t *) V3_VAddr( (void*) &shadow_pt[PTE32_INDEX(vaddr)] ); + + PrintDebug("Setting not present\n"); + + shadow_pte->present = 0; + } + + + return 0; +} diff --git a/palacios/src/palacios/vmm_shadow_paging_32pae.h b/palacios/src/palacios/vmm_shadow_paging_32pae.h index 58a4300..42570de 100644 --- a/palacios/src/palacios/vmm_shadow_paging_32pae.h +++ b/palacios/src/palacios/vmm_shadow_paging_32pae.h @@ -25,6 +25,11 @@ static int handle_shadow_pagefault_32pae(struct guest_info * info, addr_t fault_ } +static int handle_shadow_invlpg_32pae(struct guest_info * info, addr_t vaddr) { + PrintError("32 bit PAE shadow paging not implemented\n"); + return -1; +} + diff --git a/palacios/src/palacios/vmm_shadow_paging_64.h b/palacios/src/palacios/vmm_shadow_paging_64.h index 685ed61..12a21e5 100644 --- a/palacios/src/palacios/vmm_shadow_paging_64.h +++ b/palacios/src/palacios/vmm_shadow_paging_64.h @@ -36,3 +36,9 @@ static int handle_shadow_pagefault_64(struct guest_info * info, addr_t fault_add PrintError("64 bit shadow paging not implemented\n"); return -1; } + + +static int handle_shadow_invlpg_64(struct guest_info * info, addr_t vaddr) { + PrintError("64 bit shadow paging not implemented\n"); + return -1; +} diff --git a/palacios/src/palacios/vmm_xed.c b/palacios/src/palacios/vmm_xed.c index 3c39b13..73dd4ce 100644 --- a/palacios/src/palacios/vmm_xed.c +++ b/palacios/src/palacios/vmm_xed.c @@ -1021,6 +1021,9 @@ static int xed_reg_to_v3_reg(struct guest_info * info, xed_reg_enum_t xed_reg, a static v3_op_type_t get_opcode(xed_iform_enum_t iform) { switch (iform) { + + /* Control Instructions */ + case XED_IFORM_MOV_CR_GPR64_CR: case XED_IFORM_MOV_CR_GPR32_CR: return V3_OP_MOVCR2; @@ -1038,6 +1041,12 @@ static v3_op_type_t get_opcode(xed_iform_enum_t iform) { case XED_IFORM_CLTS: return V3_OP_CLTS; + case XED_IFORM_INVLPG_MEMb: + return V3_OP_INVLPG; + + + /* Data Instructions */ + case XED_IFORM_ADC_MEMv_GPRv: case XED_IFORM_ADC_MEMv_IMM: case XED_IFORM_ADC_MEMb_GPR8: @@ -1149,6 +1158,7 @@ static v3_op_type_t get_opcode(xed_iform_enum_t iform) { case XED_IFORM_SETZ_MEMb: return V3_OP_SETZ; + case XED_IFORM_MOVSB: case XED_IFORM_MOVSW: case XED_IFORM_MOVSD: