target/i386: Added consistency checks for EFER

EFER.SVME has to be set, and EFER reserved bits must
be zero.
In addition the combinations
 * EFER.LMA or EFER.LME is non-zero and the processor does not support LM
 * non-zero EFER.LME and CR0.PG and zero CR4.PAE
 * non-zero EFER.LME and CR0.PG and zero CR0.PE
 * non-zero EFER.LME, CR0.PG, CR4.PAE, CS.L and CS.D
are all invalid.
(AMD64 Architecture Programmer's Manual, V2, 15.5)

Signed-off-by: Lara Lazier <laramglazier@gmail.com>
Message-Id: <20210721152651.14683-3-laramglazier@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Lara Lazier 2021-07-21 17:26:51 +02:00 committed by Paolo Bonzini
parent 213ff024a2
commit d499f196fe
2 changed files with 44 additions and 0 deletions

View file

@ -475,6 +475,11 @@ typedef enum X86Seg {
#define MSR_EFER_SVME (1 << 12)
#define MSR_EFER_FFXSR (1 << 14)
#define MSR_EFER_RESERVED\
(~(target_ulong)(MSR_EFER_SCE | MSR_EFER_LME\
| MSR_EFER_LMA | MSR_EFER_NXE | MSR_EFER_SVME\
| MSR_EFER_FFXSR))
#define MSR_STAR 0xc0000081
#define MSR_LSTAR 0xc0000082
#define MSR_CSTAR 0xc0000083

View file

@ -75,6 +75,41 @@ static inline bool ctl_has_irq(uint32_t int_ctl)
return (int_ctl & V_IRQ_MASK) && (int_prio >= tpr);
}
static inline bool is_efer_invalid_state (CPUX86State *env)
{
if (!(env->efer & MSR_EFER_SVME)) {
return true;
}
if (env->efer & MSR_EFER_RESERVED) {
return true;
}
if ((env->efer & (MSR_EFER_LMA | MSR_EFER_LME)) &&
!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
return true;
}
if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
&& !(env->cr[4] & CR4_PAE_MASK)) {
return true;
}
if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
&& !(env->cr[0] & CR0_PE_MASK)) {
return true;
}
if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK)
&& (env->cr[4] & CR4_PAE_MASK)
&& (env->segs[R_CS].flags & DESC_L_MASK)
&& (env->segs[R_CS].flags & DESC_B_MASK)) {
return true;
}
return false;
}
void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
{
CPUState *cs = env_cpu(env);
@ -291,6 +326,10 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
}
#endif
if (is_efer_invalid_state(env)) {
cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC());
}
switch (x86_ldub_phys(cs,
env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
case TLB_CONTROL_DO_NOTHING: