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