Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 17