Program Listing for File cpuid.hpp

Return to documentation for file (platform/amd64/cpuid.hpp)

/* SPDX-License-Identifier: BSD-2-Clause */
#pragma once
#include <cstdint>
#include <frg/array.hpp>
#include <lib/error.hpp>
#include <lib/result.hpp>

namespace Gaia::Amd64 {

#define CPUID_LEAF_EXTENDED_FEATURES 0x80000001
#define CPUID_PROC_EXTENDED_STATE_ENUMERATION 13

struct Cpuid {
  uint32_t eax;
  uint32_t ebx;
  uint32_t ecx;
  uint32_t edx;

  static inline Result<Cpuid, Error> cpuid(uint32_t leaf = 0,
                                           uint32_t subleaf = 0) {
    uint32_t cpuid_max;

    Cpuid ret;

    asm volatile("cpuid"
                 : "=a"(cpuid_max)
                 : "a"(leaf & 0x80000000)
                 : "rbx", "rcx", "rdx");

    if (leaf > cpuid_max) {
      return Err(Error::INVALID_PARAMETERS);
    }

    asm volatile("cpuid"
                 : "=a"(ret.eax), "=b"(ret.ebx), "=c"(ret.ecx), "=d"(ret.edx)
                 : "a"(leaf), "c"(subleaf));

    return Ok(ret);
  }

  enum class Feature : uint32_t {
    ECX_SSE3 = 1 << 0,
    ECX_PCLMUL = 1 << 1,
    ECX_DTES64 = 1 << 2,
    ECX_MONITOR = 1 << 3,
    ECX_DS_CPL = 1 << 4,
    ECX_VMX = 1 << 5,
    ECX_SMX = 1 << 6,
    ECX_EST = 1 << 7,
    ECX_TM2 = 1 << 8,
    ECX_SSSE3 = 1 << 9,
    ECX_CID = 1 << 10,
    ECX_SDBG = 1 << 11,
    ECX_FMA = 1 << 12,
    ECX_CX16 = 1 << 13,
    ECX_XTPR = 1 << 14,
    ECX_PDCM = 1 << 15,
    ECX_PCID = 1 << 17,
    ECX_DCA = 1 << 18,
    ECX_SSE4_1 = 1 << 19,
    ECX_SSE4_2 = 1 << 20,
    ECX_X2APIC = 1 << 21,
    ECX_MOVBE = 1 << 22,
    ECX_POPCNT = 1 << 23,
    ECX_TSC = 1 << 24,
    ECX_AES = 1 << 25,
    ECX_XSAVE = 1 << 26,
    ECX_OSXSAVE = 1 << 27,
    ECX_AVX = 1 << 28,
    ECX_F16C = 1 << 29,
    ECX_RDRAND = 1 << 30,
    ECX_HYPERVISOR = 1U << 31,
    EDX_FPU = 1 << 0,
    EDX_VME = 1 << 1,
    EDX_DE = 1 << 2,
    EDX_PSE = 1 << 3,
    EDX_TSC = 1 << 4,
    EDX_MSR = 1 << 5,
    EDX_PAE = 1 << 6,
    EDX_MCE = 1 << 7,
    EDX_CX8 = 1 << 8,
    EDX_APIC = 1 << 9,
    EDX_SEP = 1 << 11,
    EDX_MTRR = 1 << 12,
    EDX_PGE = 1 << 13,
    EDX_MCA = 1 << 14,
    EDX_CMOV = 1 << 15,
    EDX_PAT = 1 << 16,
    EDX_PSE36 = 1 << 17,
    EDX_PSN = 1 << 18,
    EDX_CLFLUSH = 1 << 19,
    EDX_DS = 1 << 21,
    EDX_ACPI = 1 << 22,
    EDX_MMX = 1 << 23,
    EDX_FXSR = 1 << 24,
    EDX_SSE = 1 << 25,
    EDX_SSE2 = 1 << 26,
    EDX_SS = 1 << 27,
    EDX_HTT = 1 << 28,
    EDX_TM = 1 << 29,
    EDX_IA64 = 1 << 30,
    EDX_PBE = 1U << 31
  };

  enum class ExFeature : uint32_t {
    FPU = 1 << 0,
    VME = 1 << 1,
    DE = 1 << 2,
    PSE = 1 << 3,
    TSC = 1 << 4,
    MSR = 1 << 5,
    PAE = 1 << 6,
    MCE = 1 << 7,
    CX8 = 1 << 8,
    APIC = 1 << 9,
    SYSCALL = 1 << 11,
    MTRR = 1 << 12,
    PGE = 1 << 13,
    MCA = 1 << 14,
    CMOV = 1 << 15,
    PAT = 1 << 16,
    PSE36 = 1 << 17,
    MP = 1 << 19,
    NX = 1 << 20,
    MMXEXT = 1 << 22,
    MMX = 1 << 23,
    FXSR = 1 << 24,
    FXSR_OPT = 1 << 25,
    PDPE1GB = 1 << 26,
    RDTSCP = 1 << 27,
  };

  static inline bool has_exfeature(ExFeature feat) {
    return cpuid(CPUID_LEAF_EXTENDED_FEATURES, 0).unwrap().edx & (uint32_t)feat;
  }

  static inline bool has_ecx_feature(Feature feat) {
    return cpuid(0x1, 0).unwrap().ecx & (uint32_t)feat;
  }

  static inline bool has_edx_feature(Feature feat) {
    return cpuid(0x1, 0).unwrap().edx & (uint32_t)feat;
  }

  static frg::array<char, 12> _vendor() {
    union {
      frg::array<uint32_t, 3> regs;
      frg::array<char, 12> str;
    } brand{};

    auto ret = cpuid(0).unwrap();

    brand.regs[0] = ret.ebx;
    brand.regs[1] = ret.edx;
    brand.regs[2] = ret.ecx;

    return brand.str;
  }

  static frg::array<char, 48> _brand() {
    union {
      frg::array<Cpuid, 4> ids;
      frg::array<char, 48> str;
    } brand{};

    brand.ids[0] = cpuid(0x80000002).unwrap();
    brand.ids[1] = cpuid(0x80000003).unwrap();
    brand.ids[2] = cpuid(0x80000004).unwrap();
    brand.ids[3] = cpuid(0x80000005).unwrap();

    return brand.str;
  }

  struct Branding {
    frg::string_view vendor, brand;
  };

  static Branding branding() { return {_vendor().data(), _brand().data()}; }
};

} // namespace Gaia::Amd64