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

Archive Download this file

Revision: 77