1 | /*␊ |
2 | * Copyright 2008 Islam Ahmed Zaid. All rights reserved. <azismed@gmail.com>␊ |
3 | * AsereBLN: 2009: cleanup and bugfix␊ |
4 | */␊ |
5 | ␊ |
6 | #include "libsaio.h"␊ |
7 | #include "platform.h"␊ |
8 | #include "cpu.h"␊ |
9 | ␊ |
10 | #ifndef DEBUG_CPU␊ |
11 | #define DEBUG_CPU 0␊ |
12 | #endif␊ |
13 | ␊ |
14 | #if DEBUG_CPU␊ |
15 | #define DBG(x...)␉␉printf(x)␊ |
16 | #else␊ |
17 | #define DBG(x...)␉␉msglog(x)␊ |
18 | #endif␊ |
19 | ␊ |
20 | #if OLD_STYLE␊ |
21 | static uint64_t measure_tsc_frequency(void);␊ |
22 | ␊ |
23 | // DFE: enable_PIT2 and disable_PIT2 come from older xnu␊ |
24 | ␊ |
25 | /*␊ |
26 | * Enable or disable timer 2.␊ |
27 | * Port 0x61 controls timer 2:␊ |
28 | * bit 0 gates the clock,␊ |
29 | * bit 1 gates output to speaker.␊ |
30 | */␊ |
31 | static inline void enable_PIT2(void)␊ |
32 | {␊ |
33 | /* Enable gate, disable speaker */␊ |
34 | __asm__ volatile(␊ |
35 | ␉␉␉␉␉ " inb $0x61,%%al \n\t"␊ |
36 | ␉␉␉␉␉ " and $0xFC,%%al \n\t" /* & ~0x03 */␊ |
37 | ␉␉␉␉␉ " or $1,%%al \n\t"␊ |
38 | ␉␉␉␉␉ " outb %%al,$0x61 \n\t"␊ |
39 | ␉␉␉␉␉ : : : "%al" );␊ |
40 | }␊ |
41 | ␊ |
42 | static inline void disable_PIT2(void)␊ |
43 | {␊ |
44 | /* Disable gate and output to speaker */␊ |
45 | __asm__ volatile(␊ |
46 | ␉␉␉␉␉ " inb $0x61,%%al \n\t"␊ |
47 | ␉␉␉␉␉ " and $0xFC,%%al \n\t"␉/* & ~0x03 */␊ |
48 | ␉␉␉␉␉ " outb %%al,$0x61 \n\t"␊ |
49 | ␉␉␉␉␉ : : : "%al" );␊ |
50 | }␊ |
51 | ␊ |
52 | // DFE: set_PIT2_mode0, poll_PIT2_gate, and measure_tsc_frequency are␊ |
53 | // roughly based on Linux code␊ |
54 | ␊ |
55 | /* Set the 8254 channel 2 to mode 0 with the specified value.␊ |
56 | In mode 0, the counter will initially set its gate low when the␊ |
57 | timer expires. For this to be useful, you ought to set it high␊ |
58 | before calling this function. The enable_PIT2 function does this.␊ |
59 | */␊ |
60 | static inline void set_PIT2_mode0(uint16_t value)␊ |
61 | {␊ |
62 | __asm__ volatile(␊ |
63 | ␉␉␉␉␉ " movb $0xB0,%%al \n\t"␊ |
64 | ␉␉␉␉␉ " outb␉%%al,$0x43␉\n\t"␊ |
65 | ␉␉␉␉␉ " movb␉%%dl,%%al␉\n\t"␊ |
66 | ␉␉␉␉␉ " outb␉%%al,$0x42␉\n\t"␊ |
67 | ␉␉␉␉␉ " movb␉%%dh,%%al␉\n\t"␊ |
68 | ␉␉␉␉␉ " outb␉%%al,$0x42"␊ |
69 | ␉␉␉␉␉ : : "d"(value) /*: no clobber */ );␊ |
70 | }␊ |
71 | ␊ |
72 | /* Returns the number of times the loop ran before the PIT2 signaled */␊ |
73 | static inline unsigned long poll_PIT2_gate(void)␊ |
74 | {␊ |
75 | unsigned long count = 0;␊ |
76 | unsigned char nmi_sc_val;␊ |
77 | do {␊ |
78 | ++count;␊ |
79 | __asm__ volatile(␊ |
80 | ␉␉␉␉␉␉ "inb␉$0x61,%0"␊ |
81 | ␉␉␉␉␉␉ : "=q"(nmi_sc_val) /*:*/ /* no input */ /*:*/ /* no clobber */);␊ |
82 | } while( (nmi_sc_val & 0x20) == 0);␊ |
83 | return count;␊ |
84 | }␊ |
85 | /*␊ |
86 | * DFE: Measures the TSC frequency in Hz (64-bit) using the ACPI PM timer␊ |
87 | */␊ |
88 | static uint64_t measure_tsc_frequency(void)␊ |
89 | {␊ |
90 | uint64_t tscStart;␊ |
91 | uint64_t tscEnd;␊ |
92 | uint64_t tscDelta = 0xffffffffffffffffULL;␊ |
93 | unsigned long pollCount;␊ |
94 | uint64_t retval = 0;␊ |
95 | int i;␊ |
96 | ␉␊ |
97 | /* Time how many TSC ticks elapse in 30 msec using the 8254 PIT␊ |
98 | * counter 2. We run this loop 3 times to make sure the cache␊ |
99 | * is hot and we take the minimum delta from all of the runs.␊ |
100 | * That is to say that we're biased towards measuring the minimum␊ |
101 | * number of TSC ticks that occur while waiting for the timer to␊ |
102 | * expire. That theoretically helps avoid inconsistencies when␊ |
103 | * running under a VM if the TSC is not virtualized and the host␊ |
104 | * steals time. The TSC is normally virtualized for VMware.␊ |
105 | */␊ |
106 | for(i = 0; i < 10; ++i)␊ |
107 | {␊ |
108 | enable_PIT2();␊ |
109 | set_PIT2_mode0(CALIBRATE_LATCH);␊ |
110 | tscStart = rdtsc64();␊ |
111 | pollCount = poll_PIT2_gate();␊ |
112 | tscEnd = rdtsc64();␊ |
113 | /* The poll loop must have run at least a few times for accuracy */␊ |
114 | if(pollCount <= 1)␊ |
115 | continue;␊ |
116 | /* The TSC must increment at LEAST once every millisecond. We␊ |
117 | * should have waited exactly 30 msec so the TSC delta should␊ |
118 | * be >= 30. Anything less and the processor is way too slow.␊ |
119 | */␊ |
120 | if((tscEnd - tscStart) <= CALIBRATE_TIME_MSEC)␊ |
121 | continue;␊ |
122 | // tscDelta = min(tscDelta, (tscEnd - tscStart))␊ |
123 | if( (tscEnd - tscStart) < tscDelta )␊ |
124 | tscDelta = tscEnd - tscStart;␊ |
125 | }␊ |
126 | /* tscDelta is now the least number of TSC ticks the processor made in␊ |
127 | * a timespan of 0.03 s (e.g. 30 milliseconds)␊ |
128 | * Linux thus divides by 30 which gives the answer in kiloHertz because␊ |
129 | * 1 / ms = kHz. But we're xnu and most of the rest of the code uses␊ |
130 | * Hz so we need to convert our milliseconds to seconds. Since we're␊ |
131 | * dividing by the milliseconds, we simply multiply by 1000.␊ |
132 | */␊ |
133 | ␉␊ |
134 | /* Unlike linux, we're not limited to 32-bit, but we do need to take care␊ |
135 | * that we're going to multiply by 1000 first so we do need at least some␊ |
136 | * arithmetic headroom. For now, 32-bit should be enough.␊ |
137 | * Also unlike Linux, our compiler can do 64-bit integer arithmetic.␊ |
138 | */␊ |
139 | if(tscDelta > (1ULL<<32))␊ |
140 | retval = 0;␊ |
141 | else␊ |
142 | {␊ |
143 | retval = tscDelta * 1000 / 30;␊ |
144 | }␊ |
145 | disable_PIT2();␊ |
146 | return retval;␊ |
147 | }␊ |
148 | ␊ |
149 | #else␊ |
150 | /*␊ |
151 | License for x2apic_enabled, get_apicbase, compute_bclk.␊ |
152 | ␊ |
153 | Copyright (c) 2010, Intel Corporation␊ |
154 | All rights reserved.␊ |
155 | ␊ |
156 | Redistribution and use in source and binary forms, with or without␊ |
157 | modification, are permitted provided that the following conditions are met:␊ |
158 | ␊ |
159 | * Redistributions of source code must retain the above copyright notice,␊ |
160 | this list of conditions and the following disclaimer.␊ |
161 | * Redistributions in binary form must reproduce the above copyright notice,␊ |
162 | this list of conditions and the following disclaimer in the documentation␊ |
163 | and/or other materials provided with the distribution.␊ |
164 | * Neither the name of Intel Corporation nor the names of its contributors␊ |
165 | may be used to endorse or promote products derived from this software␊ |
166 | without specific prior written permission.␊ |
167 | ␊ |
168 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND␊ |
169 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED␊ |
170 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE␊ |
171 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR␊ |
172 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES␊ |
173 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;␊ |
174 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON␊ |
175 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT␊ |
176 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS␊ |
177 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.␊ |
178 | */␊ |
179 | static inline __attribute__((always_inline)) void rdmsr32(uint32_t msr, uint32_t * lo_data_addr, uint32_t * hi_data_addr);␊ |
180 | static inline __attribute__((always_inline)) void wrmsr32(uint32_t msr, uint32_t lo_data, uint32_t hi_data);␊ |
181 | static uint32_t x2apic_enabled(void);␊ |
182 | static uint32_t get_apicbase(void);␊ |
183 | static uint32_t compute_bclk(void);␊ |
184 | static inline __attribute__((always_inline)) void rdmsr32(uint32_t msr, uint32_t * lo_data_addr, uint32_t * hi_data_addr)␊ |
185 | { ␊ |
186 | __asm__ volatile(␊ |
187 | "rdmsr"␊ |
188 | : "=a" (*lo_data_addr), "=d" (*hi_data_addr)␊ |
189 | : "c" (msr)␊ |
190 | ); ␊ |
191 | }␉␊ |
192 | static inline __attribute__((always_inline)) void wrmsr32(uint32_t msr, uint32_t lo_data, uint32_t hi_data)␊ |
193 | {␊ |
194 | __asm__ __volatile__ (␊ |
195 | "wrmsr"␊ |
196 | : /* No outputs */␊ |
197 | : "c" (msr), "a" (lo_data), "d" (hi_data)␊ |
198 | );␊ |
199 | }␊ |
200 | #define MSR_APIC_BASE 0x1B␊ |
201 | #define APIC_TMR_INITIAL_CNT 0x380␊ |
202 | #define APIC_TMR_CURRENT_CNT 0x390␊ |
203 | #define APIC_TMR_DIVIDE_CFG 0x3E0␊ |
204 | #define MSR_APIC_TMR_INITIAL_CNT 0x838␊ |
205 | #define MSR_APIC_TMR_CURRENT_CNT 0x839␊ |
206 | #define MSR_APIC_TMR_DIVIDE_CFG 0x83E␊ |
207 | static uint32_t x2apic_enabled(void)␊ |
208 | {␊ |
209 | uint64_t temp64;␊ |
210 | ␉␊ |
211 | temp64 = rdmsr64(MSR_APIC_BASE);␊ |
212 | ␉␊ |
213 | return (uint32_t) (temp64 & (1 << 10)) ? 1 : 0;␊ |
214 | }␊ |
215 | static uint32_t get_apicbase(void)␊ |
216 | {␊ |
217 | uint64_t temp64;␊ |
218 | ␉␊ |
219 | temp64 = rdmsr64(MSR_APIC_BASE);␊ |
220 | ␉␊ |
221 | return (uint32_t) (temp64 & 0xfffff000);␊ |
222 | }␊ |
223 | static uint32_t compute_bclk(void)␊ |
224 | {␊ |
225 | uint32_t dummy;␊ |
226 | uint32_t start, stop;␊ |
227 | uint8_t temp8;␊ |
228 | uint16_t delay_count;␊ |
229 | uint32_t bclk;␊ |
230 | ␉␊ |
231 | #define DELAY_IN_US 1000␊ |
232 | ␉␊ |
233 | // Compute fixed delay as time␊ |
234 | // delay count = desired time * PIT frequency␊ |
235 | // PIT frequency = 1.193182 MHz␊ |
236 | delay_count = 1193182 / DELAY_IN_US;␊ |
237 | ␉␊ |
238 | // PIT channel 2 gate is controlled by IO port 0x61, bit 0␊ |
239 | #define PIT_CH2_LATCH_REG 0x61␊ |
240 | #define CH2_SPEAKER (1 << 1) // bit 1 -- 1 = speaker enabled 0 = speaker disabled␊ |
241 | #define CH2_GATE_IN (1 << 0) // bit 0 -- 1 = gate enabled, 0 = gate disabled␊ |
242 | #define CH2_GATE_OUT (1 << 5) // bit 5 -- 1 = gate latched, 0 = gate not latched␊ |
243 | ␉␊ |
244 | // PIT Command register␊ |
245 | #define PIT_MODE_COMMAND_REG 0x43␊ |
246 | #define SELECT_CH2 (2 << 6)␊ |
247 | #define ACCESS_MODE_LOBYTE_HIBYTE (3 << 4)␊ |
248 | #define MODE0_INTERRUPT_ON_TERMINAL_COUNT 0 // Despite name, no interrupts on CH2␊ |
249 | ␉␊ |
250 | // PIT Channel 2 data port␊ |
251 | #define PIT_CH2_DATA 0x42␊ |
252 | ␉␊ |
253 | // Disable the PIT channel 2 speaker and gate␊ |
254 | temp8 = inb(PIT_CH2_LATCH_REG);␊ |
255 | temp8 &= ~(CH2_SPEAKER | CH2_GATE_IN);␊ |
256 | outb(PIT_CH2_LATCH_REG, temp8);␊ |
257 | ␉␊ |
258 | // Setup command and mode␊ |
259 | outb(PIT_MODE_COMMAND_REG, SELECT_CH2 | ACCESS_MODE_LOBYTE_HIBYTE | MODE0_INTERRUPT_ON_TERMINAL_COUNT);␊ |
260 | ␉␊ |
261 | // Set time for fixed delay␊ |
262 | outb(PIT_CH2_DATA, (uint8_t) (delay_count));␊ |
263 | outb(PIT_CH2_DATA, (uint8_t) (delay_count >> 8));␊ |
264 | ␉␊ |
265 | // Prepare to enable channel 2 gate but leave the speaker disabled␊ |
266 | temp8 = inb(PIT_CH2_LATCH_REG);␊ |
267 | temp8 &= ~CH2_SPEAKER;␊ |
268 | temp8 |= CH2_GATE_IN;␊ |
269 | ␉␊ |
270 | if (x2apic_enabled())␊ |
271 | ␉{␊ |
272 | // Set APIC Timer Divide Value as 2␊ |
273 | wrmsr32(MSR_APIC_TMR_DIVIDE_CFG, 0, 0);␊ |
274 | ␉␉␊ |
275 | // start APIC timer with a known value␊ |
276 | start = ~0UL;␊ |
277 | wrmsr32(MSR_APIC_TMR_INITIAL_CNT, start, 0);␊ |
278 | }␊ |
279 | else␊ |
280 | ␉{␊ |
281 | // Set APIC Timer Divide Value as 2␊ |
282 | *(volatile uint32_t *)(uint32_t) (get_apicbase() + APIC_TMR_DIVIDE_CFG) = 0UL;␊ |
283 | ␉␉␊ |
284 | // start APIC timer with a known value␊ |
285 | start = ~0UL;␊ |
286 | *(volatile uint32_t *)(uint32_t) (get_apicbase() + APIC_TMR_INITIAL_CNT) = start;␊ |
287 | }␊ |
288 | ␉␊ |
289 | // Actually start the PIT channel 2␊ |
290 | outb(PIT_CH2_LATCH_REG, temp8);␊ |
291 | ␉␊ |
292 | // Wait for the fixed delay␊ |
293 | while (!(inb(PIT_CH2_LATCH_REG) & CH2_GATE_OUT));␊ |
294 | ␉␊ |
295 | if (x2apic_enabled())␊ |
296 | ␉{␊ |
297 | // read the APIC timer to determine the change that occurred over this fixed delay␊ |
298 | rdmsr32(MSR_APIC_TMR_CURRENT_CNT, &stop, &dummy);␊ |
299 | ␉␉␊ |
300 | // stop APIC timer␊ |
301 | wrmsr32(MSR_APIC_TMR_INITIAL_CNT, 0, 0);␊ |
302 | ␉␉␊ |
303 | }␊ |
304 | else␊ |
305 | ␉{␊ |
306 | // read the APIC timer to determine the change that occurred over this fixed delay␊ |
307 | stop = *(volatile uint32_t *)(uint32_t) (get_apicbase() + APIC_TMR_CURRENT_CNT);␊ |
308 | ␉␉␊ |
309 | // stop APIC timer␊ |
310 | *(volatile uint32_t *)(uint32_t) (get_apicbase() + APIC_TMR_INITIAL_CNT) = 0UL;␊ |
311 | }␊ |
312 | ␉␊ |
313 | // Disable channel 2 speaker and gate input␊ |
314 | temp8 = inb(PIT_CH2_LATCH_REG);␊ |
315 | temp8 &= ~(CH2_SPEAKER | CH2_GATE_IN);␊ |
316 | outb(PIT_CH2_LATCH_REG, temp8);␊ |
317 | ␉␊ |
318 | bclk = (start - stop) * 2 / DELAY_IN_US;␊ |
319 | ␉␊ |
320 | // Round bclk to the nearest 100/12 integer value␊ |
321 | bclk = ((((bclk * 24) + 100) / 200) * 200) / 24;␊ |
322 | DBG("\nCompute bclk: %dMHz\n", bclk);␊ |
323 | return bclk;␊ |
324 | }␊ |
325 | #endif␊ |
326 | ␊ |
327 | /*␊ |
328 | * Calculates the FSB and CPU frequencies using specific MSRs for each CPU␊ |
329 | * - multi. is read from a specific MSR. In the case of Intel, there is:␊ |
330 | * a max multi. (used to calculate the FSB freq.),␊ |
331 | * and a current multi. (used to calculate the CPU freq.)␊ |
332 | * - fsbFrequency = tscFrequency / multi␊ |
333 | * - cpuFrequency = fsbFrequency * multi␊ |
334 | */␊ |
335 | ␊ |
336 | void scan_cpu(PlatformInfo_t *p)␊ |
337 | {␊ |
338 | ␉uint64_t␉tscFrequency, fsbFrequency, cpuFrequency;␊ |
339 | ␉uint64_t␉msr;␊ |
340 | ␉uint8_t␉␉maxcoef = 0, maxdiv = 0, currcoef = 0, currdiv = 0;␊ |
341 | uint32_t␉reg[4];␊ |
342 | uint32_t cores_per_package;␊ |
343 | uint32_t logical_per_package; ␊ |
344 | ␊ |
345 | ␉do_cpuid(0, reg);␊ |
346 | p->CPU.Vendor␉␉= reg[ebx];␊ |
347 | p->CPU.cpuid_max_basic = reg[eax];␊ |
348 | ␊ |
349 | do_cpuid2(0x00000004, 0, reg);␊ |
350 | cores_per_package␉␉= bitfield(reg[eax], 31, 26) + 1;␊ |
351 | ␊ |
352 | /* get extended cpuid results */␊ |
353 | ␉do_cpuid(0x80000000, reg);␊ |
354 | ␉uint32_t cpuid_max_ext = reg[eax];␊ |
355 | ␊ |
356 | ␊ |
357 | ␉/* Begin of Copyright: from Apple's XNU cpuid.c */␊ |
358 | ␉␊ |
359 | ␉/* get brand string (if supported) */␊ |
360 | ␉if (cpuid_max_ext > 0x80000004)␊ |
361 | ␉{␉␉␊ |
362 | char str[128], *s;␊ |
363 | ␉␉/*␊ |
364 | ␉␉ * The brand string 48 bytes (max), guaranteed to␊ |
365 | ␉␉ * be NUL terminated.␊ |
366 | ␉␉ */␊ |
367 | ␉␉do_cpuid(0x80000002, reg);␊ |
368 | ␉␉bcopy((char *)reg, &str[0], 16);␊ |
369 | ␉␉do_cpuid(0x80000003, reg);␊ |
370 | ␉␉bcopy((char *)reg, &str[16], 16);␊ |
371 | ␉␉do_cpuid(0x80000004, reg);␊ |
372 | ␉␉bcopy((char *)reg, &str[32], 16);␊ |
373 | ␉␉for (s = str; *s != '\0'; s++)␊ |
374 | ␉␉{␊ |
375 | ␉␉␉if (*s != ' ') break;␊ |
376 | ␉␉}␊ |
377 | ␉␉␊ |
378 | ␉␉strlcpy(p->CPU.BrandString,␉s, sizeof(p->CPU.BrandString));␊ |
379 | ␉␉␊ |
380 | ␉␉if (!strncmp(p->CPU.BrandString, CPUID_STRING_UNKNOWN, min(sizeof(p->CPU.BrandString), (unsigned)strlen(CPUID_STRING_UNKNOWN) + 1)))␊ |
381 | ␉␉{␊ |
382 | /*␊ |
383 | * This string means we have a firmware-programmable brand string,␊ |
384 | * and the firmware couldn't figure out what sort of CPU we have.␊ |
385 | */␊ |
386 | p->CPU.BrandString[0] = '\0';␊ |
387 | }␊ |
388 | ␉} ␊ |
389 | ␊ |
390 | /*␊ |
391 | ␉ * Get processor signature and decode␊ |
392 | ␉ * and bracket this with the approved procedure for reading the␊ |
393 | ␉ * the microcode version number a.k.a. signature a.k.a. BIOS ID␊ |
394 | ␉ */␊ |
395 | ␉wrmsr64(MSR_IA32_BIOS_SIGN_ID, 0);␊ |
396 | ␉do_cpuid(1, reg);␊ |
397 | p->CPU.MicrocodeVersion =␊ |
398 | (uint32_t) (rdmsr64(MSR_IA32_BIOS_SIGN_ID) >> 32);␊ |
399 | ␉␊ |
400 | ␉p->CPU.Signature = reg[eax];␊ |
401 | ␉p->CPU.Stepping = bitfield(reg[eax], 3, 0);␊ |
402 | ␉p->CPU.Model = bitfield(reg[eax], 7, 4);␊ |
403 | ␉p->CPU.Family = bitfield(reg[eax], 11, 8);␊ |
404 | ␉p->CPU.ExtModel = bitfield(reg[eax], 19, 16);␊ |
405 | ␉p->CPU.ExtFamily = bitfield(reg[eax], 27, 20);␊ |
406 | ␉p->CPU.Brand = bitfield(reg[ebx], 7, 0);␊ |
407 | ␉p->CPU.Features = quad(reg[ecx], reg[edx]);␊ |
408 | ␊ |
409 | /* Fold extensions into family/model */␊ |
410 | ␉if (p->CPU.Family == 0x0f)␊ |
411 | ␉␉p->CPU.Family += p->CPU.ExtFamily;␊ |
412 | ␉if (p->CPU.Family == 0x0f || p->CPU.Family == 0x06)␊ |
413 | ␉␉p->CPU.Model += (p->CPU.ExtModel << 4);␊ |
414 | ␊ |
415 | if (p->CPU.Features & CPUID_FEATURE_HTT)␊ |
416 | ␉␉logical_per_package =␊ |
417 | bitfield(reg[ebx], 23, 16);␊ |
418 | ␉else␊ |
419 | ␉␉logical_per_package = 1;␊ |
420 | ␊ |
421 | ␉if (cpuid_max_ext >= 0x80000001)␊ |
422 | ␉{␊ |
423 | ␉␉do_cpuid(0x80000001, reg);␊ |
424 | ␉␉p->CPU.ExtFeatures =␊ |
425 | quad(reg[ecx], reg[edx]);␊ |
426 | ␊ |
427 | ␉}␊ |
428 | ␊ |
429 | ␉/* Fold in the Invariant TSC feature bit, if present */␊ |
430 | ␉if (cpuid_max_ext >= 0x80000007)␊ |
431 | ␉{␊ |
432 | ␉␉do_cpuid(0x80000007, reg); ␊ |
433 | ␉␉p->CPU.ExtFeatures |=␊ |
434 | reg[edx] & (uint32_t)CPUID_EXTFEATURE_TSCI;␊ |
435 | ␉} ␊ |
436 | ␊ |
437 | if (p->CPU.cpuid_max_basic >= 0x5) { ␊ |
438 | ␉␉/*␊ |
439 | ␉␉ * Extract the Monitor/Mwait Leaf info:␊ |
440 | ␉␉ */␊ |
441 | ␉␉do_cpuid(5, reg); ␊ |
442 | p->CPU.sub_Cstates = reg[edx];␊ |
443 | p->CPU.extensions = reg[ecx];␉␊ |
444 | ␉}␊ |
445 | ␊ |
446 | if (p->CPU.cpuid_max_basic >= 0x6)␊ |
447 | { ␊ |
448 | ␉␉/*␊ |
449 | ␉␉ * The thermal and Power Leaf:␊ |
450 | ␉␉ */␊ |
451 | ␉␉do_cpuid(6, reg);␊ |
452 | ␉␉p->CPU.dynamic_acceleration = bitfield(reg[eax], 1, 1); // "Dynamic Acceleration Technology (Turbo Mode)"␊ |
453 | ␉␉p->CPU.invariant_APIC_timer = bitfield(reg[eax], 2, 2); // "Invariant APIC Timer"␊ |
454 | p->CPU.fine_grain_clock_mod = bitfield(reg[eax], 4, 4);␊ |
455 | ␉}␊ |
456 | ␊ |
457 | if ((p->CPU.Vendor == 0x756E6547 /* Intel */) && ␊ |
458 | ␉␉(p->CPU.Family == 0x06))␊ |
459 | ␉{␊ |
460 | /*␊ |
461 | * Find the number of enabled cores and threads␊ |
462 | * (which determines whether SMT/Hyperthreading is active).␊ |
463 | */␊ |
464 | switch (p->CPU.Model)␊ |
465 | ␉␉{␊ |
466 | ␊ |
467 | case CPUID_MODEL_DALES_32NM:␊ |
468 | case CPUID_MODEL_WESTMERE:␊ |
469 | case CPUID_MODEL_WESTMERE_EX:␊ |
470 | {␊ |
471 | msr = rdmsr64(MSR_CORE_THREAD_COUNT);␊ |
472 | p->CPU.NoThreads = bitfield((uint32_t)msr, 15, 0);␊ |
473 | p->CPU.NoCores = bitfield((uint32_t)msr, 19, 16); ␊ |
474 | break;␊ |
475 | }␊ |
476 | ␊ |
477 | case CPUID_MODEL_NEHALEM:␊ |
478 | case CPUID_MODEL_FIELDS:␊ |
479 | case CPUID_MODEL_DALES:␊ |
480 | case CPUID_MODEL_NEHALEM_EX:␊ |
481 | ␉␉␉␉case CPUID_MODEL_SANDYBRIDGE:␊ |
482 | ␉␉␉␉case CPUID_MODEL_JAKETOWN:␊ |
483 | {␊ |
484 | msr = rdmsr64(MSR_CORE_THREAD_COUNT);␊ |
485 | p->CPU.NoThreads = bitfield((uint32_t)msr, 15, 0);␊ |
486 | p->CPU.NoCores = bitfield((uint32_t)msr, 31, 16); ␊ |
487 | break;␊ |
488 | } ␊ |
489 | }␊ |
490 | }␊ |
491 | ␊ |
492 | if (p->CPU.NoCores == 0)␊ |
493 | ␉{␊ |
494 | ␉␉p->CPU.NoThreads = cores_per_package;␊ |
495 | ␉␉p->CPU.NoCores = logical_per_package;␊ |
496 | ␉}␊ |
497 | ␉␊ |
498 | ␉/* End of Copyright: from Apple's XNU cpuid.c */␊ |
499 | ␊ |
500 | #if OLD_STYLE␊ |
501 | ␉tscFrequency = measure_tsc_frequency();␊ |
502 | ␉fsbFrequency = 0;␊ |
503 | #else␊ |
504 | ␉tscFrequency = 0;␊ |
505 | ␉fsbFrequency = (uint64_t)(compute_bclk() * 1000000);␊ |
506 | #endif␊ |
507 | ␉cpuFrequency = 0;␊ |
508 | ␉␊ |
509 | ␉␉␊ |
510 | ␉if ((p->CPU.Vendor == 0x756E6547 /* Intel */) && ␊ |
511 | ␉␉((p->CPU.Family == 0x06) || ␊ |
512 | ␉␉ (p->CPU.Family == 0x0f)))␊ |
513 | ␉{␊ |
514 | ␉␉if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0c) || ␊ |
515 | ␉␉␉(p->CPU.Family == 0x0f && p->CPU.Model >= 0x03))␊ |
516 | ␉␉{␊ |
517 | ␉␉␉/* Nehalem CPU model */␊ |
518 | ␉␉␉if (p->CPU.Family == 0x06 && (p->CPU.Model == CPUID_MODEL_NEHALEM || ␊ |
519 | p->CPU.Model == CPUID_MODEL_FIELDS || ␊ |
520 | p->CPU.Model == CPUID_MODEL_DALES || ␊ |
521 | p->CPU.Model == CPUID_MODEL_DALES_32NM || ␊ |
522 | p->CPU.Model == CPUID_MODEL_WESTMERE ||␊ |
523 | p->CPU.Model == CPUID_MODEL_NEHALEM_EX ||␊ |
524 | p->CPU.Model == CPUID_MODEL_WESTMERE_EX ||␊ |
525 | p->CPU.Model == CPUID_MODEL_SANDYBRIDGE ||␊ |
526 | p->CPU.Model == CPUID_MODEL_JAKETOWN)) ␊ |
527 | ␉␉␉{␊ |
528 | ␉␉␉␉uint8_t␉␉bus_ratio_max = 0, bus_ratio_min = 0;␊ |
529 | ␉␉␉␉uint32_t␉max_ratio = 0;␊ |
530 | ␉␉␉␉uint64_t␉flex_ratio = 0;␊ |
531 | ␉␉␉␉msr = rdmsr64(MSR_PLATFORM_INFO);␊ |
532 | #if DEBUG_CPU␊ |
533 | ␉␉␉␉DBG("msr(%d): platform_info %08x\n", __LINE__, msr & 0xffffffff);␊ |
534 | #endif␊ |
535 | ␉␉␉␉bus_ratio_max = (msr >> 8) & 0xff;␊ |
536 | ␉␉␉␉bus_ratio_min = (msr >> 40) & 0xff; //valv: not sure about this one (Remarq.1)␊ |
537 | ␉␉␉␉msr = rdmsr64(MSR_FLEX_RATIO);␊ |
538 | #if DEBUG_CPU␊ |
539 | ␉␉␉␉DBG("msr(%d): flex_ratio %08x\n", __LINE__, msr & 0xffffffff);␊ |
540 | #endif␊ |
541 | ␉␉␉␉if ((msr >> 16) & 0x01)␊ |
542 | ␉␉␉␉{␊ |
543 | ␉␉␉␉␉flex_ratio = (msr >> 8) & 0xff;␊ |
544 | ␉␉␉␉␉/* bcc9: at least on the gigabyte h67ma-ud2h,␊ |
545 | ␉␉␉␉␉ where the cpu multipler can't be changed to␊ |
546 | ␉␉␉␉␉ allow overclocking, the flex_ratio msr has unexpected (to OSX)␊ |
547 | ␉␉␉␉␉ contents. These contents cause mach_kernel to␊ |
548 | ␉␉␉␉␉ fail to compute the bus ratio correctly, instead␊ |
549 | ␉␉␉␉␉ causing the system to crash since tscGranularity␊ |
550 | ␉␉␉␉␉ is inadvertently set to 0.␊ |
551 | ␉␉␉␉␉ */␊ |
552 | ␉␉␉␉␉if (flex_ratio == 0)␊ |
553 | ␉␉␉␉␉{␊ |
554 | ␉␉␉␉␉␉/* Clear bit 16 (evidently the␊ |
555 | ␉␉␉␉␉␉ presence bit) */␊ |
556 | ␉␉␉␉␉␉wrmsr64(MSR_FLEX_RATIO, (msr & 0xFFFFFFFFFFFEFFFFULL));␊ |
557 | ␉␉␉␉␉␉msr = rdmsr64(MSR_FLEX_RATIO);␊ |
558 | #if DEBUG_CPU␊ |
559 | ␉␉␉␉␉␉DBG("Unusable flex ratio detected. MSR Patched to %08x\n", msr & 0xffffffff);␊ |
560 | #endif␊ |
561 | ␉␉␉␉␉}␊ |
562 | ␉␉␉␉␉else␊ |
563 | ␉␉␉␉␉{␊ |
564 | ␉␉␉␉␉␉if (bus_ratio_max > flex_ratio)␊ |
565 | ␉␉␉␉␉␉{␊ |
566 | ␉␉␉␉␉␉␉bus_ratio_max = flex_ratio;␊ |
567 | ␉␉␉␉␉␉}␊ |
568 | ␉␉␉␉␉}␊ |
569 | ␉␉␉␉}␊ |
570 | #if OLD_STYLE␊ |
571 | ␉␉␉␉if (bus_ratio_max)␊ |
572 | ␉␉␉␉{␊ |
573 | ␉␉␉␉␉fsbFrequency = (tscFrequency / bus_ratio_max);␊ |
574 | ␉␉␉␉}␊ |
575 | #endif␊ |
576 | ␉␉␉␉//valv: Turbo Ratio Limit␊ |
577 | ␉␉␉␉if ((p->CPU.Model != 0x2e) && (p->CPU.Model != 0x2f))␊ |
578 | ␉␉␉␉{␊ |
579 | ␉␉␉␉␉//msr = rdmsr64(MSR_TURBO_RATIO_LIMIT);␊ |
580 | ␉␉␉␉␉cpuFrequency = bus_ratio_max * fsbFrequency;␊ |
581 | ␉␉␉␉␉max_ratio = bus_ratio_max * 10;␊ |
582 | ␉␉␉␉}␊ |
583 | ␉␉␉␉else␊ |
584 | ␉␉␉␉{␊ |
585 | #if OLD_STYLE␊ |
586 | ␉␉␉␉␉cpuFrequency = tscFrequency;␊ |
587 | #else␊ |
588 | ␉␉␉␉␉cpuFrequency = bus_ratio_max * fsbFrequency;␊ |
589 | #endif␊ |
590 | ␉␉␉␉}␉␉␉␉␉␉␉␉␊ |
591 | #if DEBUG_CPU␊ |
592 | ␉␉␉␉DBG("Sticking with [BCLK: %dMhz, Bus-Ratio: %d]\n", fsbFrequency / 1000000, max_ratio);␊ |
593 | #endif␊ |
594 | ␉␉␉␉currcoef = bus_ratio_max;␊ |
595 | ␉␉␉} ␊ |
596 | ␉␉␉else␊ |
597 | ␉␉␉{␊ |
598 | ␉␉␉␉msr = rdmsr64(MSR_IA32_PERF_STATUS);␊ |
599 | #if DEBUG_CPU␊ |
600 | ␉␉␉␉DBG("msr(%d): ia32_perf_stat 0x%08x\n", __LINE__, msr & 0xffffffff);␊ |
601 | #endif␊ |
602 | ␉␉␉␉currcoef = (msr >> 8) & 0x1f;␊ |
603 | ␉␉␉␉/* Non-integer bus ratio for the max-multi*/␊ |
604 | ␉␉␉␉maxdiv = (msr >> 46) & 0x01;␊ |
605 | ␉␉␉␉/* Non-integer bus ratio for the current-multi (undocumented)*/␊ |
606 | ␉␉␉␉currdiv = (msr >> 14) & 0x01;␊ |
607 | ␊ |
608 | ␉␉␉␉if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0e) || ␊ |
609 | ␉␉␉␉␉(p->CPU.Family == 0x0f)) // This will always be model >= 3␊ |
610 | ␉␉␉␉{␊ |
611 | ␉␉␉␉␉/* On these models, maxcoef defines TSC freq */␊ |
612 | ␉␉␉␉␉maxcoef = (msr >> 40) & 0x1f;␊ |
613 | ␉␉␉␉} ␊ |
614 | ␉␉␉␉else ␊ |
615 | ␉␉␉␉{␊ |
616 | ␉␉␉␉␉/* On lower models, currcoef defines TSC freq */␊ |
617 | ␉␉␉␉␉/* XXX */␊ |
618 | ␉␉␉␉␉maxcoef = currcoef;␊ |
619 | ␉␉␉␉}␊ |
620 | #if OLD_STYLE␊ |
621 | ␉␉␉␉if (maxcoef) ␊ |
622 | ␉␉␉␉{␊ |
623 | ␉␉␉␉␉if (maxdiv)␊ |
624 | ␉␉␉␉␉{␊ |
625 | ␉␉␉␉␉␉fsbFrequency = ((tscFrequency * 2) / ((maxcoef * 2) + 1));␊ |
626 | ␉␉␉␉␉}␊ |
627 | ␉␉␉␉␉else ␊ |
628 | ␉␉␉␉␉{␊ |
629 | ␉␉␉␉␉␉fsbFrequency = (tscFrequency / maxcoef);␊ |
630 | ␉␉␉␉␉}␊ |
631 | ␉␉␉␉␉␊ |
632 | ␉␉␉␉␉if (currdiv) ␊ |
633 | ␉␉␉␉␉{␊ |
634 | ␉␉␉␉␉␉cpuFrequency = (fsbFrequency * ((currcoef * 2) + 1) / 2);␊ |
635 | ␉␉␉␉␉}␊ |
636 | ␉␉␉␉␉else ␊ |
637 | ␉␉␉␉␉{␊ |
638 | ␉␉␉␉␉␉cpuFrequency = (fsbFrequency * currcoef);␊ |
639 | ␉␉␉␉␉}␊ |
640 | #if DEBUG_CPU␊ |
641 | ␉␉␉␉␉DBG("max: %d%s current: %d%s\n", maxcoef, maxdiv ? ".5" : "",currcoef, currdiv ? ".5" : "");␊ |
642 | #endif␊ |
643 | ␉␉␉␉}␊ |
644 | #else␊ |
645 | ␉␉␉␉if (currdiv) ␊ |
646 | ␉␉␉␉{␊ |
647 | ␉␉␉␉␉cpuFrequency = (fsbFrequency * ((currcoef * 2) + 1) / 2);␊ |
648 | ␉␉␉␉}␊ |
649 | ␉␉␉␉else ␊ |
650 | ␉␉␉␉{␊ |
651 | ␉␉␉␉␉cpuFrequency = (fsbFrequency * currcoef);␊ |
652 | ␉␉␉␉}␊ |
653 | ␉␉␉␉␊ |
654 | ␉␉␉␉if (maxcoef) ␊ |
655 | ␉␉␉␉{␊ |
656 | ␉␉␉␉␉if (maxdiv)␊ |
657 | ␉␉␉␉␉{␊ |
658 | ␉␉␉␉␉␉tscFrequency = (fsbFrequency * ((maxcoef * 2) + 1)) / 2;␊ |
659 | ␉␉␉␉␉}␊ |
660 | ␉␉␉␉␉else ␊ |
661 | ␉␉␉␉␉{␊ |
662 | ␉␉␉␉␉␉tscFrequency = fsbFrequency * maxcoef;␊ |
663 | ␉␉␉␉␉}␊ |
664 | ␉␉␉␉}␊ |
665 | #if DEBUG_CPU␊ |
666 | ␉␉␉␉DBG("max: %d%s current: %d%s\n", maxcoef, maxdiv ? ".5" : "",currcoef, currdiv ? ".5" : "");␊ |
667 | #endif␊ |
668 | ␊ |
669 | #endif // OLD_STYLE␊ |
670 | ␉␉␉␉␊ |
671 | ␉␉␉}␊ |
672 | ␉␉}␊ |
673 | /* Mobile CPU ? */ ␊ |
674 | ␉␉//Slice ␊ |
675 | ␉ p->CPU.isMobile = false;␊ |
676 | ␉␉switch (p->CPU.Model)␊ |
677 | ␉␉{␊ |
678 | ␉␉␉case 0x0D:␊ |
679 | ␉␉␉␉p->CPU.isMobile = true; ␊ |
680 | ␉␉␉␉break;␉␉␉␊ |
681 | ␉␉␉case 0x02:␊ |
682 | ␉␉␉case 0x03:␊ |
683 | ␉␉␉case 0x04:␊ |
684 | ␉␉␉case 0x06:␉␊ |
685 | ␉␉␉␉p->CPU.isMobile = (rdmsr64(0x2C) & (1 << 21));␊ |
686 | ␉␉␉␉break;␊ |
687 | ␉␉␉default:␊ |
688 | ␉␉␉␉p->CPU.isMobile = (rdmsr64(0x17) & (1 << 28));␊ |
689 | ␉␉␉␉break;␊ |
690 | ␉␉}␊ |
691 | ␊ |
692 | ␉␉DBG("%s platform found.\n", p->CPU.isMobile?"Mobile":"Desktop");␊ |
693 | ␉}␊ |
694 | ␉␊ |
695 | ␉p->CPU.MaxCoef = maxcoef;␊ |
696 | ␉p->CPU.MaxDiv = maxdiv;␊ |
697 | ␉p->CPU.CurrCoef = currcoef;␊ |
698 | ␉p->CPU.CurrDiv = currdiv;␊ |
699 | ␊ |
700 | ␉//p->CPU.TSCFrequency = (tscFrequency / 1000000) * 1000000;␊ |
701 | ␉//p->CPU.FSBFrequency = (fsbFrequency / 1000000) * 1000000;␊ |
702 | ␉//p->CPU.CPUFrequency = (cpuFrequency / 1000000) * 1000000;␊ |
703 | ␊ |
704 | p->CPU.TSCFrequency = tscFrequency ;␊ |
705 | ␉p->CPU.FSBFrequency = fsbFrequency ;␊ |
706 | ␉p->CPU.CPUFrequency = cpuFrequency ;␊ |
707 | ␊ |
708 | ␉DBG("CPU: Vendor/Model/ExtModel: 0x%x/0x%x/0x%x\n", p->CPU.Vendor, p->CPU.Model, p->CPU.ExtModel);␊ |
709 | ␉DBG("CPU: Family/ExtFamily: 0x%x/0x%x\n", p->CPU.Family, p->CPU.ExtFamily);␊ |
710 | ␉DBG("CPU: TSCFreq: %dMHz\n", p->CPU.TSCFrequency / 1000000);␉␊ |
711 | ␉if(p->CPU.Vendor == 0x756E6547 /* Intel */)␊ |
712 | ␉{␉␉␊ |
713 | ␉␉DBG("CPU: FSBFreq: %dMHz\n", p->CPU.FSBFrequency / 1000000);␊ |
714 | ␉␉DBG("CPU: CPUFreq: %dMHz\n", p->CPU.CPUFrequency / 1000000);␊ |
715 | ␉␉DBG("CPU: MaxCoef/CurrCoef: 0x%x/0x%x\n", p->CPU.MaxCoef, p->CPU.CurrCoef);␊ |
716 | ␉␉DBG("CPU: MaxDiv/CurrDiv: 0x%x/0x%x\n", p->CPU.MaxDiv, p->CPU.CurrDiv);␉␉␊ |
717 | ␉}␊ |
718 | ␉␊ |
719 | ␉DBG("CPU: NoCores/NoThreads: %d/%d\n", p->CPU.NoCores, p->CPU.NoThreads);␊ |
720 | ␉DBG("CPU: Features: 0x%08x\n", p->CPU.Features);␊ |
721 | DBG("CPU: ExtFeatures: 0x%08x\n", p->CPU.ExtFeatures); ␊ |
722 | DBG("CPU: MicrocodeVersion: %d\n", p->CPU.MicrocodeVersion);␊ |
723 | #if DEBUG_CPU␊ |
724 | ␉␉pause();␊ |
725 | #endif␊ |
726 | ␉␊ |
727 | }␊ |
728 | |