summaryrefslogtreecommitdiffstats
path: root/arch/x86/cpuinfo/Cpuinfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/cpuinfo/Cpuinfo.cpp')
-rw-r--r--arch/x86/cpuinfo/Cpuinfo.cpp367
1 files changed, 367 insertions, 0 deletions
diff --git a/arch/x86/cpuinfo/Cpuinfo.cpp b/arch/x86/cpuinfo/Cpuinfo.cpp
new file mode 100644
index 0000000..682f68b
--- /dev/null
+++ b/arch/x86/cpuinfo/Cpuinfo.cpp
@@ -0,0 +1,367 @@
+#include "Cpuinfo.h"
+#include "../../../kernel/GlobalConstruct.h"
+
+
+inline Cpuinfo::cpuidFunctionIndex operator++(Cpuinfo::cpuidFunctionIndex& command)
+{
+ command = Cpuinfo::cpuidFunctionIndex(int(command) + 1);
+ switch(int(command))
+ {
+ case 0x8: command = Cpuinfo::DirectCacheAccessInfo; break;
+ case 0xC: command = Cpuinfo::ExtendedStateInfo; break;
+ case 0xE: command = Cpuinfo::RDTMonitoring; break;
+ case 0x11: command = Cpuinfo::SGXInfo; break;
+ case 0x13: command = Cpuinfo::TraceInfo; break;
+ default:
+ {
+ uint32 commandInt(command);
+ if(commandInt > Cpuinfo::SOCInfo
+ and commandInt < Cpuinfo::UnimplementedStart)
+ {
+ command = Cpuinfo::UnimplementedStart;
+ }
+ else if(commandInt > Cpuinfo::UnimplementedStart
+ and commandInt < Cpuinfo::UnimplementedEnd)
+ {
+ command = Cpuinfo::UnimplementedEnd;
+ }
+ else if(commandInt > Cpuinfo::UnimplementedEnd
+ and commandInt < Cpuinfo::ExtendedCpuidStart)
+ {
+ command = Cpuinfo::ExtendedCpuidStart;
+ }
+ else if(commandInt > Cpuinfo::ExtendedCpuidEnd)
+ {
+ command = Cpuinfo::BasicInfo;
+ }
+ break;
+ }
+ };
+
+ return command;
+};
+
+Cpuinfo::Cpuinfo()
+{
+ eax = ebx = ecx = edx = 0;
+ cpuidAvailable = CPUIDCHK();
+ isBrandStringSupported = false;
+ maximumInputValue = maximumInputValueExtended = 0;
+ displayModel = displayFamily = stepping = 0;
+ brandIndex = clflushLineSize = maxNumberApicsIds = initialApicId = 0;
+ maxNumberProcessorsIds = 0;
+ currentCpuType = processorType::NotRead;
+ serialNumber = 0;
+
+ // Write memset!!!
+ // memset(internalInfoDescriptors, 0, sizeof(uint8) * amountDescriptors)
+
+ // Rewrite it! Create method memset()
+ for(uint8 i = 0; i < vendorStringSize; i++) vendorString[i] = '\0';
+ for(uint8 i = 0; i < brandStringSize; i++) brandString[i] = '\0';
+
+ dataFilling(Cpuinfo::BasicInfo, Cpuinfo::ExtendedCpuidEnd);
+};
+
+bool Cpuinfo::isEaxValueCorrect(const cpuidFunctionIndex eaxInitValue)
+{
+ if(!cpuidAvailable) return false;
+
+ else if(eaxInitValue > maximumInputValue
+ and eaxInitValue < ExtendedCpuidStart) return false;
+
+ else if(eaxInitValue > maximumInputValueExtended
+ and eaxInitValue > ExtendedCpuidStart) return false;
+
+ else if(eaxInitValue == 0x8
+ or eaxInitValue == 0xC
+ or eaxInitValue == 0xE
+ or eaxInitValue == 0x11
+ or eaxInitValue == 0x13) return false;
+
+ else return true;
+};
+
+void Cpuinfo::setBasicData()
+{
+ maximumInputValue = eax;
+
+ uint32 vendorStringInt[3] = {ebx, edx, ecx};
+
+ // Rewrite it! Create method memcpy()
+ for(int i = 0; i < 3; i++)
+ {
+ uint8 upperCharIndex = i * 4 + 3;
+ vendorString[upperCharIndex--] = vendorStringInt[i] >> 24;
+ vendorString[upperCharIndex--] = vendorStringInt[i] >> 16;
+ vendorString[upperCharIndex--] = vendorStringInt[i] >> 8;
+ vendorString[upperCharIndex--] = vendorStringInt[i];
+ }
+};
+
+void Cpuinfo::setVersionData()
+{
+ uint8 steppingId, modelId, familyId, modelIdExt, familyIdExt;
+
+ steppingId = eax & 0xf;
+ modelId = (eax >> 4) & 0xf;
+ familyId = (eax >> 8) & 0xf;
+ modelIdExt = (eax >> 16) & 0xf;
+ familyIdExt = (eax >> 20) & 0xf;
+
+ stepping = steppingId;
+ currentCpuType = (processorType)((eax >> 12) & 0x3);
+
+ if(familyId != 0xf)
+ {
+ displayFamily = familyId;
+ }
+ else displayFamily = familyIdExt + familyId;
+
+ if(familyId == 0x6 or familyId == 0xf)
+ {
+ displayModel = (modelIdExt << 4) + modelId;
+ }
+ else displayModel = modelId;
+
+ brandIndex = (uint8)ebx;
+ clflushLineSize = ((uint8)(ebx >> 8)) << 3;
+ maxNumberProcessorsIds = (ebx >> 16) & 0x0F;
+ initialApicId = ebx >> 24;
+
+ if(edx & Cpuinfo::HTT)
+ {
+ uint8 powerOfTwo = 1;
+ for(; powerOfTwo < maxNumberProcessorsIds; powerOfTwo *= 2);
+ if(maxNumberProcessorsIds == NULL) maxNumberApicsIds = NULL;
+ else maxNumberApicsIds = powerOfTwo;
+ }
+};
+
+void Cpuinfo::setInternalData()
+{
+ uint32 regs[4] = {eax, ebx, ecx, edx};
+ uint8 idxDesc = 0;
+
+ for(uint8 idx = 0; idx < 4; idx++)
+ {
+ uint32 &reg = regs[idx];
+ for(uint8 bytes = 0; bytes < 4; bytes++)
+ {
+ internalInfoDescriptors[idxDesc++] = reg & 0xff;
+ reg >>= 8;
+ }
+ }
+};
+
+void Cpuinfo::setSerialData()
+{
+ if(cpuid(VersionInfo)
+ || !(edx & Cpuinfo::PSN)
+ || cpuid(SerialNumberInfo)) return;
+
+ serialNumber = ((uint64)ecx) | (((uint64)edx) << 32);
+};
+
+void Cpuinfo::setExtendedBasicData()
+{
+ if(eax & Cpuinfo::ExtendedBasicInfo)
+ {
+ maximumInputValueExtended = eax;
+ isBrandStringSupported = true;
+ }
+ else isBrandStringSupported = false;
+};
+
+void Cpuinfo::setBrandString(brandStringPart part)
+{
+ if((part == Cpuinfo::brandString_low or
+ part == Cpuinfo::brandString_middle or
+ part == Cpuinfo::brandString_hight)
+ and isBrandStringSupported)
+ {
+ uint8 partUint = uint8(part);
+ uint32 regs[4] = {eax, ebx, ecx, edx};
+
+ // memCpy()!!!
+ for(uint8 regIndex = 0; regIndex < 4; regIndex++)
+ {
+ uint32 reg = regs[regIndex];
+ for(uint8 bytesInRegister = 0; bytesInRegister < 4; bytesInRegister++)
+ {
+ brandString[partUint++] = reg;
+ reg >>= 8;
+ }
+ }
+ }
+};
+
+bool Cpuinfo::decodeCpuidResult(const cpuidFunctionIndex eaxValue)
+{
+ switch(eaxValue)
+ {
+ case Cpuinfo::BasicInfo: setBasicData(); break;
+ case Cpuinfo::VersionInfo: setVersionData(); break;
+ case Cpuinfo::InternalInfo: setInternalData(); break;
+ case Cpuinfo::SerialNumberInfo: setSerialData(); break;
+ case Cpuinfo::MonitorMwaitInfo: break;
+ case Cpuinfo::ThermalPowerInfo: break;
+ case Cpuinfo::DirectCacheAccessInfo: break;
+ case Cpuinfo::PerformanceMonitoring: break;
+ case Cpuinfo::ClockInfo: break;
+ case Cpuinfo::FrequencyInfo: break;
+ case Cpuinfo::ExtendedBasicInfo: setExtendedBasicData(); break;
+ case Cpuinfo::MoreFeatureInfo: break;
+ case Cpuinfo::BrandStringLow: setBrandString(brandString_low); break;
+ case Cpuinfo::BrandStringMiddle: setBrandString(brandString_middle); break;
+ case Cpuinfo::BrandStringHight: setBrandString(brandString_hight); break;
+ case Cpuinfo::CacheInfo: break;
+ case Cpuinfo::MiscFeatureInfo: break;
+ case Cpuinfo::AddressSize: break;
+ default: return true; break;
+ };
+
+ return false;
+};
+
+bool Cpuinfo::decodeCpuidCommand(const cpuidFunctionIndex eaxValue)
+{
+ if(cpuid(eaxValue))
+ {
+ return true;
+ }
+ else
+ {
+ return decodeCpuidResult(eaxValue);
+ }
+};
+
+bool Cpuinfo::cpuid(const cpuidFunctionIndex eaxValue)
+{
+ // Clear registers
+ eax = ebx = ecx = edx = 0;
+
+ if(!isEaxValueCorrect(eaxValue)
+ or isCommandSupportSubLeaf(eaxValue)) return true;
+
+ asm("movl %[eaxValue], %%eax\n\t"
+ "movl %0, %%eax\n\t"
+ "cpuid\n\t"
+ "movl %%eax, %0\n\t"
+ "movl %%ebx, %1\n\t"
+ "movl %%ecx, %2\n\t"
+ "movl %%edx, %3\n\t"
+ : "=r" (eax), "=r" (ebx), "=r" (ecx), "=r" (edx)
+ : [eaxValue] "r" (eaxValue));
+
+ return false;
+};
+
+bool Cpuinfo::cpuid(const cpuidFunctionIndex eaxValue, uint32 ecxValue)
+{
+ // Clear registers
+ eax = ebx = ecx = edx = 0;
+
+ if(!isEaxValueCorrect(eaxValue)
+ or !isCommandSupportSubLeaf(eaxValue)) return true;
+
+ asm("movl %[eaxValue], %%eax\n\t"
+ "movl %[ecxValue], %%ecx\n\t"
+ "cpuid\n\t"
+ "movl %%eax, %0\n\t"
+ "movl %%ebx, %1\n\t"
+ "movl %%ecx, %2\n\t"
+ "movl %%edx, %3\n\t"
+ : "=r" (eax), "=r" (ebx), "=r" (ecx), "=r" (edx)
+ : [eaxValue] "r" (eaxValue), [ecxValue] "r" (ecxValue));
+
+ return false;
+};
+
+bool Cpuinfo::isCommandSupportSubLeaf(const cpuidFunctionIndex eaxValue)
+{
+ switch(eaxValue)
+ {
+ case DeterministicCacheInfo: return true; break;
+ case FeatureInfo: return true; break;
+ case ExtendedTopologyInfo: return true; break;
+ case ExtendedStateInfo: return true; break;
+ case RDTMonitoring: return true; break;
+ case AllocationInfo: return true; break;
+ case SGXInfo: return true; break;
+ case TraceInfo: return true; break;
+ case SOCInfo: return true; break;
+ default: return false; break;
+ };
+};
+
+const char* Cpuinfo::getVendorString()
+{
+ const char* vendorStringInvalid = "VendorStringInvalid";
+
+ if(maximumInputValue != NULL) return (const char *)vendorString;
+ else return vendorStringInvalid;
+};
+
+void Cpuinfo::dataFilling(cpuidFunctionIndex startValue,
+ cpuidFunctionIndex endValue)
+{
+ cpuidFunctionIndex command = startValue;
+ uint32 ecx = 0;
+
+ do{
+ if(isEaxValueCorrect(command))
+ {
+ if(isCommandSupportSubLeaf(command))
+ {
+ cpuid(command, ecx);
+ }
+ else decodeCpuidCommand(command);
+ }
+ }while(++command <= endValue and command != Cpuinfo::BasicInfo);
+};
+
+cpuidOutputRegisters Cpuinfo::getRegs()
+{
+ return {eax, ebx, ecx, edx};
+};
+
+uint8 Cpuinfo::getDisplayFamily()
+{
+ return displayFamily;
+};
+
+uint8 Cpuinfo::getDisplayModel()
+{
+ return displayModel;
+};
+
+uint8 Cpuinfo::getStepping()
+{
+ return stepping;
+};
+
+Cpuinfo::processorType Cpuinfo::getProcessorType()
+{
+ return currentCpuType;
+};
+
+uint8 Cpuinfo::getMaxFunctionIndex()
+{
+ return maximumInputValue;
+};
+
+uint32 Cpuinfo::getMaxFunctionIndexExtended()
+{
+ return maximumInputValueExtended;
+};
+
+uint8* Cpuinfo::getBrandString()
+{
+ return brandString;
+};
+
+uint8* Cpuinfo::getInternalDescriptors()
+{
+ return internalInfoDescriptors;
+};