blob: 8e64315fb1f6a19c48cdc68f973fcac727ddf360 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#ifndef ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_X86_CPUID_H_
#define ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_X86_CPUID_H_
#include <array>
#include <string_view>
#include <type_traits>
#include <utility>
#include <hwreg/bitfields.h>
namespace arch {
// An hwreg-compatible interface for reading CPUID values, where the
// "addresses" correspond to the EAX, EBX, ECX, and EDX registers. The values
// are expected to be programmatically filled before use, e.g., using
// the compiler-supplied <cpuid.h> (not included here, since it is x86-only):
// ```
// cpuid_count(leaf, subleaf, values_[CpuidIo::kEax], values_[CpuidIo::kEbx],
// values_[CpuidIo::kEcx], values_[CpuidIo::kEdx]);
// ```
struct CpuidIo {
enum Register : uint32_t {
kEax = 0,
kEbx = 1,
kEcx = 2,
kEdx = 3,
};
// The API needs this to be a template even though only one type is valid.
// In the general case, this is usually a template that admits multiple
// possible integer types. So calls to it from template-generic code use
// `io.template Read<uint32_t>(offset)` and the like, which is invalid if
// this is not a template function.
template <typename T>
T Read(uint32_t reg) const {
static_assert(std::is_same_v<T, uint32_t>);
ZX_ASSERT(reg < std::size(values_));
return values_[reg];
}
uint32_t values_[4];
};
// Define a "CPUID value type" as any type with the following:
// * static constexpr uint32_t members, `kLeaf` and `kSubleaf` giving the
// associated leaf and subleaf;
// * a static `Get()` method returning a `hwreg::RegisterAddr` object holding
// an "address" of one of the `CpuidIo::Register` values.
//
// CPUID "I/O" providers will deal in such types. See arch::BootCpuidIo and
// arch::testing::FakeCpuidIo for instances of such contracts.
//
// Note: there is no inherent relationship between the CPUID value type and the
// return type of `Get()`. In practice, a CPUID value type might be precisely
// the hwreg register type expressing the bit layout or a sort of getter for
// such a type (the utility of which lies in the fact that hwreg register
// types cannot be templated, for various reasons).
//
// We use Intel's terms of "leaf" and "subleaf" over AMD's "function" and
// "subfunction" as the latter pair is more overloaded and ambiguous.
// CpuidIoValue is a convenience type for defining a CPUID value type.
template <typename ValueType, uint32_t Leaf, uint32_t Subleaf, CpuidIo::Register OutputRegister>
struct CpuidIoValue {
static constexpr uint32_t kLeaf = Leaf;
static constexpr uint32_t kSubleaf = Subleaf;
static auto Get() { return hwreg::RegisterAddr<ValueType>(OutputRegister); }
};
// CpuidIoValueBase is a convenience type for defining both a CPUID value type
// as well as the associated register type.
//
// Assembly macro generation requires the use of `hwreg::EnablePrinter`; to
// make such use-cases more conveniently accessible - and since the code-gen
// cost here is rather minimal - we generally use the feature below.
template <typename ValueType, uint32_t Leaf, uint32_t Subleaf, CpuidIo::Register OutputRegister>
struct CpuidIoValueBase : public hwreg::RegisterBase<ValueType, uint32_t, hwreg::EnablePrinter>,
public CpuidIoValue<ValueType, Leaf, Subleaf, OutputRegister> {};
enum class Vendor {
kUnknown,
kIntel,
kAmd,
};
// The list is not exhaustive and is in chronological order within groupings.
// Microarchictectures that use the same processor (and, say, differ only in
// performance or SoC composition) are regarded as equivalent.
enum class Microarchitecture {
kUnknown,
// Intel Core family (64-bit, display family 0x6).
kIntelCore2,
kIntelNehalem,
kIntelWestmere,
kIntelSandyBridge,
kIntelIvyBridge,
kIntelHaswell,
kIntelBroadwell,
// Includes Kaby/Coffee/Whiskey/Amber/Comet Lake.
kIntelSkylake,
// Includes Cascade/Cooper Lake.
kIntelSkylakeServer,
// A 10nm prototype only ever released on the Intel Core i3-8121U.
kIntelCannonLake,
// Intel Atom family.
kIntelBonnell,
kIntelSilvermont,
kIntelAirmont,
kIntelGoldmont,
kIntelGoldmontPlus,
kIntelTremont,
// AMD families.
kAmdFamily0x15,
kAmdFamily0x16,
kAmdFamily0x17,
kAmdFamily0x19,
};
std::string_view ToString(Vendor vendor);
std::string_view ToString(Microarchitecture microarch);
//---------------------------------------------------------------------------//
// Leaf/Function 0x0.
//
// [intel/vol2]: Table 3-8. Information Returned by CPUID Instruction.
// [amd/vol3]: E.3.1 Function 0h—Maximum Standard Function Number and Vendor String.
//---------------------------------------------------------------------------//
// [amd/vol3]: E.3.1, CPUID Fn0000_0000_EAX Largest Standard Function Number.
struct CpuidMaximumLeaf : public CpuidIoValueBase<CpuidMaximumLeaf, 0x0, 0x0, CpuidIo::kEax> {
DEF_FIELD(31, 0, leaf);
};
// [amd/vol3]: E.3.1, CPUID Fn0000_0000_E[D,C,B]X Processor Vendor.
struct CpuidVendorB : public CpuidIoValueBase<CpuidVendorB, 0x0, 0x0, CpuidIo::kEbx> {
DEF_FIELD(31, 0, value);
};
struct CpuidVendorC : public CpuidIoValueBase<CpuidVendorC, 0x0, 0x0, CpuidIo::kEcx> {
DEF_FIELD(31, 0, value);
};
struct CpuidVendorD : public CpuidIoValueBase<CpuidVendorD, 0x0, 0x0, CpuidIo::kEdx> {
DEF_FIELD(31, 0, value);
};
template <typename CpuidIoProvider>
Vendor GetVendor(CpuidIoProvider&& io) {
using namespace std::string_view_literals;
const uint32_t ids[] = {
io.template Read<CpuidVendorB>().value(),
io.template Read<CpuidVendorD>().value(),
io.template Read<CpuidVendorC>().value(),
};
std::string_view name{reinterpret_cast<const char*>(ids), sizeof(ids)};
if (name == "GenuineIntel"sv) {
return Vendor::kIntel;
} else if (name == "AuthenticAMD"sv) {
return Vendor::kAmd;
}
return Vendor::kUnknown;
}
//---------------------------------------------------------------------------//
// Leaf/Function 0x1.
//
// [intel/vol2]: Table 3-8. Information Returned by CPUID Instruction.
// [amd/vol3]: E.3.2 Function 1h—Processor and Processor Feature Identifiers
//---------------------------------------------------------------------------//
// [intel/vol2]: Figure 3-6. Version Information Returned by CPUID in EAX.
// [amd/vol3]: E.3.2, CPUID Fn0000_0001_EAX Family, Model, Stepping Identifiers.
struct CpuidVersionInfo : public CpuidIoValueBase<CpuidVersionInfo, 0x1, 0x0, CpuidIo::kEax> {
// [intel/vol2]: Table 3-9. Processor Type Field.
enum class IntelProcessorType : uint8_t {
kOriginalOem = 0b00,
kIntelOverdrive = 0b01,
kDual = 0b10,
kReserved = 0b11,
};
// Bits [31:28] are reserved.
DEF_FIELD(27, 20, extended_family);
DEF_FIELD(19, 16, extended_model);
// Bits [15:14] are reserved.
DEF_ENUM_FIELD(IntelProcessorType, 13, 12, intel_processor); // Reserved on AMD.
DEF_FIELD(11, 8, base_family);
DEF_FIELD(7, 4, base_model);
DEF_FIELD(3, 0, stepping);
uint8_t family() const;
uint8_t model() const;
// Attempts to derives the microarchitecture with the assumption that the
// system relates to a particular vendor.
Microarchitecture microarchitecture(Vendor vendor) const;
};
template <typename CpuidIoProvider>
Microarchitecture GetMicroarchitecture(CpuidIoProvider&& io) {
auto vendor = GetVendor(io);
return std::forward<CpuidIoProvider>(io).template Read<CpuidVersionInfo>().microarchitecture(
vendor);
}
// [intel/vol2]: Table 3-10. Feature Information Returned in the ECX Register.
// [amd/vol3]: E.3.2, CPUID Fn0000_0001_ECX Feature Identifiers.
struct CpuidFeatureFlagsC : public CpuidIoValueBase<CpuidFeatureFlagsC, 0x1, 0x0, CpuidIo::kEcx> {
// AMD documented "RAZ. Reserved for use by hypervisor to indicate guest
// status."; Intel documents "Not Used. Always returns 0.".
DEF_BIT(31, hypervisor);
DEF_BIT(30, rdrand);
DEF_BIT(29, f16c);
DEF_BIT(28, avx);
DEF_BIT(27, osxsave);
DEF_BIT(26, xsave);
DEF_BIT(25, aes);
DEF_BIT(24, tsc_deadline);
DEF_BIT(23, popcnt);
DEF_BIT(22, movbe);
DEF_BIT(21, x2apic);
DEF_BIT(20, sse4_2);
DEF_BIT(19, sse4_1);
DEF_BIT(18, dca);
DEF_BIT(17, pcid);
// Bit 16 is reserved.
DEF_BIT(15, pdcm);
DEF_BIT(14, xtpr);
DEF_BIT(13, cmpxchg16b);
DEF_BIT(12, fma);
DEF_BIT(11, sdbg);
DEF_BIT(10, cnxt_id);
DEF_BIT(9, ssse3);
DEF_BIT(8, tm2);
DEF_BIT(7, eist);
DEF_BIT(6, smx);
DEF_BIT(5, vmx);
DEF_BIT(4, ds_cpl);
DEF_BIT(3, monitor);
DEF_BIT(2, dtes64);
DEF_BIT(1, pclmulqdq);
DEF_BIT(0, sse3);
};
// [intel/vol2]: Table 3-11. More on Feature Information Returned in the EDX Register.
// [amd/vol3]: E.3.6 Function 7h—Structured Extended Feature Identifiers.
struct CpuidFeatureFlagsD : public CpuidIoValueBase<CpuidFeatureFlagsD, 0x1, 0x0, CpuidIo::kEdx> {
DEF_BIT(31, pbe);
// Bit 30 is reserved.
DEF_BIT(29, tm);
DEF_BIT(28, htt);
DEF_BIT(27, ss);
DEF_BIT(26, sse2);
DEF_BIT(25, sse);
DEF_BIT(24, fxsr);
DEF_BIT(23, mmx);
DEF_BIT(22, acpi);
DEF_BIT(21, ds);
// Bit 20 is reserved.
DEF_BIT(19, clfsh);
DEF_BIT(18, psn);
DEF_BIT(17, pse36);
DEF_BIT(16, pat);
DEF_BIT(15, cmov);
DEF_BIT(14, mca);
DEF_BIT(13, pge);
DEF_BIT(12, mtrr);
DEF_BIT(11, sep);
// Bit 10 is reserved.
DEF_BIT(9, apic);
DEF_BIT(8, cx8);
DEF_BIT(7, mce);
DEF_BIT(6, pae);
DEF_BIT(5, msr);
DEF_BIT(4, tsc);
DEF_BIT(3, pse);
DEF_BIT(2, de);
DEF_BIT(1, vme);
DEF_BIT(0, fpu);
};
//---------------------------------------------------------------------------//
// Leaf/Function 0x5.
//
// [intel/vol2]: Table 3-8. Information Returned by CPUID Instruction.
// [amd/vol3]: E.3.4 Function 5h—Monitor and MWait Features.
//---------------------------------------------------------------------------//
struct CpuidMonitorMwaitA : public CpuidIoValueBase<CpuidMonitorMwaitA, 0x5, 0x0, CpuidIo::kEax> {
DEF_RSVDZ_FIELD(31, 16);
DEF_FIELD(15, 0, smallest_monitor_line_size);
};
struct CpuidMonitorMwaitB : public CpuidIoValueBase<CpuidMonitorMwaitB, 0x5, 0x0, CpuidIo::kEbx> {
DEF_RSVDZ_FIELD(31, 16);
DEF_FIELD(15, 0, largest_monitor_line_size);
};
struct CpuidMonitorMwaitC : public CpuidIoValueBase<CpuidMonitorMwaitC, 0x5, 0x0, CpuidIo::kEcx> {
// Bits [31: 2] are reserved.
DEF_BIT(1, ibe);
DEF_BIT(0, emx);
};
struct CpuidMonitorMwaitD : public CpuidIoValueBase<CpuidMonitorMwaitD, 0x5, 0x0, CpuidIo::kEdx> {
DEF_FIELD(31, 28, c7_sub_c_states);
DEF_FIELD(27, 24, c6_sub_c_states);
DEF_FIELD(23, 20, c5_sub_c_states);
DEF_FIELD(19, 16, c4_sub_c_states);
DEF_FIELD(15, 12, c3_sub_c_states);
DEF_FIELD(11, 8, c2_sub_c_states);
DEF_FIELD(7, 4, c1_sub_c_states);
DEF_FIELD(3, 0, c0_sub_c_states);
};
//---------------------------------------------------------------------------//
// Leaf/Function 0x7.
//
// [intel/vol2]: Table 3-8. Information Returned by CPUID Instruction.
// [amd/vol3]: E.3.6 Function 7h—Structured Extended Feature Identifier
//---------------------------------------------------------------------------//
// [amd/vol3]: E.3.6, CPUID Fn0000_0007_EBX_x0 Structured Extended Feature Identifiers (ECX=0).
struct CpuidExtendedFeatureFlagsB
: public CpuidIoValueBase<CpuidExtendedFeatureFlagsB, 0x7, 0x0, CpuidIo::kEbx> {
DEF_BIT(31, avx512vl);
DEF_BIT(30, avx512bw);
DEF_BIT(29, sha);
DEF_BIT(28, avx512cd);
DEF_BIT(27, avx512er);
DEF_BIT(26, avx512pf);
DEF_BIT(25, intel_pt);
DEF_BIT(24, clwb);
DEF_BIT(23, clflushopt);
// Bit 22 is reserved.
DEF_BIT(21, avx512_ifma);
DEF_BIT(20, smap);
DEF_BIT(19, adx);
DEF_BIT(18, rdseed);
DEF_BIT(17, avx512dq);
DEF_BIT(16, avx512f);
DEF_BIT(15, rdt_a);
DEF_BIT(14, mpx);
DEF_BIT(13, fpu_cs_ds_deprecated);
DEF_BIT(12, rdt_m);
DEF_BIT(11, rtm);
DEF_BIT(10, invpcid);
DEF_BIT(9, enhanced_rep_movsb_stosb);
DEF_BIT(8, bmi2);
DEF_BIT(7, smep);
DEF_BIT(6, fdp_excptn_only_x87);
DEF_BIT(5, avx2);
DEF_BIT(4, hle);
DEF_BIT(3, bmi1);
DEF_BIT(2, sgx);
DEF_BIT(1, tsc_adjust);
DEF_BIT(0, fsgsbase);
};
//---------------------------------------------------------------------------//
// Leaf/Function 0xa.
//
// [intel/vol2]: Table 3-8. Information Returned by CPUID Instruction.
//---------------------------------------------------------------------------//
struct CpuidPerformanceMonitoringA
: public CpuidIoValueBase<CpuidPerformanceMonitoringA, 0xa, 0x0, CpuidIo::kEax> {
DEF_FIELD(31, 24, ebx_vector_length);
DEF_FIELD(23, 16, general_counter_width);
DEF_FIELD(15, 8, num_general_counters);
DEF_FIELD(7, 0, version);
};
struct CpuidPerformanceMonitoringB
: public CpuidIoValueBase<CpuidPerformanceMonitoringB, 0xa, 0x0, CpuidIo::kEbx> {
DEF_RSVDZ_FIELD(31, 7);
DEF_BIT(6, branch_mispredict_retired_event_unavailable);
DEF_BIT(5, branch_instruction_retired_event_unavailable);
DEF_BIT(4, last_level_cache_miss_event_unavailable);
DEF_BIT(3, last_level_cache_reference_event_unavailable);
DEF_BIT(2, reference_cycle_event_unavailable);
DEF_BIT(1, instruction_retired_event_unavailable);
DEF_BIT(0, core_cycle_event_unavailable);
};
struct CpuidPerformanceMonitoringD
: public CpuidIoValueBase<CpuidPerformanceMonitoringD, 0xa, 0x0, CpuidIo::kEdx> {
DEF_RSVDZ_FIELD(31, 16);
DEF_BIT(15, anythread_deprecation);
DEF_RSVDZ_FIELD(14, 13);
DEF_FIELD(12, 5, fixed_counter_width);
DEF_FIELD(4, 0, num_fixed_counters);
};
//---------------------------------------------------------------------------//
// Leaf/Function 0x14.
//
// [intel/vol2]: Table 3-8. Information Returned by CPUID Instruction.
//---------------------------------------------------------------------------//
struct CpuidProcessorTraceMainB
: public CpuidIoValueBase<CpuidProcessorTraceMainB, 0x14, 0x0, CpuidIo::kEbx> {
DEF_RSVDZ_FIELD(31, 6);
DEF_BIT(5, power_event_trace);
DEF_BIT(4, ptwrite);
DEF_BIT(3, mtc);
DEF_BIT(2, ip_filtering);
DEF_BIT(1, psb);
DEF_BIT(0, crc3_filtering);
};
struct CpuidProcessorTraceMainC
: public CpuidIoValueBase<CpuidProcessorTraceMainC, 0x14, 0x0, CpuidIo::kEcx> {
DEF_BIT(31, lip);
DEF_RSVDZ_FIELD(30, 4);
DEF_BIT(3, trace_transport);
DEF_BIT(2, single_range_output);
DEF_BIT(1, topa_multi);
DEF_BIT(0, topa);
};
//---------------------------------------------------------------------------//
// Leaves/Functions 0x4000'0000 - 0x4fff'ffff.
//
// [intel/vol2]: Table 3-8. Information Returned by CPUID Instruction.
//
// This range is reserved by convention for hypervisors: the original RFC can be
// found at https://lwn.net/Articles/301888.
//
// Intel documents that "No existing or future CPU will return processor
// identification or feature information if the initial EAX value is in the
// range 40000000H to 4FFFFFFFH."
//---------------------------------------------------------------------------//
struct CpuidMaximumHypervisorLeaf
: public CpuidIoValueBase<CpuidMaximumHypervisorLeaf, 0x4000'0000, 0x0, CpuidIo::kEax> {
DEF_FIELD(31, 0, leaf);
};
struct CpuidHypervisorNameB
: public CpuidIoValueBase<CpuidHypervisorNameB, 0x4000'0000, 0x0, CpuidIo::kEbx> {
DEF_FIELD(31, 0, value);
};
struct CpuidHypervisorNameC
: public CpuidIoValueBase<CpuidHypervisorNameC, 0x4000'0000, 0x0, CpuidIo::kEcx> {
DEF_FIELD(31, 0, value);
};
struct CpuidHypervisorNameD
: public CpuidIoValueBase<CpuidHypervisorNameD, 0x4000'0000, 0x0, CpuidIo::kEdx> {
DEF_FIELD(31, 0, value);
};
// HypervisorName is a simple class that serves to hold the content of a
// hypervisor's name (or "vendor string").
class HypervisorName {
public:
template <typename CpuidIoProvider>
explicit HypervisorName(CpuidIoProvider&& io) {
// Check if we are actually within a hypervisor.
if (io.template Read<CpuidFeatureFlagsC>().hypervisor()) {
const uint32_t values[] = {
io.template Read<CpuidHypervisorNameB>().value(),
io.template Read<CpuidHypervisorNameC>().value(),
io.template Read<CpuidHypervisorNameD>().value(),
};
static_assert(kSize == sizeof(values));
memcpy(str_.data(), values, kSize);
} else {
str_[0] = '\0';
}
}
// Returns a string representation of name of the hypervisor, valid for as
// long as the associated HypervisorName is in scope.
std::string_view name() const {
std::string_view name{str_.data(), str_.size()};
return name.substr(0, name.find_first_of('\0'));
}
private:
static constexpr size_t kSize = 12;
std::array<char, kSize> str_;
};
//---------------------------------------------------------------------------//
// Leaf/Function 0x8000'0000
//
// [intel/vol2]: Table 3-8. Information Returned by CPUID Instruction.
// [amd/vol3]: E.4.1 Function 8000_0000h—Maximum Extended Function Number and Vendor String
//---------------------------------------------------------------------------//
// [amd/vol3]: CPUID Fn8000_0000_EAX Largest Extended Function Number
struct CpuidMaximumExtendedLeaf
: public CpuidIoValueBase<CpuidMaximumExtendedLeaf, 0x8000'0000, 0x0, CpuidIo::kEax> {
DEF_FIELD(31, 0, leaf);
};
//---------------------------------------------------------------------------//
// Leaves/Functions 0x8000'0002 - 0x8000'0004
//
// [intel/vol2]: Table 3-8. Information Returned by CPUID Instruction.
// [amd/vol3]: E.4.3 Functions 8000_0002h–8000_0004h—Extended Processor Name String
//---------------------------------------------------------------------------//
// The 2,3,4 below refer to the low digit of the leaf number and not the
// express (zero-based) index into how the combine to form the processor name
// string.
struct CpuidProcessorName2A
: public CpuidIoValueBase<CpuidProcessorName2A, 0x8000'0002, 0x0, CpuidIo::kEax> {
DEF_FIELD(31, 0, value);
};
struct CpuidProcessorName2B
: public CpuidIoValueBase<CpuidProcessorName2B, 0x8000'0002, 0x0, CpuidIo::kEbx> {
DEF_FIELD(31, 0, value);
};
struct CpuidProcessorName2C
: public CpuidIoValueBase<CpuidProcessorName2C, 0x8000'0002, 0x0, CpuidIo::kEcx> {
DEF_FIELD(31, 0, value);
};
struct CpuidProcessorName2D
: public CpuidIoValueBase<CpuidProcessorName2D, 0x8000'0002, 0x0, CpuidIo::kEdx> {
DEF_FIELD(31, 0, value);
};
struct CpuidProcessorName3A
: public CpuidIoValueBase<CpuidProcessorName3A, 0x8000'0003, 0x0, CpuidIo::kEax> {
DEF_FIELD(31, 0, value);
};
struct CpuidProcessorName3B
: public CpuidIoValueBase<CpuidProcessorName3B, 0x8000'0003, 0x0, CpuidIo::kEbx> {
DEF_FIELD(31, 0, value);
};
struct CpuidProcessorName3C
: public CpuidIoValueBase<CpuidProcessorName3C, 0x8000'0003, 0x0, CpuidIo::kEcx> {
DEF_FIELD(31, 0, value);
};
struct CpuidProcessorName3D
: public CpuidIoValueBase<CpuidProcessorName3D, 0x8000'0003, 0x0, CpuidIo::kEdx> {
DEF_FIELD(31, 0, value);
};
struct CpuidProcessorName4A
: public CpuidIoValueBase<CpuidProcessorName4A, 0x8000'0004, 0x0, CpuidIo::kEax> {
DEF_FIELD(31, 0, value);
};
struct CpuidProcessorName4B
: public CpuidIoValueBase<CpuidProcessorName4B, 0x8000'0004, 0x0, CpuidIo::kEbx> {
DEF_FIELD(31, 0, value);
};
struct CpuidProcessorName4C
: public CpuidIoValueBase<CpuidProcessorName4C, 0x8000'0004, 0x0, CpuidIo::kEcx> {
DEF_FIELD(31, 0, value);
};
struct CpuidProcessorName4D
: public CpuidIoValueBase<CpuidProcessorName4D, 0x8000'0004, 0x0, CpuidIo::kEdx> {
DEF_FIELD(31, 0, value);
};
// ProcessorName is a simple class that serves to hold the content of a
// processor name (or "brand string" in Intel-speak), a general identifier.
class ProcessorName {
public:
template <typename CpuidIoProvider>
explicit ProcessorName(CpuidIoProvider&& io) {
// The name string needs leaves 0x8000'0002-0x8000'0004.
if (io.template Read<CpuidMaximumExtendedLeaf>().leaf() >= CpuidProcessorName4D::kLeaf) {
const uint32_t values[] = {
io.template Read<CpuidProcessorName2A>().value(),
io.template Read<CpuidProcessorName2B>().value(),
io.template Read<CpuidProcessorName2C>().value(),
io.template Read<CpuidProcessorName2D>().value(),
io.template Read<CpuidProcessorName3A>().value(),
io.template Read<CpuidProcessorName3B>().value(),
io.template Read<CpuidProcessorName3C>().value(),
io.template Read<CpuidProcessorName3D>().value(),
io.template Read<CpuidProcessorName4A>().value(),
io.template Read<CpuidProcessorName4B>().value(),
io.template Read<CpuidProcessorName4C>().value(),
io.template Read<CpuidProcessorName4D>().value(),
};
static_assert(kSize == sizeof(values));
memcpy(str_.data(), values, kSize);
} else {
str_[0] = '\0';
}
}
ProcessorName() = delete;
// Returns a string representation of name of the processor, valid for as
// long as the associated ProcessorName is in scope.
std::string_view name() const {
std::string_view name{str_.data(), str_.size()};
return name.substr(0, name.find('\0'));
}
private:
static constexpr size_t kSize = 48;
std::array<char, kSize> str_;
};
} // namespace arch
#endif // ZIRCON_KERNEL_LIB_ARCH_INCLUDE_LIB_ARCH_X86_CPUID_H_