summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorLucas CHOLLET <lucas.chollet@free.fr>2022-05-29 23:58:32 +0200
committerLinus Groh <mail@linusgroh.de>2022-05-30 13:41:23 +0100
commita506ec08d8fcbac14a60ca6f1b52e85a4bddc097 (patch)
tree4fc01781156529fbf9632e2d0c786d5e838954b7 /Kernel
parentbe365571980d3d9622735a7432e1958b30e9cf33 (diff)
downloadserenity-a506ec08d8fcbac14a60ca6f1b52e85a4bddc097.zip
Kernel: Expose cache size for Intel CPUs
The patch also prevents any try if the CPU's vendor isn't known and improves the const-correctness of the AMD version.
Diffstat (limited to 'Kernel')
-rw-r--r--Kernel/Arch/x86/ProcessorInfo.h6
-rw-r--r--Kernel/Arch/x86/common/ProcessorInfo.cpp39
2 files changed, 38 insertions, 7 deletions
diff --git a/Kernel/Arch/x86/ProcessorInfo.h b/Kernel/Arch/x86/ProcessorInfo.h
index 339013678a..c417fd6ac4 100644
--- a/Kernel/Arch/x86/ProcessorInfo.h
+++ b/Kernel/Arch/x86/ProcessorInfo.h
@@ -42,13 +42,17 @@ public:
void set_apic_id(u32 apic_id) { m_apic_id = apic_id; }
+ static constexpr StringView s_amd_vendor_id = "AuthenticAMD";
+ static constexpr StringView s_intel_vendor_id = "GenuineIntel";
+
private:
static NonnullOwnPtr<KString> build_vendor_id_string();
static NonnullOwnPtr<KString> build_hypervisor_vendor_id_string(Processor const&);
static NonnullOwnPtr<KString> build_brand_string();
static NonnullOwnPtr<KString> build_features_string(Processor const&);
- void populate_cache_sizes();
+ void populate_cache_sizes_amd();
+ void populate_cache_sizes_intel();
NonnullOwnPtr<KString> m_vendor_id_string;
NonnullOwnPtr<KString> m_hypervisor_vendor_id_string;
diff --git a/Kernel/Arch/x86/common/ProcessorInfo.cpp b/Kernel/Arch/x86/common/ProcessorInfo.cpp
index 3743e94c0f..edc05b6306 100644
--- a/Kernel/Arch/x86/common/ProcessorInfo.cpp
+++ b/Kernel/Arch/x86/common/ProcessorInfo.cpp
@@ -37,7 +37,12 @@ ProcessorInfo::ProcessorInfo(Processor const& processor)
m_display_model = model;
}
- populate_cache_sizes();
+ // NOTE: Intel exposes detailed CPU's cache information in CPUID 04. On the
+ // other hand, AMD uses CPUID's extended function set.
+ if (m_vendor_id_string->view() == s_amd_vendor_id)
+ populate_cache_sizes_amd();
+ else if (m_vendor_id_string->view() == s_intel_vendor_id)
+ populate_cache_sizes_intel();
}
static void emit_u32(StringBuilder& builder, u32 value)
@@ -112,16 +117,15 @@ NonnullOwnPtr<KString> ProcessorInfo::build_features_string(Processor const& pro
return KString::must_create(builder.string_view());
}
-void ProcessorInfo::populate_cache_sizes()
+void ProcessorInfo::populate_cache_sizes_amd()
{
- u32 max_extended_leaf = CPUID(0x80000000).eax();
+ auto const max_extended_leaf = CPUID(0x80000000).eax();
if (max_extended_leaf < 0x80000005)
return;
- auto l1_cache_info = CPUID(0x80000005);
+ auto const l1_cache_info = CPUID(0x80000005);
- // NOTE: Except for L2, these are not available on Intel CPUs in this form and return 0 for each register in that case.
if (l1_cache_info.ecx() != 0) {
m_l1_data_cache = Cache {
.size = ((l1_cache_info.ecx() >> 24) & 0xff) * KiB,
@@ -139,7 +143,7 @@ void ProcessorInfo::populate_cache_sizes()
if (max_extended_leaf < 0x80000006)
return;
- auto l2_l3_cache_info = CPUID(0x80000006);
+ auto const l2_l3_cache_info = CPUID(0x80000006);
if (l2_l3_cache_info.ecx() != 0) {
m_l2_cache = Cache {
@@ -156,4 +160,27 @@ void ProcessorInfo::populate_cache_sizes()
}
}
+void ProcessorInfo::populate_cache_sizes_intel()
+{
+ auto const collect_cache_info = [](u32 ecx) {
+ auto const cache_info = CPUID(0x04, ecx);
+ auto const ways = ((cache_info.ebx() >> 22) & 0x3ff) + 1;
+ auto const partitions = ((cache_info.ebx() >> 12) & 0x3ff) + 1;
+ auto const line_size = (cache_info.ebx() & 0xfff) + 1;
+ auto const sets = cache_info.ecx() + 1;
+
+ return Cache {
+ .size = ways * partitions * line_size * sets,
+ .line_size = line_size
+ };
+ };
+
+ // NOTE: Those ECX numbers are the one used on recent Intel CPUs, an algorithm
+ // also exists to retrieve them.
+ m_l1_instruction_cache = collect_cache_info(0);
+ m_l1_data_cache = collect_cache_info(1);
+ m_l2_cache = collect_cache_info(2);
+ m_l3_cache = collect_cache_info(3);
+}
+
}