diff --git a/src/boot/hardware.cpp b/src/boot/hardware.cpp index 83bbea7..d2745c8 100644 --- a/src/boot/hardware.cpp +++ b/src/boot/hardware.cpp @@ -1,5 +1,6 @@ +#include + #include "console.h" -#include "cpu/cpu_id.h" #include "error.h" #include "hardware.h" #include "status.h" @@ -83,19 +84,21 @@ check_cpu_supported() status_line status {L"Checking CPU features"}; cpu::cpu_id cpu; - uint64_t missing = cpu.missing(); - if (missing) { + cpu::cpu_id::features features = cpu.validate(); + bool supported = true; + #define CPU_FEATURE_OPT(...) #define CPU_FEATURE_REQ(name, ...) \ - if (!cpu.has_feature(cpu::feature::name)) { \ - status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \ - } + if (!features[cpu::feature::name]) { \ + status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \ + supported = false; \ + } #include "cpu/features.inc" #undef CPU_FEATURE_REQ #undef CPU_FEATURE_OPT + if (!supported) error::raise(uefi::status::unsupported, L"CPU not supported"); - } } diff --git a/src/kernel/cpu.cpp b/src/kernel/cpu.cpp index 9859a8c..d827175 100644 --- a/src/kernel/cpu.cpp +++ b/src/kernel/cpu.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "assert.h" #include "cpu.h" @@ -30,18 +31,23 @@ cpu_validate() { cpu::cpu_id cpu; - log::info(logs::boot, "CPU: %s", cpu.brand_name()); + char brand_name[50]; + cpu.brand_name(brand_name); + + cpu::cpu_id::features features = cpu.validate(); + + log::info(logs::boot, "CPU: %s", brand_name); log::debug(logs::boot, " Vendor is %s", cpu.vendor_id()); log::debug(logs::boot, " Higest basic CPUID: 0x%02x", cpu.highest_basic()); log::debug(logs::boot, " Higest ext CPUID: 0x%02x", cpu.highest_ext() & ~cpu::cpu_id::cpuid_extended); #define CPU_FEATURE_OPT(name, ...) \ - log::debug(logs::boot, " Supports %9s: %s", #name, cpu.has_feature(cpu::feature::name) ? "yes" : "no"); + log::debug(logs::boot, " Supports %9s: %s", #name, features[cpu::feature::name] ? "yes" : "no"); #define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \ - CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); \ - kassert(cpu.has_feature(cpu::feature::name), "Missing required CPU feature " #name ); + log::debug(logs::boot, " Supports %9s: %s", #name, features[cpu::feature::name] ? "yes" : "no"); \ + kassert(features[cpu::feature::name], "Missing required CPU feature " #name ); #include "cpu/features.inc" #undef CPU_FEATURE_OPT diff --git a/src/libraries/cpu/cpu.module b/src/libraries/cpu/cpu.module index ffaed44..bfe985a 100644 --- a/src/libraries/cpu/cpu.module +++ b/src/libraries/cpu/cpu.module @@ -2,6 +2,7 @@ module("cpu", kind = "lib", + deps = [ "util" ], sources = [ "cpu_id.cpp", ], diff --git a/src/libraries/cpu/cpu/cpu_id.h b/src/libraries/cpu/cpu/cpu_id.h index 468f525..e264977 100644 --- a/src/libraries/cpu/cpu/cpu_id.h +++ b/src/libraries/cpu/cpu/cpu_id.h @@ -2,6 +2,7 @@ /// \file cpu_id.h Definition of required cpu features for jsix #include +#include namespace cpu { @@ -18,6 +19,7 @@ enum class feature { class cpu_id { public: + using features = util::bitset<(unsigned)feature::max>; static constexpr uint32_t cpuid_extended = 0x80000000; /// CPUID result register values @@ -42,6 +44,10 @@ public: cpu_id(); + /// Check which of the cpu::feature flags this CPU supports. + /// \returns A util::bitset mapping to cpu::feature values + features validate() const; + /// The the result of a given CPUID leaf/subleaf /// \arg leaf The leaf selector (initial EAX) /// \arg subleaf The subleaf selector (initial ECX) @@ -54,8 +60,11 @@ public: /// Get the name of the cpu vendor (eg, "GenuineIntel") inline const char * vendor_id() const { return m_vendor_id; } - /// Get the brand name of this processor model - inline const char * brand_name() const { return m_brand_name; } + /// Put the brand name of this processor model into the + /// provided buffer. + /// \arg buffer Pointer to a buffer at least 48 bytes long + /// \returns True if the brand name was obtained + bool brand_name(char *buffer) const; /// Get the highest basic CPUID leaf supported inline uint32_t highest_basic() const { return m_high_basic; } @@ -63,22 +72,10 @@ public: /// Get the highest extended CPUID leaf supported inline uint32_t highest_ext() const { return m_high_ext; } - /// Get which required options are missing as flags - inline uint64_t missing() const { return m_missing; } - - /// Validate the CPU supports the necessary options for jsix - inline bool supported() const { return m_missing; } - - /// Return true if the CPU claims to support the given feature - bool has_feature(feature feat); - private: uint32_t m_high_basic; uint32_t m_high_ext; - uint64_t m_features; - uint64_t m_missing; char m_vendor_id[13]; - char m_brand_name[48]; }; } diff --git a/src/libraries/cpu/cpu_id.cpp b/src/libraries/cpu/cpu_id.cpp index 034c4c2..4bdc3b0 100644 --- a/src/libraries/cpu/cpu_id.cpp +++ b/src/libraries/cpu/cpu_id.cpp @@ -23,9 +23,7 @@ __cpuid( if (edx) *edx = d; } -cpu_id::cpu_id() : - m_features {0}, - m_missing {0} +cpu_id::cpu_id() { __cpuid(0, 0, &m_high_basic, @@ -34,46 +32,31 @@ cpu_id::cpu_id() : reinterpret_cast(&m_vendor_id[4])); __cpuid(cpuid_extended, 0, &m_high_ext); +} - if (m_high_ext >= cpuid_extended + 4) { - __cpuid(cpuid_extended + 2, 0, - reinterpret_cast(&m_brand_name[0]), - reinterpret_cast(&m_brand_name[4]), - reinterpret_cast(&m_brand_name[8]), - reinterpret_cast(&m_brand_name[12])); - __cpuid(cpuid_extended + 3, 0, - reinterpret_cast(&m_brand_name[16]), - reinterpret_cast(&m_brand_name[20]), - reinterpret_cast(&m_brand_name[24]), - reinterpret_cast(&m_brand_name[28])); - __cpuid(cpuid_extended + 4, 0, - reinterpret_cast(&m_brand_name[32]), - reinterpret_cast(&m_brand_name[36]), - reinterpret_cast(&m_brand_name[40]), - reinterpret_cast(&m_brand_name[44])); - } else { - m_brand_name[0] = 0; - } - +cpu_id::features +cpu_id::validate() const +{ + cpu_id::features feats; uint32_t leaf = -1u; uint32_t sub = -1u; regs r; + #define CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit) \ if (leaf != feat_leaf || sub != feat_sub) { \ leaf = feat_leaf; sub = feat_sub; r = get(leaf, sub); \ } \ if (r.regname & (1ull << bit)) \ - m_features |= (1ull << static_cast(feature::name)); \ + feats.set(feature::name); #define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \ - CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); \ - if ((r.regname & (1ull << bit)) == 0) { \ - m_missing |= (1ull << static_cast(feature::name)); \ - } + CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); #include "cpu/features.inc" #undef CPU_FEATURE_OPT #undef CPU_FEATURE_REQ + + return feats; } cpu_id::regs @@ -88,12 +71,6 @@ cpu_id::get(uint32_t leaf, uint32_t sub) const return ret; } -bool -cpu_id::has_feature(feature feat) -{ - return (m_features & (1 << static_cast(feat))) != 0; -} - uint8_t cpu_id::local_apic_id() const { @@ -103,4 +80,29 @@ cpu_id::local_apic_id() const return static_cast(ebx >> 24); } +bool +cpu_id::brand_name(char *buffer) const +{ + if (m_high_ext < cpuid_extended + 4) + return false; + + __cpuid(cpuid_extended + 2, 0, + reinterpret_cast(&buffer[0]), + reinterpret_cast(&buffer[4]), + reinterpret_cast(&buffer[8]), + reinterpret_cast(&buffer[12])); + __cpuid(cpuid_extended + 3, 0, + reinterpret_cast(&buffer[16]), + reinterpret_cast(&buffer[20]), + reinterpret_cast(&buffer[24]), + reinterpret_cast(&buffer[28])); + __cpuid(cpuid_extended + 4, 0, + reinterpret_cast(&buffer[32]), + reinterpret_cast(&buffer[36]), + reinterpret_cast(&buffer[40]), + reinterpret_cast(&buffer[44])); + + return true; +} + } diff --git a/src/libraries/util/util.module b/src/libraries/util/util.module index 222d6de..1e137eb 100644 --- a/src/libraries/util/util.module +++ b/src/libraries/util/util.module @@ -9,6 +9,7 @@ module("util", public_headers = [ "util/basic_types.h", "util/bip_buffer.h", + "util/bitset.h", "util/counted.h", "util/deque.h", "util/enum_bitfields.h",