[T115] extending support for cpuid instruction
authorReto Achermann <reto.achermann@inf.ethz.ch>
Wed, 10 Jun 2015 11:53:18 +0000 (13:53 +0200)
committerReto Achermann <reto.achermann@inf.ethz.ch>
Wed, 10 Jun 2015 12:00:54 +0000 (14:00 +0200)
initial commit of a unified cpuid library for obtaining information
about cpu features, caches, tlbs, cores/threads etc.

Signed-off-by: Reto Achermann <reto.achermann@inf.ethz.ch>

14 files changed:
devices/Hakefile
devices/cpuid.dev
devices/cpuid_amd.dev [new file with mode: 0644]
devices/cpuid_intel.dev [new file with mode: 0644]
errors/errno.fugu
include/cpuid/cpuid.h
include/cpuid/cpuid_spaces.h
lib/cpuid/Hakefile [new file with mode: 0644]
lib/cpuid/cpuid_amd.c [new file with mode: 0644]
lib/cpuid/cpuid_amd.h [new file with mode: 0644]
lib/cpuid/cpuid_generic.c [new file with mode: 0644]
lib/cpuid/cpuid_intel.c [new file with mode: 0644]
lib/cpuid/cpuid_intel.h [new file with mode: 0644]
lib/cpuid/cpuid_internal.h [new file with mode: 0644]

index 756e6d0..014b3bf 100644 (file)
@@ -17,6 +17,8 @@
 [ mackerel2 (options arch) f
   | f <- [ "ac97_base_audio",
            "ac97_ext_audio",
+           "cpuid_intel",
+           "cpuid_amd",
            "ac97_ext_codec",
            "ac97_ext_modem",
            "ahci_hba",
index 19b320d..d153079 100644 (file)
@@ -231,7 +231,7 @@ device cpuid lsbfirst () "ia32 / Intel64 CPUID instruction results" {
     // 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";
@@ -240,7 +240,7 @@ device cpuid lsbfirst () "ia32 / Intel64 CPUID instruction results" {
 
     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";
diff --git a/devices/cpuid_amd.dev b/devices/cpuid_amd.dev
new file mode 100644 (file)
index 0000000..89933b4
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * 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";
+    };     
+};
+
+    
+           
+
+    
+    
+       
diff --git a/devices/cpuid_intel.dev b/devices/cpuid_intel.dev
new file mode 100644 (file)
index 0000000..7604b52
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * 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";
+    };
+};
+
+    
+           
+
+    
+    
+       
index f7b7515..3dde629 100755 (executable)
@@ -1143,3 +1143,9 @@ errors numa NUMA_ERR_ {
     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",
+};
index 4c1d76d..683b97f 100644 (file)
 /*
- * 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_
 
index a288a4a..0ec9ee2 100644 (file)
 
 #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
diff --git a/lib/cpuid/Hakefile b/lib/cpuid/Hakefile
new file mode 100644 (file)
index 0000000..5d0e3ee
--- /dev/null
@@ -0,0 +1,25 @@
+--------------------------------------------------------------------------
+-- 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"
+    ] 
+  } 
+]
diff --git a/lib/cpuid/cpuid_amd.c b/lib/cpuid/cpuid_amd.c
new file mode 100644 (file)
index 0000000..295c9cb
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * 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(&reg);
+    written = snprintf(buf, len, "%s", (char *)&reg.eax);
+    len -= written;
+    buf += written;
+
+    reg.eax = 0x80000003;
+    reg.ecx = 0x0;
+    cpuid_exec(&reg);
+    written = snprintf(buf, len, "%s", (char *)&reg.eax);
+    len -= written;
+    buf += written;
+
+    reg.eax = 0x80000004;
+    reg.ecx = 0x0;
+    cpuid_exec(&reg);
+    written = snprintf(buf, len, "%s", (char *)&reg.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(&reg);
+
+    cpuid_amd_family_t f = (cpuid_amd_family_t)&reg.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(&reg);
+
+    return reg.eax;
+}
+
+static uint32_t proc_max_input_extended(void)
+{
+    struct cpuid_regs reg  = CPUID_REGS_INITIAL(0x80000000, 0);
+    cpuid_exec(&reg);
+
+    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(&reg);
+
+    switch(idx) {
+        case 0:;
+            cpuid_amd_l1_dcache_t l1d = (cpuid_amd_l1_dcache_t)&reg.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)&reg.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)&reg.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)&reg.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(&reg);
+
+    cpuid_amd_cache_info_eax_t ci_a = (cpuid_amd_cache_info_eax_t) &reg.eax;
+    cpuid_amd_cache_info_ebx_t ci_b = (cpuid_amd_cache_info_ebx_t) &reg.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) &reg.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(&reg);
+
+    cpuid_amd_miscinfo_t mi = (cpuid_amd_miscinfo_t)&reg.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(&reg);
+        cpuid_amd_tlb_l1_t tlb;
+        if (idx < 2) {
+            tlb = (cpuid_amd_tlb_l1_t)&reg.eax;
+            ti->pagesize = LARGE_PAGE_SIZE;
+        } else {
+            tlb = (cpuid_amd_tlb_l1_t)&reg.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(&reg);
+    cpuid_amd_tlb_l1_t tlb2;
+    if (idx < 2) {
+        tlb2 = (cpuid_amd_tlb_l1_t)&reg.eax;
+    } else {
+        tlb2 = (cpuid_amd_tlb_l1_t)&reg.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(&reg);
+
+    cpuid_amd_miscinfo_t mi = (cpuid_amd_miscinfo_t)&reg.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(&reg);
+
+    cpuid_amd_apicid_t ac = (cpuid_amd_apicid_t)&reg.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(&reg);
+
+    cpuid_amd_addrspace_t as = (cpuid_amd_addrspace_t)&reg.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;
+}
diff --git a/lib/cpuid/cpuid_amd.h b/lib/cpuid/cpuid_amd.h
new file mode 100644 (file)
index 0000000..f6d8efe
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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(&reg);
+
+    return (strncmp((char *)&reg.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_ */
diff --git a/lib/cpuid/cpuid_generic.c b/lib/cpuid/cpuid_generic.c
new file mode 100644 (file)
index 0000000..e06bf1e
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * 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);
+}
diff --git a/lib/cpuid/cpuid_intel.c b/lib/cpuid/cpuid_intel.c
new file mode 100644 (file)
index 0000000..7d8e439
--- /dev/null
@@ -0,0 +1,760 @@
+/*
+ * 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(&reg);
+    written = snprintf(buf, len, "%s", (char *)&reg.eax);
+    len -= written;
+    buf += written;
+
+    reg.eax = 0x80000003;
+    reg.ecx = 0x0;
+    cpuid_exec(&reg);
+    written = snprintf(buf, len, "%s", (char *)&reg.eax);
+    len -= written;
+    buf += written;
+
+    reg.eax = 0x80000004;
+    reg.ecx = 0x0;
+    cpuid_exec(&reg);
+    written = snprintf(buf, len, "%s", (char *)&reg.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(&reg);
+
+    cpuid_intel_family_t f = (cpuid_intel_family_t)&reg.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(&reg);
+
+    return reg.eax;
+}
+
+static uint32_t proc_max_input_extended(void)
+{
+    struct cpuid_regs reg  = CPUID_REGS_INITIAL(0x80000000, 0);
+    cpuid_exec(&reg);
+
+    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(&reg);
+
+    cpuid_intel_frequency_t fq = (cpuid_intel_frequency_t)&reg.eax;
+    fi->base =  cpuid_intel_frequency_mhz_extract(fq);
+
+    fq = (cpuid_intel_frequency_t)&reg.ebx;
+    fi->max =  cpuid_intel_frequency_mhz_extract(fq);
+
+    fq = (cpuid_intel_frequency_t)&reg.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(&reg);
+
+    cpuid_intel_cache_info_basic_t ci_a = (cpuid_intel_cache_info_basic_t) &reg.eax;
+    cpuid_intel_cache_info_ebx_t ci_b = (cpuid_intel_cache_info_ebx_t) &reg.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) &reg.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(&reg);
+
+    cpuid_intel_cache_info_t ci = (cpuid_intel_cache_info_t)&reg.eax;
+    assert(cpuid_intel_cache_info_d0_extract(ci) == 0x01);
+
+    uint32_t *values = &reg.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(&reg);
+
+    cpuid_intel_miscinfo_t mi = (cpuid_intel_miscinfo_t)&reg.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(&reg);
+
+    cpuid_intel_cache_info_t ci = (cpuid_intel_cache_info_t)&reg.eax;
+    assert(cpuid_intel_cache_info_d0_extract(ci) == 0x01);
+
+    uint32_t *values = &reg.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(&reg);
+
+    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)&reg.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(&reg);
+
+    cpuid_intel_cache_info_basic_t ci = (cpuid_intel_cache_info_basic_t)&reg.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(&reg);
+
+    printf("getting the topology information %u\n", idx);
+
+    cpuid_intel_topology_ecx_t ta = (cpuid_intel_topology_eax_t)&reg.eax;
+    cpuid_intel_topology_ebx_t tb = (cpuid_intel_topology_ebx_t)&reg.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)&reg.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(&reg);
+
+    cpuid_intel_features_t ft = (cpuid_intel_features_t)&reg.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(&reg);
+
+    cpuid_intel_features_ext_edx_t ft2 = (cpuid_intel_features_ext_edx_t)&reg.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(&reg);
+
+    cpuid_intel_addrspace_t as = (cpuid_intel_addrspace_t)&reg.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;
+}
diff --git a/lib/cpuid/cpuid_intel.h b/lib/cpuid/cpuid_intel.h
new file mode 100644 (file)
index 0000000..d4cefa7
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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(&reg);
+
+    return (strncmp((char *)&reg.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_ */
diff --git a/lib/cpuid/cpuid_internal.h b/lib/cpuid/cpuid_internal.h
new file mode 100644 (file)
index 0000000..3bd2603
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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_ */