diff --git a/Lilu/Headers/kern_cpu.hpp b/Lilu/Headers/kern_cpu.hpp index 672bcff6..31e4d702 100644 --- a/Lilu/Headers/kern_cpu.hpp +++ b/Lilu/Headers/kern_cpu.hpp @@ -400,8 +400,10 @@ namespace CPUInfo { * @param b ebx output pointer (optional) * @param c ecx output pointer (optional) * @param d edx output pointer (optional) + * + * @return true if supported */ - EXPORT void getCpuid(uint32_t no, uint32_t count, uint32_t *a, uint32_t *b=nullptr, uint32_t *c=nullptr, uint32_t *d=nullptr); + EXPORT bool getCpuid(uint32_t no, uint32_t count, uint32_t *a, uint32_t *b=nullptr, uint32_t *c=nullptr, uint32_t *d=nullptr); } #endif /* kern_cpu_h */ diff --git a/Lilu/Headers/kern_util.hpp b/Lilu/Headers/kern_util.hpp index 3883c214..727f0860 100644 --- a/Lilu/Headers/kern_util.hpp +++ b/Lilu/Headers/kern_util.hpp @@ -414,6 +414,21 @@ constexpr T getBitField(T so, T hi, T lo) { return (so & getBitMask(hi, lo)) >> lo; } +/** + * Set bit field of size sizeof(T) + * Warning, you are suggested to always pass the type explicitly! + * + * @param va value + * @param hi starting high bit + * @param lo ending low bit + * + * @return bit field value + */ +template +constexpr T setBitField(T so, T hi, T lo) { + return (so << lo) & getBitMask(hi, lo); +} + /** * This is an ugly replacement to std::find_if, allowing you * to check whether a container consists only of value values. diff --git a/Lilu/Sources/kern_cpu.cpp b/Lilu/Sources/kern_cpu.cpp index d5b49a80..4cc21389 100644 --- a/Lilu/Sources/kern_cpu.cpp +++ b/Lilu/Sources/kern_cpu.cpp @@ -18,18 +18,22 @@ static CPUInfo::CpuGeneration currentGeneration = CPUInfo::CpuGeneration::Unknow static uint32_t currentFamily = 0; static uint32_t currentModel = 0; static uint32_t currentStepping = 0; +static uint32_t currentMaxLevel = 0; +static uint32_t currentMaxLevelExt = 0x80000000; void CPUInfo::loadCpuInformation() { // Start with detecting CPU vendor uint32_t b = 0, c = 0, d = 0; - getCpuid(0, 0, nullptr, &b, &c, &d); + getCpuid(0, 0, ¤tMaxLevel, &b, &c, &d); if (b == signature_INTEL_ebx && c == signature_INTEL_ecx && d == signature_INTEL_edx) currentVendor = CpuVendor::Intel; else if (b == signature_AMD_ebx && c == signature_AMD_ecx && d == signature_AMD_edx) currentVendor = CpuVendor::AMD; - // Only do extended model checking on Intel - if (currentVendor != CpuVendor::Intel) + getCpuid(0x80000000, 0, ¤tMaxLevelExt); + + // Only do extended model checking on Intel or when unsupported. + if (currentVendor != CpuVendor::Intel || currentMaxLevel < 1) return; // Detect CPU family and model @@ -174,6 +178,7 @@ bool CPUInfo::getCpuTopology(CpuTopology &topology) { topology.logicalCount[topology.packageCount]++; lcpu = lcpu->next_in_core; } + core = core->next_in_pkg; } topology.packageCount++; @@ -183,16 +188,24 @@ bool CPUInfo::getCpuTopology(CpuTopology &topology) { return true; } -void CPUInfo::getCpuid(uint32_t no, uint32_t count, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) { +bool CPUInfo::getCpuid(uint32_t no, uint32_t count, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) { uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; - asm ("xchgq %%rbx, %q1\n" - "cpuid\n" - "xchgq %%rbx, %q1" - : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) - : "0" (no), "2" (count)); + + bool supported = (no & 0x80000000) ? currentMaxLevelExt >= no : currentMaxLevel >= no; + + // At least pass zeroes on failure + if (supported) { + asm ("xchgq %%rbx, %q1\n" + "cpuid\n" + "xchgq %%rbx, %q1" + : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) + : "0" (no), "2" (count)); + } if (a) *a = eax; if (b) *b = ebx; if (c) *c = ecx; if (d) *d = edx; + + return supported; } diff --git a/Lilu/Sources/kern_user.cpp b/Lilu/Sources/kern_user.cpp index 61664805..c4d0d0b7 100644 --- a/Lilu/Sources/kern_user.cpp +++ b/Lilu/Sources/kern_user.cpp @@ -660,9 +660,10 @@ bool UserPatcher::loadDyldSharedCacheMapping() { uint8_t *buffer {nullptr}; size_t bufferSize {0}; uint32_t ebx = 0; - CPUInfo::getCpuid(7, 0, nullptr, &ebx); - if ((ebx & CPUInfo::bit_AVX2) && getKernelVersion() >= KernelVersion::Yosemite) - buffer = FileIO::readFileToBuffer(SharedCacheMapHaswell, bufferSize); + if (CPUInfo::getCpuid(7, 0, nullptr, &ebx)) { + if ((ebx & CPUInfo::bit_AVX2) && getKernelVersion() >= KernelVersion::Yosemite) + buffer = FileIO::readFileToBuffer(SharedCacheMapHaswell, bufferSize); + } if (!buffer) buffer = FileIO::readFileToBuffer(SharedCacheMapLegacy, bufferSize);