[ mackerel2 (options arch) f
| f <- [ "ac97_base_audio",
"ac97_ext_audio",
+ "cpuid_intel",
+ "cpuid_amd",
"ac97_ext_codec",
"ac97_ext_modem",
"ahci_hba",
// EAX=0x04 : Deterministic cache parameters leaf (Intel only)
//
- constants intel_cache_type "Intel cache type field" {
+ constants intel_cachetype "Intel cache type field" {
ct_null = 0 "Null, no more caches";
ct_data = 1 "Data cache";
ct_instruction = 2 "Instruction cache";
space dcpa(i) valuewise "Deterministic cache parameters leaf A";
regarray cache_type ro dcpa(0x00)[4] "Cache type information" {
- ctf 5 type(intel_cache_type) "Cache type";
+ ctf 5 type(intel_cachetype) "Cache type";
level 3 "Cache level (starts at 1)";
self_init 1 "Self initializing";
fully_assoc 1 "Fully associative";
--- /dev/null
+/*
+ * Copyright (c) 2015, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+/*
+ * cpuid_amd.dev
+ *
+ * DESCRIPTION: ia32 CPU ID instruction results
+ *
+ * See
+ * AMD CPUID Specification, Rev. 2.28, Pub.#25481, April 2008
+ */
+
+device cpuid_amd lsbfirst () "ia32 / Intel64 CPUID instruction results" {
+
+ /*
+ *============================================================================
+ * Basic Information.
+ *============================================================================
+ */
+
+ /*
+ * CPUID(0, _)
+ * ---------------------------------------------------------------------------
+ */
+ datatype basic lsbfirst (32) "" {
+ max_cpuid 32 rw "Maximum Input Value for Basic CPUID Information";
+ vendor0 32 rw "Vendor string part 1";
+ vendor2 32 rw "Vendor string part 3";
+ vendor1 32 rw "Vendor string part 2";
+ };
+
+ /*
+ * CPUID(1, _)
+ * ---------------------------------------------------------------------------
+ */
+
+ datatype family lsbfirst(32) "family information in eax register" {
+ stepping 4 rw "Processor Stepping ID";
+ model 4 rw "Processor Model";
+ family 4 rw "Processor Family";
+ _ 4 mbz "Reserved";
+ extmodel 4 rw "Extended Model ID";
+ extfamily 8 rw "Extended Family ID";
+ _ 4 mbz "Reserved";
+ };
+
+ datatype miscinfo lsbfirst(32) "info returned in ebx register" {
+ brand_idx 8 rw "Brand index";
+ cflush_sz 8 rw "CLFLUSH line size (Value * 8 = cache line size in bytes)";
+ max_log_proc 8 rw "LogicalProcessorCount is the number of cores per processor";
+ init_apicid 8 rw "Initial APIC ID";
+ };
+
+ datatype features lsbfirst(32) "features returned in {ecx, edx}" {
+ /* Feature Information (see Figure 3-6 and Table 3-19) */
+ sse3 1 rw "Streaming SIMD Extensions 3 (SSE3). ";
+ pclmulqdq 1 rw "PCLMULQDQ.";
+ dtes64 1 rw "64-bit DS Area";
+ monitor 1 rw "MONITOR/MWAIT";
+ ds_cpl 1 rw "CPL Qualified Debug Store. ";
+ vmx 1 rw "Virtual Machine Extensions";
+ smx 1 rw "Safer Mode Extensions. ";
+ eist 1 rw "Enhanced Intel SpeedStepĀ® technology. ";
+ tm2 1 rw "Thermal Monitor 2";
+ ssse3 1 rw "Supplemental Streaming SIMD Extensions 3 (SSSE3)";
+ cntx_id 1 rw "L1 Context ID. A";
+ sdbg 1 rw "IA32_DEBUG_INTERFACE MSR ";
+ fma 1 rw "FMA extensions using YMM state.";
+ cmpxchg16b 1 rw "CMPXCHG16B Available";
+ xtpr 1 rw "xTPR Update Control";
+ pdcm 1 rw "Perfmon and Debug Capability";
+ _ 1 mbz "";
+ pcid 1 rw "Process-context identifiers";
+ dca 1 rw "ability to prefetch data from a memory mapped device.";
+ sse4_1 1 rw "supports SSE4.1. ";
+ sse4_2 1 rw "supports SSE4.2. ";
+ x2apic 1 rw "supports x2APIC feature";
+ movbe 1 rw "supports MOVBE instruction";
+ popcnt 1 rw "supports the POPCNT instruction.";
+ tsc_one 1 rw "local APIC timer supports one-shot operation ";
+ aesni 1 rw " AESNI instruction extensions";
+ xsave 1 rw " XSAVE/XRSTOR processor ";
+ osxsave 1 rw "OS has set CR4.OSXSAVE[bit 18] to enable XSETBV/XGETBV instruction";
+ avx 1 rw "AVX instruction extensions";
+ f16c 1 rw "16-bit floating-point conversion instructions.";
+ rdrand 1 rw "supports RDRAND instruction.";
+ _ 1 mbz "";
+
+ /* Feature Information (see Figure 3-7 and Table 3-20) */
+ fpu 1 rw "Floating Point Unit On-Chip";
+ vme 1 rw "Virtual 8086 Mode Enhancements";
+ de 1 rw "Debugging Extensions. ";
+ pse 1 rw "Page Size Extension";
+ tsc 1 rw "Time Stamp Counter.";
+ msr 1 rw "Model Specific Registers RDMSR and WRMSR Instructions";
+ pae 1 rw "Physical Address Extension";
+ mce 1 rw "Machine Check Exception. ";
+ cx8 1 rw "CMPXCHG8B Instruction.";
+ apic 1 rw "APIC On-Chip. ";
+ _ 1 mbz "";
+ sep 1 rw "SYSENTER and SYSEXIT Instructions.";
+ mtrr 1 rw "Memory Type Range Registers";
+ pge 1 rw "Page Global Bit";
+ mca 1 rw "Machine Check Architecture.";
+ cmov 1 rw "Conditional Move Instructions";
+ pat 1 rw "Page Attribute Table";
+ pse36 1 rw "36-Bit Page Size Extension";
+ psn 1 rw "Processor Serial Number. ";
+ clfsh 1 rw "CLFLUSH Instruction";
+ _ 1 rw "";
+ ds 1 rw "Debug Store";
+ acpi 1 rw "Thermal Monitor and Software Controlled Clock Facilities";
+ mmx 1 rw "Intel MMX Technology";
+ fxsr 1 rw "FXSAVE and FXRSTOR Instructions";
+ sse 1 rw "SSE1";
+ sse2 1 rw "SSE2";
+ ss 1 rw "Self Snoop";
+ htt 1 rw "Max APIC IDs reserved field is Valid";
+ tm 1 rw "Thermal Monitor";
+ _ 1 mbz "";
+ pbe 1 rw "Pending Break Enable. ";
+ };
+
+ /*
+ * CPUID(0x80000008, _)
+ * ---------------------------------------------------------------------------
+ */
+ datatype addrspace lsbfirst(32) " Long Mode Address Size Identifiers (eax)" {
+ physical 8 rw "Maximum physical byte address size in bits";
+ linear 8 rw "Maximum linear byte address size in bits. ";
+ guest 8 rw " maximum guest physical byte address size in bits";
+ _ 8 mbz "reserved";
+ };
+
+ datatype apicid lsbfirst(32) "APIC ID Size and Core Count (ecx)" {
+ ncores 8 rw "number of physical cores - 1";
+ _ 4 mbz "Reserved";
+ apic_sz 4 rw "APIC ID size";
+ _ 16 mbz "reserved";
+ };
+
+ /*
+ * CPUID(0x80000005, _) L1 Cache and TLB Identifiers
+ * ---------------------------------------------------------------------------
+ */
+ datatype tlb_l1 lsbfirst(32) "" {
+ itlb_sz 8 rw "L2 instruction TLB number of entries for 2/4MB pages ";
+ itlb_assoc 8 rw "L2 instruction TLB associativity for 2/4MB pages ";
+ dtlb_sz 8 rw "L2 data TLB number of entries for 2/4MB pages ";
+ dtlb_assoc 8 rw "L2 data TLB associativity for 2/4MB pages";
+ };
+
+ datatype l1_2m_tlb lsbfirst(32) "Fn8000_0005_EAX L1 Cache and TLB Identifiers" {
+ itlb_sz 8 rw "L2 instruction TLB number of entries for 2/4MB pages ";
+ itlb_assoc 8 rw "L2 instruction TLB associativity for 2/4MB pages ";
+ dtlb_sz 8 rw "L2 data TLB number of entries for 2/4MB pages ";
+ dtlb_assoc 8 rw "L2 data TLB associativity for 2/4MB pages";
+ };
+
+ datatype l1_4k_tlb lsbfirst(32) "Fn8000_0005_EBX L1 Cache and TLB Identifiers" {
+ itlb_sz 8 rw "L2 instruction TLB number of entries for 4 KB pages. ";
+ itlb_assoc 8 rw "L2 instruction TLB associativity for 4 KB pages ";
+ dtlb_sz 8 rw "L2 data TLB number of entries for 4 KB pages ";
+ dtlb_assoc 8 rw "L2 data TLB associativity for 4 KB pages";
+ };
+
+ datatype l1_dcache lsbfirst(32) " Fn8000_0005_ECX L1 Cache and TLB Identifiers" {
+ linesize 8 rw "L1 cache line size in bytes. ";
+ lines_per_tag 8 rw "L1 cache lines per tag. ";
+ assoc 8 rw "L1 cache associativity. See Table 4.";
+ size 8 rw "L1 cache size in KB.";
+ };
+
+ datatype l1_icache lsbfirst(32) "Fn8000_0005_EDX L1 Cache and TLB Identifiers" {
+ linesize 8 rw "L1 cache line size in bytes. ";
+ lines_per_tag 8 rw "L1 cache lines per tag. ";
+ assoc 8 rw "L1 cache associativity. See Table 4.";
+ size 8 rw "L1 cache size in KB.";
+ };
+
+ /*
+ * CPUID(0x80000006, _) TLB and L2/L3 cache information
+ * ---------------------------------------------------------------------------
+ */
+
+ constants cache_assoc "AMD cache associativity values" {
+ cache_assoc_disabled = 0x0 "";
+ cache_assoc_direct = 0x1 "";
+ cache_assoc_2way = 0x2 "";
+ cache_assoc_4way = 0x4 "";
+ cache_assoc_8way = 0x6 "";
+ cache_assoc_16way = 0x8 "";
+ cache_assoc_32way = 0xa "";
+ cache_assoc_48way = 0xb "";
+ cache_assoc_64way = 0xc "";
+ cache_assoc_96way = 0xd "";
+ cache_assoc_128way = 0xe "";
+ cache_assoc_fully = 0xf "";
+ };
+
+ datatype tlb_l2 lsbfirst(32) "Fn8000_0006_EAX L2 TLB Identifiers" {
+ itlb_sz 12 rw "L2 instruction TLB number of entries for 2/4MB pages ";
+ itlb_assoc 4 rw "L2 instruction TLB associativity for 2/4MB pages ";
+ dtlb_sz 12 rw "L2 data TLB number of entries for 2/4MB pages ";
+ dtlb_assoc 4 rw "L2 data TLB associativity for 2/4MB pages";
+ };
+
+ datatype l2_2m_tlb lsbfirst(32) "Fn8000_0006_EAX L2 TLB Identifiers" {
+ itlb_sz 12 rw "L2 instruction TLB number of entries for 2/4MB pages ";
+ itlb_assoc 4 rw "L2 instruction TLB associativity for 2/4MB pages ";
+ dtlb_sz 12 rw "L2 data TLB number of entries for 2/4MB pages ";
+ dtlb_assoc 4 rw "L2 data TLB associativity for 2/4MB pages";
+ };
+
+ datatype l2_4k_tlb lsbfirst(32) " Fn8000_0006_EBX L2 TLB Identifiers" {
+ itlb_sz 12 rw "L2 instruction TLB number of entries for 4 KB pages. ";
+ itlb_assoc 4 rw "L2 instruction TLB associativity for 4 KB pages ";
+ dtlb_sz 12 rw "L2 data TLB number of entries for 4 KB pages ";
+ dtlb_assoc 4 rw "L2 data TLB associativity for 4 KB pages";
+ };
+
+ datatype l2_cache lsbfirst(32) "Fn8000_0006_ECX L2 Cache Identifiers" {
+ linesize 8 rw "L2 cache line size in bytes. ";
+ lines_per_tag 4 rw "L2 cache lines per tag. ";
+ assoc 4 rw "L2 cache associativity. See Table 4.";
+ size 16 rw "L2 cache size in KB.";
+ };
+
+
+ datatype l3_cache lsbfirst(32) "Fn8000_0006_EDX L3 Cache Identifiers" {
+ linesize 8 rw "L3 cache line size in bytes. ";
+ lines_per_tag 4 rw "L3 cache lines per tag. ";
+ assoc 4 rw "L3 cache associativity. See Table 4.";
+ _ 2 mbz "Reserved";
+ size 14 rw "Specifies the L3 cache size in 512kb blocks";
+ };
+
+ /*
+ * CPUID(0x80000019, _) TLB for 1G Pages
+ * ---------------------------------------------------------------------------
+ */
+ datatype tlb_1g_l1 lsbfirst(32) "TLB 1GB Page Identifiers eax" {
+ itlb_sz 12 "L1 instruction TLB number of entries for 1 GB pages";
+ itlb_assoc 4 "L1 instruction TLB associativity for 1 GB pages. See Table 4";
+ dtlb_sz 12 "L1 data TLB number of entries for 1 GB pages";
+ dtlb_assoc 4 "L1 data TLB associativity for 1 GB pages. See Table 4.";
+ };
+
+ datatype tlb_1g_l2 lsbfirst(32) "TLB 1GB Page Identifiers ebx" {
+ itlb_sz 12 "L2 instruction TLB number of entries for 1 GB pages";
+ itlb_assoc 4 "L2 instruction TLB associativity for 1 GB pages. See Table 4";
+ dtlb_sz 12 "L2 data TLB number of entries for 1 GB pages";
+ dtlb_assoc 4 "L2 data TLB associativity for 1 GB pages. See Table 4.";
+ };
+
+ /*
+ * CPUID(0x8000001D, _)
+ * ---------------------------------------------------------------------------
+ */
+ constants cache_type "AMD Cache Type values" {
+ cache_type_null = 0x0 "No more caches";
+ cache_type_data = 0x1 "data cache";
+ cache_type_instr = 0x2 "Instruction Cache";
+ cache_type_unified = 0x3 "Unified Cache";
+ };
+
+ /* EAX */
+ datatype cache_info_eax lsbfirst (32) "" {
+ ctype 5 "Cache Type Field";
+ level 3 "Cache Level (starts at 1)";
+ selfinit 1 "Self Initializing cache level (does not need SW initialization)";
+ fullyassoc 1 "Fully Associative cache";
+ _ 4 "Reserved";
+ num_sharing 12 "number of cores sharing cache - 1";
+ _ 6 "";
+ };
+
+ datatype cache_info_ebx lsbfirst (32) "" {
+ cachelinesize 12 "cache line size in bytes - 1";
+ partitions 10 "cache physical line partitions - 1";
+ assoc 10 "cache number of ways - 1";
+ };
+
+ datatype cache_info_ecx lsbfirst (32) "" {
+ num_sets 32 "The number of Sets - 1";
+ };
+
+ datatype cache_info_edx lsbfirst (32) "" {
+ wb_inv 1 "Write-Back Invalidate/Invalidate";
+ inclusive 1 "Cache Inclusiveness";
+ _ 30 "reserved";
+ };
+
+ /*
+ * CPUID(0x8000001E, _) topology extensions
+ * ---------------------------------------------------------------------------
+ */
+ datatype ext_apic lsbfirst (32) "register eax" {
+ extended_apicid 32 "extended APIC ID";
+ };
+
+ datatype cuid lsbfirst (32) "Fn8000_001E_EBX Compute Unit Identifiers" {
+ cuid 8 "compute unit id";
+ ncores 2 "Number of cores per compute unit - 1";
+ _ 22 "Reserved";
+ };
+
+ datatype nid lsbfirst (32) "Fn8000_001E_ECX Node Identifiers" {
+ nodeid 8 "Specifies the node ID";
+ nnodeds 3 "Number of nodes per processor - 1";
+ _ 21 "Reserved";
+ };
+};
+
+
+
+
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2015, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+/*
+ * cpuid_intel.dev
+ *
+ * DESCRIPTION: ia32 CPU ID instruction results
+ *
+ * See:
+ * Intel Architecture Manual, Volume 2A, pp. 3-163 - ff., April 2015
+ * Table 3-17. Information Returned by CPUID Instruction
+ */
+
+device cpuid_intel lsbfirst () "ia32 / Intel64 CPUID instruction results" {
+
+ /*
+ *============================================================================
+ * Basic Information.
+ *============================================================================
+ */
+
+ /*
+ * CPUID(0, _)
+ * ---------------------------------------------------------------------------
+ */
+ datatype basic0 lsbfirst (32) "" {
+ max_cpuid 32 rw "Maximum Input Value for Basic CPUID Information";
+ vendor0 32 rw "Vendor string part 1";
+ vendor2 32 rw "Vendor string part 3";
+ vendor1 32 rw "Vendor string part 2";
+ };
+
+ /*
+ * CPUID(1, _)
+ * ---------------------------------------------------------------------------
+ */
+ constants proc_type width(2) "" {
+ original = 0x00 "Original OEM Processor";
+ overdrive= 0x01 "Intel OverDriveĀ® Processor";
+ dual = 0x02 "Dual processor (not applicable to Intel486 processors)";
+ reserved = 0x03 "Intel reserved";
+ };
+
+ datatype family lsbfirst(32) "" {
+ /* Version Information: Type, Family, Model, and Stepping ID (see Figure 3-5) */
+
+ stepping 4 rw "Processor Stepping ID";
+ model 4 rw "Processor Model";
+ family 4 rw "Processor Family";
+ proctype 2 rw "Processor Type";
+ _ 2 mbz "Reserved";
+ extmodel 4 rw "Extended Model ID";
+ extfamily 8 rw "Extended Family ID";
+ _ 4 mbz "Reserved";
+ };
+
+ /* EAX=1 */
+
+ datatype miscinfo lsbfirst(32) "" {
+
+ brand_idx 8 rw "Brand index";
+ cflush_sz 8 rw "CLFLUSH line size (Value * 8 = cache line size in bytes)";
+ max_log_proc 8 rw "Maximum number of addressable IDs for logical processors";
+ /*in this physical package.
+ The nearest power-of-2 integer that is not smaller than
+ EBX[23:16] is the number of unique initial APIC IDs
+ reserved for addressing different logical processors in a
+ physical package. */
+ init_apicid 8 rw "Initial APIC ID";
+ };
+
+ datatype features lsbfirst(32) "" {
+ /* Feature Information (see Figure 3-6 and Table 3-19) */
+ sse3 1 rw "Streaming SIMD Extensions 3 (SSE3). ";
+ pclmulqdq 1 rw "PCLMULQDQ.";
+ dtes64 1 rw "64-bit DS Area";
+ monitor 1 rw "MONITOR/MWAIT";
+ ds_cpl 1 rw "CPL Qualified Debug Store. ";
+ vmx 1 rw "Virtual Machine Extensions";
+ smx 1 rw "Safer Mode Extensions. ";
+ eist 1 rw "Enhanced Intel SpeedStepĀ® technology. ";
+ tm2 1 rw "Thermal Monitor 2";
+ ssse3 1 rw "Supplemental Streaming SIMD Extensions 3 (SSSE3)";
+ cntx_id 1 rw "L1 Context ID. A";
+ sdbg 1 rw "IA32_DEBUG_INTERFACE MSR ";
+ fma 1 rw "FMA extensions using YMM state.";
+ cmpxchg16b 1 rw "CMPXCHG16B Available";
+ xtpr 1 rw "xTPR Update Control";
+ pdcm 1 rw "Perfmon and Debug Capability";
+ _ 1 mbz "";
+ pcid 1 rw "Process-context identifiers";
+ dca 1 rw "ability to prefetch data from a memory mapped device.";
+ sse4_1 1 rw "supports SSE4.1. ";
+ sse4_2 1 rw "supports SSE4.2. ";
+ x2apic 1 rw "supports x2APIC feature";
+ movbe 1 rw "supports MOVBE instruction";
+ popcnt 1 rw "supports the POPCNT instruction.";
+ tsc_one 1 rw "local APIC timer supports one-shot operation ";
+ aesni 1 rw " AESNI instruction extensions";
+ xsave 1 rw " XSAVE/XRSTOR processor ";
+ osxsave 1 rw "OS has set CR4.OSXSAVE[bit 18] to enable XSETBV/XGETBV instruction";
+ avx 1 rw "AVX instruction extensions";
+ f16c 1 rw "16-bit floating-point conversion instructions.";
+ rdrand 1 rw "supports RDRAND instruction.";
+ _ 1 mbz "";
+
+ /* Feature Information (see Figure 3-7 and Table 3-20) */
+ fpu 1 rw "Floating Point Unit On-Chip";
+ vme 1 rw "Virtual 8086 Mode Enhancements";
+ de 1 rw "Debugging Extensions. ";
+ pse 1 rw "Page Size Extension";
+ tsc 1 rw "Time Stamp Counter.";
+ msr 1 rw "Model Specific Registers RDMSR and WRMSR Instructions";
+ pae 1 rw "Physical Address Extension";
+ mce 1 rw "Machine Check Exception. ";
+ cx8 1 rw "CMPXCHG8B Instruction.";
+ apic 1 rw "APIC On-Chip. ";
+ _ 1 mbz "";
+ sep 1 rw "SYSENTER and SYSEXIT Instructions.";
+ mtrr 1 rw "Memory Type Range Registers";
+ pge 1 rw "Page Global Bit";
+ mca 1 rw "Machine Check Architecture.";
+ cmov 1 rw "Conditional Move Instructions";
+ pat 1 rw "Page Attribute Table";
+ pse36 1 rw "36-Bit Page Size Extension";
+ psn 1 rw "Processor Serial Number. ";
+ clfsh 1 rw "CLFLUSH Instruction";
+ _ 1 rw "";
+ ds 1 rw "Debug Store";
+ acpi 1 rw "Thermal Monitor and Software Controlled Clock Facilities";
+ mmx 1 rw "Intel MMX Technology";
+ fxsr 1 rw "FXSAVE and FXRSTOR Instructions";
+ sse 1 rw "SSE1";
+ sse2 1 rw "SSE2";
+ ss 1 rw "Self Snoop";
+ htt 1 rw "Max APIC IDs reserved field is Valid";
+ tm 1 rw "Thermal Monitor";
+ _ 1 mbz "";
+ pbe 1 rw "Pending Break Enable. ";
+ };
+
+
+ /* EAX=2 */
+ datatype cache_info lsbfirst (32) "" {
+ d0 8 "ignored, always 0x01";
+ d1 8 "Descriptor 01";
+ d2 8 "Descriptor 02";
+ d3 7 "Descriptor 03";
+ v0 1 "Contains valid descriptors";
+ };
+
+ /* EAX=3 */
+ /* not used post P3 */
+
+ /*
+ *---------------------------------------------------------------------
+ * Deterministic Cache Parameters EAX=4, ECX=idx
+ *---------------------------------------------------------------------
+ */
+
+ constants cache_type "Intel Cache Type values" {
+ cache_type_null = 0x0 "No more caches";
+ cache_type_data = 0x1 "data cache";
+ cache_type_instr = 0x2 "Instruction Cache";
+ cache_type_unified = 0x3 "Unified Cache";
+ };
+
+ /* EAX */
+ datatype cache_info_basic lsbfirst (32) "" {
+ ctype 5 "Cache Type Field";
+ level 3 "Cache Level (starts at 1)";
+ selfinit 1 "Self Initializing cache level (does not need SW initialization)";
+ fullyassoc 1 "Fully Associative cache";
+ _ 4 "Reserved";
+ maxlog 12 "Maximum number of addressable IDs for logical processors sharing this cache - 1";
+ maxphys 6 "Maximum number of addressable IDs for processor cores in the physical package - 1";
+ };
+
+ datatype cache_info_ebx lsbfirst (32) "" {
+ coherency 12 "System Coherency Line Size - 1";
+ partitions 10 "Physical Line partitions - 1";
+ assoc 10 "Ways of associativity - 1";
+ };
+
+ datatype cache_info_ecx lsbfirst (32) "" {
+ num_sets 32 "The number of Sets - 1";
+ };
+
+ datatype cache_info_edx lsbfirst (32) "" {
+ wb_inv 1 "Write-Back Invalidate/Invalidate";
+ inclusive 1 "Cache Inclusiveness";
+ cpx_idx 1 "Complex Cache Indexing";
+ _ 29 "";
+ };
+
+ /*
+ * CPUID(0x16, _) Processor Frequency Information Leaf
+ * ---------------------------------------------------------------------------
+ */
+ datatype frequency lsbfirst (32) "" {
+ mhz 16 "Processor frequency in mhz";
+ _ 16 "Reserved";
+ };
+
+ /*
+ *---------------------------------------------------------------------
+ * Extended Information
+ *---------------------------------------------------------------------
+ */
+
+ /* extended topology enumaration leaf, eax = 0xb */
+ datatype topology_eax lsbfirst (32) "" {
+ x2apic_shift 5 "";
+ _ 27 "";
+ };
+ datatype topology_ebx lsbfirst (32) "" {
+ logical_proc 16 "";
+ _ 16 "";
+ };
+ datatype topology_ecx lsbfirst (32) "" {
+ level_number 8 "";
+ level_type 8 "";
+ _ 16 "";
+ };
+ datatype topology_edx lsbfirst (32) "" {
+ x2apic 32 "";
+ };
+
+ constants topology_level "Intel Cache Type values" {
+ topology_level_invalid = 0x0 "Invalid";
+ topology_level_smt = 0x1 "SMT";
+ topology_level_core = 0x2 "Core";
+ topology_level_package = 0x3 "Package";
+ };
+
+
+ /*
+ * CPUID(0x80000001, _) Extended Function CPUID Informatio
+ * ---------------------------------------------------------------------------
+ */
+ datatype features_ext_edx "" {
+ _ 11 "";
+ syscall 1 "SYSCALL/SYSRET available in 64-bit mode";
+ _ 8 "";
+ nx 1 "Execute Disable Bit available";
+ _ 5 "";
+ page1G 1 "1-GByte pages are available if 1";
+ rdtscp 1 "RDTSCP and IA32_TSC_AUX are available if 1";
+ _ 1 "";
+ lm 1 "Intel 64 Architecture available if 1";
+ _ 2 "";
+ };
+
+
+
+ /*
+ * CPUID(0x80000008, _)
+ * ---------------------------------------------------------------------------
+ */
+ datatype addrspace lsbfirst(32) " Long Mode Address Size Identifiers (eax)" {
+ physical 8 rw "Maximum physical byte address size in bits";
+ linear 8 rw "Maximum linear byte address size in bits. ";
+ _ 16 mbz "reserved";
+ };
+};
+
+
+
+
+
+
+
failure NODEID_INVALID "Invalid node ID",
failure COREID_INVALID "Invalid core ID",
};
+
+errors cpuid CPUID_ERR_ {
+ failure UNSUPPORTED_FUNCTION "This function is not valid on this CPU.",
+ failure UNKNOWN_VENDOR "The CPU vendor is not supported",
+ failure INVALID_INDEX "There is no leaf with this index",
+};
/*
- * Copyright (c) 2007, 2008, 2009, ETH Zurich.
+ * Copyright (c) 2015, ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
*/
#ifndef CPUID_H_
#define CPUID_H_
-#define CPUID(offset, reg) __asm volatile("cpuid" : reg : "a" (offset))
-#include <barrelfish/barrelfish.h>
+/*
+ * ===============================================================================
+ * functions and definitions for accessing the raw cpuid output
+ * ===============================================================================
+ */
-static inline uint32_t cpuid_eax_read_32(cpuid_t *dev, size_t offset)
+///< struct representing the registers used for the cpuid instruction
+struct cpuid_regs
{
- uint32_t eax;
- CPUID(offset, "=a" (eax));
- return eax;
-}
+ uint32_t eax; ///< eax register [in: function, out: return value]
+ uint32_t ebx; ///< ebx register [in: none, out: return value]
+ uint32_t ecx; ///< ecx register [in: argument, out: return value]
+ uint32_t edx; ///< edx register [in: none, out: return value]
+};
+
+///< macro declaration for initializing the cpuid_regs struct
+#define CPUID_REGS_INITIAL(_EAX, _ECX) {_EAX, 0, _ECX, 0}
-static inline uint32_t cpuid_ebx_read_32(cpuid_t *dev, size_t offset)
+
+/**
+ * \brief executes the cpuid instruction and stores the result in the struct
+ *
+ * \param reg cpuid_regs struct to store the result value
+ *
+ * the reg parameter is used to supply the function & argument information and
+ * returning the values
+ */
+static inline void cpuid_exec(struct cpuid_regs *reg)
{
- uint32_t ebx;
- CPUID(offset, "=b" (ebx));
- return ebx;
+ if (reg == NULL) {
+ return;
+ }
+
+ __asm volatile("cpuid"
+ : "=a" (reg->eax), "=b" (reg->ebx),
+ "=c" (reg->ecx), "=d" (reg->edx)
+ : "a" (reg->eax), "c" (reg->ecx)
+ );
}
-static inline uint32_t cpuid_ecx_read_32(cpuid_t *dev, size_t offset)
+
+/*
+ * ===============================================================================
+ * library initialization
+ * ===============================================================================
+ */
+
+/**
+ * \brief initializes the cpuid library to handle vendor specific stuff
+ */
+errval_t cpuid_init(void);
+
+
+/*
+ * ===============================================================================
+ * vendor information
+ * ===============================================================================
+ */
+
+///< vendor string for Intel cpus as stored in {ebx, ecx, edx}
+#define CPUID_VENDOR_STRING_INTEL "GenuntelineI" //"GenuineIntel"
+
+///< vendor string for AMD cpus as stored in {ebx, ecx, edx}
+#define CPUID_VENDOR_STRING_AMD "AuthcAMDenti" //āAuthenticAMDā
+
+///< maximum size of the vendor string
+#define CPUID_VENDOR_STRING_LENGTH (3 * sizeof(uint32_t))
+
+///< type declaration for recognized cpu vendors
+typedef enum cpuid_vendor
{
- uint32_t ecx;
- CPUID(offset, "=c" (ecx));
- return ecx;
-}
+ CPUID_VENDOR_UNKNOWN = 0, ///< the CPU has an unknown vendor
+ CPUID_VENDOR_AMD = 1, ///< the CPU is an AuthenticAMD
+ CPUID_VENDOR_INTEL = 2, ///< the CPU is GenuineIntel
+} cpuid_vendor_t;
+
+/**
+ * \brief reads the CPU vendor string and returns the vendor information
+ *
+ * \return CPU vendor information CPUID_VENDOR_*
+ */
+cpuid_vendor_t cpuid_vendor(void);
+
+/**
+ * \brief returns a string representation of the vendor
+ *
+ * \return string representation of the vendor
+ */
+char *cpuid_vendor_string(void);
-static inline uint32_t cpuid_edx_read_32(cpuid_t *dev, size_t offset)
+/*
+ * ===============================================================================
+ * basic processor information
+ * ===============================================================================
+ */
+
+///< maximum length the processor name can have
+#define CPUID_PROC_NAME_LENGTH (3 * 4 * sizeof(uint32_t))
+
+///< represents the processor family information of the cpu
+struct cpuid_proc_family
{
- uint32_t edx;
- CPUID(offset, "=d" (edx));
- return edx;
-}
+ uint16_t model; ///< processor model
+ uint16_t family; ///< processor family
+ uint8_t stepping; ///< processor stepping
+ uint8_t type; ///< processor type
+};
-static inline uint32_t cpuid_dcpa_read_32(cpuid_t *dev, size_t offset)
+///< processor frequency information
+struct cpuid_freqinfo
{
- return 0;
-}
+ uint16_t base; ///< processor base frequency in MHz
+ uint16_t max; ///< processor maximum frequency in MHz
+ uint16_t bus; ///< bus (reference) frequeny in Mhz
+};
+
+/**
+ * \brief obtains the family information from the CPU
+ *
+ * \param memory to fill in the family information
+ */
+errval_t cpuid_proc_family(struct cpuid_proc_family *fmly);
+
+/**
+ * \brief obtains the processor name
+ *
+ * \param buf buffer where to store the processor name string
+ * \param len length of the buffer
+ */
+errval_t cpuid_proc_name(char *buf, size_t len);
+
+/**
+ * \brief returns the maximum input value for basic CPUID functions
+ *
+ * \return integer representing the maximum input
+ */
+uint32_t cpuid_proc_max_input_basic(void);
+
+/**
+ * \brief returns the maximum input value for extended CPUID functions
+ *
+ * \return integer representing the maximum input
+ */
+uint32_t cpuid_proc_max_input_extended(void);
+
+/**
+ * \brief obtains the processor frequency information
+ *
+ * \param fi returned frequency information
+ *
+ * \returns SYS_ERR_OK on success
+ * CPUID_ERR_*on failure
+ */
+errval_t cpuid_frequency_info(struct cpuid_freqinfo *fi);
+
+/*
+ * ===============================================================================
+ * cache topology information
+ * ===============================================================================
+ */
-static inline uint32_t cpuid_dcpb_read_32(cpuid_t *dev, size_t offset)
+///< enumration of possible cache types
+typedef enum cpuid_cache_type
{
- return 0;
-}
+ CPUID_CACHE_TYPE_INVALID = 0, ///< this cache information is invalid
+ CPUID_CACHE_TYPE_DATA = 1, ///< cache is for data only
+ CPUID_CACHE_TYPE_INSTR = 2, ///< cache is for instructions only
+ CPUID_CACHE_TYPE_UNIFIED = 3, ///< cache is unified data & instr
+} cpuid_cachetype_t;
-static inline uint32_t cpuid_dcpc_read_32(cpuid_t *dev, size_t offset)
+///< cache information obtained from the cpu
+struct cpuid_cacheinfo
{
- return 0;
-}
+ cpuid_cachetype_t type; ///< the type of the cache
+ char *name; ///< readable representation of the name
+ size_t size; ///< size of the entire cache in bytes
+ uint16_t linesize; ///< size of a cache line
+ uint16_t associativity; ///< associativity information
+ uint32_t sets; ///< number of sets
+ uint8_t level; ///< level
+ uint8_t shared; ///< number of cores sharing that cache
+ uint8_t inclusive; ///< chached data is inclusive
+};
+
+/**
+ * \brief calculates the cache line size
+ *
+ * \returns the cacheline size of the core in bytes
+ */
+uint16_t cpuid_system_coherency_size(void);
+
+/**
+ * \brief obtains cache parameters for a given index
+ *
+ * \param ci memory to be filled in with information
+ * \param idx index of the cache to obtain information for
+ *
+ * \return SYS_ERR_OK on success
+ * CPUID_ERR_NO_SUCH_INDEX if there is no cache associated with the index
+ */
+errval_t cpuid_cache_info(struct cpuid_cacheinfo *ci, uint32_t idx);
+
+/**
+ * \brief returns a string representation of the cache type
+ *
+ * \param ct type of the cache
+ *
+ * \return cache name string
+ */
+char *cpuid_cache_type_string(cpuid_cachetype_t ct);
+
+
+/*
+ * ===============================================================================
+ * TLB information
+ * ===============================================================================
+ */
+///< tlb information structure
+struct cpuid_tlbinfo
+{
+ cpuid_cachetype_t type; ///< type of this tlb
+ uint32_t pagesize; ///< page size
+ uint32_t entries; ///< number of entries
+ uint32_t associativity; ///< associativity
+ uint8_t level; ///< level
+};
+
+/**
+ * \brief obtains the TLB topology information
+ *
+ * \param ti tlb info structure to be filled in
+ * \param idx index of the TLB
+ *
+ * \returns SYS_ERR_OK on success
+ * CPUID_ERR_* on failure
+ */
+errval_t cpuid_tlb_info(struct cpuid_tlbinfo *ti, uint32_t idx);
+
+/*
+ * ===============================================================================
+ * thread and topology information
+ * ===============================================================================
+ */
+
+///< topology information this thread belongs to
+struct cpuid_threadinfo
+{
+ coreid_t package; ///< id of the package / socket
+ coreid_t core; ///< the core id relative to the socket
+ coreid_t hyperthread; ///< the thread id relative to the core
+};
+
+///< topology hierarchy information structure
+struct cpuid_topologyinfo
+{
+ int x2apic;
+ int nextshift;
+};
+
+/**
+ * \brief obtains the topology information for a given thread
+ *
+ * \param ti returns the thread information
+ *
+ * \return SYS_ERR_OK on success
+ * CPUID_ERR_* on failure
+ */
+errval_t cpuid_thread_info(struct cpuid_threadinfo *ti);
+
+/**
+ * \brief obtains topology information from the CPU
+ *
+ * \param topo pointer to store the information
+ * \param idx topology level index
+ *
+ * \return SYS_ERR_OK on success
+ * CPUID_ERR_* on failure
+ */
+errval_t cpuid_topology_info(struct cpuid_topologyinfo *topo, uint8_t idx);
+
+/*
+ * ===============================================================================
+ * feature information
+ * ===============================================================================
+ */
+
+struct cpuid_featureinfo
+{
+ /* CPU features */
+ uint32_t lm : 1; ///< CU supports long mode
+ uint32_t htt : 1; ///< CPU has hyper-threading technology
+ uint32_t apic : 1; ///< CPU has an APIC and it is enabled
+ uint32_t x2apic : 1; ///< CPU support x2APIC feature
+ uint32_t tsc : 1; ///< CPU has RDTSC and RDTSCP instruction support
+ uint32_t dca : 1; ///< CPU supports direct cache access
+ /* instructions */
+ uint32_t monitor : 1; ///< CPU has monitor/mwait instructions
+ uint32_t cmov : 1; ///< CPU supports conditional move instructions
+
+ /* virtual memory */
+ uint32_t pse36 : 1; ///< CPU has page-size extensions
+ uint32_t pse : 1; ///< CPU has page-size extensions
+ uint32_t pae : 1; ///< CPU supports physical address extensions
+ uint32_t pat : 1; ///< CPU has page attribute table
+ uint32_t pge : 1; ///< CPU has page global extension
+ uint32_t mtrr : 1; ///< CPU has memory-type range registrs
+ uint32_t page1G : 1; ///< CPU supports huge-pages
+ uint32_t page2M : 1;
+ uint32_t nx : 1; ///< CPU supports no-execute bit
+
+ /* cache control */
+ uint32_t clsh : 1;
+ uint32_t cnxt_id : 1; ///< L1 context ID
+
+ /* virtualization technology */
+ uint32_t vmx : 1; ///< CPU has virtual machine extensions
+ uint32_t vme : 1; ///< CPU has virtual machine enhancemente
+ uint32_t svm : 1; ///< secure virtual machine support
+
+ /* vector instructions */
+ uint32_t mmx : 1; ///< CPU has MMX support
+ uint32_t sse : 1; ///< CPU has SSE support
+ uint32_t sse2 : 1; ///< CPU has SSE2 support
+ uint32_t sse3 : 1; ///< CPU has SSE3 support
+ uint32_t sse41 : 1; ///< CPU has SSE4.1 support
+ uint32_t sse42 : 1; ///< CPU has SSE4.1 support
+ uint32_t avx : 1; ///< CPU has AVX support
+};
+
+/**
+ * \brief obtains the CPU's feature information
+ *
+ * \param fi structure to be filled in
+ *
+ * \return SYS_ERR_OK on success
+ * CPUID_ERR_* on failure
+ */
+errval_t cpuid_feature_info(struct cpuid_featureinfo *fi);
+
+/*
+ * ===============================================================================
+ * address space information
+ * ===============================================================================
+ */
+
+///< address space size information
+struct cpuid_adressspaceinfo
+{
+ uint8_t physical; ///< Maximum physical byte address size in bits
+ uint8_t virtual; ///< Maximum linear byte address size in bits
+ uint8_t guest_physical; ///< maximum guest physical byte address size in bits
+};
+
+/**
+ * \brief obtains the address space size information of the CPU
+ *
+ * \param ai struct to be filled in with adderss space information
+ *
+ * \returns SYS_ERR_OK on susccess
+ * CPUID_ERR_* on failure
+ */
+errval_t cpuid_address_space_info(struct cpuid_adressspaceinfo *ai);
+
#endif // CPUID_H_
#ifndef CPUID_SPACES_H
#define CPUID_SPACES_H
+#define CPUID(offset, reg) __asm volatile("cpuid" : reg : "a" (offset))
-static inline uint32_t cpuid_eax_read_32(cpuid_t *dev, size_t offset);
-//static inline void cpuid_eax_write_32(cpuid_t *dev, size_t offset,
-// uint32_t value);
+#include <barrelfish/barrelfish.h>
-static inline uint32_t cpuid_ebx_read_32(cpuid_t *dev, size_t offset);
-//static inline void cpuid_ebx_write_32(cpuid_t *dev, size_t offset,
-// uint32_t value);
+static inline uint32_t cpuid_eax_read_32(cpuid_t *dev, size_t offset)
+{
+ uint32_t eax;
+ CPUID(offset, "=a" (eax));
+ return eax;
+}
-static inline uint32_t cpuid_ecx_read_32(cpuid_t *dev, size_t offset);
-//static inline void cpuid_ecx_write_32(cpuid_t *dev, size_t offset,
-// uint32_t value);
+static inline uint32_t cpuid_ebx_read_32(cpuid_t *dev, size_t offset)
+{
+ uint32_t ebx;
+ CPUID(offset, "=b" (ebx));
+ return ebx;
+}
-static inline uint32_t cpuid_edx_read_32(cpuid_t *dev, size_t offset);
-//static inline void cpuid_edx_write_32(cpuid_t *dev, size_t offset,
-// uint32_t value);
+static inline uint32_t cpuid_ecx_read_32(cpuid_t *dev, size_t offset)
+{
+ uint32_t ecx;
+ CPUID(offset, "=c" (ecx));
+ return ecx;
+}
-static inline uint32_t cpuid_dcpa_read_32(cpuid_t *dev, size_t offset);
-//static inline void cpuid_dcpa_write_32(cpuid_t *dev, size_t offset,
-// uint32_t value);
+static inline uint32_t cpuid_edx_read_32(cpuid_t *dev, size_t offset)
+{
+ uint32_t edx;
+ CPUID(offset, "=d" (edx));
+ return edx;
+}
-static inline uint32_t cpuid_dcpb_read_32(cpuid_t *dev, size_t offset);
-//static inline void cpuid_dcpb_write_32(cpuid_t *dev, size_t offset,
-// uint32_t value);
+static inline uint32_t cpuid_dcpa_read_32(cpuid_t *dev, size_t offset)
+{
+ return 0;
+}
+
+static inline uint32_t cpuid_dcpb_read_32(cpuid_t *dev, size_t offset)
+{
+ return 0;
+}
-static inline uint32_t cpuid_dcpc_read_32(cpuid_t *dev, size_t offset);
-//static inline void cpuid_dcpc_write_32(cpuid_t *dev, size_t offset,
+static inline uint32_t cpuid_dcpc_read_32(cpuid_t *dev, size_t offset)
+{
+ return 0;
+}
// uint32_t value);
#endif // CPUID_SPACES_H
--- /dev/null
+--------------------------------------------------------------------------
+-- Copyright (c) 2007-2009, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for lib/cpuid
+--
+--------------------------------------------------------------------------
+
+[ build library {
+ target = "cpuid",
+ cFiles = [
+ "cpuid_generic.c",
+ "cpuid_amd.c",
+ "cpuid_intel.c"
+ ],
+ mackerelDevices = [
+ "cpuid_intel",
+ "cpuid_amd"
+ ]
+ }
+]
--- /dev/null
+/*
+ * Copyright (c) 2015 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <cpuid_internal.h>
+
+#include <dev/cpuid_amd_dev.h>
+/*
+ * ===============================================================================
+ * helpers
+ * ===============================================================================
+ */
+
+static uint16_t lookup_cache_assoc(uint8_t key)
+{
+ switch (key) {
+ case cpuid_amd_cache_assoc_disabled:
+ return 0;
+ case cpuid_amd_cache_assoc_direct:
+ return 1;
+ case cpuid_amd_cache_assoc_2way:
+ return 2;
+ case cpuid_amd_cache_assoc_4way:
+ return 4;
+ case cpuid_amd_cache_assoc_8way:
+ return 8;
+ case cpuid_amd_cache_assoc_16way:
+ return 16;
+ case cpuid_amd_cache_assoc_32way:
+ return 32;
+ case cpuid_amd_cache_assoc_48way:
+ return 48;
+ case cpuid_amd_cache_assoc_64way:
+ return 64;
+ case cpuid_amd_cache_assoc_96way:
+ return 96;
+ case cpuid_amd_cache_assoc_128way :
+ return 128;
+ case cpuid_amd_cache_assoc_fully :
+ return 0xff;
+ }
+ return 0;
+}
+
+/*
+ * ===============================================================================
+ * basic processor information
+ * ===============================================================================
+ */
+
+static errval_t proc_name(char *buf, size_t len)
+{
+ // check if this operation is supported
+ if (cpuid_g_max_input_extended < 4) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ size_t written;
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0x80000002, 0);
+ cpuid_exec(®);
+ written = snprintf(buf, len, "%s", (char *)®.eax);
+ len -= written;
+ buf += written;
+
+ reg.eax = 0x80000003;
+ reg.ecx = 0x0;
+ cpuid_exec(®);
+ written = snprintf(buf, len, "%s", (char *)®.eax);
+ len -= written;
+ buf += written;
+
+ reg.eax = 0x80000004;
+ reg.ecx = 0x0;
+ cpuid_exec(®);
+ written = snprintf(buf, len, "%s", (char *)®.eax);
+ len -= written;
+ buf += written;
+
+ return SYS_ERR_OK;
+}
+
+static errval_t proc_family(struct cpuid_proc_family *family)
+{
+ if (cpuid_g_max_input_basic < 1) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(1, 0);
+ cpuid_exec(®);
+
+ cpuid_amd_family_t f = (cpuid_amd_family_t)®.eax;
+
+ family->stepping = cpuid_amd_family_stepping_extract(f);
+ family->family = cpuid_amd_family_family_extract(f);
+ family->model = cpuid_amd_family_model_extract(f);
+ // amd has no proc type
+ family->type = 0x0;
+
+ if (family->family == 0x0f) {
+ uint16_t model = cpuid_amd_family_extmodel_extract(f);
+ family->model += (model << 4);
+ }
+
+ /* if family is zero we have to consider the extended family id */
+ if (family->family != 0x0f) {
+ family->family += cpuid_amd_family_extfamily_extract(f);
+ }
+
+ return SYS_ERR_OK;
+}
+
+static uint32_t proc_max_input_basic(void)
+{
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0, 0);
+ cpuid_exec(®);
+
+ return reg.eax;
+}
+
+static uint32_t proc_max_input_extended(void)
+{
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0x80000000, 0);
+ cpuid_exec(®);
+
+ return reg.eax;
+}
+
+static errval_t frequency_info(struct cpuid_freqinfo *fi)
+{
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+}
+
+/*
+ * ===============================================================================
+ * cache topology information
+ * ===============================================================================
+ */
+
+static errval_t cache_info_alternate(struct cpuid_cacheinfo *ci, uint32_t idx)
+{
+ if (CPUID_EXTENDED_INPUT_MASK(cpuid_g_max_input_extended) < 0x6) {
+ CPUID_PRINTF("amd_cache_info not supported. max fnct= %x\n",
+ cpuid_g_max_input_extended);
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ if (idx >= 4) {
+ return CPUID_ERR_INVALID_INDEX;
+ }
+
+
+ uint32_t fn = 0x80000006;
+ if (idx < 2) {
+ fn = 0x80000005;
+ }
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(fn, 0);
+ cpuid_exec(®);
+
+ switch(idx) {
+ case 0:;
+ cpuid_amd_l1_dcache_t l1d = (cpuid_amd_l1_dcache_t)®.ecx;
+ ci->associativity = cpuid_amd_l1_dcache_assoc_extract(l1d);
+ ci->size = cpuid_amd_l1_dcache_size_extract(l1d) * 1024;
+ ci->linesize = cpuid_amd_l1_dcache_linesize_extract(l1d);
+ ci->level = 1;
+ ci->shared = 1;
+ ci->type = CPUID_CACHE_TYPE_DATA;
+ break;
+ case 1:;
+ cpuid_amd_l1_icache_t l1i = (cpuid_amd_l1_icache_t)®.edx;
+ ci->associativity = cpuid_amd_l1_icache_assoc_extract(l1i);
+ ci->size = cpuid_amd_l1_icache_size_extract(l1i) * 1024;
+ ci->linesize = cpuid_amd_l1_icache_linesize_extract(l1i);
+ ci->level = 1;
+ /* TODO: get the number of cores sharing that cache */
+ ci->shared = 1;
+ ci->type = CPUID_CACHE_TYPE_INSTR;
+ break;
+ case 2:;
+ cpuid_amd_l2_cache_t l2 = (cpuid_amd_l2_cache_t)®.ecx;
+ ci->associativity = lookup_cache_assoc(cpuid_amd_l2_cache_assoc_extract(l2));
+ assert(cpuid_amd_l2_cache_assoc_extract(l2));
+ assert(ci->associativity);
+ ci->size = cpuid_amd_l2_cache_size_extract(l2) * 1024;
+ ci->linesize = cpuid_amd_l2_cache_linesize_extract(l2);
+ ci->level = 2;
+ /* TODO: get the number of cores sharing that cache */
+ ci->shared = 1;
+ ci->type = CPUID_CACHE_TYPE_UNIFIED;
+ break;
+ case 3:;
+ /*
+ * This provides the processorās third level cache characteristics
+ * shared by all cores
+ */
+ cpuid_amd_l3_cache_t l3 = (cpuid_amd_l3_cache_t)®.edx;
+ ci->associativity = lookup_cache_assoc(cpuid_amd_l3_cache_assoc_extract(l3));
+ ci->size = cpuid_amd_l3_cache_size_extract(l3) * 512 * 1024;
+ ci->linesize = cpuid_amd_l3_cache_linesize_extract(l3);
+ ci->level = 3;
+ /* TODO: get the number of cores sharing that cache */
+ ci->shared = 1;
+ ci->type = CPUID_CACHE_TYPE_UNIFIED;
+ break;
+ default :
+ return CPUID_ERR_INVALID_INDEX;
+ }
+ if (ci->size == 0 || ci->associativity == 0 || ci->linesize == 0) {
+ /* no size, associativity indicates invalid / disabled cache */
+ return CPUID_ERR_INVALID_INDEX;
+ }
+
+ ci->inclusive = 1;
+ ci->sets = (ci->size / ci->linesize) / ci->associativity;
+ /* TODO: get the number of cores sharing that cache */
+ ci->shared = 1;
+ ci->name = cpuid_cache_names[ci->level][ci->type];
+
+ return SYS_ERR_OK;
+}
+
+static errval_t cache_info(struct cpuid_cacheinfo *ci, uint32_t idx)
+{
+ if (CPUID_EXTENDED_INPUT_MASK(cpuid_g_max_input_extended) < 0x1d) {
+ return cache_info_alternate(ci, idx);
+ }
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0x8000001d, idx);
+ cpuid_exec(®);
+
+ cpuid_amd_cache_info_eax_t ci_a = (cpuid_amd_cache_info_eax_t) ®.eax;
+ cpuid_amd_cache_info_ebx_t ci_b = (cpuid_amd_cache_info_ebx_t) ®.ebx;
+
+ ci->level = cpuid_amd_cache_info_eax_level_extract(ci_a);
+
+ switch (cpuid_amd_cache_info_eax_ctype_extract(ci_a)) {
+ case cpuid_amd_cache_type_data :
+ /* data cache */
+ ci->type = CPUID_CACHE_TYPE_DATA;
+ break;
+ case cpuid_amd_cache_type_instr :
+ /* instruction cache */
+ ci->type = CPUID_CACHE_TYPE_INSTR;
+ break;
+ case cpuid_amd_cache_type_unified :
+ ci->type = CPUID_CACHE_TYPE_UNIFIED;
+ /* unified cache */
+ break;
+ default:
+ /* no more cache */
+ ci->type = CPUID_CACHE_TYPE_INVALID;
+ return CPUID_ERR_INVALID_INDEX;
+ break;
+ }
+
+ ci->name = cpuid_cache_names[ci->level][ci->type];
+ ci->linesize = cpuid_amd_cache_info_ebx_cachelinesize_extract(ci_b)+1;
+
+ /* the the number of sets */
+ ci->sets = reg.ecx + 1;
+
+ if (cpuid_amd_cache_info_eax_fullyassoc_extract(ci_a)) {
+ ci->size = (size_t)ci->linesize * ci->sets;
+ ci->associativity = 0xff;
+ } else {
+ ci->associativity = cpuid_amd_cache_info_ebx_assoc_extract(ci_b)+1;
+ ci->size = (size_t)ci->linesize * ci->sets * ci->associativity;
+ }
+
+ ci->shared = cpuid_amd_cache_info_eax_num_sharing_extract(ci_a) +1;
+
+ cpuid_amd_cache_info_edx_t ci_d = (cpuid_amd_cache_info_edx_t) ®.edx;
+ ci->inclusive = cpuid_amd_cache_info_edx_inclusive_extract(ci_d);
+
+ return SYS_ERR_OK;
+}
+
+static uint16_t cache_line_size(void)
+{
+ if (cpuid_g_max_input_basic < 1) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(1, 0);
+ cpuid_exec(®);
+
+ cpuid_amd_miscinfo_t mi = (cpuid_amd_miscinfo_t)®.ebx;
+
+ return cpuid_amd_miscinfo_cflush_sz_extract(mi) * 8;
+}
+
+/*
+ * ===============================================================================
+ * TLB information
+ * ===============================================================================
+ */
+
+static errval_t tlb_info(struct cpuid_tlbinfo *ti, uint32_t idx)
+{
+ if (CPUID_EXTENDED_INPUT_MASK(cpuid_g_max_input_extended) < 0x5) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0x80000005, 0);
+ ti->pagesize = 0;
+ if (idx < 4) {
+ /* level 1 tlb 4k/2m pages */
+ ti->level = 1;
+ reg.eax = 0x80000005;
+ cpuid_exec(®);
+ cpuid_amd_tlb_l1_t tlb;
+ if (idx < 2) {
+ tlb = (cpuid_amd_tlb_l1_t)®.eax;
+ ti->pagesize = LARGE_PAGE_SIZE;
+ } else {
+ tlb = (cpuid_amd_tlb_l1_t)®.ebx;
+ ti->pagesize = BASE_PAGE_SIZE;
+ }
+ if (idx & 0x1) {
+ ti->type = CPUID_CACHE_TYPE_DATA;
+ ti->associativity = cpuid_amd_tlb_l1_dtlb_assoc_extract(tlb);
+ ti->entries = cpuid_amd_tlb_l1_dtlb_sz_extract(tlb);
+ } else {
+ ti->type = CPUID_CACHE_TYPE_INSTR;
+ ti->associativity = cpuid_amd_tlb_l1_itlb_assoc_extract(tlb);
+ ti->entries = cpuid_amd_tlb_l1_itlb_sz_extract(tlb);
+ }
+ return SYS_ERR_OK;
+ } else if (idx < 8) {
+ /* level 2 tlb 4k/2m pages */
+ if (CPUID_EXTENDED_INPUT_MASK(cpuid_g_max_input_extended) < 0x6) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+ idx -= 4;
+ ti->level = 2;
+ ti->pagesize = (idx < 2) ? LARGE_PAGE_SIZE : BASE_PAGE_SIZE;
+ reg.eax = 0x80000006;
+
+ } else if (idx < 12){
+ /* huge pages */
+ if (CPUID_EXTENDED_INPUT_MASK(cpuid_g_max_input_extended) < 0x19) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+ idx -= 8;
+ if (idx < 2) {
+ ti->level = 1;
+ } else {
+ ti->level = 2;
+ }
+ ti->pagesize = HUGE_PAGE_SIZE;
+ reg.eax = 0x80000019;
+ } else {
+ return CPUID_ERR_INVALID_INDEX;
+ }
+
+ cpuid_exec(®);
+ cpuid_amd_tlb_l1_t tlb2;
+ if (idx < 2) {
+ tlb2 = (cpuid_amd_tlb_l1_t)®.eax;
+ } else {
+ tlb2 = (cpuid_amd_tlb_l1_t)®.ebx;
+ }
+
+ if (idx & 0x1) {
+ ti->type = CPUID_CACHE_TYPE_DATA;
+ ti->associativity = cpuid_amd_tlb_l2_dtlb_assoc_extract(tlb2);
+ ti->entries = cpuid_amd_tlb_l2_dtlb_sz_extract(tlb2);
+ } else {
+ ti->type = CPUID_CACHE_TYPE_INSTR;
+ ti->associativity = cpuid_amd_tlb_l2_itlb_assoc_extract(tlb2);
+ ti->entries = cpuid_amd_tlb_l2_itlb_sz_extract(tlb2);
+ }
+ ti->associativity = lookup_cache_assoc(ti->associativity);
+
+ return SYS_ERR_OK;
+}
+
+/*
+ * ===============================================================================
+ * thread and topology information
+ * ===============================================================================
+ */
+
+static errval_t thread_info(struct cpuid_threadinfo *ti)
+{
+ if (cpuid_g_max_input_basic < 1) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0x01, 0);
+ cpuid_exec(®);
+
+ cpuid_amd_miscinfo_t mi = (cpuid_amd_miscinfo_t)®.ebx;
+
+ uint8_t local_apic_id = cpuid_amd_miscinfo_init_apicid_extract(mi);
+ uint8_t logical_processors = cpuid_amd_miscinfo_max_log_proc_extract(mi);
+
+ if (!((reg.edx >> 28) & 0x1)) {
+ /* TODO: then the following is not valid */
+ ti->core = 0;
+ ti->hyperthread = 0;
+ ti->package = local_apic_id;
+ return SYS_ERR_OK;
+ }
+
+ if (CPUID_EXTENDED_INPUT_MASK(cpuid_g_max_input_extended) < 8) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ reg.eax = 0x80000008;
+ reg.ecx = 0x0;
+ cpuid_exec(®);
+
+ cpuid_amd_apicid_t ac = (cpuid_amd_apicid_t)®.ecx;
+
+ uint8_t mnc;
+ uint8_t ApicIdCoreIdSize = cpuid_amd_apicid_apic_sz_extract(ac);
+ uint8_t nc = cpuid_amd_apicid_ncores_extract(ac);
+ if (ApicIdCoreIdSize == 0) {
+ // Used by legacy dual-core/single-core processors
+ mnc = nc + 1;
+ } else {
+ // use ApicIdCoreIdSize[3:0] field
+ mnc = 1 << ApicIdCoreIdSize;
+ }
+
+ //XXX: not sure about these calculations.
+ // uint8_t hyperthreads = logical_processors / nc;
+ uint8_t ht = logical_processors / mnc;
+ uint8_t ht_shift = cpuid_bits_needed(ht - 1);
+ uint8_t ht_mask = (1 << ht_shift) - 1;
+ uint8_t core_shift = cpuid_bits_needed(mnc - 1);
+ uint8_t core_mask = (1 << core_shift) - 1;
+
+ ti->core = (local_apic_id >> (ht_shift)) & core_mask;
+ ti->package = local_apic_id >> (ht_shift + core_shift);
+ ti->hyperthread = local_apic_id & ht_mask;
+
+ return SYS_ERR_OK;
+}
+
+static errval_t topology_info(struct cpuid_topologyinfo *topo, uint8_t idx)
+{
+ return 1;
+ return SYS_ERR_OK;
+}
+
+static errval_t feature_info(struct cpuid_featureinfo *fi)
+{
+ USER_PANIC("NYI");
+ return SYS_ERR_OK;
+}
+
+static errval_t address_space_info(struct cpuid_adressspaceinfo *ai)
+{
+ if (CPUID_EXTENDED_INPUT_MASK(cpuid_g_max_input_extended) < 0x8) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0x80000008, 0);
+ cpuid_exec(®);
+
+ cpuid_amd_addrspace_t as = (cpuid_amd_addrspace_t)®.eax;
+
+ ai->physical = cpuid_amd_addrspace_physical_extract(as);
+ ai->virtual = cpuid_amd_addrspace_linear_extract(as);
+ ai->guest_physical = cpuid_amd_addrspace_guest_extract(as);
+ if (ai->guest_physical == 0) {
+ ai->guest_physical = ai->physical;
+ }
+
+ return SYS_ERR_OK;
+}
+
+/*
+ * ===============================================================================
+ * backend initialization
+ * ===============================================================================
+ */
+
+/**
+ * \brief fills the vendor specific handler functions
+ *
+ * \param fn_tab function pointer table to be filled
+ */
+void cpuid_amd_set_handlers(struct cpuid_functions *fn_tab)
+{
+ fn_tab->proc_name = proc_name;
+ fn_tab->proc_family = proc_family;
+ fn_tab->proc_max_input_basic = proc_max_input_basic;
+ fn_tab->proc_max_input_extended = proc_max_input_extended;
+ fn_tab->frequency_info = frequency_info;
+
+ fn_tab->cache_info = cache_info;
+ fn_tab->cache_line_size = cache_line_size;
+
+ fn_tab->tlb_info = tlb_info;
+
+ fn_tab->thread_info = thread_info;
+ fn_tab->topology_info = topology_info;
+
+ fn_tab->feature_info = feature_info;
+
+ fn_tab->address_space_info = address_space_info;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef LIBCPUID_AMD_H_
+#define LIBCPUID_AMD_H_ 1
+
+#include <string.h>
+
+/**
+ * \brief verifies the CPU
+ *
+ * \returns TRUE if its a Intel CPU
+ * FALSE otherwise
+ */
+static inline bool cpuid_amd_check_vendor(void)
+{
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0, 0);
+ cpuid_exec(®);
+
+ return (strncmp((char *)®.ebx, CPUID_VENDOR_STRING_AMD, 12) == 0);
+}
+
+/**
+ * \brief fills the vendor specific handler functions
+ *
+ * \param fn_tab function pointer table to be filled
+ */
+void cpuid_amd_set_handlers(struct cpuid_functions *fn_tab);
+
+#endif /* CPUID_INTERNAL_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <cpuid_internal.h>
+
+/*
+ * ===============================================================================
+ * library internal, global variables
+ * ===============================================================================
+ */
+
+///< maximum input value for basic CPUID information
+uint32_t cpuid_g_max_input_basic = 0;
+
+///< maximum input value for extended CPUID information
+uint32_t cpuid_g_max_input_extended = 0;
+
+///< the vendor of the core this code is executed
+cpuid_vendor_t cpuid_g_vendor = CPUID_VENDOR_UNKNOWN;
+
+///< function pointer table for vendor specific handlers
+struct cpuid_functions cpuid_fn;
+
+///< cpu cache names in readable representation
+char *cpuid_cache_names[4][4] = {
+ {""},
+ {"", "l1i","l1d","l1"},
+ {"", "l2i","l2d","l2"},
+ {"", "l3i","l3d","l3"}
+};
+
+/*
+ * ===============================================================================
+ * library initialization
+ * ===============================================================================
+ */
+
+/**
+ * \brief initializes the cpuid library to handle vendor specific stuff
+ */
+errval_t cpuid_init(void)
+{
+ cpuid_g_vendor = cpuid_vendor();
+
+ assert(cpuid_fn.proc_max_input_basic);
+ cpuid_g_max_input_basic = cpuid_fn.proc_max_input_basic();
+ cpuid_g_max_input_extended = cpuid_fn.proc_max_input_extended();
+
+ CPUID_PRINTF("initializing for %s CPU. Max input = [0x%08" PRIx32 " / 0x%08"
+ PRIx32"]\n", cpuid_vendor_string(), cpuid_g_max_input_basic,
+ cpuid_g_max_input_extended);
+
+ return SYS_ERR_OK;
+}
+
+
+/*
+ * ===============================================================================
+ * vendor information
+ * ===============================================================================
+ */
+
+/**
+ * \brief reads the CPU vendor string and returns the vendor information
+ *
+ * \return CPU vendor information CPUID_VENDOR_*
+ *
+ * This function also updates the function table pointer based on the read values
+ */
+cpuid_vendor_t cpuid_vendor(void)
+{
+ if (cpuid_intel_check_vendor()) {
+ cpuid_intel_set_handlers(&cpuid_fn);
+ return CPUID_VENDOR_INTEL;
+ } else if (cpuid_amd_check_vendor()) {
+ cpuid_amd_set_handlers(&cpuid_fn);
+ return CPUID_VENDOR_AMD;
+ }
+ return CPUID_VENDOR_UNKNOWN;
+}
+
+/**
+ * \brief returns a string representation of the vendor
+ *
+ * \return string representation of the vendor
+ */
+char *cpuid_vendor_string(void)
+{
+ switch(cpuid_g_vendor) {
+ case CPUID_VENDOR_AMD :
+ return "amd";
+ break;
+ case CPUID_VENDOR_INTEL :
+ return "intel";
+ break;
+ default:
+ return "unknown";
+ }
+}
+
+
+/*
+ * ===============================================================================
+ * basic processor information
+ * ===============================================================================
+ */
+
+/**
+ * \brief obtains the family information from the CPU
+ *
+ * \param memory to fill in the family information
+ */
+errval_t cpuid_proc_family(struct cpuid_proc_family *fmly)
+{
+ if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) {
+ return CPUID_ERR_UNKNOWN_VENDOR;
+ }
+ assert(cpuid_fn.proc_family);
+
+ return cpuid_fn.proc_family(fmly);
+}
+
+/**
+ * \brief obtains the processor name
+ *
+ * \param buf buffer where to store the processor name string
+ * \param len length of the buffer
+ */
+errval_t cpuid_proc_name(char *buf, size_t len)
+{
+ if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) {
+ return CPUID_ERR_UNKNOWN_VENDOR;
+ }
+ assert(cpuid_fn.proc_name);
+
+ return cpuid_fn.proc_name(buf, len);
+}
+
+/**
+ * \brief returns the maximum input value for basic CPUID functions
+ *
+ * \return integer representing the maximum input
+ */
+uint32_t cpuid_proc_max_input_basic(void)
+{
+ if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) {
+ return 0;
+ }
+ cpuid_g_max_input_basic = cpuid_fn.proc_max_input_basic();
+
+ return cpuid_g_max_input_basic;
+}
+
+/**
+ * \brief returns the maximum input value for extended CPUID functions
+ *
+ * \return integer representing the maximum input
+ */
+uint32_t cpuid_proc_max_input_extended(void)
+{
+ if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) {
+ return 0;
+ }
+ cpuid_g_max_input_extended = cpuid_fn.proc_max_input_extended();
+
+ return cpuid_g_max_input_extended;
+}
+
+/**
+ * \brief obtains the processor frequency information
+ *
+ * \param fi returned frequency information
+ *
+ * \returns SYS_ERR_OK on success
+ * CPUID_ERR_*on failure
+ */
+errval_t cpuid_frequency_info(struct cpuid_freqinfo *fi)
+{
+ if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) {
+ return 0;
+ }
+ assert(cpuid_fn.frequency_info);
+
+ return cpuid_fn.frequency_info(fi);
+}
+
+/*
+ * ===============================================================================
+ * cache topology information
+ * ===============================================================================
+ */
+
+/**
+ * \brief calculates the system coherency size (cacheline size)
+ *
+ * \returns the coherency size of the core in bytes
+ */
+uint16_t cpuid_system_coherency_size(void)
+{
+ if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) {
+ return CPUID_ERR_UNKNOWN_VENDOR;
+ }
+ assert(cpuid_fn.cache_line_size);
+
+ return cpuid_fn.cache_line_size();
+}
+
+/**
+ * \brief obtains cache parameters for a given index
+ *
+ * \param ci memory to be filled in with information
+ * \param idx index of the cache to obtain information for
+ *
+ * \return SYS_ERR_OK on success
+ * CPUID_ERR_NO_SUCH_INDEX if there is no cache associated with the index
+ */
+errval_t cpuid_cache_info(struct cpuid_cacheinfo *ci, uint32_t idx)
+{
+ if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) {
+ return CPUID_ERR_UNKNOWN_VENDOR;
+ }
+ assert(cpuid_fn.cache_info);
+
+ return cpuid_fn.cache_info(ci, idx);
+}
+
+/**
+ * \brief returns a string representation of the cache type
+ *
+ * \param ct type of the cache
+ *
+ * \return cache name string
+ */
+char *cpuid_cache_type_string(cpuid_cachetype_t ct)
+{
+ switch(ct) {
+ case CPUID_CACHE_TYPE_DATA:
+ return "data";
+ break;
+ case CPUID_CACHE_TYPE_INSTR:
+ return "instr";
+ break;
+ case CPUID_CACHE_TYPE_UNIFIED:
+ return "unified";
+ break;
+ default:
+ return "invalid";
+ break;
+ }
+}
+
+
+/*
+ * ===============================================================================
+ * TLB information
+ * ===============================================================================
+ */
+
+/**
+ * \brief obtains the TLB topology information
+ *
+ * \param ti
+ * \param idx
+ *
+ * \returns SYS_ERR_OK on success
+ * CPUID_ERR_* on failure
+ */
+errval_t cpuid_tlb_info(struct cpuid_tlbinfo *ti, uint32_t idx)
+{
+ if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) {
+ return CPUID_ERR_UNKNOWN_VENDOR;
+ }
+ assert(cpuid_fn.tlb_info);
+
+ return cpuid_fn.tlb_info(ti, idx);
+}
+
+/*
+ * ===============================================================================
+ * thread and topology information
+ * ===============================================================================
+ */
+
+
+/**
+ * \brief obtains the topology information for a given thread
+ *
+ * \param ti returns the thread information
+ *
+ * \return SYS_ERR_OK on success
+ * CPUID_ERR_* on failure
+ */
+errval_t cpuid_thread_info(struct cpuid_threadinfo *ti)
+{
+ if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) {
+ return CPUID_ERR_UNKNOWN_VENDOR;
+ }
+ assert(cpuid_fn.thread_info);
+
+ return cpuid_fn.thread_info(ti);
+}
+
+/**
+ * \brief obtains topology information from the CPU
+ *
+ * \param topo pointer to store the information
+ * \param idx topology level index
+ *
+ * \return SYS_ERR_OK on success
+ * CPUID_ERR_* on failure
+ */
+errval_t cpuid_topology_info(struct cpuid_topologyinfo *topo, uint8_t idx)
+{
+ if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) {
+ return CPUID_ERR_UNKNOWN_VENDOR;
+ }
+ assert(cpuid_fn.topology_info);
+
+ return cpuid_fn.topology_info(topo, idx);
+}
+
+
+/*
+ * ===============================================================================
+ * feature information
+ * ===============================================================================
+ */
+/**
+ * \brief obtains the CPU's feature information
+ *
+ * \param fi structure to be filled in
+ *
+ * \return SYS_ERR_OK on success
+ * CPUID_ERR_* on failure
+ */
+errval_t cpuid_feature_info(struct cpuid_featureinfo *fi)
+{
+ if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) {
+ return CPUID_ERR_UNKNOWN_VENDOR;
+ }
+ assert(cpuid_fn.feature_info);
+
+ return cpuid_fn.feature_info(fi);
+}
+
+
+/*
+ * ===============================================================================
+ * address space information
+ * ===============================================================================
+ */
+
+/**
+ * \brief obtains the address space size information of the CPU
+ *
+ * \param ai struct to be filled in with adderss space information
+ *
+ * \returns SYS_ERR_OK on susccess
+ * CPUID_ERR_* on failure
+ */
+errval_t cpuid_address_space_info(struct cpuid_adressspaceinfo *ai)
+{
+ if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) {
+ return CPUID_ERR_UNKNOWN_VENDOR;
+ }
+ assert(cpuid_fn.address_space_info);
+
+ return cpuid_fn.address_space_info(ai);
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <cpuid_internal.h>
+
+#include <dev/cpuid_intel_dev.h>
+
+static uint8_t cache_info_in_leaf_4 = 0;
+
+/*
+ * ===============================================================================
+ * basic processor information
+ * ===============================================================================
+ */
+
+static errval_t proc_name(char *buf, size_t len)
+{
+ // check if this operation is supported
+ if (cpuid_g_max_input_extended < 4) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ size_t written;
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0x80000002, 0);
+ cpuid_exec(®);
+ written = snprintf(buf, len, "%s", (char *)®.eax);
+ len -= written;
+ buf += written;
+
+ reg.eax = 0x80000003;
+ reg.ecx = 0x0;
+ cpuid_exec(®);
+ written = snprintf(buf, len, "%s", (char *)®.eax);
+ len -= written;
+ buf += written;
+
+ reg.eax = 0x80000004;
+ reg.ecx = 0x0;
+ cpuid_exec(®);
+ written = snprintf(buf, len, "%s", (char *)®.eax);
+ len -= written;
+ buf += written;
+
+ return SYS_ERR_OK;
+}
+
+static errval_t proc_family(struct cpuid_proc_family *family)
+{
+ if (cpuid_g_max_input_basic < 1) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(1, 0);
+ cpuid_exec(®);
+
+ cpuid_intel_family_t f = (cpuid_intel_family_t)®.eax;
+
+ family->stepping = cpuid_intel_family_stepping_extract(f);
+ family->family = cpuid_intel_family_family_extract(f);
+ family->model = cpuid_intel_family_model_extract(f);
+ family->type = cpuid_intel_family_proctype_extract(f);
+
+ if (family->family == 0x06 || family->family == 0x0f) {
+ uint16_t model = cpuid_intel_family_extmodel_extract(f);
+ family->model += (model << 4);
+ }
+
+ /* if family is zero we have to consider the extended family id */
+ if (family->family != 0x0f) {
+ family->family += cpuid_intel_family_extfamily_extract(f);
+ }
+
+ return SYS_ERR_OK;
+}
+
+static uint32_t proc_max_input_basic(void)
+{
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0, 0);
+ cpuid_exec(®);
+
+ return reg.eax;
+}
+
+static uint32_t proc_max_input_extended(void)
+{
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0x80000000, 0);
+ cpuid_exec(®);
+
+ return reg.eax;
+}
+
+static errval_t frequency_info(struct cpuid_freqinfo *fi)
+{
+ if (cpuid_g_max_input_basic < 0x16) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0x16, 0);
+ cpuid_exec(®);
+
+ cpuid_intel_frequency_t fq = (cpuid_intel_frequency_t)®.eax;
+ fi->base = cpuid_intel_frequency_mhz_extract(fq);
+
+ fq = (cpuid_intel_frequency_t)®.ebx;
+ fi->max = cpuid_intel_frequency_mhz_extract(fq);
+
+ fq = (cpuid_intel_frequency_t)®.ecx;
+ fi->bus = cpuid_intel_frequency_mhz_extract(fq);
+
+ return SYS_ERR_OK;
+}
+
+/*
+ * ===============================================================================
+ * cache topology information
+ * ===============================================================================
+ */
+
+#define CPUID_FILL_TLB(_val,_tci, _assoc, _entries, _level, _type, _pgsz) \
+ case _val: \
+ _tci->is_tlb = 1; \
+ _tci->ti.associativity = _assoc; \
+ _tci->ti.entries = _entries; \
+ _tci->ti.level = _level; \
+ _tci->ti.type = _type; \
+ _tci->ti.pagesize = _pgsz;\
+ return SYS_ERR_OK;
+
+#define CPUID_FILL_CACHE(_val,_tci, _assoc, _size, _level, _type, _shared, _linesize) \
+ case _val: \
+ _tci->is_tlb = 0; \
+ _tci->ci.linesize = _linesize;\
+ _tci->ci.associativity = _assoc; \
+ _tci->ci.sets = _size / _assoc / _tci->ci.linesize; \
+ _tci->ci.level = _level; \
+ _tci->ci.type = _type; \
+ _tci->ci.size = _size; \
+ _tci->ci.shared = _shared;\
+ _tci->ci.name = cpuid_cache_names[_tci->ci.level][_tci->ci.type]; \
+ _tci->ci.inclusive=1; \
+ return SYS_ERR_OK;
+
+struct tlb_cache_info {
+ uint8_t is_tlb;
+ union {
+ struct cpuid_cacheinfo ci;
+ struct cpuid_tlbinfo ti;
+ };
+};
+
+static errval_t cache_info_lookup(struct tlb_cache_info *tci, uint8_t value)
+{
+ switch(value) {
+ case 0x00:
+ //GeneralNull descriptor, this byte contains no information
+ break;
+ //TLB Instruction TLB: 4 KByte pages, 4-way set associative, 32 entries
+ CPUID_FILL_TLB(0x01, tci, 4, 32, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
+ CPUID_FILL_TLB(0x02, tci, 0xff, 2, 1, CPUID_CACHE_TYPE_INSTR, LARGE_PAGE_SIZE);
+ CPUID_FILL_TLB(0x03, tci, 4, 64, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
+ CPUID_FILL_TLB(0x04, tci, 4, 8, 1, CPUID_CACHE_TYPE_DATA, LARGE_PAGE_SIZE);
+ CPUID_FILL_TLB(0x05, tci, 4, 32, 1, CPUID_CACHE_TYPE_DATA, LARGE_PAGE_SIZE);
+ //Cache 1st-level instruction cache: 8 KBytes, 4-way set associative, 32 byte line size
+ CPUID_FILL_CACHE(0x06,tci, 4, 8*1024, 1, CPUID_CACHE_TYPE_INSTR, 1, 32)
+ //Cache 1st-level instruction cache: 16 KBytes, 4-way set associative, 32 byte line size
+ CPUID_FILL_CACHE(0x08,tci, 4, 16*1024, 1, CPUID_CACHE_TYPE_INSTR, 1, 32)
+ //Cache 1st-level instruction cache: 32KBytes, 4-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x09,tci, 4, 32*1024, 1, CPUID_CACHE_TYPE_INSTR, 1, 64)
+ //Cache 1st-level data cache: 8 KBytes, 2-way set associative, 32 byte line size
+ CPUID_FILL_CACHE(0x0a,tci, 2, 8*1024, 1, CPUID_CACHE_TYPE_DATA, 1, 32)
+ // Instruction TLB: 4 MByte pages, 4-way set associative, 4 entries
+ CPUID_FILL_TLB(0x0b, tci, 4, 4, 1, CPUID_CACHE_TYPE_INSTR, LARGE_PAGE_SIZE);
+ //Cache 1st-level data cache: 16 KBytes, 4-way set associative, 32 byte line size
+ CPUID_FILL_CACHE(0x0c,tci, 4, 16*1024, 1, CPUID_CACHE_TYPE_DATA, 1, 32)
+ //Cache 1st-level data cache: 16 KBytes, 4-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x0d,tci, 4, 16*1024, 1, CPUID_CACHE_TYPE_DATA, 1, 64)
+ //Cache 1st-level data cache: 24 KBytes, 6-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x0e,tci, 6, 24*1024, 1, CPUID_CACHE_TYPE_DATA, 1, 64)
+ //Cache 2nd-level cache: 128 KBytes, 2-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x1d,tci, 2, 128*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 2nd-level cache: 256 KBytes, 8-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x21,tci, 2, 128*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 512 KBytes, 4-way set associative, 64 byte line size, 2 lines per sector
+ CPUID_FILL_CACHE(0x22,tci, 4, 512*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 1 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector
+ CPUID_FILL_CACHE(0x23,tci, 8, 1*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 2nd-level cache: 1 MBytes, 16-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x24,tci, 16, 1*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 2 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector
+ CPUID_FILL_CACHE(0x25,tci, 8, 2*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 4 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector
+ CPUID_FILL_CACHE(0x29,tci, 8, 4*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 1st-level data cache: 32 KBytes, 8-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x2c,tci, 8, 32*1024, 1, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 1st-level instruction cache: 32 KBytes, 8-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x30,tci, 8, 32*1024, 1, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache No 2nd-level cache or, if processor contains a valid 2nd-level cache, no 3rd-level cache
+ case 40:
+ break;
+ //Cache 2nd-level cache: 128 KBytes, 4-way set associative, 32 byte line size
+ CPUID_FILL_CACHE(0x41,tci, 4, 128*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
+ //Cache 2nd-level cache: 256 KBytes, 4-way set associative, 32 byte line size
+ CPUID_FILL_CACHE(0x42,tci, 4, 256*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
+ //Cache 2nd-level cache: 512 KBytes, 4-way set associative, 32 byte line size
+ CPUID_FILL_CACHE(0x43,tci, 4, 512*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
+ //Cache 2nd-level cache: 1 MByte, 4-way set associative, 32 byte line size
+ CPUID_FILL_CACHE(0x44,tci, 4, 1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
+ //Cache 2nd-level cache: 2 MByte, 4-way set associative, 32 byte line size
+ CPUID_FILL_CACHE(0x45,tci, 4, 2*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
+ //Cache 3rd-level cache: 4 MByte, 4-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x46,tci, 4, 4*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 8 MByte, 8-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x47,tci, 8, 8*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 2nd-level cache: 3MByte, 12-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x48,tci, 12, 3*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 4MB, 16-way set associative, 64-byte line size (Intel Xeon processor MP, Family 0FH, Model 06H); 2nd-level cache: 4 MByte, 16-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x49,tci, 16, 4*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 6MByte, 12-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x4a,tci, 12, 6*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 8MByte, 16-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x4b,tci, 16, 8*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 12MByte, 12-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x4c,tci, 12, 12*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 16MByte, 16-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x4d,tci, 16, 16*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 2nd-level cache: 6MByte, 24-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x4e,tci, 24, 24*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //TLB Instruction TLB: 4 KByte pages, 32 entries
+ CPUID_FILL_TLB(0x4f, tci, 0xff, 32, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
+ //TLB Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 64 entries
+ CPUID_FILL_TLB(0x50, tci, 0xff, 64, 1, CPUID_CACHE_TYPE_INSTR, LARGE_PAGE_SIZE);
+ //TLB Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 128 entries
+ CPUID_FILL_TLB(0x51, tci, 0xff, 128, 1, CPUID_CACHE_TYPE_INSTR, LARGE_PAGE_SIZE);
+ //TLB Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 256 entries
+ CPUID_FILL_TLB(0x52, tci, 0xff, 256, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
+ //TLB Instruction TLB: 2-MByte or 4-MByte pages, fully associative, 7 entries
+ CPUID_FILL_TLB(0x55, tci, 0xff, 7, 1, CPUID_CACHE_TYPE_INSTR, LARGE_PAGE_SIZE);
+ //TLB Data TLB0: 4 MByte pages, 4-way set associative, 16 entries
+ CPUID_FILL_TLB(0x56, tci, 4, 16, 1, CPUID_CACHE_TYPE_DATA, LARGE_PAGE_SIZE);
+ //TLB Data TLB0: 4 KByte pages, 4-way associative, 16 entries
+ CPUID_FILL_TLB(0x57, tci, 4, 16, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
+ //TLB Data TLB0: 4 KByte pages, fully associative, 16 entries
+ CPUID_FILL_TLB(0x59, tci, 0xff, 16, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
+ //TLB Data TLB0: 2-MByte or 4 MByte pages, 4-way set associative, 32 entries
+ CPUID_FILL_TLB(0x5a, tci, 4, 32, 1, CPUID_CACHE_TYPE_DATA, LARGE_PAGE_SIZE);
+ //TLB Data TLB: 4 KByte and 4 MByte pages, 64 entries
+ CPUID_FILL_TLB(0x5b, tci, 0xff, 64, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
+ //TLB Data TLB: 4 KByte and 4 MByte pages,128 entries
+ CPUID_FILL_TLB(0x5c, tci, 0xff, 128, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
+ //TLB Data TLB: 4 KByte and 4 MByte pages,256 entries
+ CPUID_FILL_TLB(0x5d, tci, 0xff, 256, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
+ case 0x60:
+ //Cache 1st-level data cache: 16 KByte, 8-way set associative, 64 byte line size
+ break;
+ //TLB Instruction TLB: 4 KByte pages, fully associative, 48 entries
+ CPUID_FILL_TLB(0x61, tci, 0xff, 48, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
+ //TLB Data TLB: 1 GByte pages, 4-way set associative, 4 entries
+ CPUID_FILL_TLB(0x63, tci, 4, 4, 1, CPUID_CACHE_TYPE_INSTR, HUGE_PAGE_SIZE);
+ //Cache 1st-level data cache: 8 KByte, 4-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x66,tci, 4, 8*1024, 1, CPUID_CACHE_TYPE_DATA, 1, 64)
+ //Cache 1st-level data cache: 16 KByte, 4-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x67,tci, 4, 16*1024, 1, CPUID_CACHE_TYPE_DATA, 1, 64)
+ //Cache 1st-level data cache: 32 KByte, 4-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x68,tci, 4, 32*1024, 1, CPUID_CACHE_TYPE_DATA, 1, 64)
+ case 0x70:
+ //Cache Trace cache: 12 K-μop, 8-way set associative
+ case 0x71:
+ //Cache Trace cache: 16 K-μop, 8-way set associative
+ case 0x72:
+ //Cache Trace cache: 32 K-μop, 8-way set associative
+ break;
+ //TLB Instruction TLB: 2M/4M pages, fully associative, 8 entries
+ CPUID_FILL_TLB(0x76, tci, 0xff, 8, 1, CPUID_CACHE_TYPE_INSTR, LARGE_PAGE_SIZE);
+ //Cache 2nd-level cache: 1 MByte, 4-way set associative, 64byte line size
+ CPUID_FILL_CACHE(0x78,tci, 4, 1*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 2nd-level cache: 128 KByte, 8-way set associative, 64 byte line size, 2 lines per sector
+ CPUID_FILL_CACHE(0x79,tci, 8, 128*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 2nd-level cache: 256 KByte, 8-way set associative, 64 byte line size, 2 lines per sector
+ CPUID_FILL_CACHE(0x7a,tci, 8, 256*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 2nd-level cache: 512 KByte, 8-way set associative, 64 byte line size, 2 lines per sector
+ CPUID_FILL_CACHE(0x7b,tci, 8, 512*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size, 2 lines per sector
+ CPUID_FILL_CACHE(0x7c,tci, 8, 1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 2nd-level cache: 2 MByte, 8-way set associative, 64byte line size
+ CPUID_FILL_CACHE(0x7d,tci, 8, 2*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 2nd-level cache: 512 KByte, 2-way set associative, 64-byte line size
+ CPUID_FILL_CACHE(0x7f,tci, 2, 512*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 2nd-level cache: 512 KByte, 8-way set associative, 64-byte line size
+ CPUID_FILL_CACHE(0x80,tci, 8, 512*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 2nd-level cache: 256 KByte, 8-way set associative, 32 byte line size
+ CPUID_FILL_CACHE(0x82,tci, 8, 256*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
+ //Cache 2nd-level cache: 512 KByte, 8-way set associative, 32 byte line size
+ CPUID_FILL_CACHE(0x83,tci, 8, 512*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
+ //Cache 2nd-level cache: 1 MByte, 8-way set associative, 32 byte line size
+ CPUID_FILL_CACHE(0x84,tci, 8, 1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
+ //Cache 2nd-level cache: 2 MByte, 8-way set associative, 32 byte line size
+ CPUID_FILL_CACHE(0x85,tci, 8, 2*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
+ //Cache 2nd-level cache: 512 KByte, 4-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x86,tci, 4, 512*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0x87,tci, 8, 1*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //DTLB DTLB: 4k pages, fully associative, 32 entries
+ CPUID_FILL_TLB(0xa0, tci, 0xff, 32, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
+ //TLB Instruction TLB: 4 KByte pages, 4-way set associative, 128 entries
+ CPUID_FILL_TLB(0xb0, tci, 0x4, 128, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
+ //TLB Instruction TLB: 2M pages, 4-way, 8 entries or 4M pages, 4-way, 4 entries
+ CPUID_FILL_TLB(0xb1, tci, 0x4, 8, 1, CPUID_CACHE_TYPE_INSTR, LARGE_PAGE_SIZE);
+ //TLB Instruction TLB: 4KByte pages, 4-way set associative, 64 entries
+ CPUID_FILL_TLB(0xb2, tci, 0x4, 64, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
+ //TLB Data TLB: 4 KByte pages, 4-way set associative, 128 entries
+ CPUID_FILL_TLB(0xb3, tci, 0x4, 128, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
+ //TLB Data TLB1: 4 KByte pages, 4-way associative, 256 entries
+ CPUID_FILL_TLB(0xb4, tci, 0x4, 256, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
+ //TLB Instruction TLB: 4KByte pages, 8-way set associative, 64 entries
+ CPUID_FILL_TLB(0xb5, tci, 0x8, 64, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
+ //TLB Instruction TLB: 4KByte pages, 8-way set associative, 128 entries
+ CPUID_FILL_TLB(0xb6, tci, 0x8, 128, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
+ //TLB Data TLB1: 4 KByte pages, 4-way associative, 64 entries
+ CPUID_FILL_TLB(0xba, tci, 0x4, 64, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
+ //TLB Data TLB: 4 KByte and 4 MByte pages, 4-way associative, 8 entries
+ CPUID_FILL_TLB(0xc0, tci, 0x4, 8, 1, CPUID_CACHE_TYPE_DATA, LARGE_PAGE_SIZE + BASE_PAGE_SIZE);
+ //STLB Shared 2nd-Level TLB: 4 KByte/2MByte pages, 8-way associative, 1024 entries
+ CPUID_FILL_TLB(0xc1, tci, 0x8, 1024, 2, CPUID_CACHE_TYPE_UNIFIED, LARGE_PAGE_SIZE + BASE_PAGE_SIZE);
+ //DTLB DTLB: 4 KByte/2 MByte pages, 4-way associative, 16 entries
+ CPUID_FILL_TLB(0xc2, tci, 0x4, 16, 1, CPUID_CACHE_TYPE_DATA, LARGE_PAGE_SIZE + BASE_PAGE_SIZE);
+ //STLB Shared 2nd-Level TLB: 4 KByte /2 MByte pages, 6-way associative, 1536 entries. Also 1GBbyte pages, 4-way, 16 entries.
+ CPUID_FILL_TLB(0xc3, tci, 0x6, 1536, 2, CPUID_CACHE_TYPE_UNIFIED, BASE_PAGE_SIZE);
+ //STLB Shared 2nd-Level TLB: 4 KByte pages, 4-way associative, 512 entries
+ CPUID_FILL_TLB(0xca, tci, 0x4, 512, 2, CPUID_CACHE_TYPE_UNIFIED, BASE_PAGE_SIZE);
+ //Cache 3rd-level cache: 512 KByte, 4-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xd0,tci, 4, 512*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 1 MByte, 4-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xd1,tci, 4, 1*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 2 MByte, 4-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xd2,tci, 4, 2*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 1 MByte, 8-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xd6,tci, 8, 1*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 2 MByte, 8-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xd7,tci, 8, 2*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 4 MByte, 8-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xd8,tci, 8, 4*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 1.5 MByte, 12-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xdc,tci, 12, 512*1024 + 1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 3 MByte, 12-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xdd,tci, 12, 3*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xde,tci, 12, 6*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 2 MByte, 16-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xe2,tci, 16, 2*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 4 MByte, 16-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xe3,tci, 16, 4*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xe4,tci, 16, 8*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 12MByte, 24-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xea,tci, 24, 12*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 18MByte, 24-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xeb,tci, 24, 18*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ //Cache 3rd-level cache: 24MByte, 24-way set associative, 64 byte line size
+ CPUID_FILL_CACHE(0xec,tci, 24, 24*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
+ case 0xF0:
+ //Prefetch: 64byte prefetching
+ case 0xF1:
+ //Prefetching 128-Byte prefetching
+ case 0xFF:
+ //General CPUID leaf 2 does not report cache descriptor information, use CPUID leaf 4 to query cache parameters
+ default:
+ break;
+ }
+
+ return CPUID_ERR_INVALID_INDEX;
+}
+
+
+static errval_t cache_info_alternate(struct cpuid_cacheinfo *ci, uint32_t idx)
+{
+ if (cpuid_g_max_input_basic < 4) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(4, idx);
+ cpuid_exec(®);
+
+ cpuid_intel_cache_info_basic_t ci_a = (cpuid_intel_cache_info_basic_t) ®.eax;
+ cpuid_intel_cache_info_ebx_t ci_b = (cpuid_intel_cache_info_ebx_t) ®.ebx;
+
+ ci->level = cpuid_intel_cache_info_basic_level_extract(ci_a);
+
+ switch (cpuid_intel_cache_info_basic_ctype_extract(ci_a)) {
+ case cpuid_intel_cache_type_data :
+ /* data cache */
+ ci->type = CPUID_CACHE_TYPE_DATA;
+ break;
+ case cpuid_intel_cache_type_instr :
+ /* instruction cache */
+ ci->type = CPUID_CACHE_TYPE_INSTR;
+ break;
+ case cpuid_intel_cache_type_unified :
+ ci->type = CPUID_CACHE_TYPE_UNIFIED;
+ /* unified cache */
+ break;
+ default:
+ /* no more cache */
+ ci->type = CPUID_CACHE_TYPE_INVALID;
+ return CPUID_ERR_INVALID_INDEX;
+ break;
+ }
+
+ ci->name = cpuid_cache_names[ci->level][ci->type];
+ ci->linesize = cpuid_intel_cache_info_ebx_coherency_extract(ci_b)+1;
+
+ /* the the number of sets */
+ ci->sets = reg.ecx + 1;
+
+ if (cpuid_intel_cache_info_basic_fullyassoc_extract(ci_a)) {
+ ci->size = (size_t)ci->linesize * ci->sets;
+ ci->associativity = 0xff;
+ } else {
+ ci->associativity = cpuid_intel_cache_info_ebx_assoc_extract(ci_b)+1;
+ ci->size = (size_t)ci->linesize * ci->sets * ci->associativity;
+ }
+
+ ci->shared = cpuid_intel_cache_info_basic_maxlog_extract(ci_a) +1;
+
+ cpuid_intel_cache_info_edx_t ci_d = (cpuid_intel_cache_info_edx_t) ®.edx;
+ ci->inclusive = cpuid_intel_cache_info_edx_inclusive_extract(ci_d);
+
+ return SYS_ERR_OK;
+}
+
+
+static errval_t cache_info(struct cpuid_cacheinfo *cinfo, uint32_t idx)
+{
+ if (cpuid_g_max_input_basic < 2) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ if (cache_info_in_leaf_4) {
+ return cache_info_alternate(cinfo, idx);
+ }
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(2, 0);
+ cpuid_exec(®);
+
+ cpuid_intel_cache_info_t ci = (cpuid_intel_cache_info_t)®.eax;
+ assert(cpuid_intel_cache_info_d0_extract(ci) == 0x01);
+
+ uint32_t *values = ®.eax;
+ uint8_t *cval;
+ uint32_t currentidx = 0;
+ for (int i = 0; i < 4; ++i) {
+ ci = (cpuid_intel_cache_info_t)(values + i);
+
+ /* check for validity */
+ if (cpuid_intel_cache_info_v0_extract(ci)) {
+ continue;
+ }
+
+ cval = (uint8_t *)ci;
+ for (int j = (i == 0); j < 4; ++j) {
+ struct tlb_cache_info tci;
+ if (cval[j] == 0x00) {
+ continue;
+ } else if (cval[j] == 0xff) {
+ /*
+ * a value of 0xff indicates that the cache values are reported
+ * in leaf 4 of cpuid
+ */
+ cache_info_in_leaf_4 = 0x1;
+ return cache_info_alternate(cinfo, idx);
+ }
+
+ if (err_is_ok(cache_info_lookup(&tci, cval[j]))) {
+ if (!tci.is_tlb) {
+ if (currentidx == idx) {
+ *cinfo = tci.ci;
+ return SYS_ERR_OK;
+ }
+ currentidx++;
+ }
+ }
+
+ }
+ }
+
+ return CPUID_ERR_INVALID_INDEX;
+
+}
+
+static uint16_t cache_line_size(void)
+{
+ if (cpuid_g_max_input_basic < 1) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(1, 0);
+ cpuid_exec(®);
+
+ cpuid_intel_miscinfo_t mi = (cpuid_intel_miscinfo_t)®.ebx;
+
+ return cpuid_intel_miscinfo_cflush_sz_extract(mi) * 8;
+}
+
+static errval_t tlb_info(struct cpuid_tlbinfo *ti, uint32_t idx)
+{
+ if (cpuid_g_max_input_basic < 2) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(2, 0);
+ cpuid_exec(®);
+
+ cpuid_intel_cache_info_t ci = (cpuid_intel_cache_info_t)®.eax;
+ assert(cpuid_intel_cache_info_d0_extract(ci) == 0x01);
+
+ uint32_t *values = ®.eax;
+ uint8_t *cval;
+ uint32_t currentidx = 0;
+ for (int i = 0; i < 4; ++i) {
+ ci = (cpuid_intel_cache_info_t)(values + i);
+
+ /* check for validity */
+ if (cpuid_intel_cache_info_v0_extract(ci)) {
+ continue;
+ }
+
+ cval = (uint8_t *)ci;
+ for (int j = (i == 0); j < 4; ++j) {
+ struct tlb_cache_info tci;
+ if (cval[j] == 0x00) {
+ continue;
+ }
+ if (err_is_ok(cache_info_lookup(&tci, cval[j]))) {
+ if (tci.is_tlb) {
+ if (currentidx == idx) {
+ *ti = tci.ti;
+ return SYS_ERR_OK;
+ }
+ currentidx++;
+ }
+ }
+
+ }
+ }
+
+ return CPUID_ERR_INVALID_INDEX;
+
+}
+
+/*
+ * ===============================================================================
+ * thread and topology information
+ * ===============================================================================
+ */
+
+static errval_t thread_info(struct cpuid_threadinfo *ti)
+{
+ if (cpuid_g_max_input_basic < 4) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0x1, 0);
+
+ cpuid_exec(®);
+
+ if (!((reg.edx >> 28) & 0x1)) {
+ /* TODO: the cpu supports no hyperthreading */
+ ti->hyperthread = 0;
+ USER_PANIC("NYI");
+ return SYS_ERR_OK;
+ }
+
+ cpuid_intel_miscinfo_t f = (cpuid_intel_miscinfo_t)®.ebx;
+
+ coreid_t logical_cores = cpuid_intel_miscinfo_max_log_proc_extract(f);
+ coreid_t apic_id = cpuid_intel_miscinfo_init_apicid_extract(f);
+
+ reg.eax = 0x4;
+ reg.ecx = 0;
+ cpuid_exec(®);
+
+ cpuid_intel_cache_info_basic_t ci = (cpuid_intel_cache_info_basic_t)®.eax;
+ coreid_t cores_per_package = cpuid_intel_cache_info_basic_maxphys_extract(ci);
+ coreid_t ht = logical_cores / cores_per_package;
+
+ uint8_t ht_shift = cpuid_bits_needed(ht - 1);
+ uint8_t ht_mask = (1 << ht_shift) - 1;
+ uint8_t core_shift = cpuid_bits_needed(cores_per_package - 1);
+ uint8_t core_mask = (1 << core_shift) - 1;
+
+ ti->core = (apic_id >> (ht_shift)) & core_mask;
+ ti->package = apic_id >> (ht_shift + core_shift);
+ ti->hyperthread = apic_id & ht_mask;
+
+ return SYS_ERR_OK;
+}
+
+static errval_t topology_info(struct cpuid_topologyinfo *topo, uint8_t idx)
+{
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0xb, idx);
+ cpuid_exec(®);
+
+ printf("getting the topology information %u\n", idx);
+
+ cpuid_intel_topology_ecx_t ta = (cpuid_intel_topology_eax_t)®.eax;
+ cpuid_intel_topology_ebx_t tb = (cpuid_intel_topology_ebx_t)®.ebx;
+
+ printf("getting the topology information %u, %u\n", idx, cpuid_intel_topology_eax_x2apic_shift_extract(ta));
+
+ cpuid_intel_topology_ecx_t tc = (cpuid_intel_topology_ecx_t)®.ecx;
+ switch (cpuid_intel_topology_ecx_level_type_extract(tc)) {
+ case cpuid_intel_topology_level_smt:
+ printf("found smt at level %u\n", idx);
+ break;
+ case cpuid_intel_topology_level_core:
+ printf("found core at level %u\n", idx);
+ break;
+ case cpuid_intel_topology_level_invalid:
+ printf("level invalid %u\n", idx);
+ return CPUID_ERR_INVALID_INDEX;
+ break;
+ default:
+ printf("level u %u\n", idx);
+ return CPUID_ERR_INVALID_INDEX;
+ break;
+ }
+
+
+ printf("Level numer=%u, logical proc=%u\n", cpuid_intel_topology_ecx_level_number_extract(tc), cpuid_intel_topology_ebx_logical_proc_extract(tb));
+
+
+ topo->nextshift = cpuid_intel_topology_eax_x2apic_shift_extract(ta);
+ topo->x2apic = reg.edx;
+
+ return SYS_ERR_OK;
+}
+
+static errval_t feature_info(struct cpuid_featureinfo *fi)
+{
+ if (cpuid_g_max_input_basic < 0x1) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0x1, 0);
+ cpuid_exec(®);
+
+ cpuid_intel_features_t ft = (cpuid_intel_features_t)®.ecx;
+ /* CPU features */
+
+ fi->htt = cpuid_intel_features_htt_extract(ft);
+ fi->apic = cpuid_intel_features_apic_extract(ft);
+ fi->x2apic = cpuid_intel_features_x2apic_extract(ft);
+ fi->tsc = cpuid_intel_features_tsc_extract(ft);
+ fi->dca = cpuid_intel_features_dca_extract(ft);
+
+ /* instructions */
+ fi->monitor = cpuid_intel_features_monitor_extract(ft);
+ fi->cmov = cpuid_intel_features_cmov_extract(ft);
+
+ /* virtual memory */
+ fi->pse36 = cpuid_intel_features_pse36_extract(ft);
+ fi->pse = cpuid_intel_features_pse_extract(ft);
+ fi->pae = cpuid_intel_features_pae_extract(ft);
+ fi->pat = cpuid_intel_features_pat_extract(ft);
+ fi->pge = cpuid_intel_features_pge_extract(ft);
+ fi->mtrr = cpuid_intel_features_mtrr_extract(ft);
+
+ fi->page2M = 1;
+
+
+ /* cache control */
+ fi->clsh = cpuid_intel_features_clfsh_extract(ft);
+ fi->cnxt_id = cpuid_intel_features_cntx_id_extract(ft);
+
+ /* virtualization technology */
+ fi->vmx = cpuid_intel_features_vmx_extract(ft);
+ fi->vme = cpuid_intel_features_vme_extract(ft);
+ fi->svm = 0;
+
+ /* vector instructions */
+ fi->mmx = cpuid_intel_features_mmx_extract(ft);
+ fi->sse = cpuid_intel_features_sse_extract(ft);
+ fi->sse2 = cpuid_intel_features_sse2_extract(ft);
+ fi->sse3 = cpuid_intel_features_sse3_extract(ft);
+ fi->sse41 = cpuid_intel_features_sse4_1_extract(ft);
+ fi->sse42 = cpuid_intel_features_sse4_2_extract(ft);
+ fi->avx = cpuid_intel_features_avx_extract(ft);
+
+ if (CPUID_EXTENDED_INPUT_MASK(cpuid_g_max_input_extended) < 0x1) {
+ return SYS_ERR_OK;
+ }
+
+ reg.eax = 0x80000001;
+ reg.ecx = 0;
+ cpuid_exec(®);
+
+ cpuid_intel_features_ext_edx_t ft2 = (cpuid_intel_features_ext_edx_t)®.edx;
+ fi->nx = cpuid_intel_features_ext_edx_nx_extract(ft2);
+ fi->page1G = cpuid_intel_features_ext_edx_page1G_extract(ft2);;
+ fi->lm = cpuid_intel_features_ext_edx_lm_extract(ft2);
+
+ return SYS_ERR_OK;
+}
+
+static errval_t address_space_info(struct cpuid_adressspaceinfo *ai)
+{
+ if (CPUID_EXTENDED_INPUT_MASK(cpuid_g_max_input_extended) < 0x8) {
+ return CPUID_ERR_UNSUPPORTED_FUNCTION;
+ }
+
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0x80000008, 0);
+ cpuid_exec(®);
+
+ cpuid_intel_addrspace_t as = (cpuid_intel_addrspace_t)®.eax;
+
+ ai->physical = cpuid_intel_addrspace_physical_extract(as);
+ ai->virtual = cpuid_intel_addrspace_linear_extract(as);
+ /* this information is not provided by intel*/
+ ai->guest_physical = 0;
+
+ return SYS_ERR_OK;
+}
+
+/*
+ * ===============================================================================
+ * backend initialization
+ * ===============================================================================
+ */
+
+/**
+ * \brief fills the vendor specific handler functions
+ *
+ * \param fn_tab function pointer table to be filled
+ */
+void cpuid_intel_set_handlers(struct cpuid_functions *fn_tab)
+{
+ fn_tab->proc_name = proc_name;
+ fn_tab->proc_family = proc_family;
+ fn_tab->proc_max_input_basic = proc_max_input_basic;
+ fn_tab->proc_max_input_extended = proc_max_input_extended;
+ fn_tab->frequency_info = frequency_info;
+
+ fn_tab->cache_info = cache_info;
+ fn_tab->cache_line_size = cache_line_size;
+
+ fn_tab->tlb_info = tlb_info;
+
+ fn_tab->thread_info = thread_info;
+ fn_tab->topology_info = topology_info;
+
+ fn_tab->feature_info = feature_info;
+
+ fn_tab->address_space_info = address_space_info;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef LIBCPUID_INTEL_H_
+#define LIBCPUID_INTEL_H_ 1
+
+#include <string.h>
+
+
+/**
+ * \brief verifies the CPU
+ *
+ * \returns TRUE if its a Intel CPU
+ * FALSE otherwise
+ */
+static inline bool cpuid_intel_check_vendor(void)
+{
+ struct cpuid_regs reg = CPUID_REGS_INITIAL(0, 0);
+ cpuid_exec(®);
+
+ return (strncmp((char *)®.ebx, CPUID_VENDOR_STRING_INTEL, 12) == 0);
+}
+
+/**
+ * \brief fills the vendor specific handler functions
+ *
+ * \param fn_tab function pointer table to be filled
+ */
+void cpuid_intel_set_handlers(struct cpuid_functions *fn_tab);
+
+
+
+
+#endif /* CPUID_INTERNAL_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2015 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef LIBCPUID_INTERNAL_H_
+#define LIBCPUID_INTERNAL_H_ 1
+
+#include <barrelfish/barrelfish.h>
+#include <cpuid/cpuid.h>
+
+/*
+ * ===============================================================================
+ * library configuration
+ * ===============================================================================
+ */
+///< enables verbose output of library operations
+#define CPUID_VERBOSE_OUTPUT 0
+
+
+/*
+ * ===============================================================================
+ * declarations
+ * ===============================================================================
+ */
+
+///< function table for vendor specific handlers
+struct cpuid_functions
+{
+ errval_t (*proc_family)(struct cpuid_proc_family *fmly);
+ errval_t (*proc_name)(char *buf, size_t len);
+ uint32_t (*proc_max_input_basic)(void);
+ uint32_t (*proc_max_input_extended)(void);
+ errval_t (*frequency_info)(struct cpuid_freqinfo *fi);
+
+ uint16_t (*cache_line_size)(void);
+ errval_t (*cache_info)(struct cpuid_cacheinfo *ci, uint32_t idx);
+
+ errval_t (*tlb_info)(struct cpuid_tlbinfo *ti, uint32_t idx);
+
+ errval_t (*thread_info)(struct cpuid_threadinfo *ti);
+ errval_t (*topology_info)(struct cpuid_topologyinfo *topo, uint8_t idx);
+
+ errval_t (*feature_info)(struct cpuid_featureinfo *fi);
+
+ errval_t (*address_space_info)(struct cpuid_adressspaceinfo *ai);
+};
+
+
+///< maximum input value for basic CPUID information
+extern uint32_t cpuid_g_max_input_basic;
+
+///< maximum input value for extended CPUID information
+extern uint32_t cpuid_g_max_input_extended;
+
+///< the vendor of the core this code is executed
+extern cpuid_vendor_t cpuid_g_vendor;
+
+///< function pointer table for vendor specific handlers
+extern struct cpuid_functions cpuid_fn;
+
+///< cpu cache names in readable representation
+extern char *cpuid_cache_names[4][4];
+
+/*
+ * ===============================================================================
+ * macros
+ * ===============================================================================
+ */
+
+#if CPUID_VERBOSE_OUTPUT
+#define CPUID_PRINTF(x...) debug_printf("libcpuid: " x)
+#else
+#define CPUID_PRINTF(x...)
+#endif
+
+///< masks the extended value
+#define CPUID_EXTENDED_INPUT_MASK(x) (x & 0x7fffffff)
+
+/*
+ * ===============================================================================
+ * functions
+ * ===============================================================================
+ */
+
+static inline uint8_t cpuid_bits_needed(uint8_t count)
+{
+ uint8_t mask = 0x80;
+ uint8_t cnt = 8;
+
+ while ((cnt > 0) && ((mask & count) != mask)) {
+ mask >>= 1;
+ cnt--;
+ }
+ return (cnt);
+}
+
+#include "cpuid_amd.h"
+#include "cpuid_intel.h"
+
+#endif /* CPUID_INTERNAL_H_ */