1/*
2 * Copyright (c) 2015 ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <cpuid_internal.h>
11
12#include <dev/cpuid_intel_dev.h>
13
14static uint8_t cache_info_in_leaf_4 = 0;
15
16/*
17 * ===============================================================================
18 * basic processor information
19 * ===============================================================================
20 */
21
22static errval_t proc_name(char *buf, size_t len)
23{
24    // check if this operation is supported
25    if (cpuid_g_max_input_extended < 4) {
26        return CPUID_ERR_UNSUPPORTED_FUNCTION;
27    }
28
29    size_t written;
30
31    struct cpuid_regs reg = CPUID_REGS_INITIAL(0x80000002, 0);
32    cpuid_exec(&reg);
33    written = snprintf(buf, len, "%s", (char *)&reg.eax);
34    len -= written;
35    buf += written;
36
37    reg.eax = 0x80000003;
38    reg.ecx = 0x0;
39    cpuid_exec(&reg);
40    written = snprintf(buf, len, "%s", (char *)&reg.eax);
41    len -= written;
42    buf += written;
43
44    reg.eax = 0x80000004;
45    reg.ecx = 0x0;
46    cpuid_exec(&reg);
47    written = snprintf(buf, len, "%s", (char *)&reg.eax);
48    len -= written;
49    buf += written;
50
51    return SYS_ERR_OK;
52}
53
54static errval_t proc_family(struct cpuid_proc_family *family)
55{
56    if (cpuid_g_max_input_basic < 1) {
57        return CPUID_ERR_UNSUPPORTED_FUNCTION;
58    }
59
60    struct cpuid_regs reg = CPUID_REGS_INITIAL(1, 0);
61    cpuid_exec(&reg);
62
63    cpuid_intel_family_t f = (cpuid_intel_family_t)&reg.eax;
64
65    family->stepping = cpuid_intel_family_stepping_extract(f);
66    family->family = cpuid_intel_family_family_extract(f);
67    family->model = cpuid_intel_family_model_extract(f);
68    family->type = cpuid_intel_family_proctype_extract(f);
69
70    if (family->family == 0x06 || family->family == 0x0f) {
71        uint16_t model = cpuid_intel_family_extmodel_extract(f);
72        family->model += (model << 4);
73    }
74
75    /* if family is zero we have to consider the extended family id */
76    if (family->family != 0x0f) {
77        family->family += cpuid_intel_family_extfamily_extract(f);
78    }
79
80    return SYS_ERR_OK;
81}
82
83static uint32_t proc_max_input_basic(void)
84{
85    struct cpuid_regs reg  = CPUID_REGS_INITIAL(0, 0);
86    cpuid_exec(&reg);
87
88    return reg.eax;
89}
90
91static uint32_t proc_max_input_extended(void)
92{
93    struct cpuid_regs reg  = CPUID_REGS_INITIAL(0x80000000, 0);
94    cpuid_exec(&reg);
95
96    return reg.eax;
97}
98
99static errval_t frequency_info(struct cpuid_freqinfo *fi)
100{
101    if (cpuid_g_max_input_basic < 0x16) {
102        return CPUID_ERR_UNSUPPORTED_FUNCTION;
103    }
104
105    struct cpuid_regs reg = CPUID_REGS_INITIAL(0x16, 0);
106    cpuid_exec(&reg);
107
108    cpuid_intel_frequency_t fq = (cpuid_intel_frequency_t)&reg.eax;
109    fi->base =  cpuid_intel_frequency_mhz_extract(fq);
110
111    fq = (cpuid_intel_frequency_t)&reg.ebx;
112    fi->max =  cpuid_intel_frequency_mhz_extract(fq);
113
114    fq = (cpuid_intel_frequency_t)&reg.ecx;
115    fi->bus =  cpuid_intel_frequency_mhz_extract(fq);
116
117    return SYS_ERR_OK;
118}
119
120/*
121 * ===============================================================================
122 * cache topology information
123 * ===============================================================================
124 */
125
126#define CPUID_FILL_TLB(_val,_tci, _assoc, _entries, _level, _type, _pgsz) \
127                case _val: \
128                    _tci->is_tlb = 1; \
129                    _tci->ti.associativity = _assoc; \
130                    _tci->ti.entries = _entries; \
131                    _tci->ti.level = _level; \
132                    _tci->ti.type = _type; \
133                    _tci->ti.pagesize = _pgsz;\
134                    return SYS_ERR_OK;
135
136#define CPUID_FILL_CACHE(_val,_tci, _assoc, _size, _level, _type, _shared, _linesize) \
137                case _val: \
138                    _tci->is_tlb = 0; \
139                    _tci->ci.linesize = _linesize;\
140                    _tci->ci.associativity = _assoc; \
141                    _tci->ci.sets = _size / _assoc / _tci->ci.linesize; \
142                    _tci->ci.level = _level; \
143                    _tci->ci.type = _type; \
144                    _tci->ci.size = _size; \
145                    _tci->ci.shared = _shared;\
146                    _tci->ci.name = cpuid_cache_names[_tci->ci.level][_tci->ci.type]; \
147                    _tci->ci.inclusive=1; \
148                    return SYS_ERR_OK;
149
150struct tlb_cache_info {
151    uint8_t is_tlb;
152    union {
153        struct cpuid_cacheinfo ci;
154        struct cpuid_tlbinfo ti;
155    };
156};
157
158static errval_t cache_info_lookup(struct tlb_cache_info *tci, uint8_t value)
159{
160    switch(value) {
161        case 0x00:
162        //GeneralNull descriptor, this byte contains no information
163            break;
164        //TLB Instruction TLB: 4 KByte pages, 4-way set associative, 32 entries
165        CPUID_FILL_TLB(0x01, tci, 4, 32, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
166        CPUID_FILL_TLB(0x02, tci, 0xff, 2, 1, CPUID_CACHE_TYPE_INSTR, LARGE_PAGE_SIZE);
167        CPUID_FILL_TLB(0x03, tci, 4, 64, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
168        CPUID_FILL_TLB(0x04, tci, 4, 8, 1, CPUID_CACHE_TYPE_DATA, LARGE_PAGE_SIZE);
169        CPUID_FILL_TLB(0x05, tci, 4, 32, 1, CPUID_CACHE_TYPE_DATA, LARGE_PAGE_SIZE);
170        //Cache 1st-level instruction cache: 8 KBytes, 4-way set associative, 32 byte line size
171        CPUID_FILL_CACHE(0x06,tci, 4, 8*1024, 1, CPUID_CACHE_TYPE_INSTR, 1, 32)
172        //Cache 1st-level instruction cache: 16 KBytes, 4-way set associative, 32 byte line size
173        CPUID_FILL_CACHE(0x08,tci, 4, 16*1024, 1, CPUID_CACHE_TYPE_INSTR, 1, 32)
174        //Cache 1st-level instruction cache: 32KBytes, 4-way set associative, 64 byte line size
175        CPUID_FILL_CACHE(0x09,tci, 4, 32*1024, 1, CPUID_CACHE_TYPE_INSTR, 1, 64)
176        //Cache 1st-level data cache: 8 KBytes, 2-way set associative, 32 byte line size
177        CPUID_FILL_CACHE(0x0a,tci, 2, 8*1024, 1, CPUID_CACHE_TYPE_DATA, 1, 32)
178        // Instruction TLB: 4 MByte pages, 4-way set associative, 4 entries
179        CPUID_FILL_TLB(0x0b, tci, 4, 4, 1, CPUID_CACHE_TYPE_INSTR, LARGE_PAGE_SIZE);
180        //Cache 1st-level data cache: 16 KBytes, 4-way set associative, 32 byte line size
181        CPUID_FILL_CACHE(0x0c,tci, 4, 16*1024, 1, CPUID_CACHE_TYPE_DATA, 1, 32)
182        //Cache 1st-level data cache: 16 KBytes, 4-way set associative, 64 byte line size
183        CPUID_FILL_CACHE(0x0d,tci, 4, 16*1024, 1, CPUID_CACHE_TYPE_DATA, 1, 64)
184        //Cache 1st-level data cache: 24 KBytes, 6-way set associative, 64 byte line size
185        CPUID_FILL_CACHE(0x0e,tci, 6, 24*1024, 1, CPUID_CACHE_TYPE_DATA, 1, 64)
186        //Cache 2nd-level cache: 128 KBytes, 2-way set associative, 64 byte line size
187        CPUID_FILL_CACHE(0x1d,tci, 2, 128*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
188        //Cache 2nd-level cache: 256 KBytes, 8-way set associative, 64 byte line size
189        CPUID_FILL_CACHE(0x21,tci, 2, 128*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
190        //Cache 3rd-level cache: 512 KBytes, 4-way set associative, 64 byte line size, 2 lines per sector
191        CPUID_FILL_CACHE(0x22,tci, 4, 512*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
192        //Cache 3rd-level cache: 1 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector
193        CPUID_FILL_CACHE(0x23,tci, 8, 1*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
194        //Cache 2nd-level cache: 1 MBytes, 16-way set associative, 64 byte line size
195        CPUID_FILL_CACHE(0x24,tci, 16, 1*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
196        //Cache 3rd-level cache: 2 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector
197        CPUID_FILL_CACHE(0x25,tci, 8, 2*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
198        //Cache 3rd-level cache: 4 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector
199        CPUID_FILL_CACHE(0x29,tci, 8, 4*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
200        //Cache 1st-level data cache: 32 KBytes, 8-way set associative, 64 byte line size
201        CPUID_FILL_CACHE(0x2c,tci, 8, 32*1024, 1, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
202        //Cache 1st-level instruction cache: 32 KBytes, 8-way set associative, 64 byte line size
203        CPUID_FILL_CACHE(0x30,tci, 8, 32*1024, 1, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
204        //Cache No 2nd-level cache or, if processor contains a valid 2nd-level cache, no 3rd-level cache
205        case 40:
206            break;
207        //Cache 2nd-level cache: 128 KBytes, 4-way set associative, 32 byte line size
208        CPUID_FILL_CACHE(0x41,tci, 4, 128*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
209        //Cache 2nd-level cache: 256 KBytes, 4-way set associative, 32 byte line size
210        CPUID_FILL_CACHE(0x42,tci, 4, 256*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
211        //Cache 2nd-level cache: 512 KBytes, 4-way set associative, 32 byte line size
212        CPUID_FILL_CACHE(0x43,tci, 4, 512*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
213        //Cache 2nd-level cache: 1 MByte, 4-way set associative, 32 byte line size
214        CPUID_FILL_CACHE(0x44,tci, 4, 1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
215        //Cache 2nd-level cache: 2 MByte, 4-way set associative, 32 byte line size
216        CPUID_FILL_CACHE(0x45,tci, 4, 2*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
217        //Cache 3rd-level cache: 4 MByte, 4-way set associative, 64 byte line size
218        CPUID_FILL_CACHE(0x46,tci, 4, 4*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
219        //Cache 3rd-level cache: 8 MByte, 8-way set associative, 64 byte line size
220        CPUID_FILL_CACHE(0x47,tci, 8, 8*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
221        //Cache 2nd-level cache: 3MByte, 12-way set associative, 64 byte line size
222        CPUID_FILL_CACHE(0x48,tci, 12, 3*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
223        //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
224        CPUID_FILL_CACHE(0x49,tci, 16, 4*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
225        //Cache 3rd-level cache: 6MByte, 12-way set associative, 64 byte line size
226        CPUID_FILL_CACHE(0x4a,tci, 12, 6*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
227        //Cache 3rd-level cache: 8MByte, 16-way set associative, 64 byte line size
228        CPUID_FILL_CACHE(0x4b,tci, 16, 8*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
229        //Cache 3rd-level cache: 12MByte, 12-way set associative, 64 byte line size
230        CPUID_FILL_CACHE(0x4c,tci, 12, 12*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
231        //Cache 3rd-level cache: 16MByte, 16-way set associative, 64 byte line size
232        CPUID_FILL_CACHE(0x4d,tci, 16, 16*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
233        //Cache 2nd-level cache: 6MByte, 24-way set associative, 64 byte line size
234        CPUID_FILL_CACHE(0x4e,tci, 24, 24*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
235        //TLB Instruction TLB: 4 KByte pages, 32 entries
236        CPUID_FILL_TLB(0x4f, tci, 0xff, 32, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
237        //TLB Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 64 entries
238        CPUID_FILL_TLB(0x50, tci, 0xff, 64, 1, CPUID_CACHE_TYPE_INSTR, LARGE_PAGE_SIZE);
239        //TLB Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 128 entries
240        CPUID_FILL_TLB(0x51, tci, 0xff, 128, 1, CPUID_CACHE_TYPE_INSTR, LARGE_PAGE_SIZE);
241        //TLB Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 256 entries
242        CPUID_FILL_TLB(0x52, tci, 0xff, 256, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
243        //TLB Instruction TLB: 2-MByte or 4-MByte pages, fully associative, 7 entries
244        CPUID_FILL_TLB(0x55, tci, 0xff, 7, 1, CPUID_CACHE_TYPE_INSTR, LARGE_PAGE_SIZE);
245        //TLB Data TLB0: 4 MByte pages, 4-way set associative, 16 entries
246        CPUID_FILL_TLB(0x56, tci, 4, 16, 1, CPUID_CACHE_TYPE_DATA, LARGE_PAGE_SIZE);
247        //TLB Data TLB0: 4 KByte pages, 4-way associative, 16 entries
248        CPUID_FILL_TLB(0x57, tci, 4, 16, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
249        //TLB Data TLB0: 4 KByte pages, fully associative, 16 entries
250        CPUID_FILL_TLB(0x59, tci, 0xff, 16, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
251        //TLB Data TLB0: 2-MByte or 4 MByte pages, 4-way set associative, 32 entries
252        CPUID_FILL_TLB(0x5a, tci, 4, 32, 1, CPUID_CACHE_TYPE_DATA, LARGE_PAGE_SIZE);
253        //TLB Data TLB: 4 KByte and 4 MByte pages, 64 entries
254        CPUID_FILL_TLB(0x5b, tci, 0xff, 64, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
255        //TLB Data TLB: 4 KByte and 4 MByte pages,128 entries
256        CPUID_FILL_TLB(0x5c, tci, 0xff, 128, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
257        //TLB Data TLB: 4 KByte and 4 MByte pages,256 entries
258        CPUID_FILL_TLB(0x5d, tci, 0xff, 256, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
259        case 0x60:
260        //Cache 1st-level data cache: 16 KByte, 8-way set associative, 64 byte line size
261            break;
262        //TLB Instruction TLB: 4 KByte pages, fully associative, 48 entries
263        CPUID_FILL_TLB(0x61, tci, 0xff, 48, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
264        //TLB Data TLB: 1 GByte pages, 4-way set associative, 4 entries
265        CPUID_FILL_TLB(0x63, tci, 4, 4, 1, CPUID_CACHE_TYPE_INSTR, HUGE_PAGE_SIZE);
266        //Cache 1st-level data cache: 8 KByte, 4-way set associative, 64 byte line size
267        CPUID_FILL_CACHE(0x66,tci, 4, 8*1024, 1, CPUID_CACHE_TYPE_DATA, 1, 64)
268        //Cache 1st-level data cache: 16 KByte, 4-way set associative, 64 byte line size
269        CPUID_FILL_CACHE(0x67,tci, 4, 16*1024, 1, CPUID_CACHE_TYPE_DATA, 1, 64)
270        //Cache 1st-level data cache: 32 KByte, 4-way set associative, 64 byte line size
271        CPUID_FILL_CACHE(0x68,tci, 4, 32*1024, 1, CPUID_CACHE_TYPE_DATA, 1, 64)
272        case 0x70:
273        //Cache Trace cache: 12 K-��op, 8-way set associative
274        case 0x71:
275        //Cache Trace cache: 16 K-��op, 8-way set associative
276        case 0x72:
277        //Cache Trace cache: 32 K-��op, 8-way set associative
278            break;
279        //TLB Instruction TLB: 2M/4M pages, fully associative, 8 entries
280        CPUID_FILL_TLB(0x76, tci, 0xff, 8, 1, CPUID_CACHE_TYPE_INSTR, LARGE_PAGE_SIZE);
281        //Cache 2nd-level cache: 1 MByte, 4-way set associative, 64byte line size
282        CPUID_FILL_CACHE(0x78,tci, 4, 1*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
283        //Cache 2nd-level cache: 128 KByte, 8-way set associative, 64 byte line size, 2 lines per sector
284        CPUID_FILL_CACHE(0x79,tci, 8, 128*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
285        //Cache 2nd-level cache: 256 KByte, 8-way set associative, 64 byte line size, 2 lines per sector
286        CPUID_FILL_CACHE(0x7a,tci, 8, 256*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
287        //Cache 2nd-level cache: 512 KByte, 8-way set associative, 64 byte line size, 2 lines per sector
288        CPUID_FILL_CACHE(0x7b,tci, 8, 512*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
289        //Cache 2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size, 2 lines per sector
290        CPUID_FILL_CACHE(0x7c,tci, 8, 1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
291        //Cache 2nd-level cache: 2 MByte, 8-way set associative, 64byte line size
292        CPUID_FILL_CACHE(0x7d,tci, 8, 2*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
293        //Cache 2nd-level cache: 512 KByte, 2-way set associative, 64-byte line size
294        CPUID_FILL_CACHE(0x7f,tci, 2, 512*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
295        //Cache 2nd-level cache: 512 KByte, 8-way set associative, 64-byte line size
296        CPUID_FILL_CACHE(0x80,tci, 8, 512*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
297        //Cache 2nd-level cache: 256 KByte, 8-way set associative, 32 byte line size
298        CPUID_FILL_CACHE(0x82,tci, 8, 256*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
299        //Cache 2nd-level cache: 512 KByte, 8-way set associative, 32 byte line size
300        CPUID_FILL_CACHE(0x83,tci, 8, 512*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
301        //Cache 2nd-level cache: 1 MByte, 8-way set associative, 32 byte line size
302        CPUID_FILL_CACHE(0x84,tci, 8, 1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
303        //Cache 2nd-level cache: 2 MByte, 8-way set associative, 32 byte line size
304        CPUID_FILL_CACHE(0x85,tci, 8, 2*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 32)
305        //Cache 2nd-level cache: 512 KByte, 4-way set associative, 64 byte line size
306        CPUID_FILL_CACHE(0x86,tci, 4, 512*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
307        //Cache 2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size
308        CPUID_FILL_CACHE(0x87,tci, 8, 1*1024*1024, 2, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
309        //DTLB DTLB: 4k pages, fully associative, 32 entries
310        CPUID_FILL_TLB(0xa0, tci, 0xff, 32, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
311        //TLB Instruction TLB: 4 KByte pages, 4-way set associative, 128 entries
312        CPUID_FILL_TLB(0xb0, tci, 0x4, 128, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
313        //TLB Instruction TLB: 2M pages, 4-way, 8 entries or 4M pages, 4-way, 4 entries
314        CPUID_FILL_TLB(0xb1, tci, 0x4, 8, 1, CPUID_CACHE_TYPE_INSTR, LARGE_PAGE_SIZE);
315        //TLB Instruction TLB: 4KByte pages, 4-way set associative, 64 entries
316        CPUID_FILL_TLB(0xb2, tci, 0x4, 64, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
317        //TLB Data TLB: 4 KByte pages, 4-way set associative, 128 entries
318        CPUID_FILL_TLB(0xb3, tci, 0x4, 128, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
319        //TLB Data TLB1: 4 KByte pages, 4-way associative, 256 entries
320        CPUID_FILL_TLB(0xb4, tci, 0x4, 256, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
321        //TLB Instruction TLB: 4KByte pages, 8-way set associative, 64 entries
322        CPUID_FILL_TLB(0xb5, tci, 0x8, 64, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
323        //TLB Instruction TLB: 4KByte pages, 8-way set associative, 128 entries
324        CPUID_FILL_TLB(0xb6, tci, 0x8, 128, 1, CPUID_CACHE_TYPE_INSTR, BASE_PAGE_SIZE);
325        //TLB Data TLB1: 4 KByte pages, 4-way associative, 64 entries
326        CPUID_FILL_TLB(0xba, tci, 0x4, 64, 1, CPUID_CACHE_TYPE_DATA, BASE_PAGE_SIZE);
327        //TLB Data TLB: 4 KByte and 4 MByte pages, 4-way associative, 8 entries
328        CPUID_FILL_TLB(0xc0, tci, 0x4, 8, 1, CPUID_CACHE_TYPE_DATA, LARGE_PAGE_SIZE + BASE_PAGE_SIZE);
329        //STLB Shared 2nd-Level TLB: 4 KByte/2MByte pages, 8-way associative, 1024 entries
330        CPUID_FILL_TLB(0xc1, tci, 0x8, 1024, 2, CPUID_CACHE_TYPE_UNIFIED, LARGE_PAGE_SIZE + BASE_PAGE_SIZE);
331        //DTLB DTLB: 4 KByte/2 MByte pages, 4-way associative, 16 entries
332        CPUID_FILL_TLB(0xc2, tci, 0x4, 16, 1, CPUID_CACHE_TYPE_DATA, LARGE_PAGE_SIZE + BASE_PAGE_SIZE);
333        //STLB Shared 2nd-Level TLB: 4 KByte /2 MByte pages, 6-way associative, 1536 entries. Also 1GBbyte pages, 4-way, 16 entries.
334        CPUID_FILL_TLB(0xc3, tci, 0x6, 1536, 2, CPUID_CACHE_TYPE_UNIFIED, BASE_PAGE_SIZE);
335        //STLB Shared 2nd-Level TLB: 4 KByte pages, 4-way associative, 512 entries
336        CPUID_FILL_TLB(0xca, tci, 0x4, 512, 2, CPUID_CACHE_TYPE_UNIFIED, BASE_PAGE_SIZE);
337        //Cache 3rd-level cache: 512 KByte, 4-way set associative, 64 byte line size
338        CPUID_FILL_CACHE(0xd0,tci, 4, 512*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
339        //Cache 3rd-level cache: 1 MByte, 4-way set associative, 64 byte line size
340        CPUID_FILL_CACHE(0xd1,tci, 4, 1*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
341        //Cache 3rd-level cache: 2 MByte, 4-way set associative, 64 byte line size
342        CPUID_FILL_CACHE(0xd2,tci, 4, 2*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
343        //Cache 3rd-level cache: 1 MByte, 8-way set associative, 64 byte line size
344        CPUID_FILL_CACHE(0xd6,tci, 8, 1*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
345        //Cache 3rd-level cache: 2 MByte, 8-way set associative, 64 byte line size
346        CPUID_FILL_CACHE(0xd7,tci, 8, 2*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
347        //Cache 3rd-level cache: 4 MByte, 8-way set associative, 64 byte line size
348        CPUID_FILL_CACHE(0xd8,tci, 8, 4*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
349        //Cache 3rd-level cache: 1.5 MByte, 12-way set associative, 64 byte line size
350        CPUID_FILL_CACHE(0xdc,tci, 12, 512*1024 + 1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
351        //Cache 3rd-level cache: 3 MByte, 12-way set associative, 64 byte line size
352        CPUID_FILL_CACHE(0xdd,tci, 12, 3*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
353        //Cache 3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size
354        CPUID_FILL_CACHE(0xde,tci, 12, 6*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
355        //Cache 3rd-level cache: 2 MByte, 16-way set associative, 64 byte line size
356        CPUID_FILL_CACHE(0xe2,tci, 16, 2*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
357        //Cache 3rd-level cache: 4 MByte, 16-way set associative, 64 byte line size
358        CPUID_FILL_CACHE(0xe3,tci, 16, 4*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
359        //Cache 3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size
360        CPUID_FILL_CACHE(0xe4,tci, 16, 8*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
361        //Cache 3rd-level cache: 12MByte, 24-way set associative, 64 byte line size
362        CPUID_FILL_CACHE(0xea,tci, 24, 12*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
363        //Cache 3rd-level cache: 18MByte, 24-way set associative, 64 byte line size
364        CPUID_FILL_CACHE(0xeb,tci, 24, 18*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
365        //Cache 3rd-level cache: 24MByte, 24-way set associative, 64 byte line size
366        CPUID_FILL_CACHE(0xec,tci, 24, 24*1024*1024, 3, CPUID_CACHE_TYPE_UNIFIED, 1, 64)
367        case 0xF0:
368        //Prefetch: 64byte prefetching
369        case 0xF1:
370        //Prefetching 128-Byte prefetching
371        case 0xFF:
372         //General CPUID leaf 2 does not report cache descriptor information, use CPUID leaf 4 to query cache parameters
373        default:
374            break;
375    }
376
377    return CPUID_ERR_INVALID_INDEX;
378}
379
380
381static errval_t cache_info_alternate(struct cpuid_cacheinfo *ci, uint32_t idx)
382{
383    if (cpuid_g_max_input_basic < 4) {
384        return CPUID_ERR_UNSUPPORTED_FUNCTION;
385    }
386
387    struct cpuid_regs reg = CPUID_REGS_INITIAL(4, idx);
388    cpuid_exec(&reg);
389
390    cpuid_intel_cache_info_basic_t ci_a = (cpuid_intel_cache_info_basic_t) &reg.eax;
391    cpuid_intel_cache_info_ebx_t ci_b = (cpuid_intel_cache_info_ebx_t) &reg.ebx;
392
393    ci->level = cpuid_intel_cache_info_basic_level_extract(ci_a);
394
395    switch (cpuid_intel_cache_info_basic_ctype_extract(ci_a)) {
396        case cpuid_intel_cache_type_data :
397            /* data cache */
398            ci->type = CPUID_CACHE_TYPE_DATA;
399            break;
400        case cpuid_intel_cache_type_instr :
401            /* instruction cache */
402            ci->type = CPUID_CACHE_TYPE_INSTR;
403            break;
404        case cpuid_intel_cache_type_unified :
405            ci->type = CPUID_CACHE_TYPE_UNIFIED;
406            /* unified cache */
407            break;
408        default:
409            /* no more cache */
410            ci->type = CPUID_CACHE_TYPE_INVALID;
411            return CPUID_ERR_INVALID_INDEX;
412            break;
413    }
414
415    ci->name = cpuid_cache_names[ci->level][ci->type];
416    ci->linesize = cpuid_intel_cache_info_ebx_coherency_extract(ci_b)+1;
417
418    /* the the number of sets */
419    ci->sets = reg.ecx + 1;
420
421    if (cpuid_intel_cache_info_basic_fullyassoc_extract(ci_a)) {
422        ci->size = (size_t)ci->linesize * ci->sets;
423        ci->associativity = 0xff;
424    } else {
425        ci->associativity = cpuid_intel_cache_info_ebx_assoc_extract(ci_b)+1;
426        ci->size = (size_t)ci->linesize * ci->sets * ci->associativity;
427    }
428
429    ci->shared = cpuid_intel_cache_info_basic_maxlog_extract(ci_a) +1;
430
431    cpuid_intel_cache_info_edx_t ci_d = (cpuid_intel_cache_info_edx_t) &reg.edx;
432    ci->inclusive = cpuid_intel_cache_info_edx_inclusive_extract(ci_d);
433
434    return SYS_ERR_OK;
435}
436
437
438static errval_t cache_info(struct cpuid_cacheinfo *cinfo, uint32_t idx)
439{
440    if (cpuid_g_max_input_basic < 2) {
441        return CPUID_ERR_UNSUPPORTED_FUNCTION;
442    }
443
444    if (cache_info_in_leaf_4) {
445        return cache_info_alternate(cinfo, idx);
446    }
447
448    struct cpuid_regs reg = CPUID_REGS_INITIAL(2, 0);
449    cpuid_exec(&reg);
450
451    cpuid_intel_cache_info_t ci = (cpuid_intel_cache_info_t)&reg.eax;
452    assert(cpuid_intel_cache_info_d0_extract(ci) == 0x01);
453
454    uint32_t *values = &reg.eax;
455    uint8_t *cval;
456    uint32_t currentidx = 0;
457    for (int i = 0; i < 4; ++i) {
458        ci = (cpuid_intel_cache_info_t)(values + i);
459
460        /* check for validity */
461        if (cpuid_intel_cache_info_v0_extract(ci)) {
462            continue;
463        }
464
465        cval = (uint8_t *)ci;
466        for (int j = (i == 0); j < 4; ++j) {
467            struct tlb_cache_info tci;
468            if (cval[j] == 0x00) {
469                continue;
470            } else if (cval[j] == 0xff) {
471                /*
472                 * a value of 0xff indicates that the cache values are reported
473                 * in leaf 4 of cpuid
474                 */
475                cache_info_in_leaf_4 = 0x1;
476                return cache_info_alternate(cinfo, idx);
477            }
478
479            if (err_is_ok(cache_info_lookup(&tci, cval[j]))) {
480                if (!tci.is_tlb) {
481                    if (currentidx == idx) {
482                        *cinfo = tci.ci;
483                        return SYS_ERR_OK;
484                    }
485                    currentidx++;
486                }
487            }
488
489        }
490    }
491
492    return CPUID_ERR_INVALID_INDEX;
493
494}
495
496static uint16_t cache_line_size(void)
497{
498    if (cpuid_g_max_input_basic < 1) {
499        return CPUID_ERR_UNSUPPORTED_FUNCTION;
500    }
501
502    struct cpuid_regs reg = CPUID_REGS_INITIAL(1, 0);
503    cpuid_exec(&reg);
504
505    cpuid_intel_miscinfo_t mi = (cpuid_intel_miscinfo_t)&reg.ebx;
506
507    return cpuid_intel_miscinfo_cflush_sz_extract(mi) * 8;
508}
509
510static errval_t tlb_info(struct cpuid_tlbinfo *ti, uint32_t idx)
511{
512    if (cpuid_g_max_input_basic < 2) {
513        return CPUID_ERR_UNSUPPORTED_FUNCTION;
514    }
515
516    struct cpuid_regs reg = CPUID_REGS_INITIAL(2, 0);
517    cpuid_exec(&reg);
518
519    cpuid_intel_cache_info_t ci = (cpuid_intel_cache_info_t)&reg.eax;
520    assert(cpuid_intel_cache_info_d0_extract(ci) == 0x01);
521
522    uint32_t *values = &reg.eax;
523    uint8_t *cval;
524    uint32_t currentidx = 0;
525    for (int i = 0; i < 4; ++i) {
526        ci = (cpuid_intel_cache_info_t)(values + i);
527
528        /* check for validity */
529        if (cpuid_intel_cache_info_v0_extract(ci)) {
530            continue;
531        }
532
533        cval = (uint8_t *)ci;
534        for (int j = (i == 0); j < 4; ++j) {
535            struct tlb_cache_info tci;
536            if (cval[j] == 0x00) {
537                continue;
538            }
539            if (err_is_ok(cache_info_lookup(&tci, cval[j]))) {
540                if (tci.is_tlb) {
541                    if (currentidx == idx) {
542                        *ti = tci.ti;
543                        return SYS_ERR_OK;
544                    }
545                    currentidx++;
546                }
547            }
548
549        }
550    }
551
552    return CPUID_ERR_INVALID_INDEX;
553
554}
555
556/*
557 * ===============================================================================
558 * thread and topology information
559 * ===============================================================================
560 */
561
562static errval_t thread_info(struct cpuid_threadinfo *ti)
563{
564    if (cpuid_g_max_input_basic < 4) {
565        return CPUID_ERR_UNSUPPORTED_FUNCTION;
566    }
567
568    struct cpuid_regs reg = CPUID_REGS_INITIAL(0x1, 0);
569
570    cpuid_exec(&reg);
571
572    if (!((reg.edx >> 28) & 0x1)) {
573        /* TODO: the cpu supports no hyperthreading */
574        ti->hyperthread = 0;
575        USER_PANIC("NYI");
576        return SYS_ERR_OK;
577    }
578
579    cpuid_intel_miscinfo_t f = (cpuid_intel_miscinfo_t)&reg.ebx;
580
581    coreid_t logical_cores = cpuid_intel_miscinfo_max_log_proc_extract(f);
582    coreid_t apic_id = cpuid_intel_miscinfo_init_apicid_extract(f);
583
584    reg.eax = 0x4;
585    reg.ecx = 0;
586    cpuid_exec(&reg);
587
588    cpuid_intel_cache_info_basic_t ci = (cpuid_intel_cache_info_basic_t)&reg.eax;
589    coreid_t cores_per_package = cpuid_intel_cache_info_basic_maxphys_extract(ci);
590    coreid_t ht = logical_cores / cores_per_package;
591
592    uint8_t ht_shift = cpuid_bits_needed(ht - 1);
593    uint8_t ht_mask = (1 << ht_shift) - 1;
594    uint8_t core_shift = cpuid_bits_needed(cores_per_package - 1);
595    uint8_t core_mask = (1 << core_shift) - 1;
596
597    ti->core = (apic_id >> (ht_shift)) & core_mask;
598    ti->package = apic_id >> (ht_shift + core_shift);
599    ti->hyperthread = apic_id & ht_mask;
600
601    return SYS_ERR_OK;
602}
603
604static errval_t topology_info(struct cpuid_topologyinfo *topo, uint8_t idx)
605{
606    struct cpuid_regs reg = CPUID_REGS_INITIAL(0xb, idx);
607    cpuid_exec(&reg);
608
609    printf("getting the topology information %u\n", idx);
610
611    cpuid_intel_topology_ecx_t ta = (cpuid_intel_topology_eax_t)&reg.eax;
612    cpuid_intel_topology_ebx_t tb = (cpuid_intel_topology_ebx_t)&reg.ebx;
613
614    printf("getting the topology information %u, %u\n", idx, cpuid_intel_topology_eax_x2apic_shift_extract(ta));
615
616    cpuid_intel_topology_ecx_t tc = (cpuid_intel_topology_ecx_t)&reg.ecx;
617    switch (cpuid_intel_topology_ecx_level_type_extract(tc)) {
618        case cpuid_intel_topology_level_smt:
619            printf("found smt at level %u\n", idx);
620            break;
621        case cpuid_intel_topology_level_core:
622            printf("found core at level %u\n", idx);
623            break;
624        case cpuid_intel_topology_level_invalid:
625            printf("level invalid %u\n", idx);
626            return CPUID_ERR_INVALID_INDEX;
627            break;
628        default:
629            printf("level u %u\n", idx);
630            return CPUID_ERR_INVALID_INDEX;
631            break;
632    }
633
634
635    printf("Level numer=%u, logical proc=%u\n", cpuid_intel_topology_ecx_level_number_extract(tc), cpuid_intel_topology_ebx_logical_proc_extract(tb));
636
637
638    topo->nextshift = cpuid_intel_topology_eax_x2apic_shift_extract(ta);
639    topo->x2apic = reg.edx;
640
641    return SYS_ERR_OK;
642}
643
644static errval_t feature_info(struct cpuid_featureinfo *fi)
645{
646    if (cpuid_g_max_input_basic < 0x1) {
647        return CPUID_ERR_UNSUPPORTED_FUNCTION;
648    }
649
650    struct cpuid_regs reg  = CPUID_REGS_INITIAL(0x1, 0);
651    cpuid_exec(&reg);
652
653    cpuid_intel_features_t ft = (cpuid_intel_features_t)&reg.ecx;
654    /* CPU features */
655
656    fi->htt     = cpuid_intel_features_htt_extract(ft);
657    fi->apic    = cpuid_intel_features_apic_extract(ft);
658    fi->x2apic  = cpuid_intel_features_x2apic_extract(ft);
659    fi->tsc     = cpuid_intel_features_tsc_extract(ft);
660    fi->dca     = cpuid_intel_features_dca_extract(ft);
661
662    /* instructions  */
663    fi->monitor = cpuid_intel_features_monitor_extract(ft);
664    fi->cmov    = cpuid_intel_features_cmov_extract(ft);
665
666    /* virtual memory */
667    fi->pse36  = cpuid_intel_features_pse36_extract(ft);
668    fi->pse    = cpuid_intel_features_pse_extract(ft);
669    fi->pae    = cpuid_intel_features_pae_extract(ft);
670    fi->pat    = cpuid_intel_features_pat_extract(ft);
671    fi->pge    = cpuid_intel_features_pge_extract(ft);
672    fi->mtrr   = cpuid_intel_features_mtrr_extract(ft);
673
674    fi->page2M = 1;
675
676
677    /* cache control */
678    fi->clsh    = cpuid_intel_features_clfsh_extract(ft);
679    fi->cnxt_id = cpuid_intel_features_cntx_id_extract(ft);
680
681    /* virtualization technology */
682    fi->vmx    = cpuid_intel_features_vmx_extract(ft);
683    fi->vme    = cpuid_intel_features_vme_extract(ft);
684    fi->svm    = 0;
685
686    /* vector instructions */
687    fi->mmx   = cpuid_intel_features_mmx_extract(ft);
688    fi->sse   = cpuid_intel_features_sse_extract(ft);
689    fi->sse2  = cpuid_intel_features_sse2_extract(ft);
690    fi->sse3  = cpuid_intel_features_sse3_extract(ft);
691    fi->sse41 = cpuid_intel_features_sse4_1_extract(ft);
692    fi->sse42 = cpuid_intel_features_sse4_2_extract(ft);
693    fi->avx   = cpuid_intel_features_avx_extract(ft);
694
695    if (CPUID_EXTENDED_INPUT_MASK(cpuid_g_max_input_extended) < 0x1) {
696        return SYS_ERR_OK;
697    }
698
699    reg.eax = 0x80000001;
700    reg.ecx = 0;
701    cpuid_exec(&reg);
702
703    cpuid_intel_features_ext_edx_t ft2 = (cpuid_intel_features_ext_edx_t)&reg.edx;
704    fi->nx     = cpuid_intel_features_ext_edx_nx_extract(ft2);
705    fi->page1G = cpuid_intel_features_ext_edx_page1G_extract(ft2);;
706    fi->lm     = cpuid_intel_features_ext_edx_lm_extract(ft2);
707
708    return SYS_ERR_OK;
709}
710
711static errval_t address_space_info(struct cpuid_adressspaceinfo *ai)
712{
713    if (CPUID_EXTENDED_INPUT_MASK(cpuid_g_max_input_extended) < 0x8) {
714        return CPUID_ERR_UNSUPPORTED_FUNCTION;
715    }
716
717    struct cpuid_regs reg  = CPUID_REGS_INITIAL(0x80000008, 0);
718    cpuid_exec(&reg);
719
720    cpuid_intel_addrspace_t as = (cpuid_intel_addrspace_t)&reg.eax;
721
722    ai->physical = cpuid_intel_addrspace_physical_extract(as);
723    ai->virtual = cpuid_intel_addrspace_linear_extract(as);
724    /* this information is not provided by intel*/
725    ai->guest_physical = 0;
726
727    return SYS_ERR_OK;
728}
729
730/*
731 * ===============================================================================
732 * backend initialization
733 * ===============================================================================
734 */
735
736/**
737 * \brief fills the vendor specific handler functions
738 *
739 * \param fn_tab  function pointer table to be filled
740 */
741void cpuid_intel_set_handlers(struct cpuid_functions *fn_tab)
742{
743    fn_tab->proc_name = proc_name;
744    fn_tab->proc_family = proc_family;
745    fn_tab->proc_max_input_basic = proc_max_input_basic;
746    fn_tab->proc_max_input_extended = proc_max_input_extended;
747    fn_tab->frequency_info = frequency_info;
748
749    fn_tab->cache_info = cache_info;
750    fn_tab->cache_line_size = cache_line_size;
751
752    fn_tab->tlb_info = tlb_info;
753
754    fn_tab->thread_info = thread_info;
755    fn_tab->topology_info = topology_info;
756
757    fn_tab->feature_info = feature_info;
758
759    fn_tab->address_space_info = address_space_info;
760}
761