[cpu] Split cpuid validation into separate lib
In order to allow the bootloader to do preliminary CPUID validation while UEFI is still handling displaying information to the user, split most of the kernel's CPUID handling into a library to be used by both kernel and boot.
This commit is contained in:
11
modules.yaml
11
modules.yaml
@@ -6,6 +6,7 @@ modules:
|
|||||||
output: jsix.elf
|
output: jsix.elf
|
||||||
target: host
|
target: host
|
||||||
deps:
|
deps:
|
||||||
|
- cpu
|
||||||
- kutil
|
- kutil
|
||||||
includes:
|
includes:
|
||||||
- src/kernel
|
- src/kernel
|
||||||
@@ -62,6 +63,8 @@ modules:
|
|||||||
kind: exe
|
kind: exe
|
||||||
target: boot
|
target: boot
|
||||||
output: boot.efi
|
output: boot.efi
|
||||||
|
deps:
|
||||||
|
- cpu
|
||||||
source:
|
source:
|
||||||
- src/boot/main.cpp
|
- src/boot/main.cpp
|
||||||
- src/boot/console.cpp
|
- src/boot/console.cpp
|
||||||
@@ -110,6 +113,14 @@ modules:
|
|||||||
- src/libraries/kutil/memory.cpp
|
- src/libraries/kutil/memory.cpp
|
||||||
- src/libraries/kutil/printf.c
|
- src/libraries/kutil/printf.c
|
||||||
|
|
||||||
|
cpu:
|
||||||
|
kind: lib
|
||||||
|
output: libcpu.a
|
||||||
|
includes:
|
||||||
|
- src/libraries/cpu/include
|
||||||
|
source:
|
||||||
|
- src/libraries/cpu/cpu.cpp
|
||||||
|
|
||||||
|
|
||||||
libc:
|
libc:
|
||||||
kind: lib
|
kind: lib
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
|
#include "cpu/cpu.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
@@ -94,6 +95,28 @@ add_module(args::header *args, args::mod_type type, buffer &data)
|
|||||||
m.size = data.size;
|
m.size = data.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check that all required cpu features are supported
|
||||||
|
void
|
||||||
|
check_cpu_supported()
|
||||||
|
{
|
||||||
|
status_line status {L"Checking CPU features"};
|
||||||
|
|
||||||
|
cpu::cpu_id cpu;
|
||||||
|
uint64_t missing = cpu.missing();
|
||||||
|
if (missing) {
|
||||||
|
#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); \
|
||||||
|
}
|
||||||
|
#include "cpu/features.inc"
|
||||||
|
#undef CPU_FEATURE_REQ
|
||||||
|
#undef CPU_FEATURE_OPT
|
||||||
|
|
||||||
|
error::raise(uefi::status::unsupported, L"CPU not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The main procedure for the portion of the loader that runs while
|
/// The main procedure for the portion of the loader that runs while
|
||||||
/// UEFI is still in control of the machine. (ie, while the loader still
|
/// UEFI is still in control of the machine. (ie, while the loader still
|
||||||
/// has access to boot services.
|
/// has access to boot services.
|
||||||
@@ -160,6 +183,7 @@ efi_main(uefi::handle image, uefi::system_table *st)
|
|||||||
{
|
{
|
||||||
using namespace boot;
|
using namespace boot;
|
||||||
console con(st->boot_services, st->con_out);
|
console con(st->boot_services, st->con_out);
|
||||||
|
check_cpu_supported();
|
||||||
|
|
||||||
args::header *args = uefi_preboot(image, st);
|
args::header *args = uefi_preboot(image, st);
|
||||||
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
memory::efi_mem_map map = uefi_exit(args, image, st->boot_services);
|
||||||
|
|||||||
@@ -1,116 +1,31 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "kutil/assert.h"
|
||||||
#include "kutil/memory.h"
|
#include "kutil/memory.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
#include "cpu/cpu.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
cpu_data bsp_cpu_data;
|
cpu_data bsp_cpu_data;
|
||||||
|
|
||||||
static constexpr uint32_t cpuid_extended = 0x80000000;
|
|
||||||
|
|
||||||
|
|
||||||
inline static void
|
|
||||||
__cpuid(
|
|
||||||
uint32_t leaf,
|
|
||||||
uint32_t subleaf,
|
|
||||||
uint32_t *eax,
|
|
||||||
uint32_t *ebx = nullptr,
|
|
||||||
uint32_t *ecx = nullptr,
|
|
||||||
uint32_t *edx = nullptr)
|
|
||||||
{
|
|
||||||
uint32_t a, b, c, d;
|
|
||||||
__asm__ __volatile__ ( "cpuid"
|
|
||||||
: "=a"(a), "=b"(b), "=c"(c), "=d"(d)
|
|
||||||
: "a"(leaf), "c"(subleaf)
|
|
||||||
);
|
|
||||||
if (eax) *eax = a;
|
|
||||||
if (ebx) *ebx = b;
|
|
||||||
if (ecx) *ecx = c;
|
|
||||||
if (edx) *edx = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
cpu_id::cpu_id() :
|
|
||||||
m_features(0)
|
|
||||||
{
|
|
||||||
__cpuid(0, 0,
|
|
||||||
&m_high_basic,
|
|
||||||
reinterpret_cast<uint32_t *>(&m_vendor_id[0]),
|
|
||||||
reinterpret_cast<uint32_t *>(&m_vendor_id[8]),
|
|
||||||
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::regs
|
|
||||||
cpu_id::get(uint32_t leaf, uint32_t sub) const
|
|
||||||
{
|
|
||||||
regs ret {0, 0, 0, 0};
|
|
||||||
|
|
||||||
if ((leaf & cpuid_extended) == 0 && leaf > m_high_basic) return ret;
|
|
||||||
if ((leaf & cpuid_extended) != 0 && leaf > m_high_ext) return ret;
|
|
||||||
|
|
||||||
__cpuid(leaf, sub, &ret.eax, &ret.ebx, &ret.ecx, &ret.edx);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
cpu_id::validate()
|
cpu_validate()
|
||||||
{
|
{
|
||||||
bool fail = false;
|
cpu::cpu_id cpu;
|
||||||
uint32_t leaf = 0;
|
|
||||||
uint32_t sub = 0;
|
|
||||||
regs r;
|
|
||||||
|
|
||||||
log::info(logs::boot, "CPU: %s", brand_name());
|
log::info(logs::boot, "CPU: %s", cpu.brand_name());
|
||||||
log::debug(logs::boot, " Vendor is %s", vendor_id());
|
log::debug(logs::boot, " Vendor is %s", cpu.vendor_id());
|
||||||
|
|
||||||
log::debug(logs::boot, " Higest basic CPUID: 0x%02x", highest_basic());
|
log::debug(logs::boot, " Higest basic CPUID: 0x%02x", cpu.highest_basic());
|
||||||
log::debug(logs::boot, " Higest ext CPUID: 0x%02x", highest_ext() & ~cpuid_extended);
|
log::debug(logs::boot, " Higest ext CPUID: 0x%02x", cpu.highest_ext() & ~cpu::cpu_id::cpuid_extended);
|
||||||
|
|
||||||
#define CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit) \
|
#define CPU_FEATURE_OPT(name, ...) \
|
||||||
if (leaf != feat_leaf || sub != feat_sub) { \
|
log::debug(logs::boot, " Supports %9s: %s", #name, cpu.has_feature(cpu::feature::name) ? "yes" : "no");
|
||||||
leaf = feat_leaf; sub = feat_sub; r = get(leaf, sub); \
|
|
||||||
} \
|
|
||||||
if (r.regname & (1ull << bit)) \
|
|
||||||
m_features |= (1ull << static_cast<uint64_t>(cpu_feature::name)); \
|
|
||||||
log::debug(logs::boot, " Supports %9s: %s", #name, (r.regname & (1ull << bit)) ? "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); \
|
CPU_FEATURE_OPT(name, feat_leaf, feat_sub, regname, bit); \
|
||||||
if ((r.regname & (1ull << bit)) == 0) { \
|
kassert(cpu.has_feature(cpu::feature::name), "Missing required CPU feature " #name );
|
||||||
log::error(logs::boot, "CPU missing required feature " #name); \
|
|
||||||
fail = true; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "cpu_features.inc"
|
#include "cpu/features.inc"
|
||||||
#undef CPU_FEATURE_OPT
|
#undef CPU_FEATURE_OPT
|
||||||
#undef CPU_FEATURE_REQ
|
#undef CPU_FEATURE_REQ
|
||||||
|
|
||||||
if (fail)
|
|
||||||
log::fatal(logs::boot, "CPU not supported.");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
cpu_id::has_feature(cpu_feature feat)
|
|
||||||
{
|
|
||||||
return (m_features & (1 << static_cast<uint64_t>(feat))) != 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,69 +27,6 @@ struct cpu_data
|
|||||||
|
|
||||||
extern cpu_data bsp_cpu_data;
|
extern cpu_data bsp_cpu_data;
|
||||||
|
|
||||||
/// Enum of the cpu features jsix cares about
|
// We already validated the required options in the bootloader,
|
||||||
enum class cpu_feature {
|
// but iterate the options and log about them.
|
||||||
#define CPU_FEATURE_REQ(name, ...) name,
|
void cpu_validate();
|
||||||
#define CPU_FEATURE_OPT(name, ...) name,
|
|
||||||
#include "cpu_features.inc"
|
|
||||||
#undef CPU_FEATURE_OPT
|
|
||||||
#undef CPU_FEATURE_REQ
|
|
||||||
max
|
|
||||||
};
|
|
||||||
|
|
||||||
class cpu_id
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// CPUID result register values
|
|
||||||
struct regs {
|
|
||||||
union {
|
|
||||||
uint32_t reg[4];
|
|
||||||
uint32_t eax, ebx, ecx, edx;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Return true if bit |bit| of EAX is set
|
|
||||||
bool eax_bit(unsigned bit) { return (eax >> bit) & 0x1; }
|
|
||||||
|
|
||||||
/// Return true if bit |bit| of EBX is set
|
|
||||||
bool ebx_bit(unsigned bit) { return (ebx >> bit) & 0x1; }
|
|
||||||
|
|
||||||
/// Return true if bit |bit| of ECX is set
|
|
||||||
bool ecx_bit(unsigned bit) { return (ecx >> bit) & 0x1; }
|
|
||||||
|
|
||||||
/// Return true if bit |bit| of EDX is set
|
|
||||||
bool edx_bit(unsigned bit) { return (edx >> bit) & 0x1; }
|
|
||||||
};
|
|
||||||
|
|
||||||
cpu_id();
|
|
||||||
|
|
||||||
/// The the result of a given CPUID leaf/subleaf
|
|
||||||
/// \arg leaf The leaf selector (initial EAX)
|
|
||||||
/// \arg subleaf The subleaf selector (initial ECX)
|
|
||||||
/// \returns A |regs| struct of the values retuned
|
|
||||||
regs get(uint32_t leaf, uint32_t sub = 0) const;
|
|
||||||
|
|
||||||
/// 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; }
|
|
||||||
|
|
||||||
/// Get the highest basic CPUID leaf supported
|
|
||||||
inline uint32_t highest_basic() const { return m_high_basic; }
|
|
||||||
|
|
||||||
/// Get the highest extended CPUID leaf supported
|
|
||||||
inline uint32_t highest_ext() const { return m_high_ext; }
|
|
||||||
|
|
||||||
/// Validate the CPU supports the necessary options for jsix
|
|
||||||
void validate();
|
|
||||||
|
|
||||||
/// Return true if the CPU claims to support the given feature
|
|
||||||
bool has_feature(cpu_feature feat);
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t m_high_basic;
|
|
||||||
uint32_t m_high_ext;
|
|
||||||
char m_vendor_id[13];
|
|
||||||
char m_brand_name[48];
|
|
||||||
uint64_t m_features;
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -135,8 +135,7 @@ kernel_main(args::header *header)
|
|||||||
run_constructors();
|
run_constructors();
|
||||||
memory_initialize_post_ctors(header);
|
memory_initialize_post_ctors(header);
|
||||||
|
|
||||||
cpu_id cpu;
|
cpu_validate();
|
||||||
cpu.validate();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < header->num_modules; ++i) {
|
for (size_t i = 0; i < header->num_modules; ++i) {
|
||||||
args::module &mod = header->modules[i];
|
args::module &mod = header->modules[i];
|
||||||
|
|||||||
97
src/libraries/cpu/cpu.cpp
Normal file
97
src/libraries/cpu/cpu.cpp
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include "cpu/cpu.h"
|
||||||
|
|
||||||
|
namespace cpu {
|
||||||
|
|
||||||
|
inline static void
|
||||||
|
__cpuid(
|
||||||
|
uint32_t leaf,
|
||||||
|
uint32_t subleaf,
|
||||||
|
uint32_t *eax,
|
||||||
|
uint32_t *ebx = nullptr,
|
||||||
|
uint32_t *ecx = nullptr,
|
||||||
|
uint32_t *edx = nullptr)
|
||||||
|
{
|
||||||
|
uint32_t a, b, c, d;
|
||||||
|
__asm__ __volatile__ ( "cpuid"
|
||||||
|
: "=a"(a), "=b"(b), "=c"(c), "=d"(d)
|
||||||
|
: "a"(leaf), "c"(subleaf)
|
||||||
|
);
|
||||||
|
if (eax) *eax = a;
|
||||||
|
if (ebx) *ebx = b;
|
||||||
|
if (ecx) *ecx = c;
|
||||||
|
if (edx) *edx = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_id::cpu_id() :
|
||||||
|
m_features {0},
|
||||||
|
m_missing {0}
|
||||||
|
{
|
||||||
|
__cpuid(0, 0,
|
||||||
|
&m_high_basic,
|
||||||
|
reinterpret_cast<uint32_t *>(&m_vendor_id[0]),
|
||||||
|
reinterpret_cast<uint32_t *>(&m_vendor_id[8]),
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)); \
|
||||||
|
|
||||||
|
#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)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "cpu/features.inc"
|
||||||
|
#undef CPU_FEATURE_OPT
|
||||||
|
#undef CPU_FEATURE_REQ
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_id::regs
|
||||||
|
cpu_id::get(uint32_t leaf, uint32_t sub) const
|
||||||
|
{
|
||||||
|
regs ret {0, 0, 0, 0};
|
||||||
|
|
||||||
|
if ((leaf & cpuid_extended) == 0 && leaf > m_high_basic) return ret;
|
||||||
|
if ((leaf & cpuid_extended) != 0 && leaf > m_high_ext) return ret;
|
||||||
|
|
||||||
|
__cpuid(leaf, sub, &ret.eax, &ret.ebx, &ret.ecx, &ret.edx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
cpu_id::has_feature(feature feat)
|
||||||
|
{
|
||||||
|
return (m_features & (1 << static_cast<uint64_t>(feat))) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
81
src/libraries/cpu/include/cpu/cpu.h
Normal file
81
src/libraries/cpu/include/cpu/cpu.h
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file cpu.h Definition of required cpu features for jsix
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace cpu {
|
||||||
|
|
||||||
|
/// Enum of the cpu features jsix cares about
|
||||||
|
enum class feature {
|
||||||
|
#define CPU_FEATURE_REQ(name, ...) name,
|
||||||
|
#define CPU_FEATURE_OPT(name, ...) name,
|
||||||
|
#include "cpu/features.inc"
|
||||||
|
#undef CPU_FEATURE_OPT
|
||||||
|
#undef CPU_FEATURE_REQ
|
||||||
|
max
|
||||||
|
};
|
||||||
|
|
||||||
|
class cpu_id
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr uint32_t cpuid_extended = 0x80000000;
|
||||||
|
|
||||||
|
/// CPUID result register values
|
||||||
|
struct regs {
|
||||||
|
union {
|
||||||
|
uint32_t reg[4];
|
||||||
|
uint32_t eax, ebx, ecx, edx;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Return true if bit |bit| of EAX is set
|
||||||
|
bool eax_bit(unsigned bit) { return (eax >> bit) & 0x1; }
|
||||||
|
|
||||||
|
/// Return true if bit |bit| of EBX is set
|
||||||
|
bool ebx_bit(unsigned bit) { return (ebx >> bit) & 0x1; }
|
||||||
|
|
||||||
|
/// Return true if bit |bit| of ECX is set
|
||||||
|
bool ecx_bit(unsigned bit) { return (ecx >> bit) & 0x1; }
|
||||||
|
|
||||||
|
/// Return true if bit |bit| of EDX is set
|
||||||
|
bool edx_bit(unsigned bit) { return (edx >> bit) & 0x1; }
|
||||||
|
};
|
||||||
|
|
||||||
|
cpu_id();
|
||||||
|
|
||||||
|
/// The the result of a given CPUID leaf/subleaf
|
||||||
|
/// \arg leaf The leaf selector (initial EAX)
|
||||||
|
/// \arg subleaf The subleaf selector (initial ECX)
|
||||||
|
/// \returns A |regs| struct of the values retuned
|
||||||
|
regs get(uint32_t leaf, uint32_t sub = 0) const;
|
||||||
|
|
||||||
|
/// 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; }
|
||||||
|
|
||||||
|
/// Get the highest basic CPUID leaf supported
|
||||||
|
inline uint32_t highest_basic() const { return m_high_basic; }
|
||||||
|
|
||||||
|
/// 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];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user