1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: tbutils - ACPI Table utilities |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "actables.h" |
13 | |
14 | #define _COMPONENT ACPI_TABLES |
15 | ACPI_MODULE_NAME("tbutils" ) |
16 | |
17 | /* Local prototypes */ |
18 | static acpi_physical_address |
19 | acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); |
20 | |
21 | #if (!ACPI_REDUCED_HARDWARE) |
22 | /******************************************************************************* |
23 | * |
24 | * FUNCTION: acpi_tb_initialize_facs |
25 | * |
26 | * PARAMETERS: None |
27 | * |
28 | * RETURN: Status |
29 | * |
30 | * DESCRIPTION: Create a permanent mapping for the FADT and save it in a global |
31 | * for accessing the Global Lock and Firmware Waking Vector |
32 | * |
33 | ******************************************************************************/ |
34 | |
35 | acpi_status acpi_tb_initialize_facs(void) |
36 | { |
37 | struct acpi_table_facs *facs; |
38 | |
39 | /* If Hardware Reduced flag is set, there is no FACS */ |
40 | |
41 | if (acpi_gbl_reduced_hardware) { |
42 | acpi_gbl_FACS = NULL; |
43 | return (AE_OK); |
44 | } else if (acpi_gbl_FADT.Xfacs && |
45 | (!acpi_gbl_FADT.facs |
46 | || !acpi_gbl_use32_bit_facs_addresses)) { |
47 | (void)acpi_get_table_by_index(acpi_gbl_xfacs_index, |
48 | ACPI_CAST_INDIRECT_PTR(struct |
49 | acpi_table_header, |
50 | &facs)); |
51 | acpi_gbl_FACS = facs; |
52 | } else if (acpi_gbl_FADT.facs) { |
53 | (void)acpi_get_table_by_index(acpi_gbl_facs_index, |
54 | ACPI_CAST_INDIRECT_PTR(struct |
55 | acpi_table_header, |
56 | &facs)); |
57 | acpi_gbl_FACS = facs; |
58 | } |
59 | |
60 | /* If there is no FACS, just continue. There was already an error msg */ |
61 | |
62 | return (AE_OK); |
63 | } |
64 | #endif /* !ACPI_REDUCED_HARDWARE */ |
65 | |
66 | /******************************************************************************* |
67 | * |
68 | * FUNCTION: acpi_tb_check_dsdt_header |
69 | * |
70 | * PARAMETERS: None |
71 | * |
72 | * RETURN: None |
73 | * |
74 | * DESCRIPTION: Quick compare to check validity of the DSDT. This will detect |
75 | * if the DSDT has been replaced from outside the OS and/or if |
76 | * the DSDT header has been corrupted. |
77 | * |
78 | ******************************************************************************/ |
79 | |
80 | void (void) |
81 | { |
82 | |
83 | /* Compare original length and checksum to current values */ |
84 | |
85 | if (acpi_gbl_original_dsdt_header.length != acpi_gbl_DSDT->length || |
86 | acpi_gbl_original_dsdt_header.checksum != acpi_gbl_DSDT->checksum) { |
87 | ACPI_BIOS_ERROR((AE_INFO, |
88 | "The DSDT has been corrupted or replaced - " |
89 | "old, new headers below" )); |
90 | |
91 | acpi_tb_print_table_header(address: 0, header: &acpi_gbl_original_dsdt_header); |
92 | acpi_tb_print_table_header(address: 0, header: acpi_gbl_DSDT); |
93 | |
94 | ACPI_ERROR((AE_INFO, |
95 | "Please send DMI info to linux-acpi@vger.kernel.org\n" |
96 | "If system does not work as expected, please boot with acpi=copy_dsdt" )); |
97 | |
98 | /* Disable further error messages */ |
99 | |
100 | acpi_gbl_original_dsdt_header.length = acpi_gbl_DSDT->length; |
101 | acpi_gbl_original_dsdt_header.checksum = |
102 | acpi_gbl_DSDT->checksum; |
103 | } |
104 | } |
105 | |
106 | /******************************************************************************* |
107 | * |
108 | * FUNCTION: acpi_tb_copy_dsdt |
109 | * |
110 | * PARAMETERS: table_index - Index of installed table to copy |
111 | * |
112 | * RETURN: The copied DSDT |
113 | * |
114 | * DESCRIPTION: Implements a subsystem option to copy the DSDT to local memory. |
115 | * Some very bad BIOSs are known to either corrupt the DSDT or |
116 | * install a new, bad DSDT. This copy works around the problem. |
117 | * |
118 | ******************************************************************************/ |
119 | |
120 | struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) |
121 | { |
122 | struct acpi_table_header *new_table; |
123 | struct acpi_table_desc *table_desc; |
124 | |
125 | table_desc = &acpi_gbl_root_table_list.tables[table_index]; |
126 | |
127 | new_table = ACPI_ALLOCATE(table_desc->length); |
128 | if (!new_table) { |
129 | ACPI_ERROR((AE_INFO, "Could not copy DSDT of length 0x%X" , |
130 | table_desc->length)); |
131 | return (NULL); |
132 | } |
133 | |
134 | memcpy(new_table, table_desc->pointer, table_desc->length); |
135 | acpi_tb_uninstall_table(table_desc); |
136 | |
137 | acpi_tb_init_table_descriptor(table_desc: &acpi_gbl_root_table_list. |
138 | tables[acpi_gbl_dsdt_index], |
139 | ACPI_PTR_TO_PHYSADDR(new_table), |
140 | ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, |
141 | table: new_table); |
142 | |
143 | ACPI_INFO(("Forced DSDT copy: length 0x%05X copied locally, original unmapped" , new_table->length)); |
144 | |
145 | return (new_table); |
146 | } |
147 | |
148 | /******************************************************************************* |
149 | * |
150 | * FUNCTION: acpi_tb_get_root_table_entry |
151 | * |
152 | * PARAMETERS: table_entry - Pointer to the RSDT/XSDT table entry |
153 | * table_entry_size - sizeof 32 or 64 (RSDT or XSDT) |
154 | * |
155 | * RETURN: Physical address extracted from the root table |
156 | * |
157 | * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on |
158 | * both 32-bit and 64-bit platforms |
159 | * |
160 | * NOTE: acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on |
161 | * 64-bit platforms. |
162 | * |
163 | ******************************************************************************/ |
164 | |
165 | static acpi_physical_address |
166 | acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size) |
167 | { |
168 | u32 address32; |
169 | u64 address64; |
170 | |
171 | /* |
172 | * Get the table physical address (32-bit for RSDT, 64-bit for XSDT): |
173 | * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT |
174 | */ |
175 | if (table_entry_size == ACPI_RSDT_ENTRY_SIZE) { |
176 | /* |
177 | * 32-bit platform, RSDT: Return 32-bit table entry |
178 | * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return |
179 | */ |
180 | ACPI_MOVE_32_TO_32(&address32, table_entry); |
181 | return address32; |
182 | } else { |
183 | /* |
184 | * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return |
185 | * 64-bit platform, XSDT: Move (unaligned) 64-bit to local, |
186 | * return 64-bit |
187 | */ |
188 | ACPI_MOVE_64_TO_64(&address64, table_entry); |
189 | |
190 | #if ACPI_MACHINE_WIDTH == 32 |
191 | if (address64 > ACPI_UINT32_MAX) { |
192 | |
193 | /* Will truncate 64-bit address to 32 bits, issue warning */ |
194 | |
195 | ACPI_BIOS_WARNING((AE_INFO, |
196 | "64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X)," |
197 | " truncating" , |
198 | ACPI_FORMAT_UINT64(address64))); |
199 | } |
200 | #endif |
201 | return ((acpi_physical_address)(address64)); |
202 | } |
203 | } |
204 | |
205 | /******************************************************************************* |
206 | * |
207 | * FUNCTION: acpi_tb_parse_root_table |
208 | * |
209 | * PARAMETERS: rsdp_address - Pointer to the RSDP |
210 | * |
211 | * RETURN: Status |
212 | * |
213 | * DESCRIPTION: This function is called to parse the Root System Description |
214 | * Table (RSDT or XSDT) |
215 | * |
216 | * NOTE: Tables are mapped (not copied) for efficiency. The FACS must |
217 | * be mapped and cannot be copied because it contains the actual |
218 | * memory location of the ACPI Global Lock. |
219 | * |
220 | ******************************************************************************/ |
221 | |
222 | acpi_status ACPI_INIT_FUNCTION |
223 | acpi_tb_parse_root_table(acpi_physical_address rsdp_address) |
224 | { |
225 | struct acpi_table_rsdp *rsdp; |
226 | u32 table_entry_size; |
227 | u32 i; |
228 | u32 table_count; |
229 | struct acpi_table_header *table; |
230 | acpi_physical_address address; |
231 | u32 length; |
232 | u8 *table_entry; |
233 | acpi_status status; |
234 | u32 table_index; |
235 | |
236 | ACPI_FUNCTION_TRACE(tb_parse_root_table); |
237 | |
238 | /* Map the entire RSDP and extract the address of the RSDT or XSDT */ |
239 | |
240 | rsdp = acpi_os_map_memory(where: rsdp_address, length: sizeof(struct acpi_table_rsdp)); |
241 | if (!rsdp) { |
242 | return_ACPI_STATUS(AE_NO_MEMORY); |
243 | } |
244 | |
245 | acpi_tb_print_table_header(address: rsdp_address, |
246 | ACPI_CAST_PTR(struct acpi_table_header, |
247 | rsdp)); |
248 | |
249 | /* Use XSDT if present and not overridden. Otherwise, use RSDT */ |
250 | |
251 | if ((rsdp->revision > 1) && |
252 | rsdp->xsdt_physical_address && !acpi_gbl_do_not_use_xsdt) { |
253 | /* |
254 | * RSDP contains an XSDT (64-bit physical addresses). We must use |
255 | * the XSDT if the revision is > 1 and the XSDT pointer is present, |
256 | * as per the ACPI specification. |
257 | */ |
258 | address = (acpi_physical_address)rsdp->xsdt_physical_address; |
259 | table_entry_size = ACPI_XSDT_ENTRY_SIZE; |
260 | } else { |
261 | /* Root table is an RSDT (32-bit physical addresses) */ |
262 | |
263 | address = (acpi_physical_address)rsdp->rsdt_physical_address; |
264 | table_entry_size = ACPI_RSDT_ENTRY_SIZE; |
265 | } |
266 | |
267 | /* |
268 | * It is not possible to map more than one entry in some environments, |
269 | * so unmap the RSDP here before mapping other tables |
270 | */ |
271 | acpi_os_unmap_memory(logical_address: rsdp, size: sizeof(struct acpi_table_rsdp)); |
272 | |
273 | /* Map the RSDT/XSDT table header to get the full table length */ |
274 | |
275 | table = acpi_os_map_memory(where: address, length: sizeof(struct acpi_table_header)); |
276 | if (!table) { |
277 | return_ACPI_STATUS(AE_NO_MEMORY); |
278 | } |
279 | |
280 | acpi_tb_print_table_header(address, header: table); |
281 | |
282 | /* |
283 | * Validate length of the table, and map entire table. |
284 | * Minimum length table must contain at least one entry. |
285 | */ |
286 | length = table->length; |
287 | acpi_os_unmap_memory(logical_address: table, size: sizeof(struct acpi_table_header)); |
288 | |
289 | if (length < (sizeof(struct acpi_table_header) + table_entry_size)) { |
290 | ACPI_BIOS_ERROR((AE_INFO, |
291 | "Invalid table length 0x%X in RSDT/XSDT" , |
292 | length)); |
293 | return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); |
294 | } |
295 | |
296 | table = acpi_os_map_memory(where: address, length); |
297 | if (!table) { |
298 | return_ACPI_STATUS(AE_NO_MEMORY); |
299 | } |
300 | |
301 | /* Validate the root table checksum */ |
302 | |
303 | status = acpi_ut_verify_checksum(table, length); |
304 | if (ACPI_FAILURE(status)) { |
305 | acpi_os_unmap_memory(logical_address: table, size: length); |
306 | return_ACPI_STATUS(status); |
307 | } |
308 | |
309 | /* Get the number of entries and pointer to first entry */ |
310 | |
311 | table_count = (u32)((table->length - sizeof(struct acpi_table_header)) / |
312 | table_entry_size); |
313 | table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header)); |
314 | |
315 | /* Initialize the root table array from the RSDT/XSDT */ |
316 | |
317 | for (i = 0; i < table_count; i++) { |
318 | |
319 | /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */ |
320 | |
321 | address = |
322 | acpi_tb_get_root_table_entry(table_entry, table_entry_size); |
323 | |
324 | /* Skip NULL entries in RSDT/XSDT */ |
325 | |
326 | if (!address) { |
327 | goto next_table; |
328 | } |
329 | |
330 | status = acpi_tb_install_standard_table(address, |
331 | ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, |
332 | NULL, FALSE, TRUE, |
333 | table_index: &table_index); |
334 | |
335 | if (ACPI_SUCCESS(status) && |
336 | ACPI_COMPARE_NAMESEG(&acpi_gbl_root_table_list. |
337 | tables[table_index].signature, |
338 | ACPI_SIG_FADT)) { |
339 | acpi_gbl_fadt_index = table_index; |
340 | acpi_tb_parse_fadt(); |
341 | } |
342 | |
343 | next_table: |
344 | |
345 | table_entry += table_entry_size; |
346 | } |
347 | |
348 | acpi_os_unmap_memory(logical_address: table, size: length); |
349 | return_ACPI_STATUS(AE_OK); |
350 | } |
351 | |
352 | /******************************************************************************* |
353 | * |
354 | * FUNCTION: acpi_tb_get_table |
355 | * |
356 | * PARAMETERS: table_desc - Table descriptor |
357 | * out_table - Where the pointer to the table is returned |
358 | * |
359 | * RETURN: Status and pointer to the requested table |
360 | * |
361 | * DESCRIPTION: Increase a reference to a table descriptor and return the |
362 | * validated table pointer. |
363 | * If the table descriptor is an entry of the root table list, |
364 | * this API must be invoked with ACPI_MTX_TABLES acquired. |
365 | * |
366 | ******************************************************************************/ |
367 | |
368 | acpi_status |
369 | acpi_tb_get_table(struct acpi_table_desc *table_desc, |
370 | struct acpi_table_header **out_table) |
371 | { |
372 | acpi_status status; |
373 | |
374 | ACPI_FUNCTION_TRACE(acpi_tb_get_table); |
375 | |
376 | if (table_desc->validation_count == 0) { |
377 | |
378 | /* Table need to be "VALIDATED" */ |
379 | |
380 | status = acpi_tb_validate_table(table_desc); |
381 | if (ACPI_FAILURE(status)) { |
382 | return_ACPI_STATUS(status); |
383 | } |
384 | } |
385 | |
386 | if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) { |
387 | table_desc->validation_count++; |
388 | |
389 | /* |
390 | * Detect validation_count overflows to ensure that the warning |
391 | * message will only be printed once. |
392 | */ |
393 | if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) { |
394 | ACPI_WARNING((AE_INFO, |
395 | "Table %p, Validation count overflows\n" , |
396 | table_desc)); |
397 | } |
398 | } |
399 | |
400 | *out_table = table_desc->pointer; |
401 | return_ACPI_STATUS(AE_OK); |
402 | } |
403 | |
404 | /******************************************************************************* |
405 | * |
406 | * FUNCTION: acpi_tb_put_table |
407 | * |
408 | * PARAMETERS: table_desc - Table descriptor |
409 | * |
410 | * RETURN: None |
411 | * |
412 | * DESCRIPTION: Decrease a reference to a table descriptor and release the |
413 | * validated table pointer if no references. |
414 | * If the table descriptor is an entry of the root table list, |
415 | * this API must be invoked with ACPI_MTX_TABLES acquired. |
416 | * |
417 | ******************************************************************************/ |
418 | |
419 | void acpi_tb_put_table(struct acpi_table_desc *table_desc) |
420 | { |
421 | |
422 | ACPI_FUNCTION_TRACE(acpi_tb_put_table); |
423 | |
424 | if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) { |
425 | table_desc->validation_count--; |
426 | |
427 | /* |
428 | * Detect validation_count underflows to ensure that the warning |
429 | * message will only be printed once. |
430 | */ |
431 | if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) { |
432 | ACPI_WARNING((AE_INFO, |
433 | "Table %p, Validation count underflows\n" , |
434 | table_desc)); |
435 | return_VOID; |
436 | } |
437 | } |
438 | |
439 | if (table_desc->validation_count == 0) { |
440 | |
441 | /* Table need to be "INVALIDATED" */ |
442 | |
443 | acpi_tb_invalidate_table(table_desc); |
444 | } |
445 | |
446 | return_VOID; |
447 | } |
448 | |