Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/libsaio/dsdt_patcher.c

1/*
2 * Copyright 2008 mackerintel
3 */
4
5#include "libsaio.h"
6#include "boot.h"
7#include "bootstruct.h"
8#include "acpi.h"
9#include "efi_tables.h"
10#include "fake_efi.h"
11#include "dsdt_patcher.h"
12#include "platform.h"
13
14#ifndef DEBUG_DSDT
15#define DEBUG_DSDT 0
16#endif
17
18#if DEBUG_DSDT==2
19#define DBG(x...) {printf(x); sleep(1);}
20#elif DEBUG_DSDT==1
21#define DBG(x...) printf(x)
22#else
23#define DBG(x...)
24#endif
25
26/* Gets the ACPI 1.0 RSDP address */
27static struct acpi_2_rsdp* getAddressOfAcpiTable()
28{
29 /* TODO: Before searching the BIOS space we are supposed to search the first 1K of the EBDA */
30
31 void *acpi_addr = (void*)ACPI_RANGE_START;
32 for(; acpi_addr <= (void*)ACPI_RANGE_END; acpi_addr += 16)
33 {
34 if(*(uint64_t *)acpi_addr == ACPI_SIGNATURE_UINT64_LE)
35 {
36 uint8_t csum = checksum8(acpi_addr, 20);
37 if(csum == 0)
38 {
39 // Only return the table if it is a true version 1.0 table (Revision 0)
40 if(((struct acpi_2_rsdp*)acpi_addr)->Revision == 0)
41 return acpi_addr;
42 }
43 }
44 }
45 return NULL;
46}
47
48/* Gets the ACPI 2.0 RSDP address */
49static struct acpi_2_rsdp* getAddressOfAcpi20Table()
50{
51 /* TODO: Before searching the BIOS space we are supposed to search the first 1K of the EBDA */
52
53 void *acpi_addr = (void*)ACPI_RANGE_START;
54 for(; acpi_addr <= (void*)ACPI_RANGE_END; acpi_addr += 16)
55 {
56 if(*(uint64_t *)acpi_addr == ACPI_SIGNATURE_UINT64_LE)
57 {
58 uint8_t csum = checksum8(acpi_addr, 20);
59
60 /* Only assume this is a 2.0 or better table if the revision is greater than 0
61 * NOTE: ACPI 3.0 spec only seems to say that 1.0 tables have revision 1
62 * and that the current revision is 2.. I am going to assume that rev > 0 is 2.0.
63 */
64
65 if(csum == 0 && (((struct acpi_2_rsdp*)acpi_addr)->Revision > 0))
66 {
67 uint8_t csum2 = checksum8(acpi_addr, sizeof(struct acpi_2_rsdp));
68 if(csum2 == 0)
69 return acpi_addr;
70 }
71 }
72 }
73 return NULL;
74}
75
76
77/* Setup ACPI without replacing DSDT. */
78int setupAcpiNoMod()
79{
80//addConfigurationTable(&gEfiAcpiTableGuid, getAddressOfAcpiTable(), "ACPI");
81//addConfigurationTable(&gEfiAcpi20TableGuid, getAddressOfAcpi20Table(), "ACPI_20");
82/* XXX aserebln why uint32 cast if pointer is uint64 ? */
83acpi10_p = (uint32_t)getAddressOfAcpiTable();
84acpi20_p = (uint32_t)getAddressOfAcpi20Table();
85addConfigurationTable(&gEfiAcpiTableGuid, &acpi10_p, "ACPI");
86if(acpi20_p) addConfigurationTable(&gEfiAcpi20TableGuid, &acpi20_p, "ACPI_20");
87return 1;
88}
89
90/* Setup ACPI. Replace DSDT if DSDT.aml is found */
91int setupAcpi(void)
92{
93int fd, version;
94void *new_dsdt;
95const char *dsdt_filename;
96int len;
97bool tmp;
98bool drop_ssdt;
99bool fix_restart;
100
101if (!getValueForKey(kDSDT, &dsdt_filename, &len, &bootInfo->bootConfig)) {
102dsdt_filename = "/Extra/DSDT.aml";
103}
104
105if ((fd = open_bvdev("bt(0,0)", dsdt_filename, 0)) < 0) {
106verbose("No DSDT replacement found. Leaving ACPI data as is\n");
107return setupAcpiNoMod();
108}
109
110// Load replacement DSDT
111new_dsdt = (void*)AllocateKernelMemory(file_size (fd));
112if (!new_dsdt) {
113printf("Couldn't allocate memory for DSDT\n");
114close(fd);
115return setupAcpiNoMod();
116}
117if (read(fd, new_dsdt, file_size(fd)) != file_size(fd)) {
118printf("Couldn't read file\n");
119close(fd);
120return setupAcpiNoMod();
121}
122close(fd);
123DBG("New DSDT Loaded in memory\n");
124
125drop_ssdt = getBoolForKey(kDropSSDT, &tmp, &bootInfo->bootConfig) && tmp;
126
127if (Platform.CPU.Vendor == 0x756E6547) {/* Intel */
128fix_restart = true;
129getBoolForKey(kRestartFix, &fix_restart, &bootInfo->bootConfig);
130} else {
131fix_restart = false;
132}
133
134// Do the same procedure for both versions of ACPI
135for (version=0; version<2; version++) {
136struct acpi_2_rsdp *rsdp, *rsdp_mod;
137struct acpi_2_rsdt *rsdt, *rsdt_mod;
138int rsdplength;
139
140// Find original rsdp
141rsdp=(struct acpi_2_rsdp *)(version?getAddressOfAcpi20Table():getAddressOfAcpiTable());
142if (!rsdp)
143{
144DBG("No ACPI version %d found. Ignoring\n", version+1);
145if (version)
146addConfigurationTable(&gEfiAcpi20TableGuid, NULL, "ACPI_20");
147else
148addConfigurationTable(&gEfiAcpiTableGuid, NULL, "ACPI");
149continue;
150}
151rsdplength=version?rsdp->Length:20;
152
153DBG("RSDP version %d found @%x. Length=%d\n",version+1,rsdp,rsdplength);
154
155/* FIXME: no check that memory allocation succeeded
156 * Copy and patch RSDP,RSDT, XSDT and FADT
157 * For more info see ACPI Specification pages 110 and following
158 */
159
160rsdp_mod=(struct acpi_2_rsdp *) AllocateKernelMemory(rsdplength);
161memcpy(rsdp_mod, rsdp, rsdplength);
162rsdt=(struct acpi_2_rsdt *)(rsdp->RsdtAddress);
163
164DBG("RSDT @%x, Length %d\n",rsdt, rsdt->Length);
165
166if (rsdt && (uint32_t)rsdt !=0xffffffff && rsdt->Length<0x10000)
167{
168uint32_t *rsdt_entries;
169int rsdt_entries_num;
170int dropoffset=0, i;
171
172rsdt_mod=(struct acpi_2_rsdt *)AllocateKernelMemory(rsdt->Length);
173memcpy (rsdt_mod, rsdt, rsdt->Length);
174rsdp_mod->RsdtAddress=(uint32_t)rsdt_mod;
175rsdt_entries_num=(rsdt_mod->Length-sizeof(struct acpi_2_rsdt))/4;
176rsdt_entries=(uint32_t *)(rsdt_mod+1);
177for (i=0;i<rsdt_entries_num;i++)
178{
179char *table=(char *)(rsdt_entries[i]);
180if (!table)
181continue;
182
183DBG("TABLE %c%c%c%c,",table[0],table[1],table[2],table[3]);
184
185rsdt_entries[i-dropoffset]=rsdt_entries[i];
186if (drop_ssdt && table[0]=='S' && table[1]=='S' && table[2]=='D' && table[3]=='T')
187{
188dropoffset++;
189continue;
190}
191if (table[0]=='D' && table[1]=='S' && table[2]=='D' && table[3]=='T')
192{
193DBG("DSDT found\n");
194rsdt_entries[i-dropoffset]=(uint32_t)new_dsdt;
195continue;
196}
197if (table[0]=='F' && table[1]=='A' && table[2]=='C' && table[3]=='P')
198{
199struct acpi_2_fadt *fadt, *fadt_mod;
200fadt=(struct acpi_2_fadt *)rsdt_entries[i];
201
202DBG("FADT found @%x, Length %d\n",fadt, fadt->Length);
203
204if (!fadt || (uint32_t)fadt == 0xffffffff || fadt->Length>0x10000)
205{
206printf("FADT incorrect. Not modified\n");
207continue;
208}
209
210if (fix_restart && fadt->Length < 0x81) {
211fadt_mod = (struct acpi_2_fadt *)AllocateKernelMemory(0x81);
212memcpy(fadt_mod, fadt, fadt->Length);
213fadt_mod->Length = 0x81;
214} else {
215fadt_mod = (struct acpi_2_fadt *)AllocateKernelMemory(fadt->Length);
216memcpy(fadt_mod, fadt, fadt->Length);
217}
218
219if (fix_restart) {
220fadt_mod->Flags |= 0x400;
221fadt_mod->Reset_SpaceID = 0x01;
222fadt_mod->Reset_BitWidth = 0x08;
223fadt_mod->Reset_BitOffset = 0x00;
224fadt_mod->Reset_AccessWidth = 0x01;
225fadt_mod->Reset_Address = 0x0cf9;
226fadt_mod->Reset_Value = 0x06;
227verbose("FACP: Restart Fix applied\n");
228}
229
230// Patch DSDT Address
231DBG("Old DSDT @%x,%x\n",fadt_mod->DSDT,fadt_mod->X_DSDT);
232
233fadt_mod->DSDT=(uint32_t)new_dsdt;
234if ((uint32_t)(&(fadt_mod->X_DSDT))-(uint32_t)fadt_mod+8<=fadt_mod->Length)
235fadt_mod->X_DSDT=(uint32_t)new_dsdt;
236
237DBG("New DSDT @%x,%x\n",fadt_mod->DSDT,fadt_mod->X_DSDT);
238
239// Correct the checksum
240fadt_mod->Checksum=0;
241fadt_mod->Checksum=256-checksum8(fadt_mod,fadt_mod->Length);
242
243rsdt_entries[i-dropoffset]=(uint32_t)fadt_mod;
244continue;
245}
246}
247
248// Correct the checksum of RSDT
249rsdt_mod->Length-=4*dropoffset;
250
251DBG("RSDT Original checksum %d\n", rsdt_mod->Checksum);
252
253rsdt_mod->Checksum=0;
254rsdt_mod->Checksum=256-checksum8(rsdt_mod,rsdt_mod->Length);
255
256DBG("RSDT New checksum %d at %x\n", rsdt_mod->Checksum,rsdt_mod);
257}
258else
259{
260rsdp_mod->RsdtAddress=0;
261printf("RSDT not found or RSDT incorrect\n");
262}
263
264if (version)
265{
266struct acpi_2_xsdt *xsdt, *xsdt_mod;
267
268// FIXME: handle 64-bit address correctly
269
270xsdt=(struct acpi_2_xsdt*) ((uint32_t)rsdp->XsdtAddress);
271DBG("XSDT @%x;%x, Length=%d\n", (uint32_t)(rsdp->XsdtAddress>>32),(uint32_t)rsdp->XsdtAddress,
272xsdt->Length);
273if (xsdt && (uint64_t)rsdp->XsdtAddress<0xffffffff && xsdt->Length<0x10000)
274{
275uint64_t *xsdt_entries;
276int xsdt_entries_num, i;
277int dropoffset=0;
278
279xsdt_mod=(struct acpi_2_xsdt*)AllocateKernelMemory(xsdt->Length);
280memcpy(xsdt_mod, xsdt, xsdt->Length);
281rsdp_mod->XsdtAddress=(uint32_t)xsdt_mod;
282xsdt_entries_num=(xsdt_mod->Length-sizeof(struct acpi_2_xsdt))/8;
283xsdt_entries=(uint64_t *)(xsdt_mod+1);
284for (i=0;i<xsdt_entries_num;i++)
285{
286char *table=(char *)((uint32_t)(xsdt_entries[i]));
287if (!table)
288continue;
289xsdt_entries[i-dropoffset]=xsdt_entries[i];
290if (drop_ssdt && table[0]=='S' && table[1]=='S' && table[2]=='D' && table[3]=='T')
291{
292dropoffset++;
293continue;
294}
295if (table[0]=='D' && table[1]=='S' && table[2]=='D' && table[3]=='T')
296{
297DBG("DSDT found\n");
298
299xsdt_entries[i-dropoffset]=(uint32_t)new_dsdt;
300
301DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
302
303continue;
304}
305if (table[0]=='F' && table[1]=='A' && table[2]=='C' && table[3]=='P')
306{
307struct acpi_2_fadt *fadt, *fadt_mod;
308fadt=(struct acpi_2_fadt *)(uint32_t)xsdt_entries[i];
309
310DBG("FADT found @%x,%x, Length %d\n",(uint32_t)(xsdt_entries[i]>>32),fadt,
311 fadt->Length);
312
313if (!fadt || (uint64_t)xsdt_entries[i] >= 0xffffffff || fadt->Length>0x10000)
314{
315printf("FADT incorrect or after 4GB. Dropping XSDT\n");
316goto drop_xsdt;
317}
318
319if (fix_restart && fadt->Length < 0x81) {
320fadt_mod = (struct acpi_2_fadt *)AllocateKernelMemory(0x81);
321memcpy(fadt_mod, fadt, fadt->Length);
322fadt_mod->Length = 0x81;
323} else {
324fadt_mod = (struct acpi_2_fadt*)AllocateKernelMemory(fadt->Length);
325memcpy(fadt_mod, fadt, fadt->Length);
326}
327
328if (fix_restart) {
329fadt_mod->Flags |= 0x400;
330fadt_mod->Reset_SpaceID = 0x01;
331fadt_mod->Reset_BitWidth = 0x08;
332fadt_mod->Reset_BitOffset = 0x00;
333fadt_mod->Reset_AccessWidth = 0x01;
334fadt_mod->Reset_Address = 0x0cf9;
335fadt_mod->Reset_Value = 0x06;
336verbose("FACP: Restart Fix applied\n");
337}
338
339// Patch DSDT Address
340DBG("Old DSDT @%x,%x\n",fadt_mod->DSDT,fadt_mod->X_DSDT);
341
342fadt_mod->DSDT=(uint32_t)new_dsdt;
343if ((uint32_t)(&(fadt_mod->X_DSDT))-(uint32_t)fadt_mod+8<=fadt_mod->Length)
344fadt_mod->X_DSDT=(uint32_t)new_dsdt;
345
346DBG("New DSDT @%x,%x\n",fadt_mod->DSDT,fadt_mod->X_DSDT);
347
348// Correct the checksum
349fadt_mod->Checksum=0;
350fadt_mod->Checksum=256-checksum8(fadt_mod,fadt_mod->Length);
351
352xsdt_entries[i-dropoffset]=(uint32_t)fadt_mod;
353
354DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
355
356continue;
357}
358
359DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
360
361}
362
363// Correct the checksum of XSDT
364xsdt_mod->Length-=8*dropoffset;
365xsdt_mod->Checksum=0;
366xsdt_mod->Checksum=256-checksum8(xsdt_mod,xsdt_mod->Length);
367}
368else
369{
370drop_xsdt:
371
372DBG("About to drop XSDT\n");
373
374/*FIXME: Now we just hope that if MacOS doesn't find XSDT it reverts to RSDT.
375 * A Better strategy would be to generate
376 */
377
378rsdp_mod->XsdtAddress=0xffffffffffffffffLL;
379printf("XSDT not found or XSDT incorrect\n");
380}
381}
382
383// Correct the checksum of RSDP
384
385DBG("Original checksum %d\n", rsdp_mod->Checksum);
386
387rsdp_mod->Checksum=0;
388rsdp_mod->Checksum=256-checksum8(rsdp_mod,20);
389
390DBG("New checksum %d\n", rsdp_mod->Checksum);
391
392if (version)
393{
394DBG("Original extended checksum %d\n", rsdp_mod->ExtendedChecksum);
395
396rsdp_mod->ExtendedChecksum=0;
397rsdp_mod->ExtendedChecksum=256-checksum8(rsdp_mod,rsdp_mod->Length);
398
399DBG("New extended checksum %d\n", rsdp_mod->ExtendedChecksum);
400
401}
402
403verbose("Patched ACPI version %d DSDT\n", version+1);
404if (version)
405{
406/* XXX aserebln why uint32 cast if pointer is uint64 ? */
407acpi20_p = (uint32_t)rsdp_mod;
408addConfigurationTable(&gEfiAcpi20TableGuid, &acpi20_p, "ACPI_20");
409}
410else
411{
412/* XXX aserebln why uint32 cast if pointer is uint64 ? */
413acpi10_p = (uint32_t)rsdp_mod;
414addConfigurationTable(&gEfiAcpiTableGuid, &acpi10_p, "ACPI");
415}
416}
417#if DEBUG_DSDT
418printf("(Press a key to continue...)\n");
419getc();
420#endif
421return 1;
422}
423

Archive Download this file

Revision: 23