kvm: x86: Adjust PC to remove the CS segment base address

gem5 seems to store the PC as RIP+CS_BASE. This is not what KVM
expects, so we need to subtract CS_BASE prior to transferring the PC
into KVM. This changeset adds the necessary PC manipulation and
refactors thread context updates slightly to avoid reading registers
multiple times from KVM.

--HG--
extra : rebase_source : 3f0569dca06a1fcd8694925f75c8918d954ada44
This commit is contained in:
Andreas Sandberg 2014-03-16 17:30:24 +01:00
parent f791e7b313
commit 5db547bca4
2 changed files with 32 additions and 28 deletions

View file

@ -690,7 +690,7 @@ X86KvmCPU::updateKvmStateRegs()
FOREACH_IREG(); FOREACH_IREG();
#undef APPLY_IREG #undef APPLY_IREG
regs.rip = tc->instAddr(); regs.rip = tc->instAddr() - tc->readMiscReg(MISCREG_CS_BASE);
/* You might think that setting regs.rflags to the contents /* You might think that setting regs.rflags to the contents
* MISCREG_RFLAGS here would suffice. In that case you're * MISCREG_RFLAGS here would suffice. In that case you're
@ -936,16 +936,29 @@ X86KvmCPU::updateKvmStateMSRs()
void void
X86KvmCPU::updateThreadContext() X86KvmCPU::updateThreadContext()
{ {
struct kvm_regs regs;
struct kvm_sregs sregs;
getRegisters(regs);
getSpecialRegisters(sregs);
DPRINTF(KvmContext, "X86KvmCPU::updateThreadContext():\n"); DPRINTF(KvmContext, "X86KvmCPU::updateThreadContext():\n");
if (DTRACE(KvmContext)) if (DTRACE(KvmContext))
dump(); dump();
updateThreadContextRegs(); updateThreadContextRegs(regs, sregs);
updateThreadContextSRegs(); updateThreadContextSRegs(sregs);
if (useXSave) if (useXSave) {
updateThreadContextXSave(); struct kvm_xsave xsave;
else getXSave(xsave);
updateThreadContextFPU();
updateThreadContextXSave(xsave);
} else {
struct kvm_fpu fpu;
getFPUState(fpu);
updateThreadContextFPU(fpu);
}
updateThreadContextMSRs(); updateThreadContextMSRs();
// The M5 misc reg caches some values from other // The M5 misc reg caches some values from other
@ -955,18 +968,16 @@ X86KvmCPU::updateThreadContext()
} }
void void
X86KvmCPU::updateThreadContextRegs() X86KvmCPU::updateThreadContextRegs(const struct kvm_regs &regs,
const struct kvm_sregs &sregs)
{ {
struct kvm_regs regs;
getRegisters(regs);
#define APPLY_IREG(kreg, mreg) tc->setIntReg(mreg, regs.kreg) #define APPLY_IREG(kreg, mreg) tc->setIntReg(mreg, regs.kreg)
FOREACH_IREG(); FOREACH_IREG();
#undef APPLY_IREG #undef APPLY_IREG
tc->pcState(PCState(regs.rip)); tc->pcState(PCState(regs.rip + sregs.cs.base));
// Flags are spread out across multiple semi-magic registers so we // Flags are spread out across multiple semi-magic registers so we
// need some special care when updating them. // need some special care when updating them.
@ -1011,11 +1022,8 @@ setContextSegment(ThreadContext *tc, const struct kvm_dtable &kvm_dtable,
} }
void void
X86KvmCPU::updateThreadContextSRegs() X86KvmCPU::updateThreadContextSRegs(const struct kvm_sregs &sregs)
{ {
struct kvm_sregs sregs;
getSpecialRegisters(sregs);
assert(getKvmRunState()->apic_base == sregs.apic_base); assert(getKvmRunState()->apic_base == sregs.apic_base);
assert(getKvmRunState()->cr8 == sregs.cr8); assert(getKvmRunState()->cr8 == sregs.cr8);
@ -1070,11 +1078,8 @@ updateThreadContextFPUCommon(ThreadContext *tc, const T &fpu)
} }
void void
X86KvmCPU::updateThreadContextFPU() X86KvmCPU::updateThreadContextFPU(const struct kvm_fpu &fpu)
{ {
struct kvm_fpu fpu;
getFPUState(fpu);
updateThreadContextFPUCommon(tc, fpu); updateThreadContextFPUCommon(tc, fpu);
tc->setMiscRegNoEffect(MISCREG_FISEG, 0); tc->setMiscRegNoEffect(MISCREG_FISEG, 0);
@ -1084,11 +1089,9 @@ X86KvmCPU::updateThreadContextFPU()
} }
void void
X86KvmCPU::updateThreadContextXSave() X86KvmCPU::updateThreadContextXSave(const struct kvm_xsave &kxsave)
{ {
struct kvm_xsave kxsave; const FXSave &xsave(*(const FXSave *)kxsave.region);
FXSave &xsave(*(FXSave *)kxsave.region);
getXSave(kxsave);
updateThreadContextFPUCommon(tc, xsave); updateThreadContextFPUCommon(tc, xsave);

View file

@ -209,13 +209,14 @@ class X86KvmCPU : public BaseKvmCPU
* @{ * @{
*/ */
/** Update integer registers */ /** Update integer registers */
void updateThreadContextRegs(); void updateThreadContextRegs(const struct kvm_regs &regs,
const struct kvm_sregs &sregs);
/** Update control registers (CRx, segments, etc.) */ /** Update control registers (CRx, segments, etc.) */
void updateThreadContextSRegs(); void updateThreadContextSRegs(const struct kvm_sregs &sregs);
/** Update FPU and SIMD registers using the legacy API */ /** Update FPU and SIMD registers using the legacy API */
void updateThreadContextFPU(); void updateThreadContextFPU(const struct kvm_fpu &fpu);
/** Update FPU and SIMD registers using the XSave API */ /** Update FPU and SIMD registers using the XSave API */
void updateThreadContextXSave(); void updateThreadContextXSave(const struct kvm_xsave &kxsave);
/** Update MSR registers */ /** Update MSR registers */
void updateThreadContextMSRs(); void updateThreadContextMSRs();
/** @} */ /** @} */