1 | /****************************************************************************** |
2 | * |
3 | * Module Name: tbinstal - ACPI table installation and removal |
4 | * |
5 | *****************************************************************************/ |
6 | |
7 | /* |
8 | * Copyright (C) 2000 - 2016, Intel Corp. |
9 | * All rights reserved. |
10 | * |
11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions |
13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions, and the following disclaimer, |
16 | * without modification. |
17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer |
18 | * substantially similar to the "NO WARRANTY" disclaimer below |
19 | * ("Disclaimer") and any redistribution must be conditioned upon |
20 | * including a substantially similar Disclaimer requirement for further |
21 | * binary redistribution. |
22 | * 3. Neither the names of the above-listed copyright holders nor the names |
23 | * of any contributors may be used to endorse or promote products derived |
24 | * from this software without specific prior written permission. |
25 | * |
26 | * Alternatively, this software may be distributed under the terms of the |
27 | * GNU General Public License ("GPL") version 2 as published by the Free |
28 | * Software Foundation. |
29 | * |
30 | * NO WARRANTY |
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
35 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
41 | * POSSIBILITY OF SUCH DAMAGES. |
42 | */ |
43 | |
44 | #include "acpi.h" |
45 | #include "accommon.h" |
46 | #include "actables.h" |
47 | |
48 | #define _COMPONENT ACPI_TABLES |
49 | ACPI_MODULE_NAME ("tbinstal" ) |
50 | |
51 | /* Local prototypes */ |
52 | |
53 | static BOOLEAN |
54 | AcpiTbCompareTables ( |
55 | ACPI_TABLE_DESC *TableDesc, |
56 | UINT32 TableIndex); |
57 | |
58 | |
59 | /******************************************************************************* |
60 | * |
61 | * FUNCTION: AcpiTbCompareTables |
62 | * |
63 | * PARAMETERS: TableDesc - Table 1 descriptor to be compared |
64 | * TableIndex - Index of table 2 to be compared |
65 | * |
66 | * RETURN: TRUE if both tables are identical. |
67 | * |
68 | * DESCRIPTION: This function compares a table with another table that has |
69 | * already been installed in the root table list. |
70 | * |
71 | ******************************************************************************/ |
72 | |
73 | static BOOLEAN |
74 | AcpiTbCompareTables ( |
75 | ACPI_TABLE_DESC *TableDesc, |
76 | UINT32 TableIndex) |
77 | { |
78 | ACPI_STATUS Status = AE_OK; |
79 | BOOLEAN IsIdentical; |
80 | ACPI_TABLE_HEADER *Table; |
81 | UINT32 TableLength; |
82 | UINT8 TableFlags; |
83 | |
84 | |
85 | Status = AcpiTbAcquireTable (&AcpiGbl_RootTableList.Tables[TableIndex], |
86 | &Table, &TableLength, &TableFlags); |
87 | if (ACPI_FAILURE (Status)) |
88 | { |
89 | return (FALSE); |
90 | } |
91 | |
92 | /* |
93 | * Check for a table match on the entire table length, |
94 | * not just the header. |
95 | */ |
96 | IsIdentical = (BOOLEAN)((TableDesc->Length != TableLength || |
97 | memcmp (TableDesc->Pointer, Table, TableLength)) ? |
98 | FALSE : TRUE); |
99 | |
100 | /* Release the acquired table */ |
101 | |
102 | AcpiTbReleaseTable (Table, TableLength, TableFlags); |
103 | return (IsIdentical); |
104 | } |
105 | |
106 | |
107 | /******************************************************************************* |
108 | * |
109 | * FUNCTION: AcpiTbInstallTableWithOverride |
110 | * |
111 | * PARAMETERS: NewTableDesc - New table descriptor to install |
112 | * Override - Whether override should be performed |
113 | * TableIndex - Where the table index is returned |
114 | * |
115 | * RETURN: None |
116 | * |
117 | * DESCRIPTION: Install an ACPI table into the global data structure. The |
118 | * table override mechanism is called to allow the host |
119 | * OS to replace any table before it is installed in the root |
120 | * table array. |
121 | * |
122 | ******************************************************************************/ |
123 | |
124 | void |
125 | AcpiTbInstallTableWithOverride ( |
126 | ACPI_TABLE_DESC *NewTableDesc, |
127 | BOOLEAN Override, |
128 | UINT32 *TableIndex) |
129 | { |
130 | UINT32 i; |
131 | ACPI_STATUS Status; |
132 | |
133 | |
134 | Status = AcpiTbGetNextTableDescriptor (&i, NULL); |
135 | if (ACPI_FAILURE (Status)) |
136 | { |
137 | return; |
138 | } |
139 | |
140 | /* |
141 | * ACPI Table Override: |
142 | * |
143 | * Before we install the table, let the host OS override it with a new |
144 | * one if desired. Any table within the RSDT/XSDT can be replaced, |
145 | * including the DSDT which is pointed to by the FADT. |
146 | */ |
147 | if (Override) |
148 | { |
149 | AcpiTbOverrideTable (NewTableDesc); |
150 | } |
151 | |
152 | AcpiTbInitTableDescriptor (&AcpiGbl_RootTableList.Tables[i], |
153 | NewTableDesc->Address, NewTableDesc->Flags, NewTableDesc->Pointer); |
154 | |
155 | AcpiTbPrintTableHeader (NewTableDesc->Address, NewTableDesc->Pointer); |
156 | |
157 | /* This synchronizes AcpiGbl_DsdtIndex */ |
158 | |
159 | *TableIndex = i; |
160 | |
161 | /* Set the global integer width (based upon revision of the DSDT) */ |
162 | |
163 | if (i == AcpiGbl_DsdtIndex) |
164 | { |
165 | AcpiUtSetIntegerWidth (NewTableDesc->Pointer->Revision); |
166 | } |
167 | } |
168 | |
169 | |
170 | /******************************************************************************* |
171 | * |
172 | * FUNCTION: AcpiTbInstallStandardTable |
173 | * |
174 | * PARAMETERS: Address - Address of the table (might be a virtual |
175 | * address depending on the TableFlags) |
176 | * Flags - Flags for the table |
177 | * Reload - Whether reload should be performed |
178 | * Override - Whether override should be performed |
179 | * TableIndex - Where the table index is returned |
180 | * |
181 | * RETURN: Status |
182 | * |
183 | * DESCRIPTION: This function is called to verify and install an ACPI table. |
184 | * When this function is called by "Load" or "LoadTable" opcodes, |
185 | * or by AcpiLoadTable() API, the "Reload" parameter is set. |
186 | * After sucessfully returning from this function, table is |
187 | * "INSTALLED" but not "VALIDATED". |
188 | * |
189 | ******************************************************************************/ |
190 | |
191 | ACPI_STATUS |
192 | AcpiTbInstallStandardTable ( |
193 | ACPI_PHYSICAL_ADDRESS Address, |
194 | UINT8 Flags, |
195 | BOOLEAN Reload, |
196 | BOOLEAN Override, |
197 | UINT32 *TableIndex) |
198 | { |
199 | UINT32 i; |
200 | ACPI_STATUS Status = AE_OK; |
201 | ACPI_TABLE_DESC NewTableDesc; |
202 | |
203 | |
204 | ACPI_FUNCTION_TRACE (TbInstallStandardTable); |
205 | |
206 | |
207 | /* Acquire a temporary table descriptor for validation */ |
208 | |
209 | Status = AcpiTbAcquireTempTable (&NewTableDesc, Address, Flags); |
210 | if (ACPI_FAILURE (Status)) |
211 | { |
212 | ACPI_ERROR ((AE_INFO, |
213 | "Could not acquire table length at %8.8X%8.8X" , |
214 | ACPI_FORMAT_UINT64 (Address))); |
215 | return_ACPI_STATUS (Status); |
216 | } |
217 | |
218 | /* |
219 | * Optionally do not load any SSDTs from the RSDT/XSDT. This can |
220 | * be useful for debugging ACPI problems on some machines. |
221 | */ |
222 | if (!Reload && |
223 | AcpiGbl_DisableSsdtTableInstall && |
224 | ACPI_COMPARE_NAME (&NewTableDesc.Signature, ACPI_SIG_SSDT)) |
225 | { |
226 | ACPI_INFO (( |
227 | "Ignoring installation of %4.4s at %8.8X%8.8X" , |
228 | NewTableDesc.Signature.Ascii, ACPI_FORMAT_UINT64 (Address))); |
229 | goto ReleaseAndExit; |
230 | } |
231 | |
232 | /* Validate and verify a table before installation */ |
233 | |
234 | Status = AcpiTbVerifyTempTable (&NewTableDesc, NULL); |
235 | if (ACPI_FAILURE (Status)) |
236 | { |
237 | goto ReleaseAndExit; |
238 | } |
239 | |
240 | if (Reload) |
241 | { |
242 | /* |
243 | * Validate the incoming table signature. |
244 | * |
245 | * 1) Originally, we checked the table signature for "SSDT" or "PSDT". |
246 | * 2) We added support for OEMx tables, signature "OEM". |
247 | * 3) Valid tables were encountered with a null signature, so we just |
248 | * gave up on validating the signature, (05/2008). |
249 | * 4) We encountered non-AML tables such as the MADT, which caused |
250 | * interpreter errors and kernel faults. So now, we once again allow |
251 | * only "SSDT", "OEMx", and now, also a null signature. (05/2011). |
252 | */ |
253 | if ((NewTableDesc.Signature.Ascii[0] != 0x00) && |
254 | (!ACPI_COMPARE_NAME (&NewTableDesc.Signature, ACPI_SIG_SSDT)) && |
255 | (strncmp (NewTableDesc.Signature.Ascii, "OEM" , 3))) |
256 | { |
257 | ACPI_BIOS_ERROR ((AE_INFO, |
258 | "Table has invalid signature [%4.4s] (0x%8.8X), " |
259 | "must be SSDT or OEMx" , |
260 | AcpiUtValidNameseg (NewTableDesc.Signature.Ascii) ? |
261 | NewTableDesc.Signature.Ascii : "????" , |
262 | NewTableDesc.Signature.Integer)); |
263 | |
264 | Status = AE_BAD_SIGNATURE; |
265 | goto ReleaseAndExit; |
266 | } |
267 | |
268 | /* Check if table is already registered */ |
269 | |
270 | for (i = 0; i < AcpiGbl_RootTableList.CurrentTableCount; ++i) |
271 | { |
272 | /* |
273 | * Check for a table match on the entire table length, |
274 | * not just the header. |
275 | */ |
276 | if (!AcpiTbCompareTables (&NewTableDesc, i)) |
277 | { |
278 | continue; |
279 | } |
280 | |
281 | /* |
282 | * Note: the current mechanism does not unregister a table if it is |
283 | * dynamically unloaded. The related namespace entries are deleted, |
284 | * but the table remains in the root table list. |
285 | * |
286 | * The assumption here is that the number of different tables that |
287 | * will be loaded is actually small, and there is minimal overhead |
288 | * in just keeping the table in case it is needed again. |
289 | * |
290 | * If this assumption changes in the future (perhaps on large |
291 | * machines with many table load/unload operations), tables will |
292 | * need to be unregistered when they are unloaded, and slots in the |
293 | * root table list should be reused when empty. |
294 | */ |
295 | if (AcpiGbl_RootTableList.Tables[i].Flags & |
296 | ACPI_TABLE_IS_LOADED) |
297 | { |
298 | /* Table is still loaded, this is an error */ |
299 | |
300 | Status = AE_ALREADY_EXISTS; |
301 | goto ReleaseAndExit; |
302 | } |
303 | else |
304 | { |
305 | /* |
306 | * Table was unloaded, allow it to be reloaded. |
307 | * As we are going to return AE_OK to the caller, we should |
308 | * take the responsibility of freeing the input descriptor. |
309 | * Refill the input descriptor to ensure |
310 | * AcpiTbInstallTableWithOverride() can be called again to |
311 | * indicate the re-installation. |
312 | */ |
313 | AcpiTbUninstallTable (&NewTableDesc); |
314 | *TableIndex = i; |
315 | return_ACPI_STATUS (AE_OK); |
316 | } |
317 | } |
318 | } |
319 | |
320 | /* Add the table to the global root table list */ |
321 | |
322 | AcpiTbInstallTableWithOverride (&NewTableDesc, Override, TableIndex); |
323 | |
324 | /* Invoke table handler if present */ |
325 | |
326 | if (AcpiGbl_TableHandler) |
327 | { |
328 | (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_INSTALL, |
329 | NewTableDesc.Pointer, AcpiGbl_TableHandlerContext); |
330 | } |
331 | |
332 | ReleaseAndExit: |
333 | |
334 | /* Release the temporary table descriptor */ |
335 | |
336 | AcpiTbReleaseTempTable (&NewTableDesc); |
337 | return_ACPI_STATUS (Status); |
338 | } |
339 | |
340 | |
341 | /******************************************************************************* |
342 | * |
343 | * FUNCTION: AcpiTbOverrideTable |
344 | * |
345 | * PARAMETERS: OldTableDesc - Validated table descriptor to be |
346 | * overridden |
347 | * |
348 | * RETURN: None |
349 | * |
350 | * DESCRIPTION: Attempt table override by calling the OSL override functions. |
351 | * Note: If the table is overridden, then the entire new table |
352 | * is acquired and returned by this function. |
353 | * Before/after invocation, the table descriptor is in a state |
354 | * that is "VALIDATED". |
355 | * |
356 | ******************************************************************************/ |
357 | |
358 | void |
359 | AcpiTbOverrideTable ( |
360 | ACPI_TABLE_DESC *OldTableDesc) |
361 | { |
362 | ACPI_STATUS Status; |
363 | const char *OverrideType; |
364 | ACPI_TABLE_DESC NewTableDesc; |
365 | ACPI_TABLE_HEADER *Table; |
366 | ACPI_PHYSICAL_ADDRESS Address; |
367 | UINT32 Length; |
368 | |
369 | |
370 | /* (1) Attempt logical override (returns a logical address) */ |
371 | |
372 | Status = AcpiOsTableOverride (OldTableDesc->Pointer, &Table); |
373 | if (ACPI_SUCCESS (Status) && Table) |
374 | { |
375 | AcpiTbAcquireTempTable (&NewTableDesc, ACPI_PTR_TO_PHYSADDR (Table), |
376 | ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL); |
377 | OverrideType = "Logical" ; |
378 | goto FinishOverride; |
379 | } |
380 | |
381 | /* (2) Attempt physical override (returns a physical address) */ |
382 | |
383 | Status = AcpiOsPhysicalTableOverride (OldTableDesc->Pointer, |
384 | &Address, &Length); |
385 | if (ACPI_SUCCESS (Status) && Address && Length) |
386 | { |
387 | AcpiTbAcquireTempTable (&NewTableDesc, Address, |
388 | ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL); |
389 | OverrideType = "Physical" ; |
390 | goto FinishOverride; |
391 | } |
392 | |
393 | return; /* There was no override */ |
394 | |
395 | |
396 | FinishOverride: |
397 | |
398 | /* Validate and verify a table before overriding */ |
399 | |
400 | Status = AcpiTbVerifyTempTable (&NewTableDesc, NULL); |
401 | if (ACPI_FAILURE (Status)) |
402 | { |
403 | return; |
404 | } |
405 | |
406 | ACPI_INFO (("%4.4s 0x%8.8X%8.8X" |
407 | " %s table override, new table: 0x%8.8X%8.8X" , |
408 | OldTableDesc->Signature.Ascii, |
409 | ACPI_FORMAT_UINT64 (OldTableDesc->Address), |
410 | OverrideType, ACPI_FORMAT_UINT64 (NewTableDesc.Address))); |
411 | |
412 | /* We can now uninstall the original table */ |
413 | |
414 | AcpiTbUninstallTable (OldTableDesc); |
415 | |
416 | /* |
417 | * Replace the original table descriptor and keep its state as |
418 | * "VALIDATED". |
419 | */ |
420 | AcpiTbInitTableDescriptor (OldTableDesc, NewTableDesc.Address, |
421 | NewTableDesc.Flags, NewTableDesc.Pointer); |
422 | AcpiTbValidateTempTable (OldTableDesc); |
423 | |
424 | /* Release the temporary table descriptor */ |
425 | |
426 | AcpiTbReleaseTempTable (&NewTableDesc); |
427 | } |
428 | |
429 | |
430 | /******************************************************************************* |
431 | * |
432 | * FUNCTION: AcpiTbUninstallTable |
433 | * |
434 | * PARAMETERS: TableDesc - Table descriptor |
435 | * |
436 | * RETURN: None |
437 | * |
438 | * DESCRIPTION: Delete one internal ACPI table |
439 | * |
440 | ******************************************************************************/ |
441 | |
442 | void |
443 | AcpiTbUninstallTable ( |
444 | ACPI_TABLE_DESC *TableDesc) |
445 | { |
446 | |
447 | ACPI_FUNCTION_TRACE (TbUninstallTable); |
448 | |
449 | |
450 | /* Table must be installed */ |
451 | |
452 | if (!TableDesc->Address) |
453 | { |
454 | return_VOID; |
455 | } |
456 | |
457 | AcpiTbInvalidateTable (TableDesc); |
458 | |
459 | if ((TableDesc->Flags & ACPI_TABLE_ORIGIN_MASK) == |
460 | ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL) |
461 | { |
462 | void *ptr = ACPI_PHYSADDR_TO_PTR (TableDesc->Address); |
463 | if (ptr) |
464 | { |
465 | ACPI_FREE (ptr); |
466 | } |
467 | } |
468 | |
469 | TableDesc->Address = ACPI_PTR_TO_PHYSADDR (NULL); |
470 | return_VOID; |
471 | } |
472 | |