Chameleon

Chameleon Svn Source Tree

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

Source at commit 429 created 13 years 9 months ago.
By meklort, Updated module system. Hooks can now be used within modules when cetaion functions are called in chameleon. Note that onle two hooks currently exist, more need to be added. I also updated the HelloWorld module to use a hook instead of print out right away.
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);/// Insert 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: 429