Chameleon

Chameleon Svn Source Tree

Root/branches/prasys/i386/libsaio/dsdt_patcher.c

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

Archive Download this file

Revision: 24