[cpu] Reimplement CPUID features as util::bitset

The cpu::cpu_id class no longer looks up all known features in the
constructor, but instead provides access to the map of supported
features as a bitset from the verify() method. It also exposes the
brand_name() method instead of loading the brand name string in the
constructor and storing it as part of the object.
This commit is contained in:
Justin C. Miller
2022-03-13 17:33:16 -07:00
parent e2eaf43b4a
commit 54aef00913
6 changed files with 69 additions and 59 deletions

View File

@@ -1,5 +1,6 @@
#include <cpu/cpu_id.h>
#include "console.h"
#include "cpu/cpu_id.h"
#include "error.h"
#include "hardware.h"
#include "status.h"
@@ -83,20 +84,22 @@ 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)) { \
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");
}
}
} // namespace hw

View File

@@ -1,6 +1,7 @@
#include <new>
#include <stdint.h>
#include <string.h>
#include <util/bitset.h>
#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

View File

@@ -2,6 +2,7 @@
module("cpu",
kind = "lib",
deps = [ "util" ],
sources = [
"cpu_id.cpp",
],

View File

@@ -2,6 +2,7 @@
/// \file cpu_id.h Definition of required cpu features for jsix
#include <stdint.h>
#include <util/bitset.h>
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];
};
}

View File

@@ -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<uint32_t *>(&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<uint32_t *>(&m_brand_name[0]),
reinterpret_cast<uint32_t *>(&m_brand_name[4]),
reinterpret_cast<uint32_t *>(&m_brand_name[8]),
reinterpret_cast<uint32_t *>(&m_brand_name[12]));
__cpuid(cpuid_extended + 3, 0,
reinterpret_cast<uint32_t *>(&m_brand_name[16]),
reinterpret_cast<uint32_t *>(&m_brand_name[20]),
reinterpret_cast<uint32_t *>(&m_brand_name[24]),
reinterpret_cast<uint32_t *>(&m_brand_name[28]));
__cpuid(cpuid_extended + 4, 0,
reinterpret_cast<uint32_t *>(&m_brand_name[32]),
reinterpret_cast<uint32_t *>(&m_brand_name[36]),
reinterpret_cast<uint32_t *>(&m_brand_name[40]),
reinterpret_cast<uint32_t *>(&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<uint64_t>(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<uint64_t>(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<uint64_t>(feat))) != 0;
}
uint8_t
cpu_id::local_apic_id() const
{
@@ -103,4 +80,29 @@ cpu_id::local_apic_id() const
return static_cast<uint8_t>(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<uint32_t *>(&buffer[0]),
reinterpret_cast<uint32_t *>(&buffer[4]),
reinterpret_cast<uint32_t *>(&buffer[8]),
reinterpret_cast<uint32_t *>(&buffer[12]));
__cpuid(cpuid_extended + 3, 0,
reinterpret_cast<uint32_t *>(&buffer[16]),
reinterpret_cast<uint32_t *>(&buffer[20]),
reinterpret_cast<uint32_t *>(&buffer[24]),
reinterpret_cast<uint32_t *>(&buffer[28]));
__cpuid(cpuid_extended + 4, 0,
reinterpret_cast<uint32_t *>(&buffer[32]),
reinterpret_cast<uint32_t *>(&buffer[36]),
reinterpret_cast<uint32_t *>(&buffer[40]),
reinterpret_cast<uint32_t *>(&buffer[44]));
return true;
}
}

View File

@@ -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",