Chameleon

Chameleon Svn Source Tree

Root/branches/meklortOld/i386/libsaio/cpu.c

Source at commit 1146 created 12 years 10 months ago.
By azimutz, Sync with trunk (r1145). Add nVidia dev id's, 0DF4 for "GeForce GT 450M" (issue 99) and 1251 for "GeForce GTX 560M" (thanks to oSxFr33k for testing).
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/*
21 * DFE: Measures the TSC frequency in Hz (64-bit) using the ACPI PM timer
22 */
23static uint64_t measure_tsc_frequency(void)
24{
25 uint64_t tscStart;
26 uint64_t tscEnd;
27 uint64_t tscDelta = 0xffffffffffffffffULL;
28 unsigned long pollCount;
29 uint64_t retval = 0;
30 int i;
31
32 /* Time how many TSC ticks elapse in 30 msec using the 8254 PIT
33 * counter 2. We run this loop 3 times to make sure the cache
34 * is hot and we take the minimum delta from all of the runs.
35 * That is to say that we're biased towards measuring the minimum
36 * number of TSC ticks that occur while waiting for the timer to
37 * expire. That theoretically helps avoid inconsistencies when
38 * running under a VM if the TSC is not virtualized and the host
39 * steals time. The TSC is normally virtualized for VMware.
40 */
41 for(i = 0; i < 10; ++i)
42 {
43 enable_PIT2();
44 set_PIT2_mode0(CALIBRATE_LATCH);
45 tscStart = rdtsc64();
46 pollCount = poll_PIT2_gate();
47 tscEnd = rdtsc64();
48 /* The poll loop must have run at least a few times for accuracy */
49 if(pollCount <= 1)
50 continue;
51 /* The TSC must increment at LEAST once every millisecond. We
52 * should have waited exactly 30 msec so the TSC delta should
53 * be >= 30. Anything less and the processor is way too slow.
54 */
55 if((tscEnd - tscStart) <= CALIBRATE_TIME_MSEC)
56 continue;
57 // tscDelta = min(tscDelta, (tscEnd - tscStart))
58 if( (tscEnd - tscStart) < tscDelta )
59 tscDelta = tscEnd - tscStart;
60 }
61 /* tscDelta is now the least number of TSC ticks the processor made in
62 * a timespan of 0.03 s (e.g. 30 milliseconds)
63 * Linux thus divides by 30 which gives the answer in kiloHertz because
64 * 1 / ms = kHz. But we're xnu and most of the rest of the code uses
65 * Hz so we need to convert our milliseconds to seconds. Since we're
66 * dividing by the milliseconds, we simply multiply by 1000.
67 */
68
69 /* Unlike linux, we're not limited to 32-bit, but we do need to take care
70 * that we're going to multiply by 1000 first so we do need at least some
71 * arithmetic headroom. For now, 32-bit should be enough.
72 * Also unlike Linux, our compiler can do 64-bit integer arithmetic.
73 */
74 if(tscDelta > (1ULL<<32))
75 retval = 0;
76 else
77 {
78 retval = tscDelta * 1000 / 30;
79 }
80 disable_PIT2();
81 return retval;
82}
83
84/*
85 * Calculates the FSB and CPU frequencies using specific MSRs for each CPU
86 * - multi. is read from a specific MSR. In the case of Intel, there is:
87 * a max multi. (used to calculate the FSB freq.),
88 * and a current multi. (used to calculate the CPU freq.)
89 * - fsbFrequency = tscFrequency / multi
90 * - cpuFrequency = fsbFrequency * multi
91 */
92
93void scan_cpu(PlatformInfo_t *p)
94{
95int i = 0;
96uint64_ttscFrequency, fsbFrequency, cpuFrequency;
97uint64_tmsr, flex_ratio;
98uint8_tmaxcoef, maxdiv, currcoef, currdiv;
99
100maxcoef = maxdiv = currcoef = currdiv = 0;
101
102
103// Rename CPU to GeniuneIntel
104//wrmsr64(MSR_VIA_FEAT_CONTROL2, 'GenuineI'/*'ntel'*/);
105
106
107/* get cpuid values */
108for( ; i <= 3; i++)
109{
110do_cpuid(i, p->CPU.CPUID[i]);
111}
112
113do_cpuid2(0x00000004, 0, p->CPU.CPUID[CPUID_4]);
114do_cpuid(0x80000000, p->CPU.CPUID[CPUID_80]);
115if ((p->CPU.CPUID[CPUID_80][0] & 0x0000000f) >= 1) {
116do_cpuid(0x80000001, p->CPU.CPUID[CPUID_81]);
117}
118#if DEBUG_CPU
119{
120inti;
121printf("CPUID Raw Values:\n");
122for (i=0; i<CPUID_MAX; i++) {
123printf("%02d: %08x-%08x-%08x-%08x\n", i,
124p->CPU.CPUID[i][0], p->CPU.CPUID[i][1],
125p->CPU.CPUID[i][2], p->CPU.CPUID[i][3]);
126}
127}
128#endif
129p->CPU.Vendor= p->CPU.CPUID[CPUID_0][1];
130p->CPU.Signature= p->CPU.CPUID[CPUID_1][0];
131p->CPU.Stepping= bitfield(p->CPU.CPUID[CPUID_1][0], 3, 0);
132p->CPU.Model= bitfield(p->CPU.CPUID[CPUID_1][0], 7, 4);
133p->CPU.Family= bitfield(p->CPU.CPUID[CPUID_1][0], 11, 8);
134p->CPU.ExtModel= bitfield(p->CPU.CPUID[CPUID_1][0], 19, 16);
135p->CPU.ExtFamily= bitfield(p->CPU.CPUID[CPUID_1][0], 27, 20);
136p->CPU.NoThreads= bitfield(p->CPU.CPUID[CPUID_1][1], 23, 16);
137p->CPU.NoCores= bitfield(p->CPU.CPUID[CPUID_4][0], 31, 26) + 1;
138
139p->CPU.Model += (p->CPU.ExtModel << 4);
140
141/* get brand string (if supported) */
142/* Copyright: from Apple's XNU cpuid.c */
143if (p->CPU.CPUID[CPUID_80][0] > 0x80000004) {
144uint32_treg[4];
145 char str[128], *s;
146/*
147 * The brand string 48 bytes (max), guaranteed to
148 * be NUL terminated.
149 */
150do_cpuid(0x80000002, reg);
151bcopy((char *)reg, &str[0], 16);
152do_cpuid(0x80000003, reg);
153bcopy((char *)reg, &str[16], 16);
154do_cpuid(0x80000004, reg);
155bcopy((char *)reg, &str[32], 16);
156for (s = str; *s != '\0'; s++) {
157if (*s != ' ') break;
158}
159
160strlcpy(p->CPU.BrandString,s, sizeof(p->CPU.BrandString));
161
162if (!strncmp(p->CPU.BrandString, CPU_STRING_UNKNOWN, min(sizeof(p->CPU.BrandString), strlen(CPU_STRING_UNKNOWN) + 1))) {
163 /*
164 * This string means we have a firmware-programmable brand string,
165 * and the firmware couldn't figure out what sort of CPU we have.
166 */
167 p->CPU.BrandString[0] = '\0';
168 }
169}
170
171/* setup features */
172p->CPU.Features |= (CPU_FEATURE_MMX | CPU_FEATURE_SSE | CPU_FEATURE_SSE2 | CPU_FEATURE_MSR) & p->CPU.CPUID[CPUID_1][3];
173p->CPU.Features |= (CPU_FEATURE_SSE3 | CPU_FEATURE_SSE41 | CPU_FEATURE_SSE42) & p->CPU.CPUID[CPUID_1][2];
174p->CPU.Features |= (CPU_FEATURE_EM64T) & p->CPU.CPUID[CPUID_81][3];
175
176
177//if ((CPU_FEATURE_HTT & p->CPU.CPUID[CPUID_1][3]) != 0) {
178if (p->CPU.NoThreads > p->CPU.NoCores) {
179p->CPU.Features |= CPU_FEATURE_HTT;
180}
181
182
183tscFrequency = measure_tsc_frequency();
184fsbFrequency = 0;
185cpuFrequency = 0;
186
187if ((p->CPU.Vendor == 0x756E6547 /* Intel */) &&
188((p->CPU.Family == 0x06) ||
189 (p->CPU.Family == 0x0f)))
190{
191if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0c) ||
192(p->CPU.Family == 0x0f && p->CPU.Model >= 0x03))
193{
194/* Nehalem CPU model */
195if (p->CPU.Family == 0x06 && (p->CPU.Model == 0x1a || p->CPU.Model == 0x1e ||
196 p->CPU.Model == 0x1f || p->CPU.Model == 0x25 ||
197 p->CPU.Model == 0x2c))
198{
199msr = rdmsr64(MSR_PLATFORM_INFO);
200DBG("msr(%d): platform_info %08x\n", __LINE__, msr & 0xffffffff);
201currcoef = (msr >> 8) & 0xff;
202msr = rdmsr64(MSR_FLEX_RATIO);
203DBG("msr(%d): flex_ratio %08x\n", __LINE__, msr & 0xffffffff);
204if ((msr >> 16) & 0x01)
205{
206flex_ratio = (msr >> 8) & 0xff;
207if (currcoef > flex_ratio)
208{
209currcoef = flex_ratio;
210}
211}
212
213if (currcoef) {
214fsbFrequency = (tscFrequency / currcoef);
215}
216cpuFrequency = tscFrequency;
217}
218else
219{
220msr = rdmsr64(MSR_IA32_PERF_STATUS);
221DBG("msr(%d): ia32_perf_stat 0x%08x\n", __LINE__, msr & 0xffffffff);
222currcoef = (msr >> 8) & 0x1f;
223/* Non-integer bus ratio for the max-multi*/
224maxdiv = (msr >> 46) & 0x01;
225/* Non-integer bus ratio for the current-multi (undocumented)*/
226currdiv = (msr >> 14) & 0x01;
227
228if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0e) ||
229(p->CPU.Family == 0x0f)) // This will always be model >= 3
230{
231/* On these models, maxcoef defines TSC freq */
232maxcoef = (msr >> 40) & 0x1f;
233}
234else
235{
236/* On lower models, currcoef defines TSC freq */
237/* XXX */
238maxcoef = currcoef;
239}
240
241if (maxcoef)
242{
243if (maxdiv)
244{
245fsbFrequency = ((tscFrequency * 2) / ((maxcoef * 2) + 1));
246}
247else
248{
249fsbFrequency = (tscFrequency / maxcoef);
250}
251
252if (currdiv)
253{
254cpuFrequency = (fsbFrequency * ((currcoef * 2) + 1) / 2);
255}
256else
257{
258cpuFrequency = (fsbFrequency * currcoef);
259}
260DBG("max: %d%s current: %d%s\n", maxcoef, maxdiv ? ".5" : "",currcoef, currdiv ? ".5" : "");
261}
262}
263}
264/* Mobile CPU ? */
265if (rdmsr64(0x17) & (1<<28))
266{
267p->CPU.Features |= CPU_FEATURE_MOBILE;
268}
269}
270#if 0
271else if((p->CPU.Vendor == 0x68747541 /* AMD */) && (p->CPU.Family == 0x0f))
272{
273if(p->CPU.ExtFamily == 0x00 /* K8 */)
274{
275msr = rdmsr64(K8_FIDVID_STATUS);
276currcoef = (msr & 0x3f) / 2 + 4;
277currdiv = (msr & 0x01) * 2;
278}
279else if(p->CPU.ExtFamily >= 0x01 /* K10+ */)
280{
281msr = rdmsr64(K10_COFVID_STATUS);
282if(p->CPU.ExtFamily == 0x01 /* K10 */)
283currcoef = (msr & 0x3f) + 0x10;
284else /* K11+ */
285currcoef = (msr & 0x3f) + 0x08;
286currdiv = (2 << ((msr >> 6) & 0x07));
287}
288
289if (currcoef)
290{
291if (currdiv)
292{
293fsbFrequency = ((tscFrequency * currdiv) / currcoef);
294DBG("%d.%d\n", currcoef / currdiv, ((currcoef % currdiv) * 100) / currdiv);
295}
296else
297{
298fsbFrequency = (tscFrequency / currcoef);
299DBG("%d\n", currcoef);
300}
301fsbFrequency = (tscFrequency / currcoef);
302cpuFrequency = tscFrequency;
303}
304}
305
306if (!fsbFrequency)
307{
308fsbFrequency = (DEFAULT_FSB * 1000);
309cpuFrequency = tscFrequency;
310DBG("0 ! using the default value for FSB !\n");
311}
312#endif
313else if(p->CPU.Vendor == 0x746e6543 && p->CPU.Family == 6)
314{
315switch (p->CPU.Model) {
316case CPU_VIA_NANO:
317// NOTE: TSC is constant, irrelevent of speed steping
318break;
319default:
320break;
321}
322
323msr = rdmsr64(MSR_NANO_FCR2);
324printf("MSR_IA32_EBL_CR_POWERON Returns 0x%X 0x%X\n", msr >> 32, msr & 0xffffffff);
325
326//msr = msr >> 32;
327msr |= VIA_ALTERNATIVE_VENDOR_BIT;
328//msr = msr << 32;
329
330printf("MSR_IA32_EBL_CR_POWERON Returns 0x%X 0x%X\n", msr >> 32, msr & 0xffffffff);
331wrmsr64(MSR_NANO_FCR2, msr);
332msr = rdmsr64(MSR_NANO_FCR2);
333printf("MSR_IA32_EBL_CR_POWERON Returns 0x%X 0x%X\n", msr >> 32, msr & 0xffffffff);
334
335
336/* get cpuid values */
337for( ; i <= 3; i++)
338{
339do_cpuid(i, p->CPU.CPUID[i]);
340}
341//int numcpuid_supported = p->CPU.CPUID[CPUID_0][0];// max number cpuid call
342//int numextcpuid = p->CPU.CPUID[CPUID_80][0];
343//p->CPU.Features = 0;
344//bitfield(p->CPU.CPUID[CPUID_1][1], 0, 0) FEATURE_C
345
346// CPUID_0 -> largest cpuid val in EAX
347// CPUID_0 -> rem = vendor string
348/*
349CPUID_1 EDX:
350 0 -> FPU
351 1 -> VME
352 2 -> DE
353 3 -> PSE
354 4 -> TSC
355 5 -> MSR
356 6 -> PAE
357 7 -> MCE
358 8 -> CX8
359 9 -> APIC
360 10 -> Reserved
361 11 -> Fast Call
362 12 -> MTTR
363 13 -> PGE
364 14 -> MCA
365 15 -> CMOV
366 16 -> PAT
367 17 -> PSE36
368 18 -> Serial Number
369 23 -> MMX
370 24 -> FXSR
371 25 -> SSE
372 */
373
374//CPUID_80 -> largest excpuid value in EAX
375//CPUID_81,EAX -> Signature
376//CPUID_80,EDX -> Ext Features
377//CPUID_82 -> CPU String
378//CPUID_83 -> CPU String
379//CPUID_84 -> CPU String
380p->CPU.NoThreads = p->CPU.NoCores;
381
382}
383
384p->CPU.MaxCoef = maxcoef;
385p->CPU.MaxDiv = maxdiv;
386p->CPU.CurrCoef = currcoef;
387p->CPU.CurrDiv = currdiv;
388p->CPU.TSCFrequency = tscFrequency;
389p->CPU.FSBFrequency = fsbFrequency;
390p->CPU.CPUFrequency = cpuFrequency;
391DBG("CPU: Brand: %s\n", p->CPU.BrandString);
392DBG("CPU: Vendor/Model/ExtModel: 0x%x/0x%x/0x%x\n", p->CPU.Vendor, p->CPU.Model, p->CPU.ExtModel);
393DBG("CPU: Family/ExtFamily: 0x%x/0x%x\n", p->CPU.Family, p->CPU.ExtFamily);
394DBG("CPU: MaxCoef/CurrCoef: 0x%x/0x%x\n", p->CPU.MaxCoef, p->CPU.CurrCoef);
395DBG("CPU: MaxDiv/CurrDiv: 0x%x/0x%x\n", p->CPU.MaxDiv, p->CPU.CurrDiv);
396DBG("CPU: TSCFreq: %dMHz\n", p->CPU.TSCFrequency / 1000000);
397DBG("CPU: FSBFreq: %dMHz\n", p->CPU.FSBFrequency / 1000000);
398DBG("CPU: CPUFreq: %dMHz\n", p->CPU.CPUFrequency / 1000000);
399DBG("CPU: NoCores/NoThreads: %d/%d\n", p->CPU.NoCores, p->CPU.NoThreads);
400DBG("CPU: Features: 0x%08x\n", p->CPU.Features);
401#if DEBUG_CPU
402pause();
403#endif
404}
405

Archive Download this file

Revision: 1146