Chameleon

Chameleon Svn Source Tree

Root/branches/meklort/i386/libsaio/dsdt_patcher.c

Source at commit 149 created 13 years 11 months ago.
By meklort, DSDT patcher backs up old dsdt to the IORegistery
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/** The folowing ACPI Table search algo. should be reused anywhere needed:*/
76int search_and_get_acpi_fd(const char * filename, const char ** outDirspec)
77{
78 int fd=0;
79 const char * overriden_pathname=NULL;
80 static char dirspec[512]="";
81 static bool first_time =true;
82 int len=0;
83
84 /// Take in accound user overriding if it's DSDT only
85 if (strstr(filename, "DSDT") &&
86 getValueForKey(kDSDT, &overriden_pathname, &len,
87 &bootInfo->bootConfig))
88 {
89 sprintf(dirspec, "%s", overriden_pathname);
90 fd=open (dirspec,0);
91 if (fd>=0) goto success_fd;
92 }
93 // Check that dirspec is not already assigned with a path
94 if (!first_time && *dirspec)
95 { // it is so start searching this cached patch first
96 //extract path
97 for (len=strlen(dirspec)-1; len; len--)
98 if (dirspec[len]=='/' || len==0)
99 {
100 dirspec[len]='\0';
101 break;
102 }
103 // now concat with the filename
104 strncat(dirspec, "/", sizeof(dirspec));
105 strncat(dirspec, filename, sizeof(dirspec));
106 // and test to see if we don't have our big boy here:
107 fd=open (dirspec,0);
108 if (fd>=0)
109 {
110 // printf("ACPI file search cache hit: file found at %s\n", dirspec);
111 goto success_fd;
112 }
113 }
114 // Start searching any potential location for ACPI Table
115 // search the Extra folders first
116 sprintf(dirspec,"/Extra/%s",filename);
117 fd=open (dirspec,0);
118 if (fd>=0) goto success_fd;
119
120 sprintf(dirspec,"bt(0,0)/Extra/%s",filename);
121 fd=open (dirspec,0);
122 if (fd>=0) goto success_fd;
123
124 sprintf(dirspec, "%s", filename); // search current dir
125 fd=open (dirspec,0);
126 if (fd>=0) goto success_fd;
127
128 sprintf(dirspec, "/%s", filename); // search root
129 fd=open (dirspec,0);
130 if (fd>=0) goto success_fd;
131
132 // NOT FOUND:
133 verbose("ACPI Table not found: %s\n", filename);
134 if (outDirspec) *outDirspec = "";
135 first_time = false;
136 return -1;
137 // FOUND
138success_fd:
139 first_time = false;
140 if (outDirspec) *outDirspec = dirspec;
141 return fd;
142}
143
144void *loadACPITable (const char * filename)
145{
146void *tableAddr;
147const char * dirspec=NULL;
148
149int fd = search_and_get_acpi_fd(filename, &dirspec);
150
151if (fd>=0)
152{
153 tableAddr=(void*)AllocateKernelMemory(file_size (fd));
154 if (tableAddr)
155 {
156 if (read (fd, tableAddr, file_size (fd))!=file_size (fd))
157 {
158 printf("Couldn't read table %s\n",dirspec);
159 free (tableAddr);
160 close (fd);
161 return NULL;
162 }
163
164 DBG("Table %s read and stored at: %x\n", dirspec, tableAddr);
165 close (fd);
166 return tableAddr;
167 }
168 close (fd);
169 printf("Couldn't allocate memory for table \n", dirspec);
170}
171printf("Couldn't find table %s\n", filename);
172return NULL;
173}
174
175
176struct acpi_2_fadt *
177patch_fadt(struct acpi_2_fadt *fadt, void *new_dsdt)
178{
179
180 extern void setupSystemType();
181
182struct acpi_2_fadt *fadt_mod;
183bool fadt_rev2_needed = false;
184bool fix_restart;
185const char * value;
186
187// Restart Fix
188if (Platform.CPU.Vendor == 0x756E6547) {/* Intel */
189fix_restart = true;
190getBoolForKey(kRestartFix, &fix_restart, &bootInfo->bootConfig);
191} else {
192verbose ("Not an Intel platform: Restart Fix not applied !!!\n");
193fix_restart = false;
194}
195
196if (fix_restart) fadt_rev2_needed = true;
197
198// Allocate new fadt table
199if (fadt->Length < 0x84 && fadt_rev2_needed)
200{
201fadt_mod=(struct acpi_2_fadt *)AllocateKernelMemory(0x84);
202memcpy(fadt_mod, fadt, fadt->Length);
203fadt_mod->Length = 0x84;
204fadt_mod->Revision = 0x02; // FADT rev 2 (ACPI 1.0B MS extensions)
205}
206else
207{
208fadt_mod=(struct acpi_2_fadt *)AllocateKernelMemory(fadt->Length);
209memcpy(fadt_mod, fadt, fadt->Length);
210}
211// Determine system type / PM_Model
212if ( (value=getStringForKey(kSystemType, &bootInfo->bootConfig))!=NULL)
213{
214 if (Platform.Type > 6)
215 {
216 if(fadt_mod->PM_Profile<=6)
217 Platform.Type = fadt_mod->PM_Profile; // get the fadt if correct
218 else
219 Platform.Type = 1;/* Set a fixed value (Desktop) */
220 verbose("Error: system-type must be 0..6. Defaulting to %d !\n", Platform.Type);
221 }
222 else
223 Platform.Type = (unsigned char) strtoul(value, NULL, 10);
224}
225// Set PM_Profile from System-type if only if user wanted this value to be forced
226if (fadt_mod->PM_Profile != Platform.Type)
227{
228 if (value)
229 { // user has overriden the SystemType so take care of it in FACP
230verbose("FADT: changing PM_Profile from 0x%02x to 0x%02x\n", fadt_mod->PM_Profile, Platform.Type);
231fadt_mod->PM_Profile = Platform.Type;
232 }
233 else
234 { // PM_Profile has a different value and no override has been set, so reflect the user value to ioregs
235 Platform.Type = fadt_mod->PM_Profile <= 6 ? fadt_mod->PM_Profile : 1;
236 }
237}
238// We now have to write the systemm-type in ioregs: we cannot do it before in setupDeviceTree()
239// because we need to take care of facp original content, if it is correct.
240setupSystemType();
241
242// Patch FADT to fix restart
243if (fix_restart)
244{
245fadt_mod->Flags|= 0x400;
246fadt_mod->Reset_SpaceID= 0x01; // System I/O
247fadt_mod->Reset_BitWidth= 0x08; // 1 byte
248fadt_mod->Reset_BitOffset= 0x00; // Offset 0
249fadt_mod->Reset_AccessWidth= 0x01; // Byte access
250fadt_mod->Reset_Address= 0x0cf9; // Address of the register
251fadt_mod->Reset_Value= 0x06; // Value to write to reset the system
252verbose("FADT: Restart Fix applied !\n");
253}
254
255// Save old DSDT to the IORegistery
256Node* node = DT__FindNode("/", false);
257if(node != NULL)
258{
259node = DT__AddChild(node, "dsdt");
260
261struct acpi_2_dsdt *dsdt;
262dsdt = (struct acpi_2_dsdt*) (fadt_mod->DSDT);
263DT__AddProperty(node, "originaldsdt", (dsdt->Length + sizeof(struct acpi_2_dsdt) - 1), (void*)dsdt);/// Inset old dsdt. Length is header length (36) + dsdt length
264
265}
266
267
268// Patch DSDT Address
269DBG("DSDT: Old @%x,%x, ",fadt_mod->DSDT,fadt_mod->X_DSDT);
270
271
272fadt_mod->DSDT=(uint32_t)new_dsdt;
273if ((uint32_t)(&(fadt_mod->X_DSDT))-(uint32_t)fadt_mod+8<=fadt_mod->Length)
274fadt_mod->X_DSDT=(uint32_t)new_dsdt;
275
276DBG("New @%x,%x\n",fadt_mod->DSDT,fadt_mod->X_DSDT);
277
278// Correct the checksum
279fadt_mod->Checksum=0;
280fadt_mod->Checksum=256-checksum8(fadt_mod,fadt_mod->Length);
281
282return fadt_mod;
283}
284
285/* Setup ACPI without replacing DSDT. */
286int setupAcpiNoMod()
287{
288//addConfigurationTable(&gEfiAcpiTableGuid, getAddressOfAcpiTable(), "ACPI");
289//addConfigurationTable(&gEfiAcpi20TableGuid, getAddressOfAcpi20Table(), "ACPI_20");
290/* XXX aserebln why uint32 cast if pointer is uint64 ? */
291acpi10_p = (uint32_t)getAddressOfAcpiTable();
292acpi20_p = (uint32_t)getAddressOfAcpi20Table();
293addConfigurationTable(&gEfiAcpiTableGuid, &acpi10_p, "ACPI");
294if(acpi20_p) addConfigurationTable(&gEfiAcpi20TableGuid, &acpi20_p, "ACPI_20");
295return 1;
296}
297
298/* Setup ACPI. Replace DSDT if DSDT.aml is found */
299int setupAcpi(void)
300{
301int version;
302void *new_dsdt;
303
304bool drop_ssdt;
305
306// Load replacement DSDT
307new_dsdt=loadACPITable("DSDT.aml");
308if (!new_dsdt)
309{
310return setupAcpiNoMod();
311}
312
313DBG("New DSDT Loaded in memory\n");
314
315{
316bool tmp;
317drop_ssdt=getBoolForKey(kDropSSDT, &tmp, &bootInfo->bootConfig)&&tmp;
318}
319
320// Do the same procedure for both versions of ACPI
321for (version=0; version<2; version++) {
322struct acpi_2_rsdp *rsdp, *rsdp_mod;
323struct acpi_2_rsdt *rsdt, *rsdt_mod;
324int rsdplength;
325
326// Find original rsdp
327rsdp=(struct acpi_2_rsdp *)(version?getAddressOfAcpi20Table():getAddressOfAcpiTable());
328if (!rsdp)
329{
330DBG("No ACPI version %d found. Ignoring\n", version+1);
331if (version)
332addConfigurationTable(&gEfiAcpi20TableGuid, NULL, "ACPI_20");
333else
334addConfigurationTable(&gEfiAcpiTableGuid, NULL, "ACPI");
335continue;
336}
337rsdplength=version?rsdp->Length:20;
338
339DBG("RSDP version %d found @%x. Length=%d\n",version+1,rsdp,rsdplength);
340
341/* FIXME: no check that memory allocation succeeded
342 * Copy and patch RSDP,RSDT, XSDT and FADT
343 * For more info see ACPI Specification pages 110 and following
344 */
345
346rsdp_mod=(struct acpi_2_rsdp *) AllocateKernelMemory(rsdplength);
347memcpy(rsdp_mod, rsdp, rsdplength);
348rsdt=(struct acpi_2_rsdt *)(rsdp->RsdtAddress);
349
350DBG("RSDT @%x, Length %d\n",rsdt, rsdt->Length);
351
352if (rsdt && (uint32_t)rsdt !=0xffffffff && rsdt->Length<0x10000)
353{
354uint32_t *rsdt_entries;
355int rsdt_entries_num;
356int dropoffset=0, i;
357
358rsdt_mod=(struct acpi_2_rsdt *)AllocateKernelMemory(rsdt->Length);
359memcpy (rsdt_mod, rsdt, rsdt->Length);
360rsdp_mod->RsdtAddress=(uint32_t)rsdt_mod;
361rsdt_entries_num=(rsdt_mod->Length-sizeof(struct acpi_2_rsdt))/4;
362rsdt_entries=(uint32_t *)(rsdt_mod+1);
363for (i=0;i<rsdt_entries_num;i++)
364{
365char *table=(char *)(rsdt_entries[i]);
366if (!table)
367continue;
368
369DBG("TABLE %c%c%c%c,",table[0],table[1],table[2],table[3]);
370
371rsdt_entries[i-dropoffset]=rsdt_entries[i];
372if (drop_ssdt && table[0]=='S' && table[1]=='S' && table[2]=='D' && table[3]=='T')
373{
374dropoffset++;
375continue;
376}
377if (table[0]=='D' && table[1]=='S' && table[2]=='D' && table[3]=='T')
378{
379DBG("DSDT found\n");
380rsdt_entries[i-dropoffset]=(uint32_t)new_dsdt;
381continue;
382}
383if (table[0]=='F' && table[1]=='A' && table[2]=='C' && table[3]=='P')
384{
385struct acpi_2_fadt *fadt, *fadt_mod;
386fadt=(struct acpi_2_fadt *)rsdt_entries[i];
387
388DBG("FADT found @%x, Length %d\n",fadt, fadt->Length);
389
390if (!fadt || (uint32_t)fadt == 0xffffffff || fadt->Length>0x10000)
391{
392printf("FADT incorrect. Not modified\n");
393continue;
394}
395
396fadt_mod = patch_fadt(fadt, new_dsdt);
397rsdt_entries[i-dropoffset]=(uint32_t)fadt_mod;
398continue;
399}
400}
401DBG("\n");
402
403// Correct the checksum of RSDT
404rsdt_mod->Length-=4*dropoffset;
405
406DBG("RSDT: Original checksum %d, ", rsdt_mod->Checksum);
407
408rsdt_mod->Checksum=0;
409rsdt_mod->Checksum=256-checksum8(rsdt_mod,rsdt_mod->Length);
410
411DBG("New checksum %d at %x\n", rsdt_mod->Checksum,rsdt_mod);
412}
413else
414{
415rsdp_mod->RsdtAddress=0;
416printf("RSDT not found or RSDT incorrect\n");
417}
418
419if (version)
420{
421struct acpi_2_xsdt *xsdt, *xsdt_mod;
422
423// FIXME: handle 64-bit address correctly
424
425xsdt=(struct acpi_2_xsdt*) ((uint32_t)rsdp->XsdtAddress);
426DBG("XSDT @%x;%x, Length=%d\n", (uint32_t)(rsdp->XsdtAddress>>32),(uint32_t)rsdp->XsdtAddress,
427xsdt->Length);
428if (xsdt && (uint64_t)rsdp->XsdtAddress<0xffffffff && xsdt->Length<0x10000)
429{
430uint64_t *xsdt_entries;
431int xsdt_entries_num, i;
432int dropoffset=0;
433
434xsdt_mod=(struct acpi_2_xsdt*)AllocateKernelMemory(xsdt->Length);
435memcpy(xsdt_mod, xsdt, xsdt->Length);
436rsdp_mod->XsdtAddress=(uint32_t)xsdt_mod;
437xsdt_entries_num=(xsdt_mod->Length-sizeof(struct acpi_2_xsdt))/8;
438xsdt_entries=(uint64_t *)(xsdt_mod+1);
439for (i=0;i<xsdt_entries_num;i++)
440{
441char *table=(char *)((uint32_t)(xsdt_entries[i]));
442if (!table)
443continue;
444xsdt_entries[i-dropoffset]=xsdt_entries[i];
445if (drop_ssdt && table[0]=='S' && table[1]=='S' && table[2]=='D' && table[3]=='T')
446{
447dropoffset++;
448continue;
449}
450if (table[0]=='D' && table[1]=='S' && table[2]=='D' && table[3]=='T')
451{
452DBG("DSDT found\n");
453
454xsdt_entries[i-dropoffset]=(uint32_t)new_dsdt;
455
456DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
457
458continue;
459}
460if (table[0]=='F' && table[1]=='A' && table[2]=='C' && table[3]=='P')
461{
462struct acpi_2_fadt *fadt, *fadt_mod;
463fadt=(struct acpi_2_fadt *)(uint32_t)xsdt_entries[i];
464
465DBG("FADT found @%x,%x, Length %d\n",(uint32_t)(xsdt_entries[i]>>32),fadt,
466 fadt->Length);
467
468if (!fadt || (uint64_t)xsdt_entries[i] >= 0xffffffff || fadt->Length>0x10000)
469{
470verbose("FADT incorrect or after 4GB. Dropping XSDT\n");
471goto drop_xsdt;
472}
473
474fadt_mod = patch_fadt(fadt, new_dsdt);
475xsdt_entries[i-dropoffset]=(uint32_t)fadt_mod;
476
477DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
478
479continue;
480}
481
482DBG("TABLE %c%c%c%c@%x,",table[0],table[1],table[2],table[3],xsdt_entries[i]);
483
484}
485
486// Correct the checksum of XSDT
487xsdt_mod->Length-=8*dropoffset;
488xsdt_mod->Checksum=0;
489xsdt_mod->Checksum=256-checksum8(xsdt_mod,xsdt_mod->Length);
490}
491else
492{
493drop_xsdt:
494
495DBG("About to drop XSDT\n");
496
497/*FIXME: Now we just hope that if MacOS doesn't find XSDT it reverts to RSDT.
498 * A Better strategy would be to generate
499 */
500
501rsdp_mod->XsdtAddress=0xffffffffffffffffLL;
502verbose("XSDT not found or XSDT incorrect\n");
503}
504}
505
506// Correct the checksum of RSDP
507
508DBG("RSDP: Original checksum %d, ", rsdp_mod->Checksum);
509
510rsdp_mod->Checksum=0;
511rsdp_mod->Checksum=256-checksum8(rsdp_mod,20);
512
513DBG("New checksum %d\n", rsdp_mod->Checksum);
514
515if (version)
516{
517DBG("RSDP: Original extended checksum %d", rsdp_mod->ExtendedChecksum);
518
519rsdp_mod->ExtendedChecksum=0;
520rsdp_mod->ExtendedChecksum=256-checksum8(rsdp_mod,rsdp_mod->Length);
521
522DBG("New extended checksum %d\n", rsdp_mod->ExtendedChecksum);
523
524}
525
526verbose("Patched ACPI version %d DSDT\n", version+1);
527if (version)
528{
529/* XXX aserebln why uint32 cast if pointer is uint64 ? */
530acpi20_p = (uint32_t)rsdp_mod;
531addConfigurationTable(&gEfiAcpi20TableGuid, &acpi20_p, "ACPI_20");
532}
533else
534{
535/* XXX aserebln why uint32 cast if pointer is uint64 ? */
536acpi10_p = (uint32_t)rsdp_mod;
537addConfigurationTable(&gEfiAcpiTableGuid, &acpi10_p, "ACPI");
538}
539}
540#if DEBUG_DSDT
541printf("Press a key to continue... (DEBUG_DSDT)\n");
542getc();
543#endif
544return 1;
545}
546

Archive Download this file

Revision: 149