Chameleon Applications

Chameleon Applications Svn Source Tree

Root/branches/iFabio/Chameleon/i386/libsaio/cpu.c

Source at commit 307 created 12 years 11 months ago.
By ifabio, merge changes from trunk (929). Also merge the module changes from Azimutz branche (fix compile error) Also edited the info.plist into AHCIPortInjector.kext: http://forum.voodooprojects.org/index.php/topic,1170.0.html
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 "bootstruct.h"
10#include "boot.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...)msglog(x)
20#endif
21
22/*
23 * DFE: Measures the TSC frequency in Hz (64-bit) using the ACPI PM timer
24 */
25static uint64_t measure_tsc_frequency(void)
26{
27 uint64_t tscStart;
28 uint64_t tscEnd;
29 uint64_t tscDelta = 0xffffffffffffffffULL;
30 unsigned long pollCount;
31 uint64_t retval = 0;
32 int i;
33
34 /* Time how many TSC ticks elapse in 30 msec using the 8254 PIT
35 * counter 2. We run this loop 3 times to make sure the cache
36 * is hot and we take the minimum delta from all of the runs.
37 * That is to say that we're biased towards measuring the minimum
38 * number of TSC ticks that occur while waiting for the timer to
39 * expire. That theoretically helps avoid inconsistencies when
40 * running under a VM if the TSC is not virtualized and the host
41 * steals time. The TSC is normally virtualized for VMware.
42 */
43 for(i = 0; i < 10; ++i)
44 {
45 enable_PIT2();
46 set_PIT2_mode0(CALIBRATE_LATCH);
47 tscStart = rdtsc64();
48 pollCount = poll_PIT2_gate();
49 tscEnd = rdtsc64();
50 /* The poll loop must have run at least a few times for accuracy */
51 if(pollCount <= 1)
52 continue;
53 /* The TSC must increment at LEAST once every millisecond. We
54 * should have waited exactly 30 msec so the TSC delta should
55 * be >= 30. Anything less and the processor is way too slow.
56 */
57 if((tscEnd - tscStart) <= CALIBRATE_TIME_MSEC)
58 continue;
59 // tscDelta = min(tscDelta, (tscEnd - tscStart))
60 if( (tscEnd - tscStart) < tscDelta )
61 tscDelta = tscEnd - tscStart;
62 }
63 /* tscDelta is now the least number of TSC ticks the processor made in
64 * a timespan of 0.03 s (e.g. 30 milliseconds)
65 * Linux thus divides by 30 which gives the answer in kiloHertz because
66 * 1 / ms = kHz. But we're xnu and most of the rest of the code uses
67 * Hz so we need to convert our milliseconds to seconds. Since we're
68 * dividing by the milliseconds, we simply multiply by 1000.
69 */
70
71 /* Unlike linux, we're not limited to 32-bit, but we do need to take care
72 * that we're going to multiply by 1000 first so we do need at least some
73 * arithmetic headroom. For now, 32-bit should be enough.
74 * Also unlike Linux, our compiler can do 64-bit integer arithmetic.
75 */
76 if(tscDelta > (1ULL<<32))
77 retval = 0;
78 else
79 {
80 retval = tscDelta * 1000 / 30;
81 }
82 disable_PIT2();
83 return retval;
84}
85
86/*
87 * Calculates the FSB and CPU frequencies using specific MSRs for each CPU
88 * - multi. is read from a specific MSR. In the case of Intel, there is:
89 * a max multi. (used to calculate the FSB freq.),
90 * and a current multi. (used to calculate the CPU freq.)
91 * - fsbFrequency = tscFrequency / multi
92 * - cpuFrequency = fsbFrequency * multi
93 */
94
95void scan_cpu(PlatformInfo_t *p)
96{
97uint64_ttscFrequency, fsbFrequency, cpuFrequency;
98uint64_tmsr, flex_ratio;
99uint8_tmaxcoef, maxdiv, currcoef, bus_ratio_max, currdiv;
100const char *newratio;
101int len, myfsb;
102uint8_t bus_ratio_min;
103uint32_t max_ratio, min_ratio;
104
105max_ratio = min_ratio = myfsb = bus_ratio_min = 0;
106maxcoef = maxdiv = bus_ratio_max = currcoef = currdiv = 0;
107
108/* get cpuid values */
109do_cpuid(0x00000000, p->CPU.CPUID[CPUID_0]);
110do_cpuid(0x00000001, p->CPU.CPUID[CPUID_1]);
111do_cpuid(0x00000002, p->CPU.CPUID[CPUID_2]);
112do_cpuid(0x00000003, p->CPU.CPUID[CPUID_3]);
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);
136
137 p->CPU.Model += (p->CPU.ExtModel << 4);
138
139 if (p->CPU.Vendor == 0x756E6547 /* Intel */ &&
140 p->CPU.Family == 0x06 &&
141 p->CPU.Model >= CPUID_MODEL_NEHALEM &&
142 p->CPU.Model != CPUID_MODEL_ATOM // MSR is *NOT* available on the Intel Atom CPU
143 ){
144 msr = rdmsr64(MSR_CORE_THREAD_COUNT);// Undocumented MSR in Nehalem and newer CPUs
145 p->CPU.NoCores= bitfield((uint32_t)msr, 31, 16);// Using undocumented MSR to get actual values
146 p->CPU.NoThreads= bitfield((uint32_t)msr, 15, 0);// Using undocumented MSR to get actual values
147} else {
148 p->CPU.NoThreads= bitfield(p->CPU.CPUID[CPUID_1][1], 23, 16);// Use previous method for Cores and Threads
149 p->CPU.NoCores= bitfield(p->CPU.CPUID[CPUID_4][0], 31, 26) + 1;
150}
151
152/* get brand string (if supported) */
153/* Copyright: from Apple's XNU cpuid.c */
154if (p->CPU.CPUID[CPUID_80][0] > 0x80000004) {
155uint32_treg[4];
156 char str[128], *s;
157/*
158 * The brand string 48 bytes (max), guaranteed to
159 * be NUL terminated.
160 */
161do_cpuid(0x80000002, reg);
162bcopy((char *)reg, &str[0], 16);
163do_cpuid(0x80000003, reg);
164bcopy((char *)reg, &str[16], 16);
165do_cpuid(0x80000004, reg);
166bcopy((char *)reg, &str[32], 16);
167for (s = str; *s != '\0'; s++) {
168if (*s != ' ') break;
169}
170
171strlcpy(p->CPU.BrandString,s, sizeof(p->CPU.BrandString));
172
173if (!strncmp(p->CPU.BrandString, CPU_STRING_UNKNOWN, min(sizeof(p->CPU.BrandString), strlen(CPU_STRING_UNKNOWN) + 1))) {
174 /*
175 * This string means we have a firmware-programmable brand string,
176 * and the firmware couldn't figure out what sort of CPU we have.
177 */
178 p->CPU.BrandString[0] = '\0';
179 }
180}
181
182/* setup features */
183if ((bit(23) & p->CPU.CPUID[CPUID_1][3]) != 0) {
184p->CPU.Features |= CPU_FEATURE_MMX;
185}
186if ((bit(25) & p->CPU.CPUID[CPUID_1][3]) != 0) {
187p->CPU.Features |= CPU_FEATURE_SSE;
188}
189if ((bit(26) & p->CPU.CPUID[CPUID_1][3]) != 0) {
190p->CPU.Features |= CPU_FEATURE_SSE2;
191}
192if ((bit(0) & p->CPU.CPUID[CPUID_1][2]) != 0) {
193p->CPU.Features |= CPU_FEATURE_SSE3;
194}
195if ((bit(19) & p->CPU.CPUID[CPUID_1][2]) != 0) {
196p->CPU.Features |= CPU_FEATURE_SSE41;
197}
198if ((bit(20) & p->CPU.CPUID[CPUID_1][2]) != 0) {
199p->CPU.Features |= CPU_FEATURE_SSE42;
200}
201if ((bit(29) & p->CPU.CPUID[CPUID_81][3]) != 0) {
202p->CPU.Features |= CPU_FEATURE_EM64T;
203}
204if ((bit(5) & p->CPU.CPUID[CPUID_1][3]) != 0) {
205p->CPU.Features |= CPU_FEATURE_MSR;
206}
207//if ((bit(28) & p->CPU.CPUID[CPUID_1][3]) != 0) {
208if (p->CPU.NoThreads > p->CPU.NoCores) {
209p->CPU.Features |= CPU_FEATURE_HTT;
210}
211
212tscFrequency = measure_tsc_frequency();
213fsbFrequency = 0;
214cpuFrequency = 0;
215
216if ((p->CPU.Vendor == 0x756E6547 /* Intel */) && ((p->CPU.Family == 0x06) || (p->CPU.Family == 0x0f))) {
217int intelCPU = p->CPU.Model;
218if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0c) || (p->CPU.Family == 0x0f && p->CPU.Model >= 0x03)) {
219/* Nehalem CPU model */
220if (p->CPU.Family == 0x06 && (p->CPU.Model == CPU_MODEL_NEHALEM ||
221 p->CPU.Model == CPU_MODEL_FIELDS ||
222 p->CPU.Model == CPU_MODEL_DALES ||
223 p->CPU.Model == CPU_MODEL_DALES_32NM ||
224 p->CPU.Model == CPU_MODEL_WESTMERE ||
225 p->CPU.Model == CPU_MODEL_NEHALEM_EX ||
226 p->CPU.Model == CPU_MODEL_WESTMERE_EX ||
227 p->CPU.Model == CPU_MODEL_SANDY ||
228 p->CPU.Model == CPU_MODEL_SANDY_XEON)) {
229msr = rdmsr64(MSR_PLATFORM_INFO);
230DBG("msr(%d): platform_info %08x\n", __LINE__, msr & 0xffffffff);
231bus_ratio_max = (msr >> 8) & 0xff;
232bus_ratio_min = (msr >> 40) & 0xff; //valv: not sure about this one (Remarq.1)
233msr = rdmsr64(MSR_FLEX_RATIO);
234DBG("msr(%d): flex_ratio %08x\n", __LINE__, msr & 0xffffffff);
235if ((msr >> 16) & 0x01) {
236flex_ratio = (msr >> 8) & 0xff;
237/* bcc9: at least on the gigabyte h67ma-ud2h,
238 where the cpu multipler can't be changed to
239 allow overclocking, the flex_ratio msr has unexpected (to OSX)
240 contents. These contents cause mach_kernel to
241 fail to compute the bus ratio correctly, instead
242 causing the system to crash since tscGranularity
243 is inadvertently set to 0.
244*/
245if (flex_ratio == 0) {
246/* Clear bit 16 (evidently the
247 presence bit) */
248wrmsr64(MSR_FLEX_RATIO, (msr & 0xFFFFFFFFFFFEFFFFULL));
249msr = rdmsr64(MSR_FLEX_RATIO);
250verbose("Unusable flex ratio detected. Patched MSR now %08x\n", msr & 0xffffffff);
251} else {
252if (bus_ratio_max > flex_ratio) {
253bus_ratio_max = flex_ratio;
254}
255}
256}
257
258if (bus_ratio_max) {
259fsbFrequency = (tscFrequency / bus_ratio_max);
260}
261//valv: Turbo Ratio Limit
262if ((intelCPU != 0x2e) && (intelCPU != 0x2f)) {
263msr = rdmsr64(MSR_TURBO_RATIO_LIMIT);
264cpuFrequency = bus_ratio_max * fsbFrequency;
265max_ratio = bus_ratio_max * 10;
266} else {
267cpuFrequency = tscFrequency;
268}
269if ((getValueForKey(kbusratio, &newratio, &len, &bootInfo->bootConfig)) && (len <= 4)) {
270max_ratio = atoi(newratio);
271max_ratio = (max_ratio * 10);
272if (len >= 3) max_ratio = (max_ratio + 5);
273
274verbose("Bus-Ratio: min=%d, max=%s\n", bus_ratio_min, newratio);
275
276// extreme overclockers may love 320 ;)
277if ((max_ratio >= min_ratio) && (max_ratio <= 320)) {
278cpuFrequency = (fsbFrequency * max_ratio) / 10;
279if (len >= 3) maxdiv = 1;
280else maxdiv = 0;
281} else {
282max_ratio = (bus_ratio_max * 10);
283}
284}
285//valv: to be uncommented if Remarq.1 didn't stick
286/*if(bus_ratio_max > 0) bus_ratio = flex_ratio;*/
287p->CPU.MaxRatio = max_ratio;
288p->CPU.MinRatio = min_ratio;
289
290myfsb = fsbFrequency / 1000000;
291verbose("Sticking with [BCLK: %dMhz, Bus-Ratio: %d]\n", myfsb, max_ratio);
292currcoef = bus_ratio_max;
293} else {
294msr = rdmsr64(MSR_IA32_PERF_STATUS);
295DBG("msr(%d): ia32_perf_stat 0x%08x\n", __LINE__, msr & 0xffffffff);
296currcoef = (msr >> 8) & 0x1f;
297/* Non-integer bus ratio for the max-multi*/
298maxdiv = (msr >> 46) & 0x01;
299/* Non-integer bus ratio for the current-multi (undocumented)*/
300currdiv = (msr >> 14) & 0x01;
301
302if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0e) || (p->CPU.Family == 0x0f)) // This will always be model >= 3
303{
304/* On these models, maxcoef defines TSC freq */
305maxcoef = (msr >> 40) & 0x1f;
306} else {
307/* On lower models, currcoef defines TSC freq */
308/* XXX */
309maxcoef = currcoef;
310}
311
312if (maxcoef) {
313if (maxdiv) {
314fsbFrequency = ((tscFrequency * 2) / ((maxcoef * 2) + 1));
315} else {
316fsbFrequency = (tscFrequency / maxcoef);
317}
318if (currdiv) {
319cpuFrequency = (fsbFrequency * ((currcoef * 2) + 1) / 2);
320} else {
321cpuFrequency = (fsbFrequency * currcoef);
322}
323DBG("max: %d%s current: %d%s\n", maxcoef, maxdiv ? ".5" : "",currcoef, currdiv ? ".5" : "");
324}
325}
326}
327/* Mobile CPU ? */
328if (rdmsr64(0x17) & (1<<28)) {
329p->CPU.Features |= CPU_FEATURE_MOBILE;
330}
331}
332#if 0
333else if((p->CPU.Vendor == 0x68747541 /* AMD */) && (p->CPU.Family == 0x0f)) {
334if(p->CPU.ExtFamily == 0x00 /* K8 */) {
335msr = rdmsr64(K8_FIDVID_STATUS);
336currcoef = (msr & 0x3f) / 2 + 4;
337currdiv = (msr & 0x01) * 2;
338} else if(p->CPU.ExtFamily >= 0x01 /* K10+ */) {
339msr = rdmsr64(K10_COFVID_STATUS);
340if(p->CPU.ExtFamily == 0x01 /* K10 */)
341currcoef = (msr & 0x3f) + 0x10;
342else /* K11+ */
343currcoef = (msr & 0x3f) + 0x08;
344currdiv = (2 << ((msr >> 6) & 0x07));
345}
346
347if (currcoef) {
348if (currdiv) {
349fsbFrequency = ((tscFrequency * currdiv) / currcoef);
350DBG("%d.%d\n", currcoef / currdiv, ((currcoef % currdiv) * 100) / currdiv);
351} else {
352fsbFrequency = (tscFrequency / currcoef);
353DBG("%d\n", currcoef);
354}
355fsbFrequency = (tscFrequency / currcoef);
356cpuFrequency = tscFrequency;
357}
358}
359
360if (!fsbFrequency) {
361fsbFrequency = (DEFAULT_FSB * 1000);
362cpuFrequency = tscFrequency;
363DBG("0 ! using the default value for FSB !\n");
364}
365#endif
366
367p->CPU.MaxCoef = maxcoef;
368p->CPU.MaxDiv = maxdiv;
369p->CPU.CurrCoef = currcoef;
370p->CPU.CurrDiv = currdiv;
371p->CPU.TSCFrequency = tscFrequency;
372p->CPU.FSBFrequency = fsbFrequency;
373p->CPU.CPUFrequency = cpuFrequency;
374
375DBG("CPU: Vendor/Model/ExtModel: 0x%x/0x%x/0x%x\n", p->CPU.Vendor, p->CPU.Model, p->CPU.ExtModel);
376DBG("CPU: Family/ExtFamily: 0x%x/0x%x\n", p->CPU.Family, p->CPU.ExtFamily);
377DBG("CPU: MaxCoef/CurrCoef: 0x%x/0x%x\n", p->CPU.MaxCoef, p->CPU.CurrCoef);
378DBG("CPU: MaxDiv/CurrDiv: 0x%x/0x%x\n", p->CPU.MaxDiv, p->CPU.CurrDiv);
379DBG("CPU: TSCFreq: %dMHz\n", p->CPU.TSCFrequency / 1000000);
380DBG("CPU: FSBFreq: %dMHz\n", p->CPU.FSBFrequency / 1000000);
381DBG("CPU: CPUFreq: %dMHz\n", p->CPU.CPUFrequency / 1000000);
382DBG("CPU: NoCores/NoThreads: %d/%d\n", p->CPU.NoCores, p->CPU.NoThreads);
383DBG("CPU: Features: 0x%08x\n", p->CPU.Features);
384#if DEBUG_CPU
385pause();
386#endif
387}
388

Archive Download this file

Revision: 307