1 | #include "libsaio.h"␊ |
2 | #include "boot.h"␊ |
3 | #include "bootstruct.h"␊ |
4 | #include "acpi.h"␊ |
5 | ␊ |
6 | #ifndef DEBUG_ACPI␊ |
7 | #define DEBUG_ACPI 1␊ |
8 | #endif␊ |
9 | ␊ |
10 | #if DEBUG_ACPI!=0␊ |
11 | #define DBG(x...) printf(x)␊ |
12 | #else␊ |
13 | #define DBG(x...)␊ |
14 | #endif␊ |
15 | ␊ |
16 | /** Search and try opening an acpi table matching a spec defined by key, should be reused anywhere needed:*/␊ |
17 | int acpiSearchAndGetFd(const char * key, const char ** outDirspec)␊ |
18 | {␊ |
19 | int fd=0;␊ |
20 | const char * overriden_pathname=NULL;␊ |
21 | char filename[64];␊ |
22 | static char dirspec[512]="";␊ |
23 | int len=0,i=0;␊ |
24 | ␊ |
25 | sprintf(filename, "%s.aml", key);␊ |
26 | ␊ |
27 | /// Take in account user overriding for 'DSDT'.aml table␊ |
28 | // and try to find <key>.aml at the same place␊ |
29 | if (getValueForKey("DSDT", &overriden_pathname, &len, ␊ |
30 | &bootInfo->bootConfig) && len>0)␊ |
31 | {␊ |
32 | strcpy(dirspec, overriden_pathname);␊ |
33 | for (i=len-1; i>=0; i--)␊ |
34 | {␊ |
35 | if (dirspec[i]=='/')␊ |
36 | {␊ |
37 | dirspec[i+1]='\0';␊ |
38 | strcat(dirspec, filename);␊ |
39 | break;␊ |
40 | }␊ |
41 | else if (i==0) // no '/' found copy filename and seek in current directory␊ |
42 | {␊ |
43 | strcpy(dirspec, filename);␊ |
44 | break;␊ |
45 | }␊ |
46 | }␊ |
47 | fd=open (dirspec,0);␊ |
48 | if (fd>=0) goto success_fd;␊ |
49 | }␊ |
50 | ␊ |
51 | // Start searching any potential location for ACPI Table␊ |
52 | sprintf(dirspec, "/%s", filename); // start searching root␊ |
53 | fd=open (dirspec,0);␊ |
54 | if (fd>=0) goto success_fd;␊ |
55 | ␊ |
56 | sprintf(dirspec, "%s", filename); // start current dir␊ |
57 | fd=open (dirspec,0);␊ |
58 | if (fd>=0) goto success_fd;␊ |
59 | ␊ |
60 | sprintf(dirspec,"/Extra/%s",filename);␊ |
61 | fd=open (dirspec,0);␊ |
62 | if (fd>=0) goto success_fd;␊ |
63 | ␊ |
64 | sprintf(dirspec,"bt(0,0)/Extra/%s",filename);␊ |
65 | fd=open (dirspec,0);␊ |
66 | if (fd>=0) goto success_fd;␊ |
67 | ␊ |
68 | // NOT FOUND:␊ |
69 | verbose("ACPI Table not found: %s\n", filename);␊ |
70 | if (outDirspec) *outDirspec = "";␊ |
71 | return -1;␊ |
72 | // FOUND␊ |
73 | success_fd:␊ |
74 | if (outDirspec) *outDirspec = dirspec; ␊ |
75 | return fd;␊ |
76 | }␊ |
77 | ␊ |
78 | /** Load a table in kernel memory and return a pointer to it if found, NULL otherwise */␊ |
79 | void *acpiLoadTable (const char * key)␊ |
80 | {␊ |
81 | void *tableAddr;␊ |
82 | const char * dirspec=NULL;␊ |
83 | ␉␊ |
84 | int fd = acpiSearchAndGetFd(key, &dirspec);␊ |
85 | ␊ |
86 | if (fd>=0)␊ |
87 | {␊ |
88 | tableAddr=(void*)AllocateKernelMemory(file_size (fd));␊ |
89 | if (tableAddr)␊ |
90 | {␊ |
91 | if (read (fd, tableAddr, file_size (fd))!=file_size (fd))␊ |
92 | {␊ |
93 | printf("Couldn't read table %s\n",dirspec);␊ |
94 | free (tableAddr);␊ |
95 | close (fd);␊ |
96 | return NULL;␊ |
97 | }␊ |
98 | ␉ ␊ |
99 | DBG("Table %s read and stored at: %x\n", dirspec, tableAddr);␊ |
100 | close (fd);␊ |
101 | return tableAddr;␊ |
102 | }␊ |
103 | close (fd);␊ |
104 | } ␊ |
105 | printf("Couldn't allocate memory for table %s\n", dirspec);␊ |
106 | return NULL;␊ |
107 | }␊ |
108 | ␊ |
109 | /** Load an SSDTx into memory, code could be factorized here using acpiSearchAndGetFd() */␊ |
110 | void * acpiLoadSSDTTable(int ssdt_number)␊ |
111 | {␊ |
112 | char filename[64];␊ |
113 | ␊ |
114 | sprintf(filename, "SSDT-%d", ssdt_number);␊ |
115 | return acpiLoadTable(filename);␊ |
116 | }␊ |
117 | ␊ |
118 | /** Gets the ACPI 1.0 RSDP address */␊ |
119 | struct acpi_2_rsdp* acpiGetAddressOfTable10()␊ |
120 | {␊ |
121 | /* TODO: Before searching the BIOS space we are supposed to search the first 1K of the EBDA */␊ |
122 | ␉␊ |
123 | void *acpi_addr = (void*)ACPI_RANGE_START;␊ |
124 | for(; acpi_addr <= (void*)ACPI_RANGE_END; acpi_addr += 16)␊ |
125 | {␊ |
126 | if(*(uint64_t *)acpi_addr == ACPI_SIGNATURE_UINT64_LE)␊ |
127 | {␊ |
128 | uint8_t csum = checksum8(acpi_addr, 20);␊ |
129 | if(csum == 0)␊ |
130 | {␊ |
131 | // Only return the table if it is a true version 1.0 table (Revision 0)␊ |
132 | if(((struct acpi_2_rsdp*)acpi_addr)->Revision == 0)␊ |
133 | return acpi_addr;␊ |
134 | }␊ |
135 | }␊ |
136 | }␊ |
137 | return NULL;␊ |
138 | }␊ |
139 | ␊ |
140 | /** Gets the ACPI 2.0 RSDP address */␊ |
141 | struct acpi_2_rsdp* acpiGetAddressOfTable20()␊ |
142 | {␊ |
143 | /* TODO: Before searching the BIOS space we are supposed to search the first 1K of the EBDA */␊ |
144 | ␉␊ |
145 | void *acpi_addr = (void*)ACPI_RANGE_START;␊ |
146 | for(; acpi_addr <= (void*)ACPI_RANGE_END; acpi_addr += 16)␊ |
147 | {␊ |
148 | if(*(uint64_t *)acpi_addr == ACPI_SIGNATURE_UINT64_LE)␊ |
149 | {␊ |
150 | uint8_t csum = checksum8(acpi_addr, 20);␊ |
151 | ␊ |
152 | /* Only assume this is a 2.0 or better table if the revision is greater than 0␊ |
153 | * NOTE: ACPI 3.0 spec only seems to say that 1.0 tables have revision 1␊ |
154 | * and that the current revision is 2.. I am going to assume that rev > 0 is 2.0.␊ |
155 | */␊ |
156 | ␊ |
157 | if(csum == 0 && (((struct acpi_2_rsdp*)acpi_addr)->Revision > 0))␊ |
158 | {␊ |
159 | uint8_t csum2 = checksum8(acpi_addr, sizeof(struct acpi_2_rsdp));␊ |
160 | if(csum2 == 0)␊ |
161 | return acpi_addr;␊ |
162 | }␊ |
163 | }␊ |
164 | }␊ |
165 | return NULL;␊ |
166 | }␊ |
167 | ␊ |
168 | /** Fills an ACPI 2.0 GAS structure */␊ |
169 | struct acpi_2_gas acpiFillGASStruct(uint32_t Address, uint8_t Length)␊ |
170 | {␊ |
171 | struct acpi_2_gas TmpGAS;␊ |
172 | ␊ |
173 | TmpGAS.Address_Space_ID = 1; /* I/O Address */␊ |
174 | ␊ |
175 | if (Address == 0)␊ |
176 | {␊ |
177 | TmpGAS.Register_Bit_Width = 0;␊ |
178 | } else {␊ |
179 | TmpGAS.Register_Bit_Width = Length * 8;␊ |
180 | }␊ |
181 | ␊ |
182 | TmpGAS.Register_Bit_Offset = 0;␊ |
183 | TmpGAS.Access_Size = 0; /* Not set for Legacy reasons... */␊ |
184 | TmpGAS.Address = (uint64_t)Address;␊ |
185 | ␊ |
186 | return(TmpGAS);␊ |
187 | }␊ |
188 | ␊ |
189 | /* Handling acpi dropped tables enumeration */␊ |
190 | ␊ |
191 | static struct ACPIDropTableEntry sACPIKeyDropTable[16];␊ |
192 | const int sACPIKeyDropTableSize = sizeof(sACPIKeyDropTableSize) / sizeof(char);␊ |
193 | static int sACPIKeyCount = 0;␊ |
194 | static bool bACPIDropTableInitialized=false;␊ |
195 | ␊ |
196 | /* initialize the the dropped table array from user specification, if not done already*/␊ |
197 | static void acpiInitializeDropTables()␊ |
198 | {␊ |
199 | if (bACPIDropTableInitialized) return;␊ |
200 | const char * dropTablesEnum = NULL;␊ |
201 | int len = 0;␊ |
202 | bool bOverride = getValueForKey(kDrop, &dropTablesEnum, &len, &bootInfo->bootConfig);␊ |
203 | bACPIDropTableInitialized = true;␊ |
204 | bzero(sACPIKeyDropTable, sACPIKeyDropTableSize);␊ |
205 | ␊ |
206 | if (!bOverride || !dropTablesEnum || len==0) return;␊ |
207 | ␊ |
208 | // Now transform the whitespace delimited enum into an array of keys:␊ |
209 | char buffer[sACPIKeyDropTableSize*8];␊ |
210 | int i,j;␊ |
211 | // skip beginning whitespaces␊ |
212 | for (i=0; i < len; i++) ␊ |
213 | if (dropTablesEnum[i]!=' ' && dropTablesEnum[i]!='\t')␊ |
214 | break;␊ |
215 | for (;i < len; i++) ␊ |
216 | {␊ |
217 | j=0;␊ |
218 | *buffer = '\0';␊ |
219 | while(i<len && dropTablesEnum[i]!=' ' && dropTablesEnum[i]!='\t')␊ |
220 | buffer[j++] = dropTablesEnum[i++];␊ |
221 | buffer[j] = '\0';␊ |
222 | if(j>0)␊ |
223 | {␊ |
224 | DBG("ACPI: Adding Key[%d]: %s\n", sACPIKeyCount, buffer);␊ |
225 | strncpy(sACPIKeyDropTable[sACPIKeyCount++].key,buffer, ACPI_KEY_MAX_SIZE);␊ |
226 | }␊ |
227 | }␊ |
228 | }␊ |
229 | ␊ |
230 | static int _current = 0;␊ |
231 | /** Get first acpi drop key*/␊ |
232 | struct ACPIDropTableEntry* acpiGetFirstDropTable()␊ |
233 | {␊ |
234 | acpiInitializeDropTables();␊ |
235 | _current = 0;␊ |
236 | return sACPIKeyCount>0 ? &sACPIKeyDropTable[0] : NULL;␊ |
237 | }␊ |
238 | ␊ |
239 | /** Get Next acpi drop key*/␊ |
240 | struct ACPIDropTableEntry* acpiGetNextDropTable()␊ |
241 | {␊ |
242 | acpiInitializeDropTables();␊ |
243 | return (_current<sACPIKeyCount) ? &sACPIKeyDropTable[_current++] : NULL;␊ |
244 | }␊ |
245 | ␊ |
246 | /* Gets and aml table name and in input and return ture if it is in the DROP list*/␊ |
247 | bool acpiIsTableDropped(const char * key)␊ |
248 | {␊ |
249 | // Note: input key can be non zero terminated␊ |
250 | struct ACPIDropTableEntry* p;␊ |
251 | for (p = acpiGetFirstDropTable(); p; p = acpiGetNextDropTable())␊ |
252 | {␊ |
253 | if (p->key[0]==key[0] && p->key[1]==key[1] && ␊ |
254 | p->key[2]==key[2] && p->key[3]==key[3])␊ |
255 | {␊ |
256 | DBG("ACPI: Key: %s found in the drop list\n", p);␊ |
257 | return true;␊ |
258 | }␊ |
259 | }␊ |
260 | DBG("ACPI: Key: %c%c%c%c NOT found in the drop list\n", p);␊ |
261 | return false;␊ |
262 | }␊ |
263 | /* Return the content of user acpi table if it has been loaded sucessfully, NULL otherwise*/␊ |
264 | void * acpiTableUserContent(const char * key)␊ |
265 | {␊ |
266 | // Note: input key can be non zero terminated␊ |
267 | struct ACPIDropTableEntry* p;␊ |
268 | for (p = acpiGetFirstDropTable(); p; p = acpiGetNextDropTable())␊ |
269 | {␊ |
270 | if (p->key[0]==key[0] && p->key[1]==key[1] && ␊ |
271 | p->key[2]==key[2] && p->key[3]==key[3])␊ |
272 | {␊ |
273 | return p->content;␊ |
274 | }␊ |
275 | }␊ |
276 | return NULL;␊ |
277 | }␊ |
278 | ␊ |
279 | /** For each table in the drop list, try to load an equivalent user table */␊ |
280 | void acpiLoadUserTables()␊ |
281 | {␊ |
282 | struct ACPIDropTableEntry* p;␊ |
283 | for (p = acpiGetFirstDropTable(); p; p = acpiGetNextDropTable())␊ |
284 | {␊ |
285 | p->content = acpiLoadTable(p->key);␊ |
286 | ␊ |
287 | if (p->content)␊ |
288 | {␊ |
289 | DBG("ACPI: User Table %s loaded in Memory\n", p->key);␊ |
290 | }␊ |
291 | }␊ |
292 | }␊ |
293 | |