diff --git a/src/arch/x86/cpuid.cc b/src/arch/x86/cpuid.cc index 2ce763e0af..75e69735c1 100644 --- a/src/arch/x86/cpuid.cc +++ b/src/arch/x86/cpuid.cc @@ -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 diff --git a/src/arch/x86/cpuid.hh b/src/arch/x86/cpuid.hh index a48d99907d..71e8d3c626 100644 --- a/src/arch/x86/cpuid.hh +++ b/src/arch/x86/cpuid.hh @@ -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; diff --git a/src/arch/x86/kvm/x86_cpu.cc b/src/arch/x86/kvm/x86_cpu.cc index fdb557af88..e1c1b0dfc0 100644 --- a/src/arch/x86/kvm/x86_cpu.cc +++ b/src/arch/x86/kvm/x86_cpu.cc @@ -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(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);