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