unsigned long insn_buf_eip;
struct segment_register seg_reg[10];
+
+ union {
+ struct {
+ unsigned int hlt:1;
+ unsigned int mov_ss:1;
+ unsigned int sti:1;
+ unsigned int exn_raised:1;
+ } flags;
+ unsigned int flag_word;
+ };
};
static void realmode_deliver_exception(
struct realmode_emulate_ctxt *rm_ctxt =
container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
memcpy(&rm_ctxt->seg_reg[seg], reg, sizeof(struct segment_register));
-
if ( seg == x86_seg_ss )
- {
- u32 intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
- intr_shadow ^= VMX_INTR_SHADOW_MOV_SS;
- __vmwrite(GUEST_INTERRUPTIBILITY_INFO, intr_shadow);
- }
-
+ rm_ctxt->flags.mov_ss = 1;
return X86EMUL_OKAY;
}
unsigned long val,
struct x86_emulate_ctxt *ctxt)
{
+ struct realmode_emulate_ctxt *rm_ctxt =
+ container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
if ( (val & X86_EFLAGS_IF) && !(ctxt->regs->eflags & X86_EFLAGS_IF) )
- {
- u32 intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
- intr_shadow ^= VMX_INTR_SHADOW_STI;
- __vmwrite(GUEST_INTERRUPTIBILITY_INFO, intr_shadow);
- }
+ rm_ctxt->flags.sti = 1;
+ return X86EMUL_OKAY;
+}
+static int realmode_wbinvd(
+ struct x86_emulate_ctxt *ctxt)
+{
+ vmx_wbinvd_intercept();
+ return X86EMUL_OKAY;
+}
+
+static int realmode_cpuid(
+ unsigned int *eax,
+ unsigned int *ebx,
+ unsigned int *ecx,
+ unsigned int *edx,
+ struct x86_emulate_ctxt *ctxt)
+{
+ vmx_cpuid_intercept(eax, ebx, ecx, edx);
+ return X86EMUL_OKAY;
+}
+
+static int realmode_hlt(
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct realmode_emulate_ctxt *rm_ctxt =
+ container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
+ rm_ctxt->flags.hlt = 1;
return X86EMUL_OKAY;
}
struct realmode_emulate_ctxt *rm_ctxt =
container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
+ rm_ctxt->flags.exn_raised = 1;
realmode_deliver_exception(vector, 0, rm_ctxt);
return X86EMUL_OKAY;
.write_io = realmode_write_io,
.read_cr = realmode_read_cr,
.write_rflags = realmode_write_rflags,
+ .wbinvd = realmode_wbinvd,
+ .cpuid = realmode_cpuid,
+ .hlt = realmode_hlt,
.inject_hw_exception = realmode_inject_hw_exception,
.inject_sw_interrupt = realmode_inject_sw_interrupt
};
struct realmode_emulate_ctxt rm_ctxt;
unsigned long intr_info;
int i, rc = 0;
+ u32 intr_shadow, new_intr_shadow;
rm_ctxt.ctxt.regs = regs;
realmode_deliver_exception((uint8_t)intr_info, 0, &rm_ctxt);
}
+ intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
+ new_intr_shadow = intr_shadow;
+
while ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) &&
!softirq_pending(smp_processor_id()) &&
!hvm_local_events_need_delivery(curr) )
(uint32_t)(rm_ctxt.seg_reg[x86_seg_cs].base + regs->eip),
sizeof(rm_ctxt.insn_buf));
+ rm_ctxt.flag_word = 0;
+
rc = x86_emulate(&rm_ctxt.ctxt, &realmode_emulator_ops);
+ /* MOV-SS instruction toggles MOV-SS shadow, else we just clear it. */
+ if ( rm_ctxt.flags.mov_ss )
+ new_intr_shadow ^= VMX_INTR_SHADOW_MOV_SS;
+ else
+ new_intr_shadow &= ~VMX_INTR_SHADOW_MOV_SS;
+
+ /* STI instruction toggles STI shadow, else we just clear it. */
+ if ( rm_ctxt.flags.sti )
+ new_intr_shadow ^= VMX_INTR_SHADOW_STI;
+ else
+ new_intr_shadow &= ~VMX_INTR_SHADOW_STI;
+
+ /* Update interrupt shadow information in VMCS only if it changes. */
+ if ( intr_shadow != new_intr_shadow )
+ {
+ intr_shadow = new_intr_shadow;
+ __vmwrite(GUEST_INTERRUPTIBILITY_INFO, intr_shadow);
+ }
+
+ /* HLT happens after instruction retire, if no interrupt/exception. */
+ if ( unlikely(rm_ctxt.flags.hlt) &&
+ !rm_ctxt.flags.exn_raised &&
+ !hvm_local_events_need_delivery(curr) )
+ hvm_hlt(regs->eflags);
+
if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
{
rc = 0;
v->arch.hvm_vcpu.hw_cr[0] =
v->arch.hvm_vcpu.guest_cr[0] |
- X86_CR0_NE | X86_CR0_PG | X86_CR0_WP;
-#ifdef VMXASSIST
- v->arch.hvm_vcpu.hw_cr[0] |= X86_CR0_PE;
-#endif
+ X86_CR0_NE | X86_CR0_PG | X86_CR0_WP | X86_CR0_PE;
__vmwrite(GUEST_CR0, v->arch.hvm_vcpu.hw_cr[0]);
__vmwrite(CR0_READ_SHADOW, v->arch.hvm_vcpu.guest_cr[0]);
break;
}
#define bitmaskof(idx) (1U << ((idx) & 31))
-static void vmx_do_cpuid(struct cpu_user_regs *regs)
+void vmx_cpuid_intercept(
+ unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx)
{
- unsigned int input = regs->eax;
- unsigned int eax, ebx, ecx, edx;
+ unsigned int input = *eax;
#ifdef VMXASSIST
if ( input == 0x40000003 )
* NB. Unsupported interface for private use of VMXASSIST only.
* Note that this leaf lives at <max-hypervisor-leaf> + 1.
*/
- u64 value = ((u64)regs->edx << 32) | (u32)regs->ecx;
+ u64 value = ((u64)*edx << 32) | (u32)*ecx;
p2m_type_t p2mt;
unsigned long mfn;
struct vcpu *v = current;
unmap_domain_page(p);
gdprintk(XENLOG_INFO, "Output value is 0x%"PRIx64".\n", value);
- regs->ecx = (u32)value;
- regs->edx = (u32)(value >> 32);
+ *ecx = (u32)value;
+ *edx = (u32)(value >> 32);
return;
}
#endif
- hvm_cpuid(input, &eax, &ebx, &ecx, &edx);
+ hvm_cpuid(input, eax, ebx, ecx, edx);
switch ( input )
{
case 0x00000001:
- ecx &= ~VMX_VCPU_CPUID_L1_ECX_RESERVED;
- ebx &= NUM_THREADS_RESET_MASK;
- ecx &= ~(bitmaskof(X86_FEATURE_VMXE) |
- bitmaskof(X86_FEATURE_EST) |
- bitmaskof(X86_FEATURE_TM2) |
- bitmaskof(X86_FEATURE_CID) |
- bitmaskof(X86_FEATURE_PDCM) |
- bitmaskof(X86_FEATURE_DSCPL));
- edx &= ~(bitmaskof(X86_FEATURE_HT) |
- bitmaskof(X86_FEATURE_ACPI) |
- bitmaskof(X86_FEATURE_ACC) |
- bitmaskof(X86_FEATURE_DS));
+ *ecx &= ~VMX_VCPU_CPUID_L1_ECX_RESERVED;
+ *ebx &= NUM_THREADS_RESET_MASK;
+ *ecx &= ~(bitmaskof(X86_FEATURE_VMXE) |
+ bitmaskof(X86_FEATURE_EST) |
+ bitmaskof(X86_FEATURE_TM2) |
+ bitmaskof(X86_FEATURE_CID) |
+ bitmaskof(X86_FEATURE_PDCM) |
+ bitmaskof(X86_FEATURE_DSCPL));
+ *edx &= ~(bitmaskof(X86_FEATURE_HT) |
+ bitmaskof(X86_FEATURE_ACPI) |
+ bitmaskof(X86_FEATURE_ACC) |
+ bitmaskof(X86_FEATURE_DS));
break;
case 0x00000004:
- cpuid_count(input, regs->ecx, &eax, &ebx, &ecx, &edx);
- eax &= NUM_CORES_RESET_MASK;
+ cpuid_count(input, *ecx, eax, ebx, ecx, edx);
+ *eax &= NUM_CORES_RESET_MASK;
break;
case 0x00000006:
case 0x00000009:
case 0x0000000A:
- eax = ebx = ecx = edx = 0;
+ *eax = *ebx = *ecx = *edx = 0;
break;
case 0x80000001:
/* Only a few features are advertised in Intel's 0x80000001. */
- ecx &= (bitmaskof(X86_FEATURE_LAHF_LM));
- edx &= (bitmaskof(X86_FEATURE_NX) |
- bitmaskof(X86_FEATURE_LM) |
- bitmaskof(X86_FEATURE_SYSCALL));
+ *ecx &= (bitmaskof(X86_FEATURE_LAHF_LM));
+ *edx &= (bitmaskof(X86_FEATURE_NX) |
+ bitmaskof(X86_FEATURE_LM) |
+ bitmaskof(X86_FEATURE_SYSCALL));
break;
}
+ HVMTRACE_3D(CPUID, current, input,
+ ((uint64_t)*eax << 32) | *ebx, ((uint64_t)*ecx << 32) | *edx);
+}
+
+static void vmx_do_cpuid(struct cpu_user_regs *regs)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ eax = regs->eax;
+ ebx = regs->ebx;
+ ecx = regs->ecx;
+ edx = regs->edx;
+
+ vmx_cpuid_intercept(&eax, &ebx, &ecx, &edx);
+
regs->eax = eax;
regs->ebx = ebx;
regs->ecx = ecx;
regs->edx = edx;
-
- HVMTRACE_3D(CPUID, current, input,
- ((uint64_t)eax << 32) | ebx, ((uint64_t)ecx << 32) | edx);
}
#define CASE_GET_REG_P(REG, reg) \
wbinvd();
}
+void vmx_wbinvd_intercept(void)
+{
+ if ( list_empty(&(domain_hvm_iommu(current->domain)->pdev_list)) )
+ return;
+
+ if ( cpu_has_wbinvd_exiting )
+ on_each_cpu(wbinvd_ipi, NULL, 1, 1);
+ else
+ wbinvd();
+}
+
static void vmx_failed_vmentry(unsigned int exit_reason,
struct cpu_user_regs *regs)
{
unsigned int failed_vmentry_reason = (uint16_t)exit_reason;
unsigned long exit_qualification = __vmread(EXIT_QUALIFICATION);
-#ifndef VMXASSIST
- if ( (failed_vmentry_reason == EXIT_REASON_INVALID_GUEST_STATE) &&
- (exit_qualification == 0) &&
- !(current->arch.hvm_vcpu.hw_cr[0] & X86_CR0_PE) &&
- (vmx_realmode(regs) == 0) )
- return;
-#endif
-
printk("Failed vm entry (exit reason 0x%x) ", exit_reason);
switch ( failed_vmentry_reason )
{
{
inst_len = __get_instruction_length(); /* Safe: INVD, WBINVD */
__update_guest_eip(inst_len);
- if ( !list_empty(&(domain_hvm_iommu(v->domain)->pdev_list)) )
- {
- if ( cpu_has_wbinvd_exiting )
- {
- on_each_cpu(wbinvd_ipi, NULL, 1, 1);
- }
- else
- {
- wbinvd();
- /* Disable further WBINVD intercepts. */
- if ( (exit_reason == EXIT_REASON_WBINVD) &&
- (vmx_cpu_based_exec_control &
- CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) )
- __vmwrite(SECONDARY_VM_EXEC_CONTROL,
- vmx_secondary_exec_control &
- ~SECONDARY_EXEC_WBINVD_EXITING);
- }
- }
+ vmx_wbinvd_intercept();
break;
}
movl $GUEST_RFLAGS,%eax
VMWRITE(UREGS_eflags)
- cmpl $0,VCPU_vmx_launched(%ebx)
+#ifndef VMXASSIST
+ testb $X86_CR0_PE,VCPU_hvm_guest_cr0(%ebx)
+ jz vmx_goto_realmode
+#endif
+
+ cmpb $0,VCPU_vmx_launched(%ebx)
je vmx_launch
/*vmx_resume:*/
ud2
vmx_launch:
- movl $1,VCPU_vmx_launched(%ebx)
+ movb $1,VCPU_vmx_launched(%ebx)
HVM_RESTORE_ALL_NOSEGREGS
VMLAUNCH
pushf
call vm_launch_fail
ud2
+
+#ifndef VMXASSIST
+vmx_goto_realmode:
+ sti
+ movl %esp,%eax
+ push %eax
+ call vmx_realmode
+ addl $4,%esp
+ jmp vmx_asm_do_vmentry
+#endif
movl $GUEST_RFLAGS,%eax
VMWRITE(UREGS_eflags)
- cmpl $0,VCPU_vmx_launched(%rbx)
+#ifndef VMXASSIST
+ testb $X86_CR0_PE,VCPU_hvm_guest_cr0(%rbx)
+ jz vmx_goto_realmode
+#endif
+
+ cmpb $0,VCPU_vmx_launched(%rbx)
je vmx_launch
/*vmx_resume:*/
ud2
vmx_launch:
- movl $1,VCPU_vmx_launched(%rbx)
+ movb $1,VCPU_vmx_launched(%rbx)
HVM_RESTORE_ALL_NOSEGREGS
VMLAUNCH
pushfq
call vm_launch_fail
ud2
+
+#ifndef VMXASSIST
+vmx_goto_realmode:
+ sti
+ movq %rsp,%rdi
+ call vmx_realmode
+ jmp vmx_asm_do_vmentry
+#endif
BLANK();
OFFSET(VCPU_vmx_launched, struct vcpu, arch.hvm_vmx.launched);
+ OFFSET(VCPU_hvm_guest_cr0, struct vcpu, arch.hvm_vcpu.guest_cr[0]);
OFFSET(VCPU_hvm_guest_cr2, struct vcpu, arch.hvm_vcpu.guest_cr[2]);
BLANK();
BLANK();
OFFSET(VCPU_vmx_launched, struct vcpu, arch.hvm_vmx.launched);
+ OFFSET(VCPU_hvm_guest_cr0, struct vcpu, arch.hvm_vcpu.guest_cr[0]);
OFFSET(VCPU_hvm_guest_cr2, struct vcpu, arch.hvm_vcpu.guest_cr[2]);
BLANK();
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0xF0 - 0xF7 */
0, ImplicitOps, 0, 0,
- 0, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM,
+ ImplicitOps, ImplicitOps,
+ ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM,
/* 0xF8 - 0xFF */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM
ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
ByteOp|DstMem|SrcNone|ModRM|Mov, ByteOp|DstMem|SrcNone|ModRM|Mov,
/* 0xA0 - 0xA7 */
- ImplicitOps, ImplicitOps, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0,
+ ImplicitOps, ImplicitOps, ImplicitOps, DstBitBase|SrcReg|ModRM,
+ 0, 0, 0, 0,
/* 0xA8 - 0xAF */
ImplicitOps, ImplicitOps, 0, DstBitBase|SrcReg|ModRM,
0, 0, 0, DstReg|SrcMem|ModRM,
src.val = EXC_DB;
goto swint;
+ case 0xf4: /* hlt */
+ fail_if(ops->hlt == NULL);
+ if ( (rc = ops->hlt(ctxt)) != 0 )
+ goto done;
+ break;
+
case 0xf5: /* cmc */
_regs.eflags ^= EFLG_CF;
break;
src.val = x86_seg_fs;
goto pop_seg;
+ case 0xa2: /* cpuid */ {
+ unsigned int eax = _regs.eax, ebx = _regs.ebx;
+ unsigned int ecx = _regs.ecx, edx = _regs.edx;
+ fail_if(ops->cpuid == NULL);
+ if ( (rc = ops->cpuid(&eax, &ebx, &ecx, &edx, ctxt)) != 0 )
+ goto done;
+ _regs.eax = eax; _regs.ebx = ebx;
+ _regs.ecx = ecx; _regs.edx = edx;
+ break;
+ }
+
case 0xa8: /* push %%gs */
src.val = x86_seg_gs;
goto push_seg;
void vmx_do_resume(struct vcpu *);
void set_guest_time(struct vcpu *v, u64 gtime);
void vmx_vlapic_msr_changed(struct vcpu *v);
+void vmx_cpuid_intercept(
+ unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx);
+void vmx_wbinvd_intercept(void);
int vmx_realmode(struct cpu_user_regs *regs);
int vmx_realmode_io_complete(void);
int (*wbinvd)(
struct x86_emulate_ctxt *ctxt);
+ /* cpuid: Emulate CPUID via given set of EAX-EDX inputs/outputs. */
+ int (*cpuid)(
+ unsigned int *eax,
+ unsigned int *ebx,
+ unsigned int *ecx,
+ unsigned int *edx,
+ struct x86_emulate_ctxt *ctxt);
+
+ /* hlt: Emulate HLT. */
+ int (*hlt)(
+ struct x86_emulate_ctxt *ctxt);
+
/* inject_hw_exception */
int (*inject_hw_exception)(
uint8_t vector,