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

Archive Download this file

Revision: 60