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
76void *loadACPITable (const char *filename)
77{
78void *tableAddr;
79int fd;
80char dirspec[512];
81
82// Check booting partition
83sprintf(dirspec,"%s",filename);
84fd=open (dirspec,0);
85if (fd<0)
86{// Check Extra on booting partition
87sprintf(dirspec,"/Extra/%s",filename);
88fd=open (dirspec,0);
89if (fd<0)
90{// Fall back to booter partition
91sprintf(dirspec,"bt(0,0)/Extra/%s",filename);
92fd=open (dirspec,0);
93if (fd<0)
94{
95verbose("ACPI Table not found: %s\n", filename);
96return NULL;
97}
98}
99}
100
101tableAddr=(void*)AllocateKernelMemory(file_size (fd));
102if (tableAddr)
103{
104if (read (fd, tableAddr, file_size (fd))!=file_size (fd))
105{
106printf("Couldn't read table %s\n",dirspec);
107free (tableAddr);
108close (fd);
109return NULL;
110}
111
112DBG("Table %s read and stored at: %x\n", dirspec, tableAddr);
113close (fd);
114return tableAddr;
115}
116
117printf("Couldn't allocate memory for table %s\n", dirspec);
118close (fd);
119return NULL;
120}
121
122struct acpi_2_fadt *
123patch_fadt(struct acpi_2_fadt *fadt, void *new_dsdt)
124{
125
126struct acpi_2_fadt *fadt_mod;
127bool fadt_rev2_needed = false;
128bool fix_restart;
129
130// Restart Fix
131if (Platform.CPU.Vendor == 0x756E6547) {/* Intel */
132fix_restart = true;
133getBoolForKey(kRestartFix, &fix_restart, &bootInfo->bootConfig);
134} else {
135verbose ("Not an Intel platform: Restart Fix not applied !!!\n");
136fix_restart = false;
137}
138
139if (fix_restart) fadt_rev2_needed = true;
140
141// Allocate new fadt table
142if (fadt->Length < 0x84 && fadt_rev2_needed)
143{
144fadt_mod=(struct acpi_2_fadt *)AllocateKernelMemory(0x84);
145memcpy(fadt_mod, fadt, fadt->Length);
146fadt_mod->Length = 0x84;
147fadt_mod->Revision = 0x02; // FADT rev 2 (ACPI 1.0B MS extensions)
148}
149else
150{
151fadt_mod=(struct acpi_2_fadt *)AllocateKernelMemory(fadt->Length);
152memcpy(fadt_mod, fadt, fadt->Length);
153}
154
155// Set PM_Profile from System-type
156if (fadt_mod->PM_Profile != Platform.Type) {
157verbose("FADT: changing PM_Profile from 0x%02x to 0x%02x\n", fadt_mod->PM_Profile, Platform.Type);
158fadt_mod->PM_Profile = Platform.Type;
159}
160
161// Patch FADT to fix restart
162if (fix_restart)
163{
164fadt_mod->Flags|= 0x400;
165fadt_mod->Reset_SpaceID= 0x01; // System I/O
166fadt_mod->Reset_BitWidth= 0x08; // 1 byte
167fadt_mod->Reset_BitOffset= 0x00; // Offset 0
168fadt_mod->Reset_AccessWidth= 0x01; // Byte access
169fadt_mod->Reset_Address= 0x0cf9; // Address of the register
170fadt_mod->Reset_Value= 0x06; // Value to write to reset the system
171verbose("FADT: Restart Fix applied !\n");
172}
173
174// Patch DSDT Address
175DBG("DSDT: Old @%x,%x, ",fadt_mod->DSDT,fadt_mod->X_DSDT);
176
177fadt_mod->DSDT=(uint32_t)new_dsdt;
178if ((uint32_t)(&(fadt_mod->X_DSDT))-(uint32_t)fadt_mod+8<=fadt_mod->Length)
179fadt_mod->X_DSDT=(uint32_t)new_dsdt;
180
181DBG("New @%x,%x\n",fadt_mod->DSDT,fadt_mod->X_DSDT);
182
183// Correct the checksum
184fadt_mod->Checksum=0;
185fadt_mod->Checksum=256-checksum8(fadt_mod,fadt_mod->Length);
186
187return fadt_mod;
188}
189
190/* Setup ACPI without replacing DSDT. */
191int setupAcpiNoMod()
192{
193//addConfigurationTable(&gEfiAcpiTableGuid, getAddressOfAcpiTable(), "ACPI");
194//addConfigurationTable(&gEfiAcpi20TableGuid, getAddressOfAcpi20Table(), "ACPI_20");
195/* XXX aserebln why uint32 cast if pointer is uint64 ? */
196acpi10_p = (uint32_t)getAddressOfAcpiTable();
197acpi20_p = (uint32_t)getAddressOfAcpi20Table();
198addConfigurationTable(&gEfiAcpiTableGuid, &acpi10_p, "ACPI");
199if(acpi20_p) addConfigurationTable(&gEfiAcpi20TableGuid, &acpi20_p, "ACPI_20");
200return 1;
201}
202
203/* Setup ACPI. Replace DSDT if DSDT.aml is found */
204int setupAcpi(void)
205{
206int version;
207void *new_dsdt;
208const char *dsdt_filename;
209
210char dirspec[512];
211
212int fd;
213
214int len;
215bool tmp;
216bool drop_ssdt;
217bool fix_restart;
218
219if (!getValueForKey(kDSDT, &dsdt_filename, &len, &bootInfo->bootConfig)) {
220dsdt_filename = "/Extra/DSDT.aml";
221}
222
223if (!getValueForKey("DSDT", &dsdt_filename, &len, &bootInfo->bootConfig))
224dsdt_filename="DSDT.aml";
225
226// Rek: Was originally removed by JrCs patch, would like to keep compat for RC5 and take the time
227// to discuss and agree on this extra dsdt file location checking removal for RC6
228// For now, I believe the results could be catastrophic for users relying on that feature:
229
230// Check booting partition
231sprintf(dirspec,"%s",dsdt_filename);
232fd=open (dirspec,0);
233if (fd<0)
234{// Check Extra on booting partition
235sprintf(dirspec,"/Extra/%s",dsdt_filename);
236fd=open (dirspec,0);
237if (fd<0)
238{// Fall back to booter partition
239sprintf(dirspec,"bt(0,0)/Extra/%s",dsdt_filename);
240fd=open (dirspec,0);
241if (fd<0)
242{
243verbose("No DSDT replacement found. Leaving ACPI data as is\n");
244return setupAcpiNoMod();
245}
246}
247}
248
249// Load replacement DSDT
250new_dsdt=loadACPITable(dsdt_filename);
251if (!new_dsdt)
252{
253close(fd);
254return setupAcpiNoMod();
255}
256
257DBG("New DSDT Loaded in memory\n");
258
259{
260bool tmp;
261drop_ssdt=getBoolForKey(kDropSSDT, &tmp, &bootInfo->bootConfig)&&tmp;
262}
263
264// Do the same procedure for both versions of ACPI
265for (version=0; version<2; version++) {
266struct acpi_2_rsdp *rsdp, *rsdp_mod;
267struct acpi_2_rsdt *rsdt, *rsdt_mod;
268int rsdplength;
269
270// Find original rsdp
271rsdp=(struct acpi_2_rsdp *)(version?getAddressOfAcpi20Table():getAddressOfAcpiTable());
272if (!rsdp)
273{
274DBG("No ACPI version %d found. Ignoring\n", version+1);
275if (version)
276addConfigurationTable(&gEfiAcpi20TableGuid, NULL, "ACPI_20");
277else
278addConfigurationTable(&gEfiAcpiTableGuid, NULL, "ACPI");
279continue;
280}
281rsdplength=version?rsdp->Length:20;
282
283DBG("RSDP version %d found @%x. Length=%d\n",version+1,rsdp,rsdplength);
284
285/* FIXME: no check that memory allocation succeeded
286 * Copy and patch RSDP,RSDT, XSDT and FADT
287 * For more info see ACPI Specification pages 110 and following
288 */
289
290rsdp_mod=(struct acpi_2_rsdp *) AllocateKernelMemory(rsdplength);
291memcpy(rsdp_mod, rsdp, rsdplength);
292rsdt=(struct acpi_2_rsdt *)(rsdp->RsdtAddress);
293
294DBG("RSDT @%x, Length %d\n",rsdt, rsdt->Length);
295
296if (rsdt && (uint32_t)rsdt !=0xffffffff && rsdt->Length<0x10000)
297{
298uint32_t *rsdt_entries;
299int rsdt_entries_num;
300int dropoffset=0, i;
301
302rsdt_mod=(struct acpi_2_rsdt *)AllocateKernelMemory(rsdt->Length);
303memcpy (rsdt_mod, rsdt, rsdt->Length);
304rsdp_mod->RsdtAddress=(uint32_t)rsdt_mod;
305rsdt_entries_num=(rsdt_mod->Length-sizeof(struct acpi_2_rsdt))/4;
306rsdt_entries=(uint32_t *)(rsdt_mod+1);
307for (i=0;i<rsdt_entries_num;i++)
308{
309char *table=(char *)(rsdt_entries[i]);
310if (!table)
311continue;
312
313DBG("TABLE %c%c%c%c,",table[0],table[1],table[2],table[3]);
314
315rsdt_entries[i-dropoffset]=rsdt_entries[i];
316if (drop_ssdt && table[0]=='S' && table[1]=='S' && table[2]=='D' && table[3]=='T')
317{
318dropoffset++;
319continue;
320}
321if (table[0]=='D' && table[1]=='S' && table[2]=='D' && table[3]=='T')
322{
323DBG("DSDT found\n");
324rsdt_entries[i-dropoffset]=(uint32_t)new_dsdt;
325continue;
326}
327if (table[0]=='F' && table[1]=='A' && table[2]=='C' && table[3]=='P')
328{
329struct acpi_2_fadt *fadt, *fadt_mod;
330fadt=(struct acpi_2_fadt *)rsdt_entries[i];
331
332DBG("FADT found @%x, Length %d\n",fadt, fadt->Length);
333
334if (!fadt || (uint32_t)fadt == 0xffffffff || fadt->Length>0x10000)
335{
336printf("FADT incorrect. Not modified\n");
337continue;
338}
339
340fadt_mod = patch_fadt(fadt, new_dsdt);
341rsdt_entries[i-dropoffset]=(uint32_t)fadt_mod;
342continue;
343}
344}
345DBG("\n");
346
347// Correct the checksum of RSDT
348rsdt_mod->Length-=4*dropoffset;
349
350DBG("RSDT: Original checksum %d, ", rsdt_mod->Checksum);
351
352rsdt_mod->Checksum=0;
353rsdt_mod->Checksum=256-checksum8(rsdt_mod,rsdt_mod->Length);
354
355DBG("New checksum %d at %x\n", rsdt_mod->Checksum,rsdt_mod);
356}
357else
358{
359rsdp_mod->RsdtAddress=0;
360printf("RSDT not found or RSDT incorrect\n");
361}
362
363if (version)
364{
365struct acpi_2_xsdt *xsdt, *xsdt_mod;
366
367// FIXME: handle 64-bit address correctly
368
369xsdt=(struct acpi_2_xsdt*) ((uint32_t)rsdp->XsdtAddress);
370DBG("XSDT @%x;%x, Length=%d\n", (uint32_t)(rsdp->XsdtAddress>>32),(uint32_t)rsdp->XsdtAddress,
371xsdt->Length);
372if (xsdt && (uint64_t)rsdp->XsdtAddress<0xffffffff && xsdt->Length<0x10000)
373{
374uint64_t *xsdt_entries;
375int xsdt_entries_num, i;
376int dropoffset=0;
377
378xsdt_mod=(struct acpi_2_xsdt*)AllocateKernelMemory(xsdt->Length);
379memcpy(xsdt_mod, xsdt, xsdt->Length);
380rsdp_mod->XsdtAddress=(uint32_t)xsdt_mod;
381xsdt_entries_num=(xsdt_mod->Length-sizeof(struct acpi_2_xsdt))/8;
382xsdt_entries=(uint64_t *)(xsdt_mod+1);
383for (i=0;i<xsdt_entries_num;i++)
384{
385char *table=(char *)((uint32_t)(xsdt_entries[i]));
386if (!table)
387continue;
388xsdt_entries[i-dropoffset]=xsdt_entries[i];
389if (drop_ssdt && table[0]=='S' && table[1]=='S' && table[2]=='D' && table[3]=='T')
390{
391dropoffset++;
392continue;
393}
394if (table[0]=='D' && table[1]=='S' && table[2]=='D' && table[3]=='T')
395{
396DBG("DSDT found\n");
397
398xsdt_entries[i-dropoffset]=(uint32_t)new_dsdt;
399
400DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
401
402continue;
403}
404if (table[0]=='F' && table[1]=='A' && table[2]=='C' && table[3]=='P')
405{
406struct acpi_2_fadt *fadt, *fadt_mod;
407fadt=(struct acpi_2_fadt *)(uint32_t)xsdt_entries[i];
408
409DBG("FADT found @%x,%x, Length %d\n",(uint32_t)(xsdt_entries[i]>>32),fadt,
410 fadt->Length);
411
412if (!fadt || (uint64_t)xsdt_entries[i] >= 0xffffffff || fadt->Length>0x10000)
413{
414verbose("FADT incorrect or after 4GB. Dropping XSDT\n");
415goto drop_xsdt;
416}
417
418fadt_mod = patch_fadt(fadt, new_dsdt);
419xsdt_entries[i-dropoffset]=(uint32_t)fadt_mod;
420
421DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
422
423continue;
424}
425
426DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
427
428}
429
430// Correct the checksum of XSDT
431xsdt_mod->Length-=8*dropoffset;
432xsdt_mod->Checksum=0;
433xsdt_mod->Checksum=256-checksum8(xsdt_mod,xsdt_mod->Length);
434}
435else
436{
437drop_xsdt:
438
439DBG("About to drop XSDT\n");
440
441/*FIXME: Now we just hope that if MacOS doesn't find XSDT it reverts to RSDT.
442 * A Better strategy would be to generate
443 */
444
445rsdp_mod->XsdtAddress=0xffffffffffffffffLL;
446verbose("XSDT not found or XSDT incorrect\n");
447}
448}
449
450// Correct the checksum of RSDP
451
452DBG("RSDP: Original checksum %d, ", rsdp_mod->Checksum);
453
454rsdp_mod->Checksum=0;
455rsdp_mod->Checksum=256-checksum8(rsdp_mod,20);
456
457DBG("New checksum %d\n", rsdp_mod->Checksum);
458
459if (version)
460{
461DBG("RSDP: Original extended checksum %d", rsdp_mod->ExtendedChecksum);
462
463rsdp_mod->ExtendedChecksum=0;
464rsdp_mod->ExtendedChecksum=256-checksum8(rsdp_mod,rsdp_mod->Length);
465
466DBG("New extended checksum %d\n", rsdp_mod->ExtendedChecksum);
467
468}
469
470verbose("Patched ACPI version %d DSDT\n", version+1);
471if (version)
472{
473/* XXX aserebln why uint32 cast if pointer is uint64 ? */
474acpi20_p = (uint32_t)rsdp_mod;
475addConfigurationTable(&gEfiAcpi20TableGuid, &acpi20_p, "ACPI_20");
476}
477else
478{
479/* XXX aserebln why uint32 cast if pointer is uint64 ? */
480acpi10_p = (uint32_t)rsdp_mod;
481addConfigurationTable(&gEfiAcpiTableGuid, &acpi10_p, "ACPI");
482}
483}
484#if DEBUG_DSDT
485printf("Press a key to continue... (DEBUG_DSDT)\n");
486getc();
487#endif
488return 1;
489}
490

Archive Download this file

Revision: 27