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 | #include "boot.h"␊ |
10 | #include "bootstruct.h"␊ |
11 | ␊ |
12 | #ifndef DEBUG_CPU␊ |
13 | #define DEBUG_CPU 0␊ |
14 | #endif␊ |
15 | ␊ |
16 | #if DEBUG_CPU␊ |
17 | #define DBG(x...)␉␉printf(x)␊ |
18 | #else␊ |
19 | #define DBG(x...)␊ |
20 | #endif␊ |
21 | ␊ |
22 | ␊ |
23 | static inline uint64_t rdtsc64(void)␊ |
24 | {␊ |
25 | ␉uint64_t ret;␊ |
26 | ␉__asm__ volatile("rdtsc" : "=A" (ret));␊ |
27 | ␉return ret;␊ |
28 | }␊ |
29 | ␊ |
30 | static inline uint64_t rdmsr64(uint32_t msr)␊ |
31 | {␊ |
32 | uint64_t ret;␊ |
33 | __asm__ volatile("rdmsr" : "=A" (ret) : "c" (msr));␊ |
34 | return ret;␊ |
35 | }␊ |
36 | ␊ |
37 | static inline void do_cpuid(uint32_t selector, uint32_t *data)␊ |
38 | {␊ |
39 | ␉asm volatile ("cpuid"␊ |
40 | ␉ : "=a" (data[0]),␊ |
41 | ␉ "=b" (data[1]),␊ |
42 | ␉ "=c" (data[2]),␊ |
43 | ␉ "=d" (data[3])␊ |
44 | ␉ : "a" (selector));␊ |
45 | }␊ |
46 | ␊ |
47 | static inline void do_cpuid2(uint32_t selector, uint32_t selector2, uint32_t *data)␊ |
48 | {␊ |
49 | ␉asm volatile ("cpuid"␊ |
50 | ␉ : "=a" (data[0]),␊ |
51 | ␉ "=b" (data[1]),␊ |
52 | ␉ "=c" (data[2]),␊ |
53 | ␉ "=d" (data[3])␊ |
54 | ␉ : "a" (selector), "c" (selector2));␊ |
55 | }␊ |
56 | ␊ |
57 | /*static inline unsigned long long rdmsr46(unsigned int msr, unsigned low, unsigned high)␊ |
58 | {␊ |
59 | ␉//unsigned low, high;␊ |
60 | ␉asm volatile("rdmsr" : "=a" (low), "=d" (high));␊ |
61 | ␉return ((low) | ((uint64_t)(high) << 32));␊ |
62 | }*/␊ |
63 | ␊ |
64 | // DFE: enable_PIT2 and disable_PIT2 come from older xnu␊ |
65 | ␊ |
66 | /*␊ |
67 | * Enable or disable timer 2.␊ |
68 | * Port 0x61 controls timer 2:␊ |
69 | * bit 0 gates the clock,␊ |
70 | * bit 1 gates output to speaker.␊ |
71 | */␊ |
72 | static inline void enable_PIT2(void)␊ |
73 | {␊ |
74 | /* Enable gate, disable speaker */␊ |
75 | __asm__ volatile(␊ |
76 | " inb $0x61,%%al \n\t"␊ |
77 | " and $0xFC,%%al \n\t" /* & ~0x03 */␊ |
78 | " or $1,%%al \n\t"␊ |
79 | " outb %%al,$0x61 \n\t"␊ |
80 | : : : "%al" );␊ |
81 | }␊ |
82 | ␊ |
83 | static inline void disable_PIT2(void)␊ |
84 | {␊ |
85 | /* Disable gate and output to speaker */␊ |
86 | __asm__ volatile(␊ |
87 | " inb $0x61,%%al \n\t"␊ |
88 | " and $0xFC,%%al \n\t"␉/* & ~0x03 */␊ |
89 | " outb %%al,$0x61 \n\t"␊ |
90 | : : : "%al" );␊ |
91 | }␊ |
92 | ␊ |
93 | // DFE: set_PIT2_mode0, poll_PIT2_gate, and measure_tsc_frequency are␊ |
94 | // roughly based on Linux code␊ |
95 | ␊ |
96 | /* Set the 8254 channel 2 to mode 0 with the specified value.␊ |
97 | In mode 0, the counter will initially set its gate low when the␊ |
98 | timer expires. For this to be useful, you ought to set it high␊ |
99 | before calling this function. The enable_PIT2 function does this.␊ |
100 | */␊ |
101 | static inline void set_PIT2_mode0(uint16_t value)␊ |
102 | {␊ |
103 | __asm__ volatile(␊ |
104 | " movb $0xB0,%%al \n\t"␊ |
105 | " outb␉%%al,$0x43␉\n\t"␊ |
106 | " movb␉%%dl,%%al␉\n\t"␊ |
107 | " outb␉%%al,$0x42␉\n\t"␊ |
108 | " movb␉%%dh,%%al␉\n\t"␊ |
109 | " outb␉%%al,$0x42"␊ |
110 | : : "d"(value) /*: no clobber */ );␊ |
111 | }␊ |
112 | ␊ |
113 | /* Returns the number of times the loop ran before the PIT2 signaled */␊ |
114 | static inline unsigned long poll_PIT2_gate(void)␊ |
115 | {␊ |
116 | unsigned long count = 0;␊ |
117 | unsigned char nmi_sc_val;␊ |
118 | do {␊ |
119 | ++count;␊ |
120 | __asm__ volatile(␊ |
121 | "inb␉$0x61,%0"␊ |
122 | : "=q"(nmi_sc_val) /*:*/ /* no input */ /*:*/ /* no clobber */);␊ |
123 | } while( (nmi_sc_val & 0x20) == 0);␊ |
124 | return count;␊ |
125 | }␊ |
126 | ␊ |
127 | /*␊ |
128 | * DFE: Measures the TSC frequency in Hz (64-bit) using the ACPI PM timer␊ |
129 | */␊ |
130 | static uint64_t measure_tsc_frequency(void)␊ |
131 | {␊ |
132 | uint64_t tscStart;␊ |
133 | uint64_t tscEnd;␊ |
134 | uint64_t tscDelta = 0xffffffffffffffffULL;␊ |
135 | unsigned long pollCount;␊ |
136 | uint64_t retval = 0;␊ |
137 | int i;␊ |
138 | ␊ |
139 | /* Time how many TSC ticks elapse in 30 msec using the 8254 PIT␊ |
140 | * counter 2. We run this loop 3 times to make sure the cache␊ |
141 | * is hot and we take the minimum delta from all of the runs.␊ |
142 | * That is to say that we're biased towards measuring the minimum␊ |
143 | * number of TSC ticks that occur while waiting for the timer to␊ |
144 | * expire. That theoretically helps avoid inconsistencies when␊ |
145 | * running under a VM if the TSC is not virtualized and the host␊ |
146 | * steals time. The TSC is normally virtualized for VMware.␊ |
147 | */␊ |
148 | for(i = 0; i < 10; ++i)␊ |
149 | {␊ |
150 | enable_PIT2();␊ |
151 | set_PIT2_mode0(CALIBRATE_LATCH);␊ |
152 | tscStart = rdtsc64();␊ |
153 | pollCount = poll_PIT2_gate();␊ |
154 | tscEnd = rdtsc64();␊ |
155 | /* The poll loop must have run at least a few times for accuracy */␊ |
156 | if(pollCount <= 1)␊ |
157 | continue;␊ |
158 | /* The TSC must increment at LEAST once every millisecond. We␊ |
159 | * should have waited exactly 30 msec so the TSC delta should␊ |
160 | * be >= 30. Anything less and the processor is way too slow.␊ |
161 | */␊ |
162 | if((tscEnd - tscStart) <= CALIBRATE_TIME_MSEC)␊ |
163 | continue;␊ |
164 | // tscDelta = min(tscDelta, (tscEnd - tscStart))␊ |
165 | if( (tscEnd - tscStart) < tscDelta )␊ |
166 | tscDelta = tscEnd - tscStart;␊ |
167 | }␊ |
168 | /* tscDelta is now the least number of TSC ticks the processor made in␊ |
169 | * a timespan of 0.03 s (e.g. 30 milliseconds)␊ |
170 | * Linux thus divides by 30 which gives the answer in kiloHertz because␊ |
171 | * 1 / ms = kHz. But we're xnu and most of the rest of the code uses␊ |
172 | * Hz so we need to convert our milliseconds to seconds. Since we're␊ |
173 | * dividing by the milliseconds, we simply multiply by 1000.␊ |
174 | */␊ |
175 | ␊ |
176 | /* Unlike linux, we're not limited to 32-bit, but we do need to take care␊ |
177 | * that we're going to multiply by 1000 first so we do need at least some␊ |
178 | * arithmetic headroom. For now, 32-bit should be enough.␊ |
179 | * Also unlike Linux, our compiler can do 64-bit integer arithmetic.␊ |
180 | */␊ |
181 | if(tscDelta > (1ULL<<32))␊ |
182 | retval = 0;␊ |
183 | else␊ |
184 | {␊ |
185 | retval = tscDelta * 1000 / 30;␊ |
186 | }␊ |
187 | disable_PIT2();␊ |
188 | return retval;␊ |
189 | }␊ |
190 | ␊ |
191 | /*␊ |
192 | * Calculates the FSB and CPU frequencies using specific MSRs for each CPU␊ |
193 | * - multi. is read from a specific MSR. In the case of Intel, there is:␊ |
194 | * a max multi. (used to calculate the FSB freq.),␊ |
195 | * and a current multi. (used to calculate the CPU freq.)␊ |
196 | * - fsbFrequency = tscFrequency / multi␊ |
197 | * - cpuFrequency = fsbFrequency * multi␊ |
198 | */␊ |
199 | ␊ |
200 | void scan_cpu(PlatformInfo_t *p)␊ |
201 | {␊ |
202 | ␉uint64_t␉tscFrequency, fsbFrequency, cpuFrequency, minfsb, maxfsb;␊ |
203 | ␉uint64_t␉msr, flex_ratio;␊ |
204 | ␉int␉␉␉bus_ratio;␊ |
205 | ␉uint8_t␉␉maxcoef, maxdiv, currcoef, currdiv;␊ |
206 | ␉bool␉␉fix_fsb;␊ |
207 | //␉const uint32_t fsb_cloud[] = {266666667, 133333333, 200000000, 166666667, 333333333, 100000000, 400000000, 0};␊ |
208 | //␉uint32_t␉lo, hi;␊ |
209 | ␊ |
210 | ␉maxcoef = maxdiv = currcoef = currdiv = 0;␊ |
211 | ␊ |
212 | ␉/* get cpuid values */␊ |
213 | ␉do_cpuid(0x00000000, p->CPU.CPUID[CPUID_0]);␊ |
214 | ␉do_cpuid(0x00000001, p->CPU.CPUID[CPUID_1]);␊ |
215 | ␉do_cpuid(0x00000002, p->CPU.CPUID[CPUID_2]);␊ |
216 | ␉do_cpuid(0x00000003, p->CPU.CPUID[CPUID_3]);␊ |
217 | ␉do_cpuid2(0x00000004, 0, p->CPU.CPUID[CPUID_4]);␊ |
218 | ␉do_cpuid(0x80000000, p->CPU.CPUID[CPUID_80]);␊ |
219 | ␉if ((p->CPU.CPUID[CPUID_80][0] & 0x0000000f) >= 1) {␊ |
220 | ␉␉do_cpuid(0x80000001, p->CPU.CPUID[CPUID_81]);␊ |
221 | ␉}␊ |
222 | #if DEBUG_CPU␊ |
223 | ␉{␊ |
224 | ␉␉int␉␉i;␊ |
225 | ␉␉printf("CPUID Raw Values:\n");␊ |
226 | ␉␉for (i=0; i<CPUID_MAX; i++) {␊ |
227 | ␉␉␉printf("%02d: %08x-%08x-%08x-%08x\n", i,␊ |
228 | ␉␉␉␉p->CPU.CPUID[i][0], p->CPU.CPUID[i][1],␊ |
229 | ␉␉␉␉p->CPU.CPUID[i][2], p->CPU.CPUID[i][3]);␊ |
230 | ␉␉}␊ |
231 | ␉}␊ |
232 | #endif␊ |
233 | ␉p->CPU.Vendor␉␉= p->CPU.CPUID[CPUID_0][1];␊ |
234 | ␉p->CPU.Model␉␉= bitfield(p->CPU.CPUID[CPUID_1][0], 7, 4);␊ |
235 | ␉p->CPU.Family␉␉= bitfield(p->CPU.CPUID[CPUID_1][0], 11, 8);␊ |
236 | ␉p->CPU.ExtModel␉␉= bitfield(p->CPU.CPUID[CPUID_1][0], 19, 16);␊ |
237 | ␉p->CPU.ExtFamily␉= bitfield(p->CPU.CPUID[CPUID_1][0], 27, 20);␊ |
238 | ␉p->CPU.NoThreads␉= bitfield(p->CPU.CPUID[CPUID_1][1], 23, 16);␊ |
239 | ␉p->CPU.NoCores␉␉= bitfield(p->CPU.CPUID[CPUID_4][0], 31, 26) + 1;␊ |
240 | ␊ |
241 | ␉p->CPU.Model += (p->CPU.ExtModel << 4);␊ |
242 | ␊ |
243 | ␉/* setup features */␊ |
244 | ␉if ((bit(23) & p->CPU.CPUID[CPUID_1][3]) != 0) {␊ |
245 | ␉␉p->CPU.Features |= CPU_FEATURE_MMX;␊ |
246 | ␉}␊ |
247 | ␉if ((bit(25) & p->CPU.CPUID[CPUID_1][3]) != 0) {␊ |
248 | ␉␉p->CPU.Features |= CPU_FEATURE_SSE;␊ |
249 | ␉}␊ |
250 | ␉if ((bit(26) & p->CPU.CPUID[CPUID_1][3]) != 0) {␊ |
251 | ␉␉p->CPU.Features |= CPU_FEATURE_SSE2;␊ |
252 | ␉}␊ |
253 | ␉if ((bit(0) & p->CPU.CPUID[CPUID_1][2]) != 0) {␊ |
254 | ␉␉p->CPU.Features |= CPU_FEATURE_SSE3;␊ |
255 | ␉}␊ |
256 | ␉if ((bit(19) & p->CPU.CPUID[CPUID_1][2]) != 0) {␊ |
257 | ␉␉p->CPU.Features |= CPU_FEATURE_SSE41;␊ |
258 | ␉}␊ |
259 | ␉if ((bit(20) & p->CPU.CPUID[CPUID_1][2]) != 0) {␊ |
260 | ␉␉p->CPU.Features |= CPU_FEATURE_SSE42;␊ |
261 | ␉}␊ |
262 | ␉if ((bit(29) & p->CPU.CPUID[CPUID_81][3]) != 0) {␊ |
263 | ␉␉p->CPU.Features |= CPU_FEATURE_EM64T;␊ |
264 | ␉}␊ |
265 | ␉//if ((bit(28) & p->CPU.CPUID[CPUID_1][3]) != 0) {␊ |
266 | ␉if (p->CPU.NoThreads > p->CPU.NoCores) {␊ |
267 | ␉␉p->CPU.Features |= CPU_FEATURE_HTT;␊ |
268 | ␉}␊ |
269 | ␊ |
270 | ␉tscFrequency = measure_tsc_frequency();␊ |
271 | ␉fsbFrequency = 0;␊ |
272 | ␉cpuFrequency = 0;␊ |
273 | ␉minfsb = 183000000;␊ |
274 | ␉maxfsb = 185000000;␊ |
275 | ␉fix_fsb = false;␊ |
276 | ␊ |
277 | ␉if ((p->CPU.Vendor == 0x756E6547 /* Intel */) && ((p->CPU.Family == 0x06) || (p->CPU.Family == 0x0f))) {␊ |
278 | ␉␉if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0c) || (p->CPU.Family == 0x0f && p->CPU.Model >= 0x03)) {␊ |
279 | ␉␉␉if (p->CPU.Family == 0x06) {␊ |
280 | /* TODO: Split detection algo into sections, maybe relying on ExtModel, like this:␊ |
281 | ␉␉␉␉if (p->CPU.ExtModel == 0x1) {␊ |
282 | ␉␉␉␉} else if (p->CPU.ExtModel == 0x2) {␊ |
283 | ␉␉␉␉}*/␊ |
284 | ␉␉␉␉int intelCPU = p->CPU.Model;␊ |
285 | ␉␉␉␉int bus;␊ |
286 | ␊ |
287 | ␉␉␉␉switch (intelCPU) {␊ |
288 | ␉␉␉␉␉case 0x1a:␉␉// Core i7 LGA1366, Xeon 550, 45nm␊ |
289 | // TODO: 0x1e needs to be split to avoid 860 & 875k collision.␊ |
290 | ␉␉␉␉␉case 0x1e:␉␉// Core i7, i5 LGA1156, "Lynnfield", "Jasper", 45nm␊ |
291 | ␉␉␉␉␉case 0x1f:␉␉// Core i7, i5, Nehalem␊ |
292 | ␉␉␉␉␉case 0x25:␉␉// Core i7, i5, i3 LGA1156, "Westmere", 32nm␊ |
293 | ␉␉␉␉␉case 0x2c:␉␉// Core i7 LGA1366, Six-core, "Westmere", 32nm␊ |
294 | ␉␉␉␉␉case 0x2e:␉␉// Core i7, Nehalem-Ex, Xeon␊ |
295 | ␉␉␉␉␉case 0x2f:␊ |
296 | ␉␉␉␉␉␉msr = rdmsr64(MSR_PLATFORM_INFO);␊ |
297 | ␉␉␉␉␉␉currcoef = (msr >> 8) & 0xff;␊ |
298 | ␉␉␉␉␉␉msr = rdmsr64(MSR_FLEX_RATIO);␊ |
299 | ␉␉␉␉␉␉if ((msr >> 16) & 0x01) {␊ |
300 | ␉␉␉␉␉␉␉flex_ratio = (msr >> 8) & 0xff;␊ |
301 | ␉␉␉␉␉␉␉if (currcoef > flex_ratio) {␊ |
302 | ␉␉␉␉␉␉␉␉currcoef = flex_ratio;␊ |
303 | ␉␉␉␉␉␉␉}␊ |
304 | ␉␉␉␉␉␉}␊ |
305 | ␉␉␉␉␉␉if (currcoef) {␊ |
306 | ␉␉␉␉␉␉␉fsbFrequency = (tscFrequency / currcoef);␊ |
307 | ␉␉␉␉␉␉}␊ |
308 | ␉␉␉␉␉␉cpuFrequency = tscFrequency;␊ |
309 | ␉␉␉␉␉␉break;␊ |
310 | ␉␉␉␉␉case 0xe:␉␉// Core Duo/Solo, Pentium M DC␊ |
311 | ␉␉␉␉␉case 0xf:␉␉// Core Xeon, Core 2 DC, 65nm␊ |
312 | ␉␉␉␉␉case 0x16:␉␉// Celeron, Core 2 SC, 65nm␊ |
313 | ␉␉␉␉␉case 0x17:␉␉// Core 2 Duo/Extreme, Xeon, 45nm␊ |
314 | ␉␉␉␉␉case 0x1c:␉␉// Atom :)␊ |
315 | ␉␉␉␉␉case 0x27:␉␉// Atom Lincroft, 45nm␊ |
316 | ␉␉␉␉␉␉␉␉getBoolForKey(kFixFSB, &fix_fsb, &bootInfo->bootConfig);␊ |
317 | ␉␉␉␉␉␉␉␉if (fix_fsb) {␊ |
318 | ␉␉␉␉␉␉␉␉␉msr = rdmsr64(MSR_FSB_FREQ);␊ |
319 | ␉␉␉␉␉␉␉␉␉bus = (msr >> 0) & 0x7;␊ |
320 | ␉␉␉␉␉␉␉␉␉switch (bus) {␊ |
321 | ␉␉␉␉␉␉␉␉␉␉case 0:␊ |
322 | ␉␉␉␉␉␉␉␉␉␉␉fsbFrequency = 266666667;␊ |
323 | ␉␉␉␉␉␉␉␉␉␉␉break;␊ |
324 | ␉␉␉␉␉␉␉␉␉␉case 1:␊ |
325 | ␉␉␉␉␉␉␉␉␉␉␉fsbFrequency = 133333333;␊ |
326 | ␉␉␉␉␉␉␉␉␉␉␉break;␊ |
327 | ␉␉␉␉␉␉␉␉␉␉case 2:␊ |
328 | ␉␉␉␉␉␉␉␉␉␉␉fsbFrequency = 200000000;␊ |
329 | ␉␉␉␉␉␉␉␉␉␉␉break;␊ |
330 | ␉␉␉␉␉␉␉␉␉␉case 3:␊ |
331 | ␉␉␉␉␉␉␉␉␉␉␉fsbFrequency = 166666667;␊ |
332 | ␉␉␉␉␉␉␉␉␉␉␉break;␊ |
333 | ␉␉␉␉␉␉␉␉␉␉case 4:␊ |
334 | ␉␉␉␉␉␉␉␉␉␉␉fsbFrequency = 333333333;␊ |
335 | ␉␉␉␉␉␉␉␉␉␉␉break;␊ |
336 | ␉␉␉␉␉␉␉␉␉␉case 5:␊ |
337 | ␉␉␉␉␉␉␉␉␉␉␉fsbFrequency = 100000000;␊ |
338 | ␉␉␉␉␉␉␉␉␉␉␉break;␊ |
339 | ␉␉␉␉␉␉␉␉␉␉case 6:␊ |
340 | ␉␉␉␉␉␉␉␉␉␉␉fsbFrequency = 400000000;␊ |
341 | ␉␉␉␉␉␉␉␉␉␉␉break;␊ |
342 | ␉␉␉␉␉␉␉␉␉␉default:␊ |
343 | ␉␉␉␉␉␉␉␉␉␉␉fsbFrequency = 200000000;␊ |
344 | ␉␉␉␉␉␉␉␉␉␉␉DBG("Defaulting the FSB frequency to 200Mhz \n");␊ |
345 | ␉␉␉␉␉␉␉␉␉␉␉break;␊ |
346 | ␉␉␉␉␉␉␉␉␉}␊ |
347 | ␉␉␉␉␉␉␉␉␉verbose("CPU: FSB Fix applied !\n");␊ |
348 | ␉␉␉␉␉␉␉␉␉if (!getIntForKey(kbusratio, &bus_ratio, &bootInfo->bootConfig)) {␊ |
349 | ␉␉␉␉␉␉␉␉␉␉verbose("CPU: using oldschool cpu freq detection !\n");␊ |
350 | ␉␉␉␉␉␉␉␉␉␉goto oldschool;␊ |
351 | ␉␉␉␉␉␉␉␉␉} else␊ |
352 | ␉␉␉␉␉␉␉␉␉␉cpuFrequency = (fsbFrequency * (bus_ratio / 10));␊ |
353 | ␉␉␉␉␉␉␉␉␉␉␊ |
354 | ␉␉␉␉␉␉␉␉␉if (((fsbFrequency) > (minfsb) && (fsbFrequency) < (maxfsb)) || (!fsbFrequency)) {␊ |
355 | ␉␉␉␉␉␉␉␉␉␉␉fsbFrequency = 200000000;␊ |
356 | ␉␉␉␉␉␉␉␉␉}␊ |
357 | ␉␉␉␉␉␉␉␉} else {␊ |
358 | ␉␉␉␉␉␉␉␉␉verbose("CPU: No FSB Fix applied ! fall back to oldschool \n");␊ |
359 | ␉␉␉␉␉␉␉␉␉goto oldschool;␊ |
360 | ␉␉␉␉␉␉␉␉}␊ |
361 | /*␉␉␉␉␉␉␉␉msr = rdmsr64(IA32_PERF_STATUS);␊ |
362 | ␉␉␉␉␉␉␉␉currdiv = (msr >> 14) & 0x01;␊ |
363 | ␉␉␉␉␉␉␉␉maxdiv = (msr >> 46) & 0x01;␊ |
364 | ␉␉␉␉␉␉␉␉lo = (uint32_t)rdmsr64(IA32_PERF_STATUS);␊ |
365 | ␉␉␉␉␉␉␉␉hi = (uint32_t)(rdmsr64(IA32_PERF_STATUS) >> 32);␊ |
366 | ␉␉␉␉␉␉␉␉if (lo >> 31) {␊ |
367 | ␉␉␉␉␉␉␉␉␉currcoef = (hi >> 8) & 0x1f;␊ |
368 | ␉␉␉␉␉␉␉␉} else {␊ |
369 | ␉␉␉␉␉␉␉␉␉lo = (uint32_t)rdmsr64(MSR_IA32_PLATFORM_ID);␊ |
370 | ␉␉␉␉␉␉␉␉␉currcoef = (lo >> 8) & 0x1f;␊ |
371 | ␉␉␉␉␉␉␉␉}␊ |
372 | ␉␉␉␉␉␉␉␉if (maxdiv) {␊ |
373 | ␉␉␉␉␉␉␉␉␉cpuFrequency = (fsbFrequency * (currcoef + 1));␊ |
374 | ␉␉␉␉␉␉␉␉} else {␊ |
375 | ␉␉␉␉␉␉␉␉␉cpuFrequency = (fsbFrequency * currcoef);␊ |
376 | ␉␉␉␉␉␉␉␉}␊ |
377 | ␉␉␉␉␉␉␉␉if (currdiv) {␊ |
378 | ␉␉␉␉␉␉␉␉␉cpuFrequency = (fsbFrequency * ((currcoef * 2) + 1) / 2);␊ |
379 | ␉␉␉␉␉␉␉␉} else {␊ |
380 | ␉␉␉␉␉␉␉␉␉cpuFrequency = (fsbFrequency * currcoef);␊ |
381 | ␉␉␉␉␉␉␉␉}*/␊ |
382 | ␉␉␉␉␉␉␉␉//cpuFrequency = tscFrequency;␊ |
383 | ␉␉␉␉␉␉␉␉break;␊ |
384 | /*␉␉␉␉␉case 0x17:␉␉// Core 2 Duo/Extreme, Xeon, 45nm␊ |
385 | ␉␉␉␉␉␉lo = (uint32_t)rdmsr64(IA32_PERF_STATUS);␊ |
386 | ␉␉␉␉␉␉hi = (uint32_t)(rdmsr64(IA32_PERF_STATUS) >> 32);␊ |
387 | ␉␉␉␉␉␉//rdmsr46(IA32_PERF_STATUS, lo, hi);␊ |
388 | ␉␉␉␉␉␉if (lo >> 31) {␊ |
389 | ␉␉␉␉␉␉␉currcoef = (hi >> 8) & 0x1f;␊ |
390 | ␉␉␉␉␉␉} else {␊ |
391 | ␉␉␉␉␉␉␉lo = (uint32_t)rdmsr64(MSR_IA32_PLATFORM_ID);␊ |
392 | ␉␉␉␉␉␉//␉hi = (uint32_t)(rdmsr64(MSR_IA32_PLATFORM_ID) >> 32);␊ |
393 | ␉␉␉␉␉␉//␉rdmsr46(MSR_IA32_PLATFORM_ID, lo, hi);␊ |
394 | ␉␉␉␉␉␉␉currcoef = (lo >> 8) & 0x1f;␊ |
395 | ␉␉␉␉␉␉}␊ |
396 | ␉␉␉␉␉␉fsbFrequency = ((fsb_cloud[lo & 0x7]) * 2);␊ |
397 | ␉␉␉␉␉␉//cpuFrequency = (fsbFrequency * currcoef);␊ |
398 | ␉␉␉␉␉␉if (!fsbFrequency) {␊ |
399 | ␉␉␉␉␉␉␉fsbFrequency = (DEFAULT_FSB * 2000);␊ |
400 | ␉␉␉␉␉␉␉DBG("0 ! Defaulting the FSB frequency to 200Mhz !\n");␊ |
401 | ␉␉␉␉␉␉}*/␊ |
402 | ␉␉␉␉␉case 0x1d:␉␉// Xeon MP MP 7400␊ |
403 | ␉␉␉␉␉default:␊ |
404 | ␉␉␉␉␉␉goto oldschool;␊ |
405 | ␉␉␉␉␉␉break;␊ |
406 | ␉␉␉␉}␊ |
407 | ␉␉␉} else {␊ |
408 | oldschool:␊ |
409 | ␉␉␉␉␉msr = rdmsr64(IA32_PERF_STATUS);␊ |
410 | ␉␉␉␉␉DBG("msr(%d): ia32_perf_stat 0x%08x\n", __LINE__, msr & 0xffffffff);␊ |
411 | ␉␉␉␉␉currcoef = (msr >> 8) & 0x1f;␊ |
412 | ␉␉␉␉␉/* Non-integer bus ratio for the max-multi*/␊ |
413 | ␉␉␉␉␉maxdiv = (msr >> 46) & 0x01;␊ |
414 | ␉␉␉␉␉/* Non-integer bus ratio for the current-multi (undocumented)*/␊ |
415 | ␉␉␉␉␉currdiv = (msr >> 14) & 0x01;␊ |
416 | ␊ |
417 | ␉␉␉␉␉if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0e) || (p->CPU.Family == 0x0f)) // This will always be model >= 3␊ |
418 | ␉␉␉␉␉{␊ |
419 | ␉␉␉␉␉␉/* On these models, maxcoef defines TSC freq */␊ |
420 | ␉␉␉␉␉␉maxcoef = (msr >> 40) & 0x1f;␊ |
421 | ␉␉␉␉␉} else {␊ |
422 | ␉␉␉␉␉␉/* On lower models, currcoef defines TSC freq */␊ |
423 | ␉␉␉␉␉␉/* XXX */␊ |
424 | ␉␉␉␉␉␉maxcoef = currcoef;␊ |
425 | ␉␉␉␉␉}␊ |
426 | ␊ |
427 | ␉␉␉␉␉if (maxcoef) {␊ |
428 | ␉␉␉␉␉␉if (!fix_fsb) {␊ |
429 | ␉␉␉␉␉␉␉if (maxdiv) {␊ |
430 | ␉␉␉␉␉␉␉␉fsbFrequency = ((tscFrequency * 2) / ((maxcoef * 2) + 1));␊ |
431 | ␉␉␉␉␉␉␉} else {␊ |
432 | ␉␉␉␉␉␉␉␉fsbFrequency = (tscFrequency / maxcoef);␊ |
433 | ␉␉␉␉␉␉␉}␊ |
434 | ␉␉␉␉␉␉}␊ |
435 | ␉␉␉␉␉␉if (currdiv) {␊ |
436 | ␉␉␉␉␉␉␉cpuFrequency = (fsbFrequency * ((currcoef * 2) + 1) / 2);␊ |
437 | ␉␉␉␉␉␉} else {␊ |
438 | ␉␉␉␉␉␉␉cpuFrequency = (fsbFrequency * currcoef);␊ |
439 | ␉␉␉␉␉␉}␊ |
440 | ␉␉␉␉␉␉DBG("max: %d%s current: %d%s\n", maxcoef, maxdiv ? ".5" : "",currcoef, currdiv ? ".5" : "");␊ |
441 | ␉␉␉␉␉}␊ |
442 | ␉␉␉␉␉/*if (p->CPU.Family == 0x06 && p->CPU.Model >= 0x0e)␊ |
443 | ␉␉␉␉␉{␊ |
444 | ␉␉␉␉␉␉maxcoef = (msr >> 40) & 0x1f;␊ |
445 | ␉␉␉␉␉␉if (maxcoef) {␊ |
446 | ␉␉␉␉␉␉␉if (maxdiv) {␊ |
447 | ␉␉␉␉␉␉␉␉fsbFrequency = ((tscFrequency * 2) / ((maxcoef * 2) + 1));␊ |
448 | ␉␉␉␉␉␉␉} else {␊ |
449 | ␉␉␉␉␉␉␉␉fsbFrequency = (tscFrequency / maxcoef);␊ |
450 | ␉␉␉␉␉␉␉}␊ |
451 | ␉␉␉␉␉␉␉if (currdiv) {␊ |
452 | ␉␉␉␉␉␉␉␉cpuFrequency = (fsbFrequency * ((currcoef * 2) + 1) / 2);␊ |
453 | ␉␉␉␉␉␉␉} else {␊ |
454 | ␉␉␉␉␉␉␉␉cpuFrequency = (fsbFrequency * currcoef);␊ |
455 | ␉␉␉␉␉␉␉}␊ |
456 | ␉␉␉␉␉␉}␊ |
457 | ␉␉␉␉␉␉if (((fsbFrequency) > (minfsb) && (fsbFrequency) < (maxfsb)) || (!fsbFrequency)) {␊ |
458 | ␉␉␉␉␉␉␉fsbFrequency = 200000000;␊ |
459 | ␉␉␉␉␉␉␉DBG("Defaulting FSB frequency to 200Mhz !\n");␊ |
460 | ␉␉␉␉␉␉}␊ |
461 | ␉␉␉␉␉}␊ |
462 | ␉␉␉␉␉if (p->CPU.Family == 0x0f) {␊ |
463 | ␉␉␉␉␉␉msr = rdmsr64(0x0000002C); // Xeon related register.␊ |
464 | ␉␉␉␉␉␉int bus;␊ |
465 | ␉␉␉␉␉␉bus = (msr >> 16) & 0x7;␊ |
466 | ␉␉␉␉␉␉switch (bus) {␊ |
467 | ␉␉␉␉␉␉␉case 0:␊ |
468 | ␉␉␉␉␉␉␉␉if (p->CPU.Model == 2) {␊ |
469 | ␉␉␉␉␉␉␉␉␉fsbFrequency = 100000000;␊ |
470 | ␉␉␉␉␉␉␉␉} else {␊ |
471 | ␉␉␉␉␉␉␉␉␉fsbFrequency = 266666667;␊ |
472 | ␉␉␉␉␉␉␉␉}␊ |
473 | ␉␉␉␉␉␉␉␉break;␊ |
474 | ␉␉␉␉␉␉␉case 1:␊ |
475 | ␉␉␉␉␉␉␉␉fsbFrequency = 133333333;␊ |
476 | ␉␉␉␉␉␉␉␉break;␊ |
477 | ␉␉␉␉␉␉␉case 2:␊ |
478 | ␉␉␉␉␉␉␉␉fsbFrequency = 200000000;␊ |
479 | ␉␉␉␉␉␉␉␉break;␊ |
480 | ␉␉␉␉␉␉␉case 3:␊ |
481 | ␉␉␉␉␉␉␉␉fsbFrequency = 166666667;␊ |
482 | ␉␉␉␉␉␉␉␉break;␊ |
483 | ␉␉␉␉␉␉␉case 4:␊ |
484 | ␉␉␉␉␉␉␉␉fsbFrequency = 333333333;␊ |
485 | ␉␉␉␉␉␉␉␉break;␊ |
486 | ␉␉␉␉␉␉␉default:␊ |
487 | ␉␉␉␉␉␉␉␉break;␊ |
488 | ␉␉␉␉␉␉}␊ |
489 | ␉␉␉␉␉} else {␊ |
490 | ␉␉␉␉␉␉fsbFrequency = 100000000;␊ |
491 | ␉␉␉␉␉␉DBG("Defaulting FSB frequency to 100Mhz !\n");␊ |
492 | ␉␉␉␉␉}*/␊ |
493 | ␉␉␉␉␉if (((fsbFrequency) > (minfsb) && (fsbFrequency) < (maxfsb)) || (!fsbFrequency)) {␊ |
494 | ␉␉␉␉␉␉fsbFrequency = 200000000;␊ |
495 | ␉␉␉␉␉␉DBG("Defaulting FSB frequency to 200Mhz !\n");␊ |
496 | ␉␉␉␉␉}␊ |
497 | ␉␉␉␉}␊ |
498 | ␉␉␉}␊ |
499 | ␊ |
500 | ␉␉// Mobile CPU ?␊ |
501 | ␉␉if (rdmsr64(0x17) & (1<<28)) {␊ |
502 | ␉␉␉p->CPU.Features |= CPU_FEATURE_MOBILE;␊ |
503 | ␉␉}␊ |
504 | ␉}␊ |
505 | #if 0␊ |
506 | ␉else if((p->CPU.Vendor == 0x68747541 /* AMD */) && (p->CPU.Family == 0x0f)) {␊ |
507 | ␉␉if(p->CPU.ExtFamily == 0x00 /* K8 */) {␊ |
508 | ␉␉␉msr = rdmsr64(K8_FIDVID_STATUS);␊ |
509 | ␉␉␉currcoef = (msr & 0x3f) / 2 + 4;␊ |
510 | ␉␉␉currdiv = (msr & 0x01) * 2;␊ |
511 | ␉␉} else if(p->CPU.ExtFamily >= 0x01 /* K10+ */) {␊ |
512 | ␉␉␉msr = rdmsr64(K10_COFVID_STATUS);␊ |
513 | ␉␉␉if(p->CPU.ExtFamily == 0x01 /* K10 */)␊ |
514 | ␉␉␉␉currcoef = (msr & 0x3f) + 0x10;␊ |
515 | ␉␉␉else /* K11+ */␊ |
516 | ␉␉␉␉currcoef = (msr & 0x3f) + 0x08;␊ |
517 | ␉␉␉currdiv = (2 << ((msr >> 6) & 0x07));␊ |
518 | ␉␉}␊ |
519 | ␊ |
520 | ␉␉if (currcoef) {␊ |
521 | ␉␉␉if (currdiv) {␊ |
522 | ␉␉␉␉fsbFrequency = ((tscFrequency * currdiv) / currcoef);␊ |
523 | ␉␉␉␉DBG("%d.%d\n", currcoef / currdiv, ((currcoef % currdiv) * 100) / currdiv);␊ |
524 | ␉␉␉} else {␊ |
525 | ␉␉␉␉fsbFrequency = (tscFrequency / currcoef);␊ |
526 | ␉␉␉␉DBG("%d\n", currcoef);␊ |
527 | ␉␉␉}␊ |
528 | ␉␉␉fsbFrequency = (tscFrequency / currcoef);␊ |
529 | ␉␉␉cpuFrequency = tscFrequency;␊ |
530 | ␉␉}␊ |
531 | ␉}␊ |
532 | ␊ |
533 | ␉if (!fsbFrequency) {␊ |
534 | ␉␉fsbFrequency = (DEFAULT_FSB * 1000);␊ |
535 | ␉␉cpuFrequency = tscFrequency;␊ |
536 | ␉␉DBG("0 ! using the default value for FSB !\n");␊ |
537 | ␉}␊ |
538 | #endif␊ |
539 | ␊ |
540 | ␉p->CPU.MaxCoef = maxcoef;␊ |
541 | ␉p->CPU.MaxDiv = maxdiv;␊ |
542 | ␉p->CPU.CurrCoef = currcoef;␊ |
543 | ␉p->CPU.CurrDiv = currdiv;␊ |
544 | ␉p->CPU.TSCFrequency = tscFrequency;␊ |
545 | ␉p->CPU.FSBFrequency = fsbFrequency;␊ |
546 | ␉p->CPU.CPUFrequency = cpuFrequency;␊ |
547 | #if DEBUG_CPU␊ |
548 | ␉DBG("CPU: Vendor/Model/ExtModel: 0x%x/0x%x/0x%x\n", p->CPU.Vendor, p->CPU.Model, p->CPU.ExtModel);␊ |
549 | ␉DBG("CPU: Family/ExtFamily: 0x%x/0x%x\n", p->CPU.Family, p->CPU.ExtFamily);␊ |
550 | ␉DBG("CPU: MaxCoef/CurrCoef: 0x%x/0x%x\n", p->CPU.MaxCoef, p->CPU.CurrCoef);␊ |
551 | ␉DBG("CPU: MaxDiv/CurrDiv: 0x%x/0x%x\n", p->CPU.MaxDiv, p->CPU.CurrDiv);␊ |
552 | ␉DBG("CPU: TSCFreq: %dMHz\n", p->CPU.TSCFrequency / 1000000);␊ |
553 | ␉DBG("CPU: FSBFreq: %dMHz\n", p->CPU.FSBFrequency / 1000000);␊ |
554 | ␉DBG("CPU: CPUFreq: %dMHz\n", p->CPU.CPUFrequency / 1000000);␊ |
555 | ␉DBG("CPU: NoCores/NoThreads: %d/%d\n", p->CPU.NoCores, p->CPU.NoThreads);␊ |
556 | ␉DBG("CPU: Features: 0x%08x\n", p->CPU.Features);␊ |
557 | ␉pause();␊ |
558 | #endif␊ |
559 | }␊ |
560 | |