blob: d8b2a4346affa04810e393bcd3bdea4a0e1dd8ef [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
#include <lib/arch/x86/cpuid.h>
namespace arch {
namespace {
constexpr std::optional<bool> IsFullyAssociative(CpuidL2L3Associativity assoc) {
switch (assoc) {
case CpuidL2L3Associativity::kDisabled:
return std::nullopt;
case CpuidL2L3Associativity::kFullyAssociative:
return true;
default:
return false;
}
}
constexpr size_t ToWays(CpuidL2L3Associativity assoc) {
switch (assoc) {
case CpuidL2L3Associativity::kDisabled:
case CpuidL2L3Associativity::kSeeLeaf0x8000001d:
case CpuidL2L3Associativity::kFullyAssociative:
return 0;
case CpuidL2L3Associativity::kDirectMapped:
return 1;
case CpuidL2L3Associativity::k2Way:
return 2;
case CpuidL2L3Associativity::k3Way:
return 3;
case CpuidL2L3Associativity::k4Way:
return 4;
case CpuidL2L3Associativity::k6Way:
return 6;
case CpuidL2L3Associativity::k8Way:
return 8;
case CpuidL2L3Associativity::k16Way:
return 16;
case CpuidL2L3Associativity::k32Way:
return 32;
case CpuidL2L3Associativity::k48Way:
return 48;
case CpuidL2L3Associativity::k64Way:
return 64;
case CpuidL2L3Associativity::k96Way:
return 96;
case CpuidL2L3Associativity::k128Way:
return 128;
}
return 0;
}
} // namespace
std::string_view ToString(Vendor vendor) {
switch (vendor) {
case Vendor::kUnknown:
return "Unknown";
case Vendor::kIntel:
return "Intel";
case Vendor::kAmd:
return "AMD";
}
__UNREACHABLE;
}
std::string_view ToString(Microarchitecture microarch) {
switch (microarch) {
case Microarchitecture::kUnknown:
return "Unknown";
case Microarchitecture::kIntelCore2:
return "Intel Core 2";
case Microarchitecture::kIntelNehalem:
return "Intel Nehalem";
case Microarchitecture::kIntelWestmere:
return "Intel Westmere";
case Microarchitecture::kIntelSandyBridge:
return "Intel Sandy Bridge";
case Microarchitecture::kIntelIvyBridge:
return "Intel Ivy Bridge";
case Microarchitecture::kIntelBroadwell:
return "Intel Broadwell";
case Microarchitecture::kIntelHaswell:
return "Intel Haswell";
case Microarchitecture::kIntelSkylake:
return "Intel Skylake";
case Microarchitecture::kIntelSkylakeServer:
return "Intel Skylake (server)";
case Microarchitecture::kIntelCannonLake:
return "Intel Cannon Lake";
case Microarchitecture::kIntelIceLake:
return "Intel Ice Lake";
case Microarchitecture::kIntelTigerLake:
return "Intel Tiger Lake";
case Microarchitecture::kIntelAlderLake:
return "Intel Alder Lake";
case Microarchitecture::kIntelRaptorLake:
return "Intel Raptor Lake";
case Microarchitecture::kIntelBonnell:
return "Intel Bonnell";
case Microarchitecture::kIntelSaltwell:
return "Intel Saltwell";
case Microarchitecture::kIntelSilvermont:
return "Intel Silvermont";
case Microarchitecture::kIntelAirmont:
return "Intel Airmont";
case Microarchitecture::kIntelGoldmont:
return "Intel Goldmont";
case Microarchitecture::kIntelGoldmontPlus:
return "Intel Goldmont Plus";
case Microarchitecture::kIntelTremont:
return "Intel Tremont";
case Microarchitecture::kAmdFamilyBulldozer:
return "AMD Bulldozer";
case Microarchitecture::kAmdFamilyJaguar:
return "AMD Jaguar";
case Microarchitecture::kAmdFamilyZen:
return "AMD Zen 1-2";
case Microarchitecture::kAmdFamilyZen3:
return "AMD Zen 3-4";
}
__UNREACHABLE;
}
uint8_t CpuidVersionInfo::family() const {
if (base_family() == 0xf) {
return (static_cast<uint8_t>(base_family() + extended_family()));
}
return static_cast<uint8_t>(base_family());
}
uint8_t CpuidVersionInfo::model() const {
if (base_family() == 0x6 || base_family() == 0xf) {
return (static_cast<uint8_t>(extended_model() << 4)) | static_cast<uint8_t>(base_model());
}
return static_cast<uint8_t>(base_model());
}
// TODO(fxbug.dev/60649): check in a source of truth for this information and
// refer to that here.
Microarchitecture CpuidVersionInfo::microarchitecture(Vendor vendor) const {
switch (vendor) {
case Vendor::kIntel: {
// Table largely from https://en.wikichip.org/wiki/intel/cpuid
switch (family()) {
case 0x6: {
switch (model()) {
// Big cores
case 0x0f: // Merom
case 0x16: // Merom L
case 0x17: // Penryn, Wolfdale, Yorkfield, Harpertown, QC
case 0x1d: // Dunnington
return Microarchitecture::kIntelCore2;
case 0x1a: // Bloomfield, EP, WS
case 0x1e: // Lynnfield, Clarksfield
case 0x1f: // Auburndale, Havendale
case 0x2e: // EX
return Microarchitecture::kIntelNehalem;
case 0x25: // Arrandale, Clarkdale
case 0x2c: // Gulftown, EP
case 0x2f: // EX
return Microarchitecture::kIntelWestmere;
case 0x2a: // M, H
case 0x2d: // E, EN, EP
return Microarchitecture::kIntelSandyBridge;
case 0x3a: // M, H, Gladden
case 0x3e: // E, EN, EP, EX
return Microarchitecture::kIntelIvyBridge;
case 0x3c: // S
case 0x3f: // E, EP, EX
case 0x45: // ULT
case 0x46: // GT3E
return Microarchitecture::kIntelHaswell;
case 0x3d: // U, Y, S
case 0x47: // H, C, W
case 0x56: // DE, Hewitt Lake
case 0x4f: // E, EP, EX
return Microarchitecture::kIntelBroadwell;
case 0x4e: // Skylake Y, U
case 0x5e: // Skylake DT, H, S
case 0x8e: // Kaby Lake Y, U; Coffee Lake U; Whiskey Lake U; Amber Lake Y;
// Comet Lake U
case 0x9e: // Kaby Lake T, H, S, X; Coffee Lake S, H, E
case 0xa5: // Comet Lake S, H
return Microarchitecture::kIntelSkylake;
case 0x55: // Skylake SP, X, DE, W; Cascade Lake SP, X, W; Cooper Lake
return Microarchitecture::kIntelSkylakeServer;
case 0x66: // Cannon Lake U
return Microarchitecture::kIntelCannonLake;
case 0x6a: // Ice Lake Server SP
case 0x6c: // Ice Lake Server DE
case 0x7d: // Ice Lake Y
case 0x7e: // Ice Lake U
return Microarchitecture::kIntelIceLake;
case 0x8c: // Tiger Lake UP
case 0x8d: // Tiger Lake H
return Microarchitecture::kIntelTigerLake;
case 0x97: // Alder Lake S
case 0x9a: // Alder Lake H, P, U
return Microarchitecture::kIntelAlderLake;
case 0xb7: // Raptor Lake S
return Microarchitecture::kIntelRaptorLake;
// Small cores
case 0x1c: // Silverthorne, Diamondville, Pineview
case 0x26: // Lincroft
return Microarchitecture::kIntelBonnell;
case 0x27: // Penwell
case 0x35: // Cloverview
case 0x36: // Cedarview
return Microarchitecture::kIntelSaltwell;
case 0x37: // Bay Trail
case 0x4a: // Tangier
case 0x4d: // Avoton, Rangeley
case 0x5a: // Anniedale
case 0x5d: // SoFIA
return Microarchitecture::kIntelSilvermont;
case 0x4c: // Cherry Trail, Braswell
return Microarchitecture::kIntelAirmont;
case 0x5c: // Apollo Lake, Broxton
case 0x5f: // Denverton
return Microarchitecture::kIntelGoldmont;
case 0x7a: // Gemini Lake
return Microarchitecture::kIntelGoldmontPlus;
case 0x8a: // Lakefield
case 0x96: // Elkhart Lake
case 0x9c: // Jasper Lake
return Microarchitecture::kIntelTremont;
}
return Microarchitecture::kUnknown;
}
}
return Microarchitecture::kUnknown;
}
case Vendor::kAmd: {
// Table largely from https://en.wikichip.org/wiki/amd/cpuid
switch (family()) {
case 0x15: // Bulldozer/Piledriver/Steamroller/Excavator
return Microarchitecture::kAmdFamilyBulldozer;
case 0x16: // Jaguar
return Microarchitecture::kAmdFamilyJaguar;
case 0x17: // Zen 1 - 2
return Microarchitecture::kAmdFamilyZen;
case 0x19: // Zen 3 - 4
return Microarchitecture::kAmdFamilyZen3;
}
return Microarchitecture::kUnknown;
}
case Vendor::kUnknown:
return Microarchitecture::kUnknown;
}
__UNREACHABLE;
}
std::string_view ToString(X86CacheType type) {
switch (type) {
case X86CacheType::kNull:
return "Null";
case X86CacheType::kData:
return "Data";
case X86CacheType::kInstruction:
return "Instruction";
case X86CacheType::kUnified:
return "Unified";
}
return "";
}
std::optional<bool> CpuidL1CacheInformation::fully_associative() const {
switch (assoc()) {
case 0: // Disabled.
return std::nullopt;
case CpuidL1CacheInformation::kFullyAssociative:
return true;
default:
return false;
}
}
size_t CpuidL1CacheInformation::ways_of_associativity() const {
if (assoc() == CpuidL1CacheInformation::kFullyAssociative) {
return 0;
}
return assoc();
}
std::optional<bool> CpuidL2CacheInformation::fully_associative() const {
return IsFullyAssociative(assoc());
}
size_t CpuidL2CacheInformation::ways_of_associativity() const { return ToWays(assoc()); }
std::optional<bool> CpuidL3CacheInformation::fully_associative() const {
return IsFullyAssociative(assoc());
}
size_t CpuidL3CacheInformation::ways_of_associativity() const { return ToWays(assoc()); }
} // namespace arch