1 | /*␊ |
2 | * Copyright 2008 Islam Ahmed Zaid. All rights reserved. <azismed@gmail.com>␊ |
3 | * AsereBLN: 2009: cleanup and bugfix␊ |
4 | */␊ |
5 | ␊ |
6 | #ifndef __LIBSAIO_CPU_H␊ |
7 | #define __LIBSAIO_CPU_H␊ |
8 | ␊ |
9 | #include "libsaio.h"␊ |
10 | ␊ |
11 | #define CPU_VIA_C3␉␉␉0x07␊ |
12 | #define CPU_VIA_C3_Ezra_T␉0x08␊ |
13 | ␊ |
14 | #define CPU_VIA_NANO␉␉0x0F␊ |
15 | ␊ |
16 | ␊ |
17 | ␊ |
18 | extern void scan_cpu(); //PlatformInfo_t *);␊ |
19 | ␊ |
20 | #define min(a,b) ((a) < (b) ? (a) : (b))␊ |
21 | #define quad(hi,lo) (((uint64_t)(hi)) << 32 | (lo))␊ |
22 | ␊ |
23 | ␊ |
24 | #define bit(n)␉␉␉(1UL << (n))␊ |
25 | #define bitmask(h,l)␉␉((bit(h)|(bit(h)-1)) & ~(bit(l)-1))␊ |
26 | #define bitfield(x,h,l)␉␉(((x) & bitmask(h,l)) >> l)␊ |
27 | ␊ |
28 | #define␉CPUID_VID_INTEL␉␉"GenuineIntel"␊ |
29 | #define␉CPUID_VID_AMD␉␉"AuthenticAMD"␊ |
30 | ␊ |
31 | #define CPUID_STRING_UNKNOWN "Unknown CPU Typ"␊ |
32 | ␊ |
33 | #define _Bit(n)␉␉␉(1ULL << n)␊ |
34 | #define _HBit(n)␉␉(1ULL << ((n)+32))␊ |
35 | ␊ |
36 | /*␊ |
37 | * The CPUID_FEATURE_XXX values define 64-bit values␊ |
38 | * returned in %ecx:%edx to a CPUID request with %eax of 1: ␊ |
39 | */␊ |
40 | #define␉CPUID_FEATURE_FPU _Bit(0)␉/* Floating point unit on-chip */␊ |
41 | #define␉CPUID_FEATURE_VME _Bit(1)␉/* Virtual Mode Extension */␊ |
42 | #define␉CPUID_FEATURE_DE _Bit(2)␉/* Debugging Extension */␊ |
43 | #define␉CPUID_FEATURE_PSE _Bit(3)␉/* Page Size Extension */␊ |
44 | #define␉CPUID_FEATURE_TSC _Bit(4)␉/* Time Stamp Counter */␊ |
45 | #define␉CPUID_FEATURE_MSR _Bit(5)␉/* Model Specific Registers */␊ |
46 | #define CPUID_FEATURE_PAE _Bit(6)␉/* Physical Address Extension */␊ |
47 | #define␉CPUID_FEATURE_MCE _Bit(7)␉/* Machine Check Exception */␊ |
48 | #define␉CPUID_FEATURE_CX8 _Bit(8)␉/* CMPXCHG8B */␊ |
49 | #define␉CPUID_FEATURE_APIC _Bit(9)␉/* On-chip APIC */␊ |
50 | #define CPUID_FEATURE_SEP _Bit(11)␉/* Fast System Call */␊ |
51 | #define␉CPUID_FEATURE_MTRR _Bit(12)␉/* Memory Type Range Register */␊ |
52 | #define␉CPUID_FEATURE_PGE _Bit(13)␉/* Page Global Enable */␊ |
53 | #define␉CPUID_FEATURE_MCA _Bit(14)␉/* Machine Check Architecture */␊ |
54 | #define␉CPUID_FEATURE_CMOV _Bit(15)␉/* Conditional Move Instruction */␊ |
55 | #define CPUID_FEATURE_PAT _Bit(16)␉/* Page Attribute Table */␊ |
56 | #define CPUID_FEATURE_PSE36 _Bit(17)␉/* 36-bit Page Size Extension */␊ |
57 | #define CPUID_FEATURE_PSN _Bit(18)␉/* Processor Serial Number */␊ |
58 | #define CPUID_FEATURE_CLFSH _Bit(19)␉/* CLFLUSH Instruction supported */␊ |
59 | #define CPUID_FEATURE_DS _Bit(21)␉/* Debug Store */␊ |
60 | #define CPUID_FEATURE_ACPI _Bit(22)␉/* Thermal monitor and Clock Ctrl */␊ |
61 | #define CPUID_FEATURE_MMX _Bit(23)␉/* MMX supported */␊ |
62 | #define CPUID_FEATURE_FXSR _Bit(24)␉/* Fast floating pt save/restore */␊ |
63 | #define CPUID_FEATURE_SSE _Bit(25)␉/* Streaming SIMD extensions */␊ |
64 | #define CPUID_FEATURE_SSE2 _Bit(26)␉/* Streaming SIMD extensions 2 */␊ |
65 | #define CPUID_FEATURE_SS _Bit(27)␉/* Self-Snoop */␊ |
66 | #define CPUID_FEATURE_HTT _Bit(28)␉/* Hyper-Threading Technology */␊ |
67 | #define CPUID_FEATURE_TM _Bit(29)␉/* Thermal Monitor (TM1) */␊ |
68 | #define CPUID_FEATURE_PBE _Bit(31)␉/* Pend Break Enable */␊ |
69 | ␊ |
70 | #define CPUID_FEATURE_SSE3 _HBit(0)␉/* Streaming SIMD extensions 3 */␊ |
71 | #define CPUID_FEATURE_PCLMULQDQ _HBit(1) /* PCLMULQDQ Instruction */␊ |
72 | ␊ |
73 | #define CPUID_FEATURE_MONITOR _HBit(3)␉/* Monitor/mwait */␊ |
74 | #define CPUID_FEATURE_DSCPL _HBit(4)␉/* Debug Store CPL */␊ |
75 | #define CPUID_FEATURE_VMX _HBit(5)␉/* VMX */␊ |
76 | #define CPUID_FEATURE_SMX _HBit(6)␉/* SMX */␊ |
77 | #define CPUID_FEATURE_EST _HBit(7)␉/* Enhanced SpeedsTep (GV3) */␊ |
78 | #define CPUID_FEATURE_TM2 _HBit(8)␉/* Thermal Monitor 2 */␊ |
79 | #define CPUID_FEATURE_SSSE3 _HBit(9)␉/* Supplemental SSE3 instructions */␊ |
80 | #define CPUID_FEATURE_CID _HBit(10)␉/* L1 Context ID */␊ |
81 | ␊ |
82 | #define CPUID_FEATURE_CX16 _HBit(13)␉/* CmpXchg16b instruction */␊ |
83 | #define CPUID_FEATURE_xTPR _HBit(14)␉/* Send Task PRiority msgs */␊ |
84 | #define CPUID_FEATURE_PDCM _HBit(15)␉/* Perf/Debug Capability MSR */␊ |
85 | ␊ |
86 | #define CPUID_FEATURE_DCA _HBit(18)␉/* Direct Cache Access */␊ |
87 | #define CPUID_FEATURE_SSE4_1 _HBit(19)␉/* Streaming SIMD extensions 4.1 */␊ |
88 | #define CPUID_FEATURE_SSE4_2 _HBit(20)␉/* Streaming SIMD extensions 4.2 */␊ |
89 | #define CPUID_FEATURE_xAPIC _HBit(21)␉/* Extended APIC Mode */␊ |
90 | #define CPUID_FEATURE_POPCNT _HBit(23)␉/* POPCNT instruction */␊ |
91 | #define CPUID_FEATURE_AES _HBit(25)␉/* AES instructions */␊ |
92 | #define CPUID_FEATURE_VMM _HBit(31)␉/* VMM (Hypervisor) present */␊ |
93 | ␊ |
94 | /*␊ |
95 | * The CPUID_EXTFEATURE_XXX values define 64-bit values␊ |
96 | * returned in %ecx:%edx to a CPUID request with %eax of 0x80000001: ␊ |
97 | */␊ |
98 | #define CPUID_EXTFEATURE_SYSCALL _Bit(11)␉/* SYSCALL/sysret */␊ |
99 | #define CPUID_EXTFEATURE_XD␉␉ _Bit(20)␉/* eXecute Disable */␊ |
100 | #define CPUID_EXTFEATURE_1GBPAGE _Bit(26) /* 1G-Byte Page support */␊ |
101 | #define CPUID_EXTFEATURE_RDTSCP␉ _Bit(27)␉/* RDTSCP */␊ |
102 | #define CPUID_EXTFEATURE_EM64T␉ _Bit(29)␉/* Extended Mem 64 Technology */␊ |
103 | ␊ |
104 | //#define CPUID_EXTFEATURE_LAHF␉ _HBit(20)␉/* LAFH/SAHF instructions */␊ |
105 | // New definition with Snow kernel␊ |
106 | #define CPUID_EXTFEATURE_LAHF␉ _HBit(0)␉/* LAHF/SAHF instructions */␊ |
107 | /*␊ |
108 | * The CPUID_EXTFEATURE_XXX values define 64-bit values␊ |
109 | * returned in %ecx:%edx to a CPUID request with %eax of 0x80000007: ␊ |
110 | */␊ |
111 | #define CPUID_EXTFEATURE_TSCI _Bit(8)␉/* TSC Invariant */␊ |
112 | ␊ |
113 | #define␉CPUID_CACHE_SIZE␉16␉/* Number of descriptor values */␊ |
114 | ␊ |
115 | #define CPUID_MWAIT_EXTENSION␉_Bit(0)␉/* enumeration of WMAIT extensions */␊ |
116 | #define CPUID_MWAIT_BREAK␉_Bit(1)␉/* interrupts are break events␉ */␊ |
117 | ␊ |
118 | ␊ |
119 | ␊ |
120 | ␊ |
121 | #define MSR_IA32_PLATFORM_ID␉0x0017␊ |
122 | #define MSR_P4_EBC_FREQUENCY_ID␉0x002C␊ |
123 | #define MSR_CORE_THREAD_COUNT␉0x0035␊ |
124 | #define␉MSR_IA32_PERF_STATUS␉0x0198␊ |
125 | #define MSR_IA32_PERF_CONTROL␉0x0199␊ |
126 | #define MSR_IA32_EXT_CONFIG␉␉0x00EE␊ |
127 | #define MSR_FLEX_RATIO␉␉␉0x0194 //Slice - not used␊ |
128 | #define MSR_FSB_FREQ␉␉␉0x00CD //Slice - not used␊ |
129 | #define␉MSR_PLATFORM_INFO␉␉0x00CE␉// for i7 it gives min and max␊ |
130 | #define MSR_TURBO_RATIO␉␉␉0x01AD //Slice - for i7␊ |
131 | #define MSR_IA32_EBL_CR_POWERON␉0x002A //Meklort - for VIA␊ |
132 | #define K8_FIDVID_STATUS␉␉0xC0010042␊ |
133 | #define K10_COFVID_STATUS␉␉0xC0010071␊ |
134 | ␊ |
135 | /* Centaur-Hauls/IDT defined MSRs. */␊ |
136 | #define MSR_IDT_FCR1␉␉␉0x00000107␊ |
137 | #define MSR_IDT_FCR2␉␉␉0x00000108␊ |
138 | #define MSR_IDT_FCR3␉␉␉0x00000109␊ |
139 | #define MSR_IDT_FCR4␉␉␉0x0000010a␊ |
140 | ␊ |
141 | #define MSR_IDT_MCR0␉␉␉0x00000110␊ |
142 | #define MSR_IDT_MCR1␉␉␉0x00000111␊ |
143 | #define MSR_IDT_MCR2␉␉␉0x00000112␊ |
144 | #define MSR_IDT_MCR3␉␉␉0x00000113␊ |
145 | #define MSR_IDT_MCR4␉␉␉0x00000114␊ |
146 | #define MSR_IDT_MCR5␉␉␉0x00000115␊ |
147 | #define MSR_IDT_MCR6␉␉␉0x00000116␊ |
148 | #define MSR_IDT_MCR7␉␉␉0x00000117␊ |
149 | #define MSR_IDT_MCR_CTRL␉␉0x00000120␊ |
150 | ␊ |
151 | /* VIA Nano defined MSTs */␊ |
152 | #define MSR_NANO_FCR1 0x1204 // This MSR contains control bits and family, model, etc.␊ |
153 | #define MSR_NANO_FCR2 0x1206 // This MSR contains part of the vendor string␊ |
154 | #define MSR_NANO_FCR3 0x1207 // This MSR contains part of the vendor string␊ |
155 | #define VIA_ALTERNATIVE_VENDOR_BIT (1 << 8) // This bit in MSR_IDT_FCR1 enables alternative vendor string␊ |
156 | ␊ |
157 | /* VIA Cyrix defined MSRs */␊ |
158 | #define MSR_VIA_FCR␉␉␉␉0x00001107␊ |
159 | #define MSR_VIA_LONGHAUL␉␉0x0000110a␊ |
160 | #define MSR_VIA_RNG␉␉␉␉0x0000110b␊ |
161 | #define MSR_VIA_BCR2␉␉␉0x00001147␊ |
162 | ␊ |
163 | ␊ |
164 | ␊ |
165 | #define DEFAULT_FSB␉␉100000 /* for now, hardcoding 100MHz for old CPUs */␊ |
166 | ␊ |
167 | // DFE: This constant comes from older xnu:␊ |
168 | #define CLKNUM␉␉␉1193182␉␉/* formerly 1193167 */␊ |
169 | ␊ |
170 | // DFE: These two constants come from Linux except CLOCK_TICK_RATE replaced with CLKNUM␊ |
171 | #define CALIBRATE_TIME_MSEC␉30␉␉/* 30 msecs */␊ |
172 | #define CALIBRATE_LATCH␉␉((CLKNUM * CALIBRATE_TIME_MSEC + 1000/2)/1000)␊ |
173 | ␊ |
174 | typedef enum { eax, ebx, ecx, edx } cpuid_register_t;␊ |
175 | /*␊ |
176 | * Cache ID descriptor structure, used to parse CPUID leaf 2.␊ |
177 | * Note: not used in kernel.␊ |
178 | */␊ |
179 | typedef enum { Lnone, L1I, L1D, L2U, L3U, LCACHE_MAX } cache_type_t ; ␊ |
180 | typedef struct {␊ |
181 | ␉unsigned char␉value; /* Descriptor value */␊ |
182 | ␉cache_type_t ␉type; /* Cache type */␊ |
183 | ␉unsigned int ␉size; /* Cache size */␊ |
184 | ␉unsigned int ␉linesize; /* Cache line size */␊ |
185 | ␉const char␉*description; /* Cache description */␊ |
186 | } cpuid_cache_desc_t; ␊ |
187 | ␊ |
188 | ␊ |
189 | #define CACHE_DESC(value,type,size,linesize,text) \␊ |
190 | { value, type, size, linesize, text }␊ |
191 | ␊ |
192 | /* Physical CPU info - this is exported out of the kernel (kexts), so be wary of changes */␊ |
193 | typedef struct {␊ |
194 | ␉char␉␉cpuid_vendor[16];␊ |
195 | ␉char␉␉cpuid_brand_string[48];␊ |
196 | ␉const char␉*cpuid_model_string;␊ |
197 | ␉␊ |
198 | ␉cpu_type_t␉cpuid_type;␉␉␉␉␉/* this is *not* a cpu_type_t in our <mach/machine.h> */␊ |
199 | ␉uint8_t␉␉cpuid_family;␊ |
200 | ␉uint8_t␉␉cpuid_model;␊ |
201 | ␉uint8_t␉␉cpuid_extmodel;␊ |
202 | ␉uint8_t␉␉cpuid_extfamily;␊ |
203 | ␉uint8_t␉␉cpuid_stepping;␊ |
204 | ␉uint64_t␉cpuid_features;␊ |
205 | ␉uint64_t␉cpuid_extfeatures;␊ |
206 | ␉uint32_t␉cpuid_signature;␊ |
207 | ␉uint8_t ␉cpuid_brand; ␊ |
208 | ␉␊ |
209 | ␉uint32_t␉cache_size[LCACHE_MAX];␊ |
210 | ␉uint32_t␉cache_linesize;␊ |
211 | ␉␊ |
212 | ␉uint8_t␉␉cache_info[64]; /* list of cache descriptors */␊ |
213 | ␉␊ |
214 | ␉uint32_t␉cpuid_cores_per_package;␊ |
215 | ␉uint32_t␉cpuid_logical_per_package;␊ |
216 | ␉uint32_t␉cache_sharing[LCACHE_MAX];␊ |
217 | ␉uint32_t␉cache_partitions[LCACHE_MAX];␊ |
218 | ␉␊ |
219 | ␉cpu_type_t␉cpuid_cpu_type;␉␉␉/* <mach/machine.h> */␊ |
220 | ␉cpu_subtype_t␉cpuid_cpu_subtype;␉␉/* <mach/machine.h> */␉␊ |
221 | ␉␊ |
222 | ␉/* Monitor/mwait Leaf: */␊ |
223 | ␉uint32_t␉cpuid_mwait_linesize_min;␊ |
224 | ␉uint32_t␉cpuid_mwait_linesize_max;␊ |
225 | ␉uint32_t␉cpuid_mwait_extensions;␊ |
226 | ␉uint32_t␉cpuid_mwait_sub_Cstates;␊ |
227 | ␉␊ |
228 | ␉/* Thermal and Power Management Leaf: */␊ |
229 | ␉boolean_t␉cpuid_thermal_sensor;␊ |
230 | ␉boolean_t␉cpuid_thermal_dynamic_acceleration;␊ |
231 | ␉uint32_t␉cpuid_thermal_thresholds;␊ |
232 | ␉boolean_t␉cpuid_thermal_ACNT_MCNT;␊ |
233 | ␉␊ |
234 | ␉/* Architectural Performance Monitoring Leaf: */␊ |
235 | ␉uint8_t␉␉cpuid_arch_perf_version;␊ |
236 | ␉uint8_t␉␉cpuid_arch_perf_number;␊ |
237 | ␉uint8_t␉␉cpuid_arch_perf_width;␊ |
238 | ␉uint8_t␉␉cpuid_arch_perf_events_number;␊ |
239 | ␉uint32_t␉cpuid_arch_perf_events;␊ |
240 | ␉uint8_t␉␉cpuid_arch_perf_fixed_number;␊ |
241 | ␉uint8_t␉␉cpuid_arch_perf_fixed_width;␊ |
242 | ␉␊ |
243 | ␉/* Cache details: */␊ |
244 | ␉uint32_t␉cpuid_cache_linesize;␊ |
245 | ␉uint32_t␉cpuid_cache_L2_associativity;␊ |
246 | ␉uint32_t␉cpuid_cache_size;␊ |
247 | ␉␊ |
248 | ␉/* Virtual and physical address aize: */␊ |
249 | ␉uint32_t␉cpuid_address_bits_physical;␊ |
250 | ␉uint32_t␉cpuid_address_bits_virtual;␊ |
251 | ␉␊ |
252 | ␉uint32_t␉cpuid_microcode_version;␊ |
253 | ␉␊ |
254 | ␉/* Numbers of tlbs per processor [i|d, small|large, level0|level1] */␊ |
255 | ␉uint32_t␉cpuid_tlb[2][2][2];␊ |
256 | #define␉TLB_INST␉0␊ |
257 | #define␉TLB_DATA␉1␊ |
258 | #define␉TLB_SMALL␉0␊ |
259 | #define␉TLB_LARGE␉1␊ |
260 | ␉uint32_t␉cpuid_stlb;␊ |
261 | ␉␊ |
262 | ␉uint32_t␉core_count;␊ |
263 | ␉uint32_t␉thread_count;␊ |
264 | ␉␊ |
265 | ␉/* Max leaf ids available from CPUID */␊ |
266 | ␉uint32_t␉cpuid_max_basic;␊ |
267 | ␉uint32_t␉cpuid_max_ext;␊ |
268 | } i386_cpu_info_t;␊ |
269 | ␊ |
270 | static i386_cpu_info_t cpuid_cpu_info;␊ |
271 | ␊ |
272 | static i386_cpu_info_t␉*cpuid_info(void)␊ |
273 | {␊ |
274 | ␉return ␉&cpuid_cpu_info;␊ |
275 | }␊ |
276 | ␊ |
277 | ␊ |
278 | static inline uint64_t rdtsc64(void)␊ |
279 | {␊ |
280 | ␉uint64_t ret;␊ |
281 | ␉__asm__ volatile("rdtsc" : "=A" (ret));␊ |
282 | ␉return ret;␊ |
283 | }␊ |
284 | ␊ |
285 | static inline uint64_t rdmsr64(uint32_t msr)␊ |
286 | {␊ |
287 | uint64_t ret;␊ |
288 | __asm__ volatile("rdmsr" : "=A" (ret) : "c" (msr));␊ |
289 | return ret;␊ |
290 | }␊ |
291 | ␊ |
292 | static inline void wrmsr64(uint32_t msr, uint64_t val)␊ |
293 | {␊ |
294 | ␉__asm__ volatile("wrmsr" : : "c" (msr), "A" (val));␊ |
295 | }␊ |
296 | ␊ |
297 | static inline void intel_waitforsts(void) {␊ |
298 | ␉uint32_t inline_timeout = 100000;␊ |
299 | ␉while (rdmsr64(MSR_IA32_PERF_STATUS) & (1 << 21)) { if (!inline_timeout--) break; }␊ |
300 | }␊ |
301 | ␊ |
302 | static inline void do_cpuid(uint32_t selector, uint32_t *data)␊ |
303 | {␊ |
304 | ␉asm volatile ("cpuid"␊ |
305 | ␉␉␉␉ : "=a" (data[0]),␊ |
306 | ␉␉␉␉ "=b" (data[1]),␊ |
307 | ␉␉␉␉ "=c" (data[2]),␊ |
308 | ␉␉␉␉ "=d" (data[3])␊ |
309 | ␉␉␉␉ : "a" (selector));␊ |
310 | }␊ |
311 | ␊ |
312 | static inline void do_cpuid2(uint32_t selector, uint32_t selector2, uint32_t *data)␊ |
313 | {␊ |
314 | ␉asm volatile ("cpuid"␊ |
315 | ␉␉␉␉ : "=a" (data[0]),␊ |
316 | ␉␉␉␉ "=b" (data[1]),␊ |
317 | ␉␉␉␉ "=c" (data[2]),␊ |
318 | ␉␉␉␉ "=d" (data[3])␊ |
319 | ␉␉␉␉ : "a" (selector), "c" (selector2));␊ |
320 | }␊ |
321 | ␊ |
322 | // DFE: enable_PIT2 and disable_PIT2 come from older xnu␊ |
323 | ␊ |
324 | /*␊ |
325 | * Enable or disable timer 2.␊ |
326 | * Port 0x61 controls timer 2:␊ |
327 | * bit 0 gates the clock,␊ |
328 | * bit 1 gates output to speaker.␊ |
329 | */␊ |
330 | static inline void enable_PIT2(void)␊ |
331 | {␊ |
332 | /* Enable gate, disable speaker */␊ |
333 | __asm__ volatile(␊ |
334 | ␉␉␉␉␉ " inb $0x61,%%al \n\t"␊ |
335 | ␉␉␉␉␉ " and $0xFC,%%al \n\t" /* & ~0x03 */␊ |
336 | ␉␉␉␉␉ " or $1,%%al \n\t"␊ |
337 | ␉␉␉␉␉ " outb %%al,$0x61 \n\t"␊ |
338 | ␉␉␉␉␉ : : : "%al" );␊ |
339 | }␊ |
340 | ␊ |
341 | static inline void disable_PIT2(void)␊ |
342 | {␊ |
343 | /* Disable gate and output to speaker */␊ |
344 | __asm__ volatile(␊ |
345 | ␉␉␉␉␉ " inb $0x61,%%al \n\t"␊ |
346 | ␉␉␉␉␉ " and $0xFC,%%al \n\t"␉/* & ~0x03 */␊ |
347 | ␉␉␉␉␉ " outb %%al,$0x61 \n\t"␊ |
348 | ␉␉␉␉␉ : : : "%al" );␊ |
349 | }␊ |
350 | ␊ |
351 | // DFE: set_PIT2_mode0, poll_PIT2_gate, and measure_tsc_frequency are␊ |
352 | // roughly based on Linux code␊ |
353 | ␊ |
354 | /* Set the 8254 channel 2 to mode 0 with the specified value.␊ |
355 | In mode 0, the counter will initially set its gate low when the␊ |
356 | timer expires. For this to be useful, you ought to set it high␊ |
357 | before calling this function. The enable_PIT2 function does this.␊ |
358 | */␊ |
359 | static inline void set_PIT2_mode0(uint16_t value)␊ |
360 | {␊ |
361 | __asm__ volatile(␊ |
362 | ␉␉␉␉␉ " movb $0xB0,%%al \n\t"␊ |
363 | ␉␉␉␉␉ " outb␉%%al,$0x43␉\n\t"␊ |
364 | ␉␉␉␉␉ " movb␉%%dl,%%al␉\n\t"␊ |
365 | ␉␉␉␉␉ " outb␉%%al,$0x42␉\n\t"␊ |
366 | ␉␉␉␉␉ " movb␉%%dh,%%al␉\n\t"␊ |
367 | ␉␉␉␉␉ " outb␉%%al,$0x42"␊ |
368 | ␉␉␉␉␉ : : "d"(value) /*: no clobber */ );␊ |
369 | }␊ |
370 | ␊ |
371 | /* Returns the number of times the loop ran before the PIT2 signaled */␊ |
372 | static inline unsigned long poll_PIT2_gate(void)␊ |
373 | {␊ |
374 | unsigned long count = 0;␊ |
375 | unsigned char nmi_sc_val;␊ |
376 | do {␊ |
377 | ++count;␊ |
378 | __asm__ volatile(␊ |
379 | ␉␉␉␉␉␉ "inb␉$0x61,%0"␊ |
380 | ␉␉␉␉␉␉ : "=q"(nmi_sc_val) /*:*/ /* no input */ /*:*/ /* no clobber */);␊ |
381 | } while( (nmi_sc_val & 0x20) == 0);␊ |
382 | return count;␊ |
383 | }␊ |
384 | ␊ |
385 | static void cpuid_update_generic_info()␊ |
386 | {␊ |
387 | uint32_t cpuid_reg[4];␊ |
388 | uint32_t max_extid;␊ |
389 | char str[128];␊ |
390 | char* p;␊ |
391 | ␉i386_cpu_info_t* info_p = cpuid_info();␊ |
392 | ␉␊ |
393 | /* Get vendor */␊ |
394 | do_cpuid(0, cpuid_reg);␊ |
395 | bcopy((char *)&cpuid_reg[ebx], &info_p->cpuid_vendor[0], 4); /* ug */␊ |
396 | bcopy((char *)&cpuid_reg[ecx], &info_p->cpuid_vendor[8], 4);␊ |
397 | bcopy((char *)&cpuid_reg[edx], &info_p->cpuid_vendor[4], 4);␊ |
398 | info_p->cpuid_vendor[12] = 0;␊ |
399 | ␉␊ |
400 | /* Get extended CPUID results */␊ |
401 | do_cpuid(0x80000000, cpuid_reg);␊ |
402 | max_extid = cpuid_reg[eax];␊ |
403 | ␉␊ |
404 | /* Check to see if we can get the brand string */␊ |
405 | if (max_extid >= 0x80000004) {␊ |
406 | /*␊ |
407 | * The brand string is up to 48 bytes and is guaranteed to be␊ |
408 | * NUL terminated.␊ |
409 | */␊ |
410 | do_cpuid(0x80000002, cpuid_reg);␊ |
411 | bcopy((char *)cpuid_reg, &str[0], 16);␊ |
412 | do_cpuid(0x80000003, cpuid_reg);␊ |
413 | bcopy((char *)cpuid_reg, &str[16], 16);␊ |
414 | do_cpuid(0x80000004, cpuid_reg);␊ |
415 | bcopy((char *)cpuid_reg, &str[32], 16);␊ |
416 | for (p = str; *p != '\0'; p++) {␊ |
417 | if (*p != ' ') break;␊ |
418 | }␊ |
419 | strncpy(info_p->cpuid_brand_string, p,␊ |
420 | sizeof(info_p->cpuid_brand_string));␊ |
421 | ␉␉␊ |
422 | if (!strncmp(info_p->cpuid_brand_string, CPUID_STRING_UNKNOWN,␊ |
423 | ␉␉␉␉␉ min(sizeof(info_p->cpuid_brand_string),␊ |
424 | ␉␉␉␉␉␉ strlen(CPUID_STRING_UNKNOWN) + 1))) {␊ |
425 | ␉␉␉␉␉␉ /*␊ |
426 | ␉␉␉␉␉␉ * This string means we have a firmware-programmable brand string,␊ |
427 | ␉␉␉␉␉␉ * and the firmware couldn't figure out what sort of CPU we have.␊ |
428 | ␉␉␉␉␉␉ */␊ |
429 | ␉␉␉␉␉␉ info_p->cpuid_brand_string[0] = '\0';␊ |
430 | ␉␉␉␉␉ }␊ |
431 | }␊ |
432 | ␊ |
433 | /* Get cache and addressing info */␊ |
434 | if (max_extid >= 0x80000006) {␊ |
435 | do_cpuid(0x80000006, cpuid_reg);␊ |
436 | info_p->cpuid_cache_linesize = bitfield(cpuid_reg[ecx], 7, 0);␊ |
437 | info_p->cpuid_cache_L2_associativity = bitfield(cpuid_reg[ecx], 15, 12);␊ |
438 | info_p->cpuid_cache_size = bitfield(cpuid_reg[ecx], 31, 16);␊ |
439 | do_cpuid(0x80000008, cpuid_reg);␊ |
440 | info_p->cpuid_address_bits_physical = bitfield(cpuid_reg[eax], 7, 0);␊ |
441 | info_p->cpuid_address_bits_virtual = bitfield(cpuid_reg[eax], 15, 8);␊ |
442 | }␊ |
443 | ␉␊ |
444 | /* Get processor signature and decode */␊ |
445 | do_cpuid(1, cpuid_reg);␊ |
446 | info_p->cpuid_signature = cpuid_reg[eax];␊ |
447 | info_p->cpuid_stepping = bitfield(cpuid_reg[eax], 3, 0);␊ |
448 | info_p->cpuid_model = bitfield(cpuid_reg[eax], 7, 4);␊ |
449 | info_p->cpuid_family = bitfield(cpuid_reg[eax], 11, 8);␊ |
450 | info_p->cpuid_type = bitfield(cpuid_reg[eax], 13, 12);␊ |
451 | info_p->cpuid_extmodel = bitfield(cpuid_reg[eax], 19, 16);␊ |
452 | info_p->cpuid_extfamily = bitfield(cpuid_reg[eax], 27, 20);␊ |
453 | info_p->cpuid_brand = bitfield(cpuid_reg[ebx], 7, 0);␊ |
454 | info_p->cpuid_features = quad(cpuid_reg[ecx], cpuid_reg[edx]);␊ |
455 | ␉␊ |
456 | /* Fold extensions into family/model */␊ |
457 | if (info_p->cpuid_family == 0x0f) {␊ |
458 | info_p->cpuid_family += info_p->cpuid_extfamily;␊ |
459 | }␊ |
460 | if (info_p->cpuid_family == 0x0f || info_p->cpuid_family== 0x06) {␊ |
461 | info_p->cpuid_model += (info_p->cpuid_extmodel << 4);␊ |
462 | }␊ |
463 | ␉␊ |
464 | if (info_p->cpuid_features & CPUID_FEATURE_HTT) {␊ |
465 | info_p->cpuid_logical_per_package = bitfield(cpuid_reg[ebx], 23, 16);␊ |
466 | } else {␊ |
467 | info_p->cpuid_logical_per_package = 1;␊ |
468 | }␊ |
469 | ␉␊ |
470 | if (max_extid >= 0x80000001) {␊ |
471 | do_cpuid(0x80000001, cpuid_reg);␊ |
472 | info_p->cpuid_extfeatures = quad(cpuid_reg[ecx], cpuid_reg[edx]);␊ |
473 | }␊ |
474 | ␉␊ |
475 | if (info_p->cpuid_extfeatures & CPUID_FEATURE_MONITOR) {␊ |
476 | ␉␉␊ |
477 | do_cpuid(5, cpuid_reg);␊ |
478 | info_p->cpuid_mwait_linesize_min = cpuid_reg[eax];␊ |
479 | info_p->cpuid_mwait_linesize_max = cpuid_reg[ebx];␊ |
480 | info_p->cpuid_mwait_extensions = cpuid_reg[ecx];␊ |
481 | info_p->cpuid_mwait_sub_Cstates = cpuid_reg[edx];␊ |
482 | ␉␉␊ |
483 | do_cpuid(6, cpuid_reg);␊ |
484 | info_p->cpuid_thermal_sensor = bitfield(cpuid_reg[eax], 0, 0);␊ |
485 | info_p->cpuid_thermal_dynamic_acceleration =␊ |
486 | ␉␉bitfield(cpuid_reg[eax], 1, 1);␊ |
487 | info_p->cpuid_thermal_thresholds = bitfield(cpuid_reg[ebx], 3, 0);␊ |
488 | info_p->cpuid_thermal_ACNT_MCNT = bitfield(cpuid_reg[ecx], 0, 0);␊ |
489 | ␉␉␊ |
490 | do_cpuid(0xa, cpuid_reg);␊ |
491 | info_p->cpuid_arch_perf_version = bitfield(cpuid_reg[eax], 7, 0);␊ |
492 | info_p->cpuid_arch_perf_number = bitfield(cpuid_reg[eax],15, 8);␊ |
493 | info_p->cpuid_arch_perf_width = bitfield(cpuid_reg[eax],23,16);␊ |
494 | info_p->cpuid_arch_perf_events_number = bitfield(cpuid_reg[eax],31,24);␊ |
495 | info_p->cpuid_arch_perf_events = cpuid_reg[ebx];␊ |
496 | info_p->cpuid_arch_perf_fixed_number = bitfield(cpuid_reg[edx], 4, 0);␊ |
497 | info_p->cpuid_arch_perf_fixed_width = bitfield(cpuid_reg[edx],12, 5);␊ |
498 | ␉␉␊ |
499 | }␊ |
500 | ␉␊ |
501 | ␉do_cpuid(4, cpuid_reg);␊ |
502 | ␉info_p->cpuid_cores_per_package = bitfield(cpuid_reg[eax], 31, 26) + 1;␊ |
503 | ␉␊ |
504 | ␉if (info_p->cpuid_cores_per_package == 0) {␊ |
505 | ␉␉info_p->cpuid_cores_per_package = 1;␊ |
506 | ␉␉␊ |
507 | ␉}␉␉␊ |
508 | ␉␊ |
509 | ␉switch (info_p->cpuid_model)␊ |
510 | ␉{␊ |
511 | ␉␉case 0x1C:␊ |
512 | ␉␉{␊ |
513 | ␉␉␉//uint64_t msr = rdmsr64(MSR_CORE_THREAD_COUNT);␊ |
514 | ␉␉␉info_p->core_count = 1; //bitfield((uint32_t)msr, 19, 16);␊ |
515 | ␉␉␉info_p->thread_count = 2; //bitfield((uint32_t)msr, 15, 0);␊ |
516 | ␉␉}␊ |
517 | ␉␉␉break;␊ |
518 | ␉␉case 0x19: // some i5 ???␊ |
519 | ␉␉case 0x1A: // Intel Core i7 LGA1366 (45nm)␊ |
520 | ␉␉case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)␊ |
521 | ␉␉case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)␊ |
522 | ␉␉{␊ |
523 | ␉␉␉uint64_t msr = rdmsr64(MSR_CORE_THREAD_COUNT);␊ |
524 | ␉␉␉info_p->core_count = bitfield((uint32_t)msr, 31, 16);␊ |
525 | ␉␉␉info_p->thread_count = bitfield((uint32_t)msr, 15, 0);␊ |
526 | ␉␉} break;␊ |
527 | ␉␉case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core␊ |
528 | ␉␉case 0x1F:␊ |
529 | ␉␉case 0x2F:␊ |
530 | ␉␉{␊ |
531 | ␉␉␉uint64_t msr = rdmsr64(MSR_CORE_THREAD_COUNT);␊ |
532 | ␉␉␉info_p->core_count = bitfield((uint32_t)msr, 19, 16);␊ |
533 | ␉␉␉info_p->thread_count = bitfield((uint32_t)msr, 15, 0);␊ |
534 | ␉␉␉break;␊ |
535 | ␉␉}␊ |
536 | ␉␉␉␊ |
537 | ␉␉default:␊ |
538 | ␉␉{␊ |
539 | ␉␉␉do_cpuid(1, cpuid_reg);␊ |
540 | ␉␉␉info_p->core_count = bitfield(cpuid_reg[1], 23, 16);␊ |
541 | ␉␉} break;␊ |
542 | ␉}␊ |
543 | ␉if (info_p->core_count == 0) {␊ |
544 | ␉␉info_p->core_count = info_p->cpuid_cores_per_package;␊ |
545 | ␉␉info_p->thread_count = info_p->cpuid_logical_per_package;␊ |
546 | ␉}␊ |
547 | ␉␊ |
548 | }␊ |
549 | ␊ |
550 | ␊ |
551 | #endif /* !__LIBSAIO_CPU_H */␊ |
552 | |