Przeglądaj źródła

Kernel: Expose size of L1 data/instruction, L2, and L3 CPU caches :^)

These are added as properties of the "caches" object to each processor,
if available.
Linus Groh 3 lat temu
rodzic
commit
20e2e39fcc

+ 16 - 0
Kernel/Arch/x86/ProcessorInfo.h

@@ -21,6 +21,11 @@ class ProcessorInfo {
 public:
 public:
     ProcessorInfo(Processor const& processor);
     ProcessorInfo(Processor const& processor);
 
 
+    struct Cache {
+        u64 size;
+        u64 line_size;
+    };
+
     StringView vendor_id_string() const { return m_vendor_id_string->view(); }
     StringView vendor_id_string() const { return m_vendor_id_string->view(); }
     StringView hypervisor_vendor_id_string() const { return m_hypervisor_vendor_id_string->view(); }
     StringView hypervisor_vendor_id_string() const { return m_hypervisor_vendor_id_string->view(); }
     StringView brand_string() const { return m_brand_string->view(); }
     StringView brand_string() const { return m_brand_string->view(); }
@@ -30,6 +35,10 @@ public:
     u32 stepping() const { return m_stepping; }
     u32 stepping() const { return m_stepping; }
     u32 type() const { return m_type; }
     u32 type() const { return m_type; }
     u32 apic_id() const { return m_apic_id; }
     u32 apic_id() const { return m_apic_id; }
+    Optional<Cache> const& l1_data_cache() const { return m_l1_data_cache; }
+    Optional<Cache> const& l1_instruction_cache() const { return m_l1_instruction_cache; }
+    Optional<Cache> const& l2_cache() const { return m_l2_cache; }
+    Optional<Cache> const& l3_cache() const { return m_l3_cache; }
 
 
     void set_apic_id(u32 apic_id) { m_apic_id = apic_id; }
     void set_apic_id(u32 apic_id) { m_apic_id = apic_id; }
 
 
@@ -39,6 +48,8 @@ private:
     static NonnullOwnPtr<KString> build_brand_string();
     static NonnullOwnPtr<KString> build_brand_string();
     static NonnullOwnPtr<KString> build_features_string(Processor const&);
     static NonnullOwnPtr<KString> build_features_string(Processor const&);
 
 
+    void populate_cache_sizes();
+
     NonnullOwnPtr<KString> m_vendor_id_string;
     NonnullOwnPtr<KString> m_vendor_id_string;
     NonnullOwnPtr<KString> m_hypervisor_vendor_id_string;
     NonnullOwnPtr<KString> m_hypervisor_vendor_id_string;
     NonnullOwnPtr<KString> m_brand_string;
     NonnullOwnPtr<KString> m_brand_string;
@@ -48,6 +59,11 @@ private:
     u32 m_stepping { 0 };
     u32 m_stepping { 0 };
     u32 m_type { 0 };
     u32 m_type { 0 };
     u32 m_apic_id { 0 };
     u32 m_apic_id { 0 };
+
+    Optional<Cache> m_l1_data_cache;
+    Optional<Cache> m_l1_instruction_cache;
+    Optional<Cache> m_l2_cache;
+    Optional<Cache> m_l3_cache;
 };
 };
 
 
 }
 }

+ 46 - 0
Kernel/Arch/x86/common/ProcessorInfo.cpp

@@ -36,6 +36,8 @@ ProcessorInfo::ProcessorInfo(Processor const& processor)
         m_display_family = family;
         m_display_family = family;
         m_display_model = model;
         m_display_model = model;
     }
     }
+
+    populate_cache_sizes();
 }
 }
 
 
 static void emit_u32(StringBuilder& builder, u32 value)
 static void emit_u32(StringBuilder& builder, u32 value)
@@ -110,4 +112,48 @@ NonnullOwnPtr<KString> ProcessorInfo::build_features_string(Processor const& pro
     return KString::must_create(builder.string_view());
     return KString::must_create(builder.string_view());
 }
 }
 
 
+void ProcessorInfo::populate_cache_sizes()
+{
+    u32 max_extended_leaf = CPUID(0x80000000).eax();
+
+    if (max_extended_leaf < 0x80000005)
+        return;
+
+    auto 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,
+            .line_size = l1_cache_info.ecx() & 0xff,
+        };
+    }
+
+    if (l1_cache_info.edx() != 0) {
+        m_l1_instruction_cache = Cache {
+            .size = ((l1_cache_info.edx() >> 24) & 0xff) * KiB,
+            .line_size = l1_cache_info.edx() & 0xff,
+        };
+    }
+
+    if (max_extended_leaf < 0x80000006)
+        return;
+
+    auto l2_l3_cache_info = CPUID(0x80000006);
+
+    if (l2_l3_cache_info.ecx() != 0) {
+        m_l2_cache = Cache {
+            .size = ((l2_l3_cache_info.ecx() >> 16) & 0xffff) * KiB,
+            .line_size = l2_l3_cache_info.ecx() & 0xff,
+        };
+    }
+
+    if (l2_l3_cache_info.edx() != 0) {
+        m_l3_cache = Cache {
+            .size = (static_cast<u64>((l2_l3_cache_info.edx() >> 18)) & 0x3fff) * 512 * KiB,
+            .line_size = l2_l3_cache_info.edx() & 0xff,
+        };
+    }
+}
+
 }
 }

+ 22 - 0
Kernel/GlobalProcessExposed.cpp

@@ -1,5 +1,6 @@
 /*
 /*
  * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
  * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ * Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
  *
  *
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
@@ -639,6 +640,27 @@ private:
                 TRY(obj.add("type", info.type()));
                 TRY(obj.add("type", info.type()));
                 TRY(obj.add("brand", info.brand_string()));
                 TRY(obj.add("brand", info.brand_string()));
 
 
+                auto caches = TRY(obj.add_object("caches"));
+
+                auto add_cache_info = [&](StringView name, ProcessorInfo::Cache const& cache) -> ErrorOr<void> {
+                    auto cache_object = TRY(caches.add_object(name));
+                    TRY(cache_object.add("size", cache.size));
+                    TRY(cache_object.add("line_size", cache.line_size));
+                    TRY(cache_object.finish());
+                    return {};
+                };
+
+                if (info.l1_data_cache().has_value())
+                    TRY(add_cache_info("l1_data", *info.l1_data_cache()));
+                if (info.l1_data_cache().has_value())
+                    TRY(add_cache_info("l1_instruction", *info.l1_instruction_cache()));
+                if (info.l1_data_cache().has_value())
+                    TRY(add_cache_info("l2", *info.l2_cache()));
+                if (info.l1_data_cache().has_value())
+                    TRY(add_cache_info("l3", *info.l3_cache()));
+
+                TRY(caches.finish());
+
                 TRY(obj.finish());
                 TRY(obj.finish());
                 return {};
                 return {};
             }));
             }));