Index: amd64/include/vmm.h =================================================================== --- amd64/include/vmm.h (revision 248935) +++ amd64/include/vmm.h (working copy) @@ -135,12 +135,12 @@ }; int vcpu_set_state(struct vm *vm, int vcpu, enum vcpu_state state); -enum vcpu_state vcpu_get_state(struct vm *vm, int vcpu); +enum vcpu_state vcpu_get_state(struct vm *vm, int vcpu, int *hostcpu); static int __inline -vcpu_is_running(struct vm *vm, int vcpu) +vcpu_is_running(struct vm *vm, int vcpu, int *hostcpu) { - return (vcpu_get_state(vm, vcpu) == VCPU_RUNNING); + return (vcpu_get_state(vm, vcpu, hostcpu) == VCPU_RUNNING); } void *vcpu_stats(struct vm *vm, int vcpu); Index: amd64/vmm/vmm.c =================================================================== --- amd64/vmm/vmm.c (revision 248935) +++ amd64/vmm/vmm.c (working copy) @@ -881,7 +881,7 @@ } enum vcpu_state -vcpu_get_state(struct vm *vm, int vcpuid) +vcpu_get_state(struct vm *vm, int vcpuid, int *hostcpu) { struct vcpu *vcpu; enum vcpu_state state; @@ -893,6 +893,8 @@ vcpu_lock(vcpu); state = vcpu->state; + if (hostcpu != NULL) + *hostcpu = vcpu->hostcpu; vcpu_unlock(vcpu); return (state); Index: amd64/vmm/vmm_instruction_emul.c =================================================================== --- amd64/vmm/vmm_instruction_emul.c (revision 248935) +++ amd64/vmm/vmm_instruction_emul.c (working copy) @@ -50,8 +50,11 @@ #include #endif /* _KERNEL */ +enum cpu_mode { + CPU_MODE_COMPATIBILITY, /* IA-32E mode (CS.L = 0) */ + CPU_MODE_64BIT, /* IA-32E mode (CS.L = 1) */ +}; - /* struct vie_op.op_type */ enum { VIE_OP_TYPE_NONE = 0, @@ -133,32 +136,10 @@ }; static int -vie_valid_register(enum vm_reg_name reg) -{ -#ifdef _KERNEL - /* - * XXX - * The operand register in which we store the result of the - * read must be a GPR that we can modify even if the vcpu - * is "running". All the GPRs qualify except for %rsp. - * - * This is a limitation of the vm_set_register() API - * and can be fixed if necessary. - */ - if (reg == VM_REG_GUEST_RSP) - return (0); -#endif - return (1); -} - -static int vie_read_register(void *vm, int vcpuid, enum vm_reg_name reg, uint64_t *rval) { int error; - if (!vie_valid_register(reg)) - return (EINVAL); - error = vm_get_register(vm, vcpuid, reg, rval); return (error); @@ -196,9 +177,6 @@ } } - if (!vie_valid_register(reg)) - return (EINVAL); - error = vm_get_register(vm, vcpuid, reg, &val); *rval = val >> rshift; return (error); @@ -211,9 +189,6 @@ int error; uint64_t origval; - if (!vie_valid_register(reg)) - return (EINVAL); - switch (size) { case 1: case 2: @@ -583,14 +558,17 @@ return (0); } -/* - * XXX assuming 32-bit or 64-bit guest - */ static int decode_modrm(struct vie *vie) { uint8_t x; + enum cpu_mode cpu_mode; + /* + * XXX assuming that guest is in IA-32E 64-bit mode + */ + cpu_mode = CPU_MODE_64BIT; + if (vie_peek(vie, &x)) return (-1); @@ -642,7 +620,18 @@ case VIE_MOD_INDIRECT: if (vie->rm == VIE_RM_DISP32) { vie->disp_bytes = 4; - vie->base_register = VM_REG_LAST; /* no base */ + /* + * Table 2-7. RIP-Relative Addressing + * + * In 64-bit mode mod=00 r/m=101 implies [rip] + disp32 + * whereas in compatibility mode it just implies disp32. + */ + + if (cpu_mode == CPU_MODE_64BIT) + vie->base_register = VM_REG_GUEST_RIP; + else + vie->base_register = VM_REG_LAST; + } break; } @@ -812,6 +801,13 @@ error, vie->base_register); return (-1); } + + /* + * RIP-relative addressing starts from the following + * instruction + */ + if (vie->base_register == VM_REG_GUEST_RIP) + base += vie->num_valid; } idx = 0; Index: amd64/vmm/intel/vmcs.c =================================================================== --- amd64/vmm/intel/vmcs.c (revision 248935) +++ amd64/vmm/intel/vmcs.c (working copy) @@ -174,7 +174,7 @@ } int -vmcs_getreg(struct vmcs *vmcs, int ident, uint64_t *retval) +vmcs_getreg(struct vmcs *vmcs, int running, int ident, uint64_t *retval) { int error; uint32_t encoding; @@ -194,14 +194,19 @@ if (encoding == (uint32_t)-1) return (EINVAL); - VMPTRLD(vmcs); + if (!running) + VMPTRLD(vmcs); + error = vmread(encoding, retval); - VMCLEAR(vmcs); + + if (!running) + VMCLEAR(vmcs); + return (error); } int -vmcs_setreg(struct vmcs *vmcs, int ident, uint64_t val) +vmcs_setreg(struct vmcs *vmcs, int running, int ident, uint64_t val) { int error; uint32_t encoding; @@ -216,9 +221,14 @@ val = vmcs_fix_regval(encoding, val); - VMPTRLD(vmcs); + if (!running) + VMPTRLD(vmcs); + error = vmwrite(encoding, val); - VMCLEAR(vmcs); + + if (!running) + VMCLEAR(vmcs); + return (error); } Index: amd64/vmm/intel/vmx.c =================================================================== --- amd64/vmm/intel/vmx.c (revision 248935) +++ amd64/vmm/intel/vmx.c (working copy) @@ -647,11 +647,11 @@ shadow_value = cr4_ones_mask; } - error = vmcs_setreg(vmcs, VMCS_IDENT(mask_ident), mask_value); + error = vmcs_setreg(vmcs, 0, VMCS_IDENT(mask_ident), mask_value); if (error) return (error); - error = vmcs_setreg(vmcs, VMCS_IDENT(shadow_ident), shadow_value); + error = vmcs_setreg(vmcs, 0, VMCS_IDENT(shadow_ident), shadow_value); if (error) return (error); @@ -1597,50 +1597,35 @@ static int vmx_getreg(void *arg, int vcpu, int reg, uint64_t *retval) { + int running, hostcpu; struct vmx *vmx = arg; + running = vcpu_is_running(vmx->vm, vcpu, &hostcpu); + if (running && hostcpu != curcpu) + panic("vmx_getreg: %s%d is running", vm_name(vmx->vm), vcpu); + if (vmxctx_getreg(&vmx->ctx[vcpu], reg, retval) == 0) return (0); - /* - * If the vcpu is running then don't mess with the VMCS. - * - * vmcs_getreg will VMCLEAR the vmcs when it is done which will cause - * the subsequent vmlaunch/vmresume to fail. - */ - if (vcpu_is_running(vmx->vm, vcpu)) - panic("vmx_getreg: %s%d is running", vm_name(vmx->vm), vcpu); - - return (vmcs_getreg(&vmx->vmcs[vcpu], reg, retval)); + return (vmcs_getreg(&vmx->vmcs[vcpu], running, reg, retval)); } static int vmx_setreg(void *arg, int vcpu, int reg, uint64_t val) { - int error; + int error, hostcpu, running; uint64_t ctls; struct vmx *vmx = arg; - /* - * XXX Allow caller to set contents of the guest registers saved in - * the 'vmxctx' even though the vcpu might be running. We need this - * specifically to support the rdmsr emulation that will set the - * %eax and %edx registers during vm exit processing. - */ + running = vcpu_is_running(vmx->vm, vcpu, &hostcpu); + if (running && hostcpu != curcpu) + panic("vmx_setreg: %s%d is running", vm_name(vmx->vm), vcpu); + if (vmxctx_setreg(&vmx->ctx[vcpu], reg, val) == 0) return (0); - /* - * If the vcpu is running then don't mess with the VMCS. - * - * vmcs_setreg will VMCLEAR the vmcs when it is done which will cause - * the subsequent vmlaunch/vmresume to fail. - */ - if (vcpu_is_running(vmx->vm, vcpu)) - panic("vmx_setreg: %s%d is running", vm_name(vmx->vm), vcpu); + error = vmcs_setreg(&vmx->vmcs[vcpu], running, reg, val); - error = vmcs_setreg(&vmx->vmcs[vcpu], reg, val); - if (error == 0) { /* * If the "load EFER" VM-entry control is 1 then the @@ -1649,13 +1634,13 @@ */ if ((entry_ctls & VM_ENTRY_LOAD_EFER) != 0 && (reg == VM_REG_GUEST_EFER)) { - vmcs_getreg(&vmx->vmcs[vcpu], + vmcs_getreg(&vmx->vmcs[vcpu], running, VMCS_IDENT(VMCS_ENTRY_CTLS), &ctls); if (val & EFER_LMA) ctls |= VM_ENTRY_GUEST_LMA; else ctls &= ~VM_ENTRY_GUEST_LMA; - vmcs_setreg(&vmx->vmcs[vcpu], + vmcs_setreg(&vmx->vmcs[vcpu], running, VMCS_IDENT(VMCS_ENTRY_CTLS), ctls); } } @@ -1702,7 +1687,7 @@ * If there is already an exception pending to be delivered to the * vcpu then just return. */ - error = vmcs_getreg(vmcs, VMCS_IDENT(VMCS_ENTRY_INTR_INFO), &info); + error = vmcs_getreg(vmcs, 0, VMCS_IDENT(VMCS_ENTRY_INTR_INFO), &info); if (error) return (error); @@ -1711,12 +1696,12 @@ info = vector | (type_map[type] << 8) | (code_valid ? 1 << 11 : 0); info |= VMCS_INTERRUPTION_INFO_VALID; - error = vmcs_setreg(vmcs, VMCS_IDENT(VMCS_ENTRY_INTR_INFO), info); + error = vmcs_setreg(vmcs, 0, VMCS_IDENT(VMCS_ENTRY_INTR_INFO), info); if (error != 0) return (error); if (code_valid) { - error = vmcs_setreg(vmcs, + error = vmcs_setreg(vmcs, 0, VMCS_IDENT(VMCS_ENTRY_EXCEPTION_ERROR), code); } Index: amd64/vmm/intel/vmcs.h =================================================================== --- amd64/vmm/intel/vmcs.h (revision 248935) +++ amd64/vmm/intel/vmcs.h (working copy) @@ -52,8 +52,8 @@ uint32_t procbased_ctls2, uint32_t exit_ctls, uint32_t entry_ctls, u_long msr_bitmap, uint16_t vpid); -int vmcs_getreg(struct vmcs *vmcs, int ident, uint64_t *retval); -int vmcs_setreg(struct vmcs *vmcs, int ident, uint64_t val); +int vmcs_getreg(struct vmcs *vmcs, int running, int ident, uint64_t *rv); +int vmcs_setreg(struct vmcs *vmcs, int running, int ident, uint64_t val); int vmcs_getdesc(struct vmcs *vmcs, int ident, struct seg_desc *desc); int vmcs_setdesc(struct vmcs *vmcs, int ident,