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