[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 "console.h"
|
||||||
#include "cpu/cpu_id.h"
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
#include "status.h"
|
#include "status.h"
|
||||||
@@ -83,19 +84,21 @@ check_cpu_supported()
|
|||||||
status_line status {L"Checking CPU features"};
|
status_line status {L"Checking CPU features"};
|
||||||
|
|
||||||
cpu::cpu_id cpu;
|
cpu::cpu_id cpu;
|
||||||
uint64_t missing = cpu.missing();
|
cpu::cpu_id::features features = cpu.validate();
|
||||||
if (missing) {
|
bool supported = true;
|
||||||
|
|
||||||
#define CPU_FEATURE_OPT(...)
|
#define CPU_FEATURE_OPT(...)
|
||||||
#define CPU_FEATURE_REQ(name, ...) \
|
#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); \
|
status::fail(L"CPU required feature " L ## #name, uefi::status::unsupported); \
|
||||||
|
supported = false; \
|
||||||
}
|
}
|
||||||
#include "cpu/features.inc"
|
#include "cpu/features.inc"
|
||||||
#undef CPU_FEATURE_REQ
|
#undef CPU_FEATURE_REQ
|
||||||
#undef CPU_FEATURE_OPT
|
#undef CPU_FEATURE_OPT
|
||||||
|
|
||||||
|
if (!supported)
|
||||||
error::raise(uefi::status::unsupported, L"CPU not supported");
|
error::raise(uefi::status::unsupported, L"CPU not supported");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <new>
|
#include <new>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <util/bitset.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
@@ -30,18 +31,23 @@ cpu_validate()
|
|||||||
{
|
{
|
||||||
cpu::cpu_id cpu;
|
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, " Vendor is %s", cpu.vendor_id());
|
||||||
|
|
||||||
log::debug(logs::boot, " Higest basic CPUID: 0x%02x", cpu.highest_basic());
|
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);
|
log::debug(logs::boot, " Higest ext CPUID: 0x%02x", cpu.highest_ext() & ~cpu::cpu_id::cpuid_extended);
|
||||||
|
|
||||||
#define CPU_FEATURE_OPT(name, ...) \
|
#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) \
|
#define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \
|
||||||
CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); \
|
log::debug(logs::boot, " Supports %9s: %s", #name, features[cpu::feature::name] ? "yes" : "no"); \
|
||||||
kassert(cpu.has_feature(cpu::feature::name), "Missing required CPU feature " #name );
|
kassert(features[cpu::feature::name], "Missing required CPU feature " #name );
|
||||||
|
|
||||||
#include "cpu/features.inc"
|
#include "cpu/features.inc"
|
||||||
#undef CPU_FEATURE_OPT
|
#undef CPU_FEATURE_OPT
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
module("cpu",
|
module("cpu",
|
||||||
kind = "lib",
|
kind = "lib",
|
||||||
|
deps = [ "util" ],
|
||||||
sources = [
|
sources = [
|
||||||
"cpu_id.cpp",
|
"cpu_id.cpp",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
/// \file cpu_id.h Definition of required cpu features for jsix
|
/// \file cpu_id.h Definition of required cpu features for jsix
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <util/bitset.h>
|
||||||
|
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ enum class feature {
|
|||||||
class cpu_id
|
class cpu_id
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using features = util::bitset<(unsigned)feature::max>;
|
||||||
static constexpr uint32_t cpuid_extended = 0x80000000;
|
static constexpr uint32_t cpuid_extended = 0x80000000;
|
||||||
|
|
||||||
/// CPUID result register values
|
/// CPUID result register values
|
||||||
@@ -42,6 +44,10 @@ public:
|
|||||||
|
|
||||||
cpu_id();
|
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
|
/// The the result of a given CPUID leaf/subleaf
|
||||||
/// \arg leaf The leaf selector (initial EAX)
|
/// \arg leaf The leaf selector (initial EAX)
|
||||||
/// \arg subleaf The subleaf selector (initial ECX)
|
/// \arg subleaf The subleaf selector (initial ECX)
|
||||||
@@ -54,8 +60,11 @@ public:
|
|||||||
/// Get the name of the cpu vendor (eg, "GenuineIntel")
|
/// Get the name of the cpu vendor (eg, "GenuineIntel")
|
||||||
inline const char * vendor_id() const { return m_vendor_id; }
|
inline const char * vendor_id() const { return m_vendor_id; }
|
||||||
|
|
||||||
/// Get the brand name of this processor model
|
/// Put the brand name of this processor model into the
|
||||||
inline const char * brand_name() const { return m_brand_name; }
|
/// 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
|
/// Get the highest basic CPUID leaf supported
|
||||||
inline uint32_t highest_basic() const { return m_high_basic; }
|
inline uint32_t highest_basic() const { return m_high_basic; }
|
||||||
@@ -63,22 +72,10 @@ public:
|
|||||||
/// Get the highest extended CPUID leaf supported
|
/// Get the highest extended CPUID leaf supported
|
||||||
inline uint32_t highest_ext() const { return m_high_ext; }
|
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:
|
private:
|
||||||
uint32_t m_high_basic;
|
uint32_t m_high_basic;
|
||||||
uint32_t m_high_ext;
|
uint32_t m_high_ext;
|
||||||
uint64_t m_features;
|
|
||||||
uint64_t m_missing;
|
|
||||||
char m_vendor_id[13];
|
char m_vendor_id[13];
|
||||||
char m_brand_name[48];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,7 @@ __cpuid(
|
|||||||
if (edx) *edx = d;
|
if (edx) *edx = d;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_id::cpu_id() :
|
cpu_id::cpu_id()
|
||||||
m_features {0},
|
|
||||||
m_missing {0}
|
|
||||||
{
|
{
|
||||||
__cpuid(0, 0,
|
__cpuid(0, 0,
|
||||||
&m_high_basic,
|
&m_high_basic,
|
||||||
@@ -34,46 +32,31 @@ cpu_id::cpu_id() :
|
|||||||
reinterpret_cast<uint32_t *>(&m_vendor_id[4]));
|
reinterpret_cast<uint32_t *>(&m_vendor_id[4]));
|
||||||
|
|
||||||
__cpuid(cpuid_extended, 0, &m_high_ext);
|
__cpuid(cpuid_extended, 0, &m_high_ext);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_high_ext >= cpuid_extended + 4) {
|
cpu_id::features
|
||||||
__cpuid(cpuid_extended + 2, 0,
|
cpu_id::validate() const
|
||||||
reinterpret_cast<uint32_t *>(&m_brand_name[0]),
|
{
|
||||||
reinterpret_cast<uint32_t *>(&m_brand_name[4]),
|
cpu_id::features feats;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t leaf = -1u;
|
uint32_t leaf = -1u;
|
||||||
uint32_t sub = -1u;
|
uint32_t sub = -1u;
|
||||||
regs r;
|
regs r;
|
||||||
|
|
||||||
#define CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit) \
|
#define CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit) \
|
||||||
if (leaf != feat_leaf || sub != feat_sub) { \
|
if (leaf != feat_leaf || sub != feat_sub) { \
|
||||||
leaf = feat_leaf; sub = feat_sub; r = get(leaf, sub); \
|
leaf = feat_leaf; sub = feat_sub; r = get(leaf, sub); \
|
||||||
} \
|
} \
|
||||||
if (r.regname & (1ull << bit)) \
|
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) \
|
#define CPU_FEATURE_REQ(name, feat_leaf, feat_sub, regname, bit) \
|
||||||
CPU_FEATURE_OPT(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)); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "cpu/features.inc"
|
#include "cpu/features.inc"
|
||||||
#undef CPU_FEATURE_OPT
|
#undef CPU_FEATURE_OPT
|
||||||
#undef CPU_FEATURE_REQ
|
#undef CPU_FEATURE_REQ
|
||||||
|
|
||||||
|
return feats;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_id::regs
|
cpu_id::regs
|
||||||
@@ -88,12 +71,6 @@ cpu_id::get(uint32_t leaf, uint32_t sub) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
cpu_id::has_feature(feature feat)
|
|
||||||
{
|
|
||||||
return (m_features & (1 << static_cast<uint64_t>(feat))) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
cpu_id::local_apic_id() const
|
cpu_id::local_apic_id() const
|
||||||
{
|
{
|
||||||
@@ -103,4 +80,29 @@ cpu_id::local_apic_id() const
|
|||||||
return static_cast<uint8_t>(ebx >> 24);
|
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 = [
|
public_headers = [
|
||||||
"util/basic_types.h",
|
"util/basic_types.h",
|
||||||
"util/bip_buffer.h",
|
"util/bip_buffer.h",
|
||||||
|
"util/bitset.h",
|
||||||
"util/counted.h",
|
"util/counted.h",
|
||||||
"util/deque.h",
|
"util/deque.h",
|
||||||
"util/enum_bitfields.h",
|
"util/enum_bitfields.h",
|
||||||
|
|||||||
Reference in New Issue
Block a user