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 "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
74
75/* Setup ACPI without replacing DSDT. */
76int setupAcpiNoMod()
77{
78//addConfigurationTable(&gEfiAcpiTableGuid, getAddressOfAcpiTable(), "ACPI");
79//addConfigurationTable(&gEfiAcpi20TableGuid, getAddressOfAcpi20Table(), "ACPI_20");
80acpi10_p = (uint32_t)getAddressOfAcpiTable();
81acpi20_p = (uint32_t)getAddressOfAcpi20Table();
82addConfigurationTable(&gEfiAcpiTableGuid, &acpi10_p, "ACPI");
83if(acpi20_p) addConfigurationTable(&gEfiAcpi20TableGuid, &acpi20_p, "ACPI_20");
84return 1;
85}
86
87/* Setup ACPI. Replace DSDT if DSDT.aml is found */
88int setupAcpi()
89{
90int fd, version;
91void *new_dsdt;
92const char *dsdt_filename;
93char dirspec[512];
94int len;
95boolean_t drop_ssdt=NO;
96
97//DBG("Enter setupACPI\n");
98
99if (!getValueForKey("DSDT", &dsdt_filename, &len, &bootInfo->bootConfig))
100dsdt_filename="DSDT.aml";
101
102// Check booting partition
103sprintf(dirspec,"%s",dsdt_filename);
104fd=open (dirspec,0);
105if (fd<0)
106{// Check Extra on booting partition
107sprintf(dirspec,"/Extra/%s",dsdt_filename);
108fd=open (dirspec,0);
109if (fd<0)
110{// Fall back to booter partition
111sprintf(dirspec,"bt(0,0)/Extra/%s",dsdt_filename);
112fd=open (dirspec,0);
113if (fd<0)
114{
115verbose("No DSDT replacement found. Leaving ACPI data as is\n");
116return setupAcpiNoMod();
117}
118}
119}
120
121// Load replacement DSDT
122new_dsdt=(void*)AllocateKernelMemory(file_size (fd));
123if (!new_dsdt)
124{
125printf("Couldn't allocate memory for DSDT\n");
126return setupAcpiNoMod();
127}
128if (read (fd, new_dsdt, file_size (fd))!=file_size (fd))
129{
130printf("Couldn't read file\n");
131return setupAcpiNoMod();
132}
133close (fd);
134
135DBG("New DSDT Loaded in memory\n");
136
137{
138BOOL tmp;
139drop_ssdt=getBoolForKey("DropSSDT",&tmp, &bootInfo->bootConfig)&&tmp;
140}
141
142// Do the same procedure for both versions of ACPI
143for (version=0;version<2;version++)
144{
145struct acpi_2_rsdp *rsdp, *rsdp_mod;
146struct acpi_2_rsdt *rsdt, *rsdt_mod;
147int rsdplength;
148
149// Find original rsdp
150rsdp=(struct acpi_2_rsdp *)(version?getAddressOfAcpi20Table():getAddressOfAcpiTable());
151if (!rsdp)
152{
153DBG("No ACPI version %d found. Ignoring\n", version+1);
154if (version)
155addConfigurationTable(&gEfiAcpi20TableGuid, NULL, "ACPI_20");
156else
157addConfigurationTable(&gEfiAcpiTableGuid, NULL, "ACPI");
158continue;
159}
160rsdplength=version?rsdp->Length:20;
161
162DBG("RSDP version %d found @%x. Length=%d\n",version+1,rsdp,rsdplength);
163
164/* FIXME: no check that memory allocation succeeded
165 * Copy and patch RSDP,RSDT, XSDT and FADT
166 * For more info see ACPI Specification pages 110 and following
167 */
168
169rsdp_mod=(struct acpi_2_rsdp *) AllocateKernelMemory(rsdplength);
170memcpy(rsdp_mod, rsdp, rsdplength);
171rsdt=(struct acpi_2_rsdt *)(rsdp->RsdtAddress);
172
173DBG("RSDT @%x, Length %d\n",rsdt, rsdt->Length);
174
175if (rsdt && (uint32_t)rsdt !=0xffffffff && rsdt->Length<0x10000)
176{
177uint32_t *rsdt_entries;
178int rsdt_entries_num;
179int dropoffset=0, i;
180
181rsdt_mod=(struct acpi_2_rsdt *)AllocateKernelMemory(rsdt->Length);
182memcpy (rsdt_mod, rsdt, rsdt->Length);
183rsdp_mod->RsdtAddress=(uint32_t)rsdt_mod;
184rsdt_entries_num=(rsdt_mod->Length-sizeof(struct acpi_2_rsdt))/4;
185rsdt_entries=(uint32_t *)(rsdt_mod+1);
186for (i=0;i<rsdt_entries_num;i++)
187{
188char *table=(char *)(rsdt_entries[i]);
189if (!table)
190continue;
191
192DBG("TABLE %c%c%c%c,",table[0],table[1],table[2],table[3]);
193
194rsdt_entries[i-dropoffset]=rsdt_entries[i];
195if (drop_ssdt && table[0]=='S' && table[1]=='S' && table[2]=='D' && table[3]=='T')
196{
197dropoffset++;
198continue;
199}
200if (table[0]=='D' && table[1]=='S' && table[2]=='D' && table[3]=='T')
201{
202DBG("DSDT found\n");
203rsdt_entries[i-dropoffset]=(uint32_t)new_dsdt;
204continue;
205}
206if (table[0]=='F' && table[1]=='A' && table[2]=='C' && table[3]=='P')
207{
208struct acpi_2_fadt *fadt, *fadt_mod;
209fadt=(struct acpi_2_fadt *)rsdt_entries[i];
210
211DBG("FADT found @%x, Length %d\n",fadt, fadt->Length);
212
213if (!fadt || (uint32_t)fadt == 0xffffffff || fadt->Length>0x10000)
214{
215printf("FADT incorrect. Not modified\n");
216continue;
217}
218
219fadt_mod=(struct acpi_2_fadt *)AllocateKernelMemory(fadt->Length);
220memcpy(fadt_mod, fadt, fadt->Length);
221
222// Patch DSDT Address
223DBG("Old DSDT @%x,%x\n",fadt_mod->DSDT,fadt_mod->X_DSDT);
224
225fadt_mod->DSDT=(uint32_t)new_dsdt;
226if ((uint32_t)(&(fadt_mod->X_DSDT))-(uint32_t)fadt_mod+8<=fadt_mod->Length)
227fadt_mod->X_DSDT=(uint32_t)new_dsdt;
228
229DBG("New DSDT @%x,%x\n",fadt_mod->DSDT,fadt_mod->X_DSDT);
230
231// Correct the checksum
232fadt_mod->Checksum=0;
233fadt_mod->Checksum=256-checksum8(fadt_mod,fadt_mod->Length);
234
235rsdt_entries[i-dropoffset]=(uint32_t)fadt_mod;
236continue;
237}
238}
239
240// Correct the checksum of RSDT
241rsdt_mod->Length-=4*dropoffset;
242
243DBG("RSDT Original checksum %d\n", rsdt_mod->Checksum);
244
245rsdt_mod->Checksum=0;
246rsdt_mod->Checksum=256-checksum8(rsdt_mod,rsdt_mod->Length);
247
248DBG("RSDT New checksum %d at %x\n", rsdt_mod->Checksum,rsdt_mod);
249}
250else
251{
252rsdp_mod->RsdtAddress=0;
253printf("RSDT not found or RSDT incorrect\n");
254}
255
256if (version)
257{
258struct acpi_2_xsdt *xsdt, *xsdt_mod;
259
260// FIXME: handle 64-bit address correctly
261
262xsdt=(struct acpi_2_xsdt*) ((uint32_t)rsdp->XsdtAddress);
263DBG("XSDT @%x;%x, Length=%d\n", (uint32_t)(rsdp->XsdtAddress>>32),(uint32_t)rsdp->XsdtAddress,
264xsdt->Length);
265if (xsdt && (uint64_t)rsdp->XsdtAddress<0xffffffff && xsdt->Length<0x10000)
266{
267uint64_t *xsdt_entries;
268int xsdt_entries_num, i;
269int dropoffset=0;
270
271xsdt_mod=(struct acpi_2_xsdt*)AllocateKernelMemory(xsdt->Length);
272memcpy(xsdt_mod, xsdt, xsdt->Length);
273rsdp_mod->XsdtAddress=(uint32_t)xsdt_mod;
274xsdt_entries_num=(xsdt_mod->Length-sizeof(struct acpi_2_xsdt))/8;
275xsdt_entries=(uint64_t *)(xsdt_mod+1);
276for (i=0;i<xsdt_entries_num;i++)
277{
278char *table=(char *)((uint32_t)(xsdt_entries[i]));
279if (!table)
280continue;
281xsdt_entries[i-dropoffset]=xsdt_entries[i];
282if (drop_ssdt && table[0]=='S' && table[1]=='S' && table[2]=='D' && table[3]=='T')
283{
284dropoffset++;
285continue;
286}
287if (table[0]=='D' && table[1]=='S' && table[2]=='D' && table[3]=='T')
288{
289DBG("DSDT found\n");
290
291xsdt_entries[i-dropoffset]=(uint32_t)new_dsdt;
292
293DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
294
295continue;
296}
297if (table[0]=='F' && table[1]=='A' && table[2]=='C' && table[3]=='P')
298{
299struct acpi_2_fadt *fadt, *fadt_mod;
300fadt=(struct acpi_2_fadt *)(uint32_t)xsdt_entries[i];
301
302DBG("FADT found @%x,%x, Length %d\n",(uint32_t)(xsdt_entries[i]>>32),fadt,
303 fadt->Length);
304
305if (!fadt || (uint64_t)xsdt_entries[i] >= 0xffffffff || fadt->Length>0x10000)
306{
307printf("FADT incorrect or after 4GB. Dropping XSDT\n");
308goto drop_xsdt;
309}
310fadt_mod=(struct acpi_2_fadt*)AllocateKernelMemory(fadt->Length);
311memcpy(fadt_mod, fadt, fadt->Length);
312
313// Patch DSDT Address
314DBG("Old DSDT @%x,%x\n",fadt_mod->DSDT,fadt_mod->X_DSDT);
315
316fadt_mod->DSDT=(uint32_t)new_dsdt;
317if ((uint32_t)(&(fadt_mod->X_DSDT))-(uint32_t)fadt_mod+8<=fadt_mod->Length)
318fadt_mod->X_DSDT=(uint32_t)new_dsdt;
319
320DBG("New DSDT @%x,%x\n",fadt_mod->DSDT,fadt_mod->X_DSDT);
321
322// Correct the checksum
323fadt_mod->Checksum=0;
324fadt_mod->Checksum=256-checksum8(fadt_mod,fadt_mod->Length);
325
326xsdt_entries[i-dropoffset]=(uint32_t)fadt_mod;
327
328DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
329
330continue;
331}
332
333DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
334
335}
336
337// Correct the checksum of XSDT
338xsdt_mod->Length-=8*dropoffset;
339xsdt_mod->Checksum=0;
340xsdt_mod->Checksum=256-checksum8(xsdt_mod,xsdt_mod->Length);
341}
342else
343{
344drop_xsdt:
345
346DBG("About to drop XSDT\n");
347
348/*FIXME: Now we just hope that if MacOS doesn't find XSDT it reverts to RSDT.
349 * A Better strategy would be to generate
350 */
351
352rsdp_mod->XsdtAddress=0xffffffffffffffffLL;
353printf("XSDT not found or XSDT incorrect\n");
354}
355}
356
357// Correct the checksum of RSDP
358
359DBG("Original checksum %d\n", rsdp_mod->Checksum);
360
361rsdp_mod->Checksum=0;
362rsdp_mod->Checksum=256-checksum8(rsdp_mod,20);
363
364DBG("New checksum %d\n", rsdp_mod->Checksum);
365
366if (version)
367{
368DBG("Original extended checksum %d\n", rsdp_mod->ExtendedChecksum);
369
370rsdp_mod->ExtendedChecksum=0;
371rsdp_mod->ExtendedChecksum=256-checksum8(rsdp_mod,rsdp_mod->Length);
372
373DBG("New extended checksum %d\n", rsdp_mod->ExtendedChecksum);
374
375}
376
377verbose("Patched ACPI version %d DSDT\n", version+1);
378if (version)
379{
380acpi20_p = (uint32_t)rsdp_mod;
381addConfigurationTable(&gEfiAcpi20TableGuid, &acpi20_p, "ACPI_20");
382}
383else
384{
385acpi10_p = (uint32_t)rsdp_mod;
386addConfigurationTable(&gEfiAcpiTableGuid, &acpi10_p, "ACPI");
387}
388}
389#if DEBUG_DSDT
390getc();
391#endif
392return 1;
393}
394

Archive Download this file

Revision: 1