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

Archive Download this file

Revision: 15