arch-x86: Support CPUID functions with indexes
Various CPUID functions will return different values depending on the value of ECX when executing the CPUID instruction. Add support for this in the X86 KVM CPU. A subsequent patch will add a CPUID function which requires iterating through multiple ECX values. Change-Id: Ib44a52be52ea632d5e2cee3fb2ca390b60a7202a
This commit is contained in:
@@ -111,9 +111,19 @@ X86CPUID::doCpuid(ThreadContext * tc, uint32_t function, uint32_t index,
|
||||
return false;
|
||||
}
|
||||
|
||||
int cap_offset = 0;
|
||||
|
||||
// Ignore index values for functions that do not take index values.
|
||||
if (hasSignificantIndex(function)) {
|
||||
cap_offset = index * 4;
|
||||
}
|
||||
|
||||
// Ensure we have the offset and 4 dwords after it.
|
||||
assert(capabilities[function].size() >= (cap_offset + 4));
|
||||
|
||||
auto &cap_vec = capabilities[function];
|
||||
result = CpuidResult(cap_vec[0], cap_vec[1],
|
||||
cap_vec[2], cap_vec[3]);
|
||||
result = CpuidResult(cap_vec[cap_offset + 0], cap_vec[cap_offset + 1],
|
||||
cap_vec[cap_offset + 2], cap_vec[cap_offset + 3]);
|
||||
DPRINTF(X86, "CPUID function %x returning (%x, %x, %x, %x)\n",
|
||||
function, result.rax, result.rbx, result.rdx, result.rcx);
|
||||
|
||||
@@ -131,5 +141,13 @@ X86CPUID::stringToRegister(const char *str)
|
||||
return reg;
|
||||
}
|
||||
|
||||
// Return true if the CPUID function takes ECX index as an input AND
|
||||
// those multiple index values are supported in gem5.
|
||||
bool
|
||||
X86CPUID::hasSignificantIndex(uint32_t function)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace X86ISA
|
||||
} // namespace gem5
|
||||
|
||||
@@ -99,6 +99,7 @@ class X86CPUID
|
||||
|
||||
bool doCpuid(ThreadContext * tc, uint32_t function,
|
||||
uint32_t index, CpuidResult &result);
|
||||
bool hasSignificantIndex(uint32_t function);
|
||||
|
||||
private:
|
||||
const std::string vendorString;
|
||||
|
||||
@@ -74,6 +74,13 @@ using namespace X86ISA;
|
||||
// data) is used to indicate that a segment has been accessed.
|
||||
#define SEG_TYPE_BIT_ACCESSED 1
|
||||
|
||||
// Some linux distro s(e.g., RHEL7) define the KVM macros using "BIT" but do
|
||||
// not include where BIT is defined, so define it here in that case.
|
||||
#ifndef BIT
|
||||
#define BIT(nr) (1UL << (nr))
|
||||
#endif
|
||||
|
||||
|
||||
struct GEM5_PACKED FXSave
|
||||
{
|
||||
uint16_t fcw;
|
||||
@@ -1420,12 +1427,12 @@ X86KvmCPU::ioctlRun()
|
||||
|
||||
static struct kvm_cpuid_entry2
|
||||
makeKvmCpuid(uint32_t function, uint32_t index,
|
||||
CpuidResult &result)
|
||||
CpuidResult &result, uint32_t flags = 0)
|
||||
{
|
||||
struct kvm_cpuid_entry2 e;
|
||||
e.function = function;
|
||||
e.index = index;
|
||||
e.flags = 0;
|
||||
e.flags = flags;
|
||||
e.eax = (uint32_t)result.rax;
|
||||
e.ebx = (uint32_t)result.rbx;
|
||||
e.ecx = (uint32_t)result.rcx;
|
||||
@@ -1438,12 +1445,6 @@ void
|
||||
X86KvmCPU::updateCPUID()
|
||||
{
|
||||
Kvm::CPUIDVector m5_supported;
|
||||
|
||||
/* TODO: We currently don't support any of the functions that
|
||||
* iterate through data structures in the CPU using an index. It's
|
||||
* currently not a problem since M5 doesn't expose any of them at
|
||||
* the moment.
|
||||
*/
|
||||
X86ISA::ISA *isa = dynamic_cast<X86ISA::ISA *>(tc->getIsaPtr());
|
||||
|
||||
/* Basic features */
|
||||
@@ -1453,8 +1454,31 @@ X86KvmCPU::updateCPUID()
|
||||
CpuidResult cpuid;
|
||||
uint32_t idx(0);
|
||||
|
||||
isa->cpuid->doCpuid(tc, function, idx, cpuid);
|
||||
m5_supported.push_back(makeKvmCpuid(function, idx, cpuid));
|
||||
if (!isa->cpuid->hasSignificantIndex(function)) {
|
||||
isa->cpuid->doCpuid(tc, function, idx, cpuid);
|
||||
m5_supported.push_back(makeKvmCpuid(function, idx, cpuid));
|
||||
} else {
|
||||
while (true) {
|
||||
bool rv = isa->cpuid->doCpuid(tc, function, idx, cpuid);
|
||||
assert(rv);
|
||||
|
||||
if (idx &&
|
||||
!cpuid.rax && !cpuid.rbx && !cpuid.rdx && !cpuid.rcx) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* For functions in family 0, this flag tells Linux to compare
|
||||
* the index as well as the function number rather than only
|
||||
* the function number. Important: Do NOT set this flag if the
|
||||
* function does not take an index. Doing so will break SMP.
|
||||
*/
|
||||
uint32_t flag = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
|
||||
m5_supported.push_back(
|
||||
makeKvmCpuid(function, idx, cpuid, flag));
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Extended features */
|
||||
@@ -1464,8 +1488,31 @@ X86KvmCPU::updateCPUID()
|
||||
CpuidResult cpuid;
|
||||
uint32_t idx(0);
|
||||
|
||||
isa->cpuid->doCpuid(tc, function, idx, cpuid);
|
||||
m5_supported.push_back(makeKvmCpuid(function, idx, cpuid));
|
||||
if (!isa->cpuid->hasSignificantIndex(function)) {
|
||||
isa->cpuid->doCpuid(tc, function, idx, cpuid);
|
||||
m5_supported.push_back(makeKvmCpuid(function, idx, cpuid));
|
||||
} else {
|
||||
while (true) {
|
||||
bool rv = isa->cpuid->doCpuid(tc, function, idx, cpuid);
|
||||
assert(rv);
|
||||
|
||||
if (idx &&
|
||||
!cpuid.rax && !cpuid.rbx && !cpuid.rdx && !cpuid.rcx) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* For functions in family 0, this flag tells Linux to compare
|
||||
* the index as well as the function number rather than only
|
||||
* the function number. Important: Do NOT set this flag if the
|
||||
* function does not take an index. Doing so will break SMP.
|
||||
*/
|
||||
uint32_t flag = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
|
||||
m5_supported.push_back(
|
||||
makeKvmCpuid(function, idx, cpuid, flag));
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setCPUID(m5_supported);
|
||||
|
||||
Reference in New Issue
Block a user