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
138
139struct acpi_2_fadt *
140patch_fadt(struct acpi_2_fadt *fadt, void *new_dsdt)
141{
142
143 extern void setupSystemType();
144
145struct acpi_2_fadt *fadt_mod;
146bool fadt_rev2_needed = false;
147bool fix_restart;
148const char * value;
149
150// Restart Fix
151if (Platform.CPU.Vendor == 0x756E6547) {/* Intel */
152fix_restart = true;
153getBoolForKey(kRestartFix, &fix_restart, &bootInfo->bootConfig);
154} else {
155verbose ("Not an Intel platform: Restart Fix not applied !!!\n");
156fix_restart = false;
157}
158
159if (fix_restart) fadt_rev2_needed = true;
160
161// Allocate new fadt table
162if (fadt->Length < 0x84 && fadt_rev2_needed)
163{
164fadt_mod=(struct acpi_2_fadt *)AllocateKernelMemory(0x84);
165memcpy(fadt_mod, fadt, fadt->Length);
166fadt_mod->Length = 0x84;
167fadt_mod->Revision = 0x02; // FADT rev 2 (ACPI 1.0B MS extensions)
168}
169else
170{
171fadt_mod=(struct acpi_2_fadt *)AllocateKernelMemory(fadt->Length);
172memcpy(fadt_mod, fadt, fadt->Length);
173}
174// Determine system type / PM_Model
175if ( (value=getStringForKey(kSystemType, &bootInfo->bootConfig))!=NULL)
176{
177 if (Platform.Type > 6)
178 {
179 if(fadt_mod->PM_Profile<=6)
180 Platform.Type = fadt_mod->PM_Profile; // get the fadt if correct
181 else
182 Platform.Type = 1;/* Set a fixed value (Desktop) */
183 verbose("Error: system-type must be 0..6. Defaulting to %d !\n", Platform.Type);
184 }
185 else
186 Platform.Type = (unsigned char) strtoul(value, NULL, 10);
187}
188// Set PM_Profile from System-type if only if user wanted this value to be forced
189if (fadt_mod->PM_Profile != Platform.Type)
190{
191 if (value)
192 { // user has overriden the SystemType so take care of it in FACP
193verbose("FADT: changing PM_Profile from 0x%02x to 0x%02x\n", fadt_mod->PM_Profile, Platform.Type);
194fadt_mod->PM_Profile = Platform.Type;
195 }
196 else
197 { // PM_Profile has a different value and no override has been set, so reflect the user value to ioregs
198 Platform.Type = fadt_mod->PM_Profile <= 6 ? fadt_mod->PM_Profile : 1;
199 }
200}
201// We now have to write the systemm-type in ioregs: we cannot do it before in setupDeviceTree()
202// because we need to take care of facp original content, if it is correct.
203setupSystemType();
204
205// Patch FADT to fix restart
206if (fix_restart)
207{
208fadt_mod->Flags|= 0x400;
209fadt_mod->Reset_SpaceID= 0x01; // System I/O
210fadt_mod->Reset_BitWidth= 0x08; // 1 byte
211fadt_mod->Reset_BitOffset= 0x00; // Offset 0
212fadt_mod->Reset_AccessWidth= 0x01; // Byte access
213fadt_mod->Reset_Address= 0x0cf9; // Address of the register
214fadt_mod->Reset_Value= 0x06; // Value to write to reset the system
215verbose("FADT: Restart Fix applied !\n");
216}
217
218// Patch DSDT Address
219DBG("DSDT: Old @%x,%x, ",fadt_mod->DSDT,fadt_mod->X_DSDT);
220
221fadt_mod->DSDT=(uint32_t)new_dsdt;
222if ((uint32_t)(&(fadt_mod->X_DSDT))-(uint32_t)fadt_mod+8<=fadt_mod->Length)
223fadt_mod->X_DSDT=(uint32_t)new_dsdt;
224
225DBG("New @%x,%x\n",fadt_mod->DSDT,fadt_mod->X_DSDT);
226
227// Correct the checksum
228fadt_mod->Checksum=0;
229fadt_mod->Checksum=256-checksum8(fadt_mod,fadt_mod->Length);
230
231return fadt_mod;
232}
233
234/* Setup ACPI without replacing DSDT. */
235int setupAcpiNoMod()
236{
237//addConfigurationTable(&gEfiAcpiTableGuid, getAddressOfAcpiTable(), "ACPI");
238//addConfigurationTable(&gEfiAcpi20TableGuid, getAddressOfAcpi20Table(), "ACPI_20");
239/* XXX aserebln why uint32 cast if pointer is uint64 ? */
240acpi10_p = (uint32_t)getAddressOfAcpiTable();
241acpi20_p = (uint32_t)getAddressOfAcpi20Table();
242addConfigurationTable(&gEfiAcpiTableGuid, &acpi10_p, "ACPI");
243if(acpi20_p) addConfigurationTable(&gEfiAcpi20TableGuid, &acpi20_p, "ACPI_20");
244return 1;
245}
246
247/* Setup ACPI. Replace DSDT if DSDT.aml is found */
248int setupAcpi(void)
249{
250int version;
251void *new_dsdt;
252
253bool drop_ssdt;
254
255// Load replacement DSDT
256new_dsdt=loadACPITable();
257if (!new_dsdt)
258{
259return setupAcpiNoMod();
260}
261
262DBG("New DSDT Loaded in memory\n");
263
264{
265bool tmp;
266drop_ssdt=getBoolForKey(kDropSSDT, &tmp, &bootInfo->bootConfig)&&tmp;
267}
268
269// Do the same procedure for both versions of ACPI
270for (version=0; version<2; version++) {
271struct acpi_2_rsdp *rsdp, *rsdp_mod;
272struct acpi_2_rsdt *rsdt, *rsdt_mod;
273int rsdplength;
274
275// Find original rsdp
276rsdp=(struct acpi_2_rsdp *)(version?getAddressOfAcpi20Table():getAddressOfAcpiTable());
277if (!rsdp)
278{
279DBG("No ACPI version %d found. Ignoring\n", version+1);
280if (version)
281addConfigurationTable(&gEfiAcpi20TableGuid, NULL, "ACPI_20");
282else
283addConfigurationTable(&gEfiAcpiTableGuid, NULL, "ACPI");
284continue;
285}
286rsdplength=version?rsdp->Length:20;
287
288DBG("RSDP version %d found @%x. Length=%d\n",version+1,rsdp,rsdplength);
289
290/* FIXME: no check that memory allocation succeeded
291 * Copy and patch RSDP,RSDT, XSDT and FADT
292 * For more info see ACPI Specification pages 110 and following
293 */
294
295rsdp_mod=(struct acpi_2_rsdp *) AllocateKernelMemory(rsdplength);
296memcpy(rsdp_mod, rsdp, rsdplength);
297rsdt=(struct acpi_2_rsdt *)(rsdp->RsdtAddress);
298
299DBG("RSDT @%x, Length %d\n",rsdt, rsdt->Length);
300
301if (rsdt && (uint32_t)rsdt !=0xffffffff && rsdt->Length<0x10000)
302{
303uint32_t *rsdt_entries;
304int rsdt_entries_num;
305int dropoffset=0, i;
306
307rsdt_mod=(struct acpi_2_rsdt *)AllocateKernelMemory(rsdt->Length);
308memcpy (rsdt_mod, rsdt, rsdt->Length);
309rsdp_mod->RsdtAddress=(uint32_t)rsdt_mod;
310rsdt_entries_num=(rsdt_mod->Length-sizeof(struct acpi_2_rsdt))/4;
311rsdt_entries=(uint32_t *)(rsdt_mod+1);
312for (i=0;i<rsdt_entries_num;i++)
313{
314char *table=(char *)(rsdt_entries[i]);
315if (!table)
316continue;
317
318DBG("TABLE %c%c%c%c,",table[0],table[1],table[2],table[3]);
319
320rsdt_entries[i-dropoffset]=rsdt_entries[i];
321if (drop_ssdt && table[0]=='S' && table[1]=='S' && table[2]=='D' && table[3]=='T')
322{
323dropoffset++;
324continue;
325}
326if (table[0]=='D' && table[1]=='S' && table[2]=='D' && table[3]=='T')
327{
328DBG("DSDT found\n");
329rsdt_entries[i-dropoffset]=(uint32_t)new_dsdt;
330continue;
331}
332if (table[0]=='F' && table[1]=='A' && table[2]=='C' && table[3]=='P')
333{
334struct acpi_2_fadt *fadt, *fadt_mod;
335fadt=(struct acpi_2_fadt *)rsdt_entries[i];
336
337DBG("FADT found @%x, Length %d\n",fadt, fadt->Length);
338
339if (!fadt || (uint32_t)fadt == 0xffffffff || fadt->Length>0x10000)
340{
341printf("FADT incorrect. Not modified\n");
342continue;
343}
344
345fadt_mod = patch_fadt(fadt, new_dsdt);
346rsdt_entries[i-dropoffset]=(uint32_t)fadt_mod;
347continue;
348}
349}
350DBG("\n");
351
352// Correct the checksum of RSDT
353rsdt_mod->Length-=4*dropoffset;
354
355DBG("RSDT: Original checksum %d, ", rsdt_mod->Checksum);
356
357rsdt_mod->Checksum=0;
358rsdt_mod->Checksum=256-checksum8(rsdt_mod,rsdt_mod->Length);
359
360DBG("New checksum %d at %x\n", rsdt_mod->Checksum,rsdt_mod);
361}
362else
363{
364rsdp_mod->RsdtAddress=0;
365printf("RSDT not found or RSDT incorrect\n");
366}
367
368if (version)
369{
370struct acpi_2_xsdt *xsdt, *xsdt_mod;
371
372// FIXME: handle 64-bit address correctly
373
374xsdt=(struct acpi_2_xsdt*) ((uint32_t)rsdp->XsdtAddress);
375DBG("XSDT @%x;%x, Length=%d\n", (uint32_t)(rsdp->XsdtAddress>>32),(uint32_t)rsdp->XsdtAddress,
376xsdt->Length);
377if (xsdt && (uint64_t)rsdp->XsdtAddress<0xffffffff && xsdt->Length<0x10000)
378{
379uint64_t *xsdt_entries;
380int xsdt_entries_num, i;
381int dropoffset=0;
382
383xsdt_mod=(struct acpi_2_xsdt*)AllocateKernelMemory(xsdt->Length);
384memcpy(xsdt_mod, xsdt, xsdt->Length);
385rsdp_mod->XsdtAddress=(uint32_t)xsdt_mod;
386xsdt_entries_num=(xsdt_mod->Length-sizeof(struct acpi_2_xsdt))/8;
387xsdt_entries=(uint64_t *)(xsdt_mod+1);
388for (i=0;i<xsdt_entries_num;i++)
389{
390char *table=(char *)((uint32_t)(xsdt_entries[i]));
391if (!table)
392continue;
393xsdt_entries[i-dropoffset]=xsdt_entries[i];
394if (drop_ssdt && table[0]=='S' && table[1]=='S' && table[2]=='D' && table[3]=='T')
395{
396dropoffset++;
397continue;
398}
399if (table[0]=='D' && table[1]=='S' && table[2]=='D' && table[3]=='T')
400{
401DBG("DSDT found\n");
402
403xsdt_entries[i-dropoffset]=(uint32_t)new_dsdt;
404
405DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
406
407continue;
408}
409if (table[0]=='F' && table[1]=='A' && table[2]=='C' && table[3]=='P')
410{
411struct acpi_2_fadt *fadt, *fadt_mod;
412fadt=(struct acpi_2_fadt *)(uint32_t)xsdt_entries[i];
413
414DBG("FADT found @%x,%x, Length %d\n",(uint32_t)(xsdt_entries[i]>>32),fadt,
415 fadt->Length);
416
417if (!fadt || (uint64_t)xsdt_entries[i] >= 0xffffffff || fadt->Length>0x10000)
418{
419verbose("FADT incorrect or after 4GB. Dropping XSDT\n");
420goto drop_xsdt;
421}
422
423fadt_mod = patch_fadt(fadt, new_dsdt);
424xsdt_entries[i-dropoffset]=(uint32_t)fadt_mod;
425
426DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
427
428continue;
429}
430
431DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
432
433}
434
435// Correct the checksum of XSDT
436xsdt_mod->Length-=8*dropoffset;
437xsdt_mod->Checksum=0;
438xsdt_mod->Checksum=256-checksum8(xsdt_mod,xsdt_mod->Length);
439}
440else
441{
442drop_xsdt:
443
444DBG("About to drop XSDT\n");
445
446/*FIXME: Now we just hope that if MacOS doesn't find XSDT it reverts to RSDT.
447 * A Better strategy would be to generate
448 */
449
450rsdp_mod->XsdtAddress=0xffffffffffffffffLL;
451verbose("XSDT not found or XSDT incorrect\n");
452}
453}
454
455// Correct the checksum of RSDP
456
457DBG("RSDP: Original checksum %d, ", rsdp_mod->Checksum);
458
459rsdp_mod->Checksum=0;
460rsdp_mod->Checksum=256-checksum8(rsdp_mod,20);
461
462DBG("New checksum %d\n", rsdp_mod->Checksum);
463
464if (version)
465{
466DBG("RSDP: Original extended checksum %d", rsdp_mod->ExtendedChecksum);
467
468rsdp_mod->ExtendedChecksum=0;
469rsdp_mod->ExtendedChecksum=256-checksum8(rsdp_mod,rsdp_mod->Length);
470
471DBG("New extended checksum %d\n", rsdp_mod->ExtendedChecksum);
472
473}
474
475verbose("Patched ACPI version %d DSDT\n", version+1);
476if (version)
477{
478/* XXX aserebln why uint32 cast if pointer is uint64 ? */
479acpi20_p = (uint32_t)rsdp_mod;
480addConfigurationTable(&gEfiAcpi20TableGuid, &acpi20_p, "ACPI_20");
481}
482else
483{
484/* XXX aserebln why uint32 cast if pointer is uint64 ? */
485acpi10_p = (uint32_t)rsdp_mod;
486addConfigurationTable(&gEfiAcpiTableGuid, &acpi10_p, "ACPI");
487}
488}
489#if DEBUG_DSDT
490printf("Press a key to continue... (DEBUG_DSDT)\n");
491getc();
492#endif
493return 1;
494}
495

Archive Download this file

Revision: 46