Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/libsaio/state_generator.c

1/*
2 * Copyright 2008 mackerintel
3 *
4 * state_generator.h
5 * Chameleon
6 *
7 * Created by Mozodojo on 20/07/10.
8 * Copyright 2010 mozodojo. All rights reserved.
9 *
10 */
11
12#include "libsaio.h"
13#include "boot.h"
14#include "bootstruct.h"
15#include "acpi.h"
16#include "efi_tables.h"
17#include "fake_efi.h"
18#include "acpi_patcher.h"
19#include "platform.h"
20#include "cpu.h"
21#include "aml_generator.h"
22#include "state_generator.h"
23
24#ifndef DEBUG_STATE
25#define DEBUG_STATE 0
26#endif
27
28#if DEBUG_STATE==2
29#define DBG(x...) {printf(x); sleep(1);}
30#elif DEBUG_STATE==1
31#define DBG(x...) printf(x)
32#else
33#define DBG(x...) msglog(x)
34#endif
35
36extern uint8_t acpi_cpu_count;
37extern uint32_t acpi_cpu_p_blk;
38extern char* acpi_cpu_name[32];
39
40static char const pss_ssdt_header[] =
41{
420x53, 0x53, 0x44, 0x54, 0x7E, 0x00, 0x00, 0x00, /* SSDT.... */
430x01, 0x6A, 0x50, 0x6D, 0x52, 0x65, 0x66, 0x00, /* ..PmRef. */
440x43, 0x70, 0x75, 0x50, 0x6D, 0x00, 0x00, 0x00, /* CpuPm... */
450x00, 0x30, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C, /* .0..INTL */
460x31, 0x03, 0x10, 0x20,/* 1.._*/
47};
48
49static char const cst_ssdt_header[] =
50{
510x53, 0x53, 0x44, 0x54, 0xE7, 0x00, 0x00, 0x00, /* SSDT.... */
520x01, 0x17, 0x50, 0x6D, 0x52, 0x65, 0x66, 0x41, /* ..PmRefA */
530x43, 0x70, 0x75, 0x43, 0x73, 0x74, 0x00, 0x00, /* CpuCst.. */
540x00, 0x10, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C, /* ....INTL */
550x31, 0x03, 0x10, 0x20/* 1.._*/
56};
57
58char resource_template_register_fixedhw[] =
59{
600x11, 0x14, 0x0A, 0x11, 0x82, 0x0C, 0x00, 0x7F,
610x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
620x00, 0x00, 0x01, 0x79, 0x00
63};
64
65char resource_template_register_systemio[] =
66{
670x11, 0x14, 0x0A, 0x11, 0x82, 0x0C, 0x00, 0x01,
680x08, 0x00, 0x00, 0x15, 0x04, 0x00, 0x00, 0x00,
690x00, 0x00, 0x00, 0x79, 0x00,
70};
71
72
73struct acpi_2_ssdt *generate_pss_ssdt(struct acpi_2_dsdt* dsdt)
74{
75
76if (Platform.CPU.Vendor != 0x756E6547)
77{
78DBG("Not an Intel platform: P-States will not be generated !!!\n");
79return NULL;
80}
81
82if (!(Platform.CPU.Features & CPU_FEATURE_MSR))
83{
84DBG("Unsupported CPU: P-States will not be generated !!! No MSR support\n");
85return NULL;
86}
87
88if (acpi_cpu_count == 0)
89{
90get_acpi_cpu_names((void*)dsdt, dsdt->Length);
91}
92
93if (acpi_cpu_count > 0)
94{
95struct p_state initial, maximum, minimum, p_states[32];
96uint8_t p_states_count = 0;
97
98// Retrieving P-States, ported from code by superhai (c)
99switch (Platform.CPU.Family)
100{
101case 0x06:
102{
103switch (Platform.CPU.Model)
104{
105case CPUID_MODEL_DOTHAN:// Intel Pentium M
106case CPUID_MODEL_YONAH:// Intel Mobile Core Solo, Duo
107case CPUID_MODEL_MEROM:// Intel Mobile Core 2 Solo, Duo, Xeon 30xx, Xeon 51xx, Xeon X53xx, Xeon E53xx, Xeon X32xx
108case CPUID_MODEL_PENRYN:// Intel Core 2 Solo, Duo, Quad, Extreme, Xeon X54xx, Xeon X33xx
109case CPUID_MODEL_ATOM:// Intel Atom (45nm)
110{
111bool cpu_dynamic_fsb = false;
112
113if (rdmsr64(MSR_IA32_EXT_CONFIG) & (1 << 27))
114{
115wrmsr64(MSR_IA32_EXT_CONFIG, (rdmsr64(MSR_IA32_EXT_CONFIG) | (1 << 28)));
116delay(1);
117cpu_dynamic_fsb = rdmsr64(MSR_IA32_EXT_CONFIG) & (1 << 28);
118}
119
120bool cpu_noninteger_bus_ratio = (rdmsr64(MSR_IA32_PERF_STATUS) & (1ULL << 46));
121
122initial.Control = rdmsr64(MSR_IA32_PERF_STATUS);
123
124maximum.Control = ((rdmsr64(MSR_IA32_PERF_STATUS) >> 32) & 0x1F3F) | (0x4000 * cpu_noninteger_bus_ratio);
125maximum.CID = ((maximum.FID & 0x1F) << 1) | cpu_noninteger_bus_ratio;
126
127minimum.FID = ((rdmsr64(MSR_IA32_PERF_STATUS) >> 24) & 0x1F) | (0x80 * cpu_dynamic_fsb);
128minimum.VID = ((rdmsr64(MSR_IA32_PERF_STATUS) >> 48) & 0x3F);
129
130if (minimum.FID == 0)
131{
132uint64_t msr;
133uint8_t i;
134// Probe for lowest fid
135for (i = maximum.FID; i >= 0x6; i--)
136{
137msr = rdmsr64(MSR_IA32_PERF_CONTROL);
138wrmsr64(MSR_IA32_PERF_CONTROL, (msr & 0xFFFFFFFFFFFF0000ULL) | (i << 8) | minimum.VID);
139intel_waitforsts();
140minimum.FID = (rdmsr64(MSR_IA32_PERF_STATUS) >> 8) & 0x1F;
141delay(1);
142}
143
144msr = rdmsr64(MSR_IA32_PERF_CONTROL);
145wrmsr64(MSR_IA32_PERF_CONTROL, (msr & 0xFFFFFFFFFFFF0000ULL) | (maximum.FID << 8) | maximum.VID);
146intel_waitforsts();
147}
148
149if (minimum.VID == maximum.VID)
150{
151uint64_t msr;
152uint8_t i;
153// Probe for lowest vid
154for (i = maximum.VID; i > 0xA; i--)
155{
156msr = rdmsr64(MSR_IA32_PERF_CONTROL);
157wrmsr64(MSR_IA32_PERF_CONTROL, (msr & 0xFFFFFFFFFFFF0000ULL) | (minimum.FID << 8) | i);
158intel_waitforsts();
159minimum.VID = rdmsr64(MSR_IA32_PERF_STATUS) & 0x3F;
160delay(1);
161}
162
163msr = rdmsr64(MSR_IA32_PERF_CONTROL);
164wrmsr64(MSR_IA32_PERF_CONTROL, (msr & 0xFFFFFFFFFFFF0000ULL) | (maximum.FID << 8) | maximum.VID);
165intel_waitforsts();
166}
167
168minimum.CID = ((minimum.FID & 0x1F) << 1) >> cpu_dynamic_fsb;
169
170// Sanity check
171if (maximum.CID < minimum.CID)
172{
173DBG("P-States: Insane FID values!");
174p_states_count = 0;
175}
176else
177{
178uint8_t vidstep;
179uint8_t u, invalid = 0;
180// Finalize P-States
181// Find how many P-States machine supports
182p_states_count = (uint8_t)(maximum.CID - minimum.CID + 1);
183
184if (p_states_count > 32)
185{
186p_states_count = 32;
187}
188
189vidstep = ((maximum.VID << 2) - (minimum.VID << 2)) / (p_states_count - 1);
190
191for (u = 0; u < p_states_count; u++)
192{
193uint8_t i = u - invalid;
194
195p_states[i].CID = maximum.CID - u;
196p_states[i].FID = (uint8_t)(p_states[i].CID >> 1);
197
198if (p_states[i].FID < 0x6)
199{
200if (cpu_dynamic_fsb)
201{
202p_states[i].FID = (p_states[i].FID << 1) | 0x80;
203}
204}
205else if (cpu_noninteger_bus_ratio)
206{
207p_states[i].FID = p_states[i].FID | (0x40 * (p_states[i].CID & 0x1));
208}
209
210if (i && p_states[i].FID == p_states[i-1].FID)
211{
212invalid++;
213}
214p_states[i].VID = ((maximum.VID << 2) - (vidstep * u)) >> 2;
215uint32_t multiplier = p_states[i].FID & 0x1f;// = 0x08
216bool half = p_states[i].FID & 0x40;// = 0x01
217bool dfsb = p_states[i].FID & 0x80;// = 0x00
218uint32_t fsb = (uint32_t)(Platform.CPU.FSBFrequency / 1000000); // = 400
219uint32_t halffsb = (fsb + 1) >> 1;// = 200
220uint32_t frequency = (multiplier * fsb);// = 3200
221
222p_states[i].Frequency = (uint32_t)(frequency + (half * halffsb)) >> dfsb;// = 3200 + 200 = 3400
223}
224
225p_states_count -= invalid;
226}
227
228break;
229}
230case CPUID_MODEL_FIELDS:// Intel Core i5, i7, Xeon X34xx LGA1156 (45nm)
231case CPUID_MODEL_DALES:
232case CPUID_MODEL_DALES_32NM:// Intel Core i3, i5 LGA1156 (32nm)
233case CPUID_MODEL_NEHALEM:// Intel Core i7, Xeon W35xx, Xeon X55xx, Xeon E55xx LGA1366 (45nm)
234case CPUID_MODEL_NEHALEM_EX:// Intel Xeon X75xx, Xeon X65xx, Xeon E75xx, Xeon E65xx
235case CPUID_MODEL_WESTMERE:// Intel Core i7, Xeon X56xx, Xeon E56xx, Xeon W36xx LGA1366 (32nm) 6 Core
236case CPUID_MODEL_WESTMERE_EX:// Intel Xeon E7
237case CPUID_MODEL_SANDYBRIDGE:// Intel Core i3, i5, i7 LGA1155 (32nm)
238case CPUID_MODEL_JAKETOWN:// Intel Core i7, Xeon E5 LGA2011 (32nm)
239case CPUID_MODEL_IVYBRIDGE:// Intel Core i3, i5, i7 LGA1155 (22nm)
240case CPUID_MODEL_HASWELL://
241case CPUID_MODEL_IVYBRIDGE_XEON: //
242//case CPUID_MODEL_HASWELL_H://
243case CPUID_MODEL_HASWELL_SVR://
244case CPUID_MODEL_HASWELL_ULT://
245case CPUID_MODEL_CRYSTALWELL://
246
247{
248if ((Platform.CPU.Model == CPUID_MODEL_SANDYBRIDGE) || (Platform.CPU.Model == CPUID_MODEL_JAKETOWN) ||
249(Platform.CPU.Model == CPUID_MODEL_IVYBRIDGE) || (Platform.CPU.Model == CPUID_MODEL_HASWELL) ||
250(Platform.CPU.Model == CPUID_MODEL_IVYBRIDGE_XEON) || (Platform.CPU.Model == CPUID_MODEL_HASWELL_SVR) ||
251(Platform.CPU.Model == CPUID_MODEL_HASWELL_ULT) || (Platform.CPU.Model == CPUID_MODEL_CRYSTALWELL))
252{
253maximum.Control = (rdmsr64(MSR_IA32_PERF_STATUS) >> 8) & 0xff;
254}
255else
256{
257maximum.Control = rdmsr64(MSR_IA32_PERF_STATUS) & 0xff;
258}
259
260minimum.Control = (rdmsr64(MSR_PLATFORM_INFO) >> 40) & 0xff;
261
262DBG("P-States: min 0x%x, max 0x%x\n", minimum.Control, maximum.Control);
263
264// Sanity check
265if (maximum.Control < minimum.Control)
266{
267DBG("Insane control values!");
268p_states_count = 0;
269}
270else
271{
272uint8_t i;
273p_states_count = 0;
274
275for (i = maximum.Control; i >= minimum.Control; i--)
276{
277p_states[p_states_count].Control = i;
278p_states[p_states_count].CID = p_states[p_states_count].Control << 1;
279p_states[p_states_count].Frequency = (Platform.CPU.FSBFrequency / 1000000) * i;
280p_states_count++;
281}
282}
283
284break;
285}
286default:
287DBG("Unsupported CPU (0x%X): P-States not generated !!!\n", Platform.CPU.Family);
288break;
289}
290}
291}
292
293// Generating SSDT
294if (p_states_count > 0)
295{
296
297int i;
298
299AML_CHUNK* root = aml_create_node(NULL);
300aml_add_buffer(root, pss_ssdt_header, sizeof(pss_ssdt_header)); // SSDT header
301
302AML_CHUNK* scop = aml_add_scope(root, "\\_PR_");
303AML_CHUNK* name = aml_add_name(scop, "PSS_");
304AML_CHUNK* pack = aml_add_package(name);
305
306for (i = 0; i < p_states_count; i++)
307{
308AML_CHUNK* pstt = aml_add_package(pack);
309
310aml_add_dword(pstt, p_states[i].Frequency);
311aml_add_dword(pstt, 0x00000000); // Power
312aml_add_dword(pstt, 0x0000000A); // Latency
313aml_add_dword(pstt, 0x0000000A); // Latency
314aml_add_dword(pstt, p_states[i].Control);
315aml_add_dword(pstt, i+1); // Status
316}
317
318// Add aliaces
319for (i = 0; i < acpi_cpu_count; i++)
320{
321char name[9];
322sprintf(name, "_PR_%c%c%c%c", acpi_cpu_name[i][0], acpi_cpu_name[i][1], acpi_cpu_name[i][2], acpi_cpu_name[i][3]);
323
324scop = aml_add_scope(root, name);
325aml_add_alias(scop, "PSS_", "_PSS");
326}
327
328aml_calculate_size(root);
329
330struct acpi_2_ssdt *ssdt = (struct acpi_2_ssdt *)AllocateKernelMemory(root->Size);
331
332aml_write_node(root, (void*)ssdt, 0);
333
334ssdt->Length = root->Size;
335ssdt->Checksum = 0;
336ssdt->Checksum = (uint8_t)(256 - checksum8(ssdt, ssdt->Length));
337
338aml_destroy_node(root);
339
340//dumpPhysAddr("P-States SSDT content: ", ssdt, ssdt->Length);
341
342DBG("SSDT with CPU P-States generated successfully\n");
343
344return ssdt;
345}
346}
347else
348{
349DBG("ACPI CPUs not found: P-States not generated !!!\n");
350}
351
352return NULL;
353}
354
355struct acpi_2_ssdt *generate_cst_ssdt(struct acpi_2_fadt* fadt)
356{
357
358if (Platform.CPU.Vendor != 0x756E6547)
359{
360DBG("Not an Intel platform: C-States will not be generated !!!\n");
361return NULL;
362}
363
364if (fadt == NULL)
365{
366DBG("FACP not exists: C-States will not be generated !!!\n");
367return NULL;
368}
369
370struct acpi_2_dsdt* dsdt = (void*)fadt->DSDT;
371
372if (dsdt == NULL)
373{
374DBG("DSDT not found: C-States will not be generated !!!\n");
375return NULL;
376}
377
378if (acpi_cpu_count == 0)
379get_acpi_cpu_names((void*)dsdt, dsdt->Length);
380
381if (acpi_cpu_count > 0)
382{
383bool c2_enabled = false;
384bool c3_enabled = false;
385bool c4_enabled = false;
386bool cst_using_systemio = false;
387
388getBoolForKey(kEnableC2State, &c2_enabled, &bootInfo->chameleonConfig);
389getBoolForKey(kEnableC3State, &c3_enabled, &bootInfo->chameleonConfig);
390getBoolForKey(kEnableC4State, &c4_enabled, &bootInfo->chameleonConfig);
391getBoolForKey(kCSTUsingSystemIO, &cst_using_systemio, &bootInfo->chameleonConfig);
392
393c2_enabled = c2_enabled | (fadt->C2_Latency < 100);
394c3_enabled = c3_enabled | (fadt->C3_Latency < 1000);
395
396unsigned char cstates_count = 1 + (c2_enabled ? 1 : 0) + (c3_enabled ? 1 : 0);
397
398AML_CHUNK* root = aml_create_node(NULL);
399aml_add_buffer(root, cst_ssdt_header, sizeof(cst_ssdt_header)); // SSDT header
400AML_CHUNK* scop = aml_add_scope(root, "\\_PR_");
401AML_CHUNK* name = aml_add_name(scop, "CST_");
402AML_CHUNK* pack = aml_add_package(name);
403aml_add_byte(pack, cstates_count);
404
405AML_CHUNK* tmpl = aml_add_package(pack);
406if (cst_using_systemio)
407{
408// C1
409resource_template_register_fixedhw[8] = 0x00;
410resource_template_register_fixedhw[9] = 0x00;
411resource_template_register_fixedhw[18] = 0x00;
412aml_add_buffer(tmpl, resource_template_register_fixedhw, sizeof(resource_template_register_fixedhw));
413aml_add_byte(tmpl, 0x01);// C1
414aml_add_word(tmpl, 0x0001);// Latency
415aml_add_dword(tmpl, 0x000003e8);// Power
416
417uint8_t p_blk_lo, p_blk_hi;
418
419if (c2_enabled) // C2
420{
421p_blk_lo = acpi_cpu_p_blk + 4;
422p_blk_hi = (acpi_cpu_p_blk + 4) >> 8;
423
424tmpl = aml_add_package(pack);
425resource_template_register_systemio[11] = p_blk_lo; // C2
426resource_template_register_systemio[12] = p_blk_hi; // C2
427aml_add_buffer(tmpl, resource_template_register_systemio, sizeof(resource_template_register_systemio));
428aml_add_byte(tmpl, 0x02);// C2
429aml_add_word(tmpl, 0x0040);// Latency
430aml_add_dword(tmpl, 0x000001f4);// Power
431}
432
433if (c4_enabled) // C4
434{
435p_blk_lo = acpi_cpu_p_blk + 5;
436p_blk_hi = (acpi_cpu_p_blk + 5) >> 8;
437
438tmpl = aml_add_package(pack);
439resource_template_register_systemio[11] = p_blk_lo; // C4
440resource_template_register_systemio[12] = p_blk_hi; // C4
441aml_add_buffer(tmpl, resource_template_register_systemio, sizeof(resource_template_register_systemio));
442aml_add_byte(tmpl, 0x04);// C4
443aml_add_word(tmpl, 0x0080);// Latency
444aml_add_dword(tmpl, 0x000000C8);// Power
445}
446else if (c3_enabled) // C3
447{
448p_blk_lo = acpi_cpu_p_blk + 5;
449p_blk_hi = (acpi_cpu_p_blk + 5) >> 8;
450
451tmpl = aml_add_package(pack);
452resource_template_register_systemio[11] = p_blk_lo; // C3
453resource_template_register_systemio[12] = p_blk_hi; // C3
454aml_add_buffer(tmpl, resource_template_register_systemio, sizeof(resource_template_register_systemio));
455aml_add_byte(tmpl, 0x03);// C3
456aml_add_word(tmpl, 0x0060);// Latency
457aml_add_dword(tmpl, 0x0000015e);// Power
458}
459}
460else
461{
462// C1
463resource_template_register_fixedhw[8] = 0x01;
464resource_template_register_fixedhw[9] = 0x02;
465resource_template_register_fixedhw[18] = 0x01;
466
467resource_template_register_fixedhw[11] = 0x00; // C1
468aml_add_buffer(tmpl, resource_template_register_fixedhw, sizeof(resource_template_register_fixedhw));
469aml_add_byte(tmpl, 0x01);// C1
470aml_add_word(tmpl, 0x0001);// Latency
471aml_add_dword(tmpl, 0x000003e8);// Power
472
473resource_template_register_fixedhw[18] = 0x03;
474
475if (c2_enabled) // C2
476{
477tmpl = aml_add_package(pack);
478resource_template_register_fixedhw[11] = 0x10; // C2
479aml_add_buffer(tmpl, resource_template_register_fixedhw, sizeof(resource_template_register_fixedhw));
480aml_add_byte(tmpl, 0x02);// C2
481aml_add_word(tmpl, 0x0040);// Latency
482aml_add_dword(tmpl, 0x000001f4);// Power
483}
484
485if (c4_enabled) // C4
486{
487tmpl = aml_add_package(pack);
488resource_template_register_fixedhw[11] = 0x30; // C4
489aml_add_buffer(tmpl, resource_template_register_fixedhw, sizeof(resource_template_register_fixedhw));
490aml_add_byte(tmpl, 0x04);// C4
491aml_add_word(tmpl, 0x0080);// Latency
492aml_add_dword(tmpl, 0x000000C8);// Power
493}
494else if (c3_enabled)
495{
496tmpl = aml_add_package(pack);
497resource_template_register_fixedhw[11] = 0x20; // C3
498aml_add_buffer(tmpl, resource_template_register_fixedhw, sizeof(resource_template_register_fixedhw));
499aml_add_byte(tmpl, 0x03);// C3
500aml_add_word(tmpl, 0x0060);// Latency
501aml_add_dword(tmpl, 0x0000015e);// Power
502}
503}
504
505// Aliaces
506int i;
507for (i = 0; i < acpi_cpu_count; i++)
508{
509char name[9];
510sprintf(name, "_PR_%c%c%c%c", acpi_cpu_name[i][0], acpi_cpu_name[i][1], acpi_cpu_name[i][2], acpi_cpu_name[i][3]);
511
512scop = aml_add_scope(root, name);
513aml_add_alias(scop, "CST_", "_CST");
514}
515
516aml_calculate_size(root);
517
518struct acpi_2_ssdt *ssdt = (struct acpi_2_ssdt *)AllocateKernelMemory(root->Size);
519
520aml_write_node(root, (void*)ssdt, 0);
521
522ssdt->Length = root->Size;
523ssdt->Checksum = 0;
524ssdt->Checksum = 256 - checksum8(ssdt, ssdt->Length);
525
526aml_destroy_node(root);
527
528// dumpPhysAddr("C-States SSDT content: ", ssdt, ssdt->Length);
529
530DBG("SSDT with CPU C-States generated successfully\n");
531
532return ssdt;
533}
534else
535{
536DBG("ACPI CPUs not found: C-States not generated !!!\n");
537}
538
539return NULL;
540}
541

Archive Download this file

Revision: 2484