X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=blobdiff_plain;f=palacios%2Fsrc%2Fpalacios%2Fvmx_assist.c;h=5766b15c4f06b3d805e45cd285bcaa935f6f065e;hp=f926c42851717ff9c3c2421a8a6d3e77ebf19daf;hb=a34275476494aeabed460b284a70cfc9b66a9896;hpb=5bf6d0c260240e314876a2fca8e3fd56bd6a1029 diff --git a/palacios/src/palacios/vmx_assist.c b/palacios/src/palacios/vmx_assist.c index f926c42..5766b15 100644 --- a/palacios/src/palacios/vmx_assist.c +++ b/palacios/src/palacios/vmx_assist.c @@ -21,6 +21,83 @@ #include #include #include +#include + +#ifndef V3_CONFIG_DEBUG_VMX +#undef PrintDebug +#define PrintDebug(fmt, args...) +#endif + + + + +#define VMXASSIST_MAGIC 0x17101966 + + +struct vmx_assist_header { + uint64_t rsvd; // 8 bytes of nothing + uint32_t magic; + uint32_t new_ctx_gpa; + uint32_t old_ctx_gpa; +} __attribute__((packed)); + + +union vmcs_arbytes { + struct arbyte_fields { + unsigned int seg_type : 4, + s : 1, + dpl : 2, + p : 1, + reserved0 : 4, + avl : 1, + reserved1 : 1, + default_ops_size: 1, + g : 1, + null_bit : 1, + reserved2 : 15; + } __attribute__((packed)) fields; + unsigned int bytes; +} __attribute__((packed)); + +struct vmx_assist_segment { + uint32_t sel; + uint32_t limit; + uint32_t base; + union vmcs_arbytes arbytes; +} __attribute__((packed)); + + +/* + * World switch state + */ +struct vmx_assist_context { + uint32_t eip; /* execution pointer */ + uint32_t esp; /* stack pointer */ + uint32_t eflags; /* flags register */ + uint32_t cr0; + uint32_t cr3; /* page table directory */ + uint32_t cr4; + + uint32_t idtr_limit; /* idt */ + uint32_t idtr_base; + + uint32_t gdtr_limit; /* gdt */ + uint32_t gdtr_base; + + struct vmx_assist_segment cs; + struct vmx_assist_segment ds; + struct vmx_assist_segment es; + struct vmx_assist_segment ss; + struct vmx_assist_segment fs; + struct vmx_assist_segment gs; + struct vmx_assist_segment tr; + struct vmx_assist_segment ldtr; + + + unsigned char rm_irqbase[2]; +} __attribute__((packed)); + + static void vmx_save_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx); static void vmx_restore_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx); @@ -33,28 +110,28 @@ int v3_vmxassist_ctx_switch(struct guest_info * info) { - if (guest_pa_to_host_va(info, VMXASSIST_BASE, (addr_t *)&hdr) == -1) { - PrintError("Could not translate address for vmxassist header\n"); + if (v3_gpa_to_hva(info, VMXASSIST_START, (addr_t *)&hdr) == -1) { + PrintError(info->vm_info, info, "Could not translate address for vmxassist header\n"); return -1; } if (hdr->magic != VMXASSIST_MAGIC) { - PrintError("VMXASSIST_MAGIC field is invalid\n"); + PrintError(info->vm_info, info, "VMXASSIST_MAGIC field is invalid\n"); return -1; } - if (guest_pa_to_host_va(info, (addr_t)(hdr->old_ctx_gpa), (addr_t *)&(old_ctx)) == -1) { - PrintError("Could not translate address for VMXASSIST old context\n"); + if (v3_gpa_to_hva(info, (addr_t)(hdr->old_ctx_gpa), (addr_t *)&(old_ctx)) == -1) { + PrintError(info->vm_info, info, "Could not translate address for VMXASSIST old context\n"); return -1; } - if (guest_pa_to_host_va(info, (addr_t)(hdr->new_ctx_gpa), (addr_t *)&(new_ctx)) == -1) { - PrintError("Could not translate address for VMXASSIST new context\n"); + if (v3_gpa_to_hva(info, (addr_t)(hdr->new_ctx_gpa), (addr_t *)&(new_ctx)) == -1) { + PrintError(info->vm_info, info, "Could not translate address for VMXASSIST new context\n"); return -1; } - if (vmx_info->state == VMXASSIST_DISABLED) { + if (vmx_info->assist_state == VMXASSIST_OFF) { /* Save the old Context */ vmx_save_world_ctx(info, old_ctx); @@ -62,13 +139,13 @@ int v3_vmxassist_ctx_switch(struct guest_info * info) { /* restore new context, vmxassist should launch the bios the first time */ vmx_restore_world_ctx(info, new_ctx); - vmx_info->state = VMXASSIST_ENABLED; + vmx_info->assist_state = VMXASSIST_ON; - } else if (vmx_info->state == VMXASSIST_ENABLED) { + } else if (vmx_info->assist_state == VMXASSIST_ON) { /* restore old context */ vmx_restore_world_ctx(info, old_ctx); - vmx_info->state = VMXASSIST_DISABLED; + vmx_info->assist_state = VMXASSIST_OFF; } return 0; @@ -105,7 +182,7 @@ static void load_segment(struct vmx_assist_segment * vmx_assist_seg, struct v3_s static void vmx_save_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx) { struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data); - PrintDebug("Writing from RIP: 0x%p\n", (void *)info->rip); + PrintDebug(info->vm_info, info, "Writing from RIP: 0x%p\n", (void *)(addr_t)info->rip); ctx->eip = info->rip; ctx->esp = info->vm_regs.rsp; @@ -136,7 +213,7 @@ static void vmx_save_world_ctx(struct guest_info * info, struct vmx_assist_conte static void vmx_restore_world_ctx(struct guest_info * info, struct vmx_assist_context * ctx) { struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data); - PrintDebug("ctx rip: %p\n", (void *)(addr_t)ctx->eip); + PrintDebug(info->vm_info, info, "ctx rip: %p\n", (void *)(addr_t)ctx->eip); info->rip = ctx->eip; info->vm_regs.rsp = ctx->esp; @@ -165,3 +242,136 @@ static void vmx_restore_world_ctx(struct guest_info * info, struct vmx_assist_co } +int v3_vmxassist_init(struct guest_info * core, struct vmx_data * vmx_state) { + + core->rip = 0xd0000; + core->vm_regs.rsp = 0x80000; + ((struct rflags *)&(core->ctrl_regs.rflags))->rsvd1 = 1; + +#define GUEST_CR0_MASK 0x80010031 +#define GUEST_CR4_MASK 0x00002010 + core->ctrl_regs.cr0 |= GUEST_CR0_MASK; + core->ctrl_regs.cr4 |= GUEST_CR4_MASK; + + ((struct cr0_32 *)&(core->shdw_pg_state.guest_cr0))->pe = 1; + ((struct cr0_32 *)&(core->shdw_pg_state.guest_cr0))->wp = 1; + ((struct cr0_32 *)&(core->shdw_pg_state.guest_cr0))->ne = 1; + + + // Setup segment registers + { + struct v3_segment * seg_reg = (struct v3_segment *)&(core->segments); + + int i; + + for (i = 0; i < 10; i++) { + seg_reg[i].selector = 3 << 3; + seg_reg[i].limit = 0xffff; + seg_reg[i].base = 0x0; + } + + core->segments.cs.selector = 2 << 3; + + /* Set only the segment registers */ + for (i = 0; i < 6; i++) { + seg_reg[i].limit = 0xfffff; + seg_reg[i].granularity = 1; + seg_reg[i].type = 3; + seg_reg[i].system = 1; + seg_reg[i].dpl = 0; + seg_reg[i].present = 1; + seg_reg[i].db = 1; + } + + core->segments.cs.type = 0xb; + + core->segments.ldtr.selector = 0x20; + core->segments.ldtr.type = 2; + core->segments.ldtr.system = 0; + core->segments.ldtr.present = 1; + core->segments.ldtr.granularity = 0; + + + /************* Map in GDT and vmxassist *************/ + + uint64_t gdt[] __attribute__ ((aligned(32))) = { + 0x0000000000000000ULL, /* 0x00: reserved */ + 0x0000830000000000ULL, /* 0x08: 32-bit TSS */ + //0x0000890000000000ULL, /* 0x08: 32-bit TSS */ + 0x00CF9b000000FFFFULL, /* 0x10: CS 32-bit */ + 0x00CF93000000FFFFULL, /* 0x18: DS 32-bit */ + 0x000082000000FFFFULL, /* 0x20: LDTR 32-bit */ + }; + + + if (v3_write_gpa_memory(core, VMXASSIST_GDT, sizeof(uint64_t)*5, (void*)gdt)!=sizeof(uint64_t)*5) { + PrintError(core->vm_info, core, "Could not write VMXASSIST GDT\n"); + return -1; + } + + core->segments.gdtr.base = VMXASSIST_GDT; + + + uint64_t vmxassist_tss = VMXASSIST_TSS; + gdt[0x08 / sizeof(gdt[0])] |= + ((vmxassist_tss & 0xFF000000) << (56 - 24)) | + ((vmxassist_tss & 0x00FF0000) << (32 - 16)) | + ((vmxassist_tss & 0x0000FFFF) << (16)) | + (8392 - 1); + + core->segments.tr.selector = 0x08; + core->segments.tr.base = vmxassist_tss; + + //core->segments.tr.type = 0x9; + core->segments.tr.type = 0x3; + core->segments.tr.system = 0; + core->segments.tr.present = 1; + core->segments.tr.granularity = 0; + } + + if (core->shdw_pg_mode == NESTED_PAGING) { + // setup 1to1 page table internally. + int i = 0; + pde32_4MB_t * pde = NULL; + + V3_Print(core->vm_info, core, "Setting up internal VMXASSIST page tables\n"); + + if (v3_gpa_to_hva(core, VMXASSIST_1to1_PT, (addr_t *)(&pde)) == -1) { + PrintError(core->vm_info, core, "Could not find VMXASSIST 1to1 PT destination\n"); + return -1; + } + + memset(pde, 0, PAGE_SIZE); + + for (i = 0; i < 1024; i++) { + pde[i].present = 1; + pde[i].writable = 1; + pde[i].user_page = 1; + pde[i].large_page = 1; + pde[i].page_base_addr = PAGE_BASE_ADDR_4MB(i * PAGE_SIZE_4MB); + + // PrintError(core->vm_info, core, "PDE %d: %x\n", i, *(uint32_t *)&(pde[i])); + } + + core->ctrl_regs.cr3 = VMXASSIST_1to1_PT; + + } + + // setup VMXASSIST + { + + extern uint8_t v3_vmxassist_start[]; + extern uint8_t v3_vmxassist_end[]; + + if (v3_write_gpa_memory(core, VMXASSIST_START, v3_vmxassist_end-v3_vmxassist_start,v3_vmxassist_start)!=v3_vmxassist_end-v3_vmxassist_start) { + PrintError(core->vm_info, core, "Could not write VMXASSIST\n"); + return -1; + } + + + vmx_state->assist_state = VMXASSIST_OFF; + } + + + return 0; +}