mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
[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:
@@ -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,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)) { \
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
module("cpu",
|
||||
kind = "lib",
|
||||
deps = [ "util" ],
|
||||
sources = [
|
||||
"cpu_id.cpp",
|
||||
],
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user