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

Archive Download this file

Revision: 41