Branch data Line data Source code
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 - 2020, 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 : 13 : acpi_status acpi_tb_initialize_facs(void)
36 : : {
37 : 13 : struct acpi_table_facs *facs;
38 : :
39 : : /* If Hardware Reduced flag is set, there is no FACS */
40 : :
41 [ - + ]: 13 : if (acpi_gbl_reduced_hardware) {
42 : 0 : acpi_gbl_FACS = NULL;
43 : 0 : return (AE_OK);
44 [ - + ]: 13 : } else if (acpi_gbl_FADT.Xfacs &&
45 [ # # ]: 0 : (!acpi_gbl_FADT.facs
46 [ # # ]: 0 : || !acpi_gbl_use32_bit_facs_addresses)) {
47 : 0 : (void)acpi_get_table_by_index(acpi_gbl_xfacs_index,
48 : : ACPI_CAST_INDIRECT_PTR(struct
49 : : acpi_table_header,
50 : : &facs));
51 : 0 : acpi_gbl_FACS = facs;
52 [ + - ]: 13 : } else if (acpi_gbl_FADT.facs) {
53 : 13 : (void)acpi_get_table_by_index(acpi_gbl_facs_index,
54 : : ACPI_CAST_INDIRECT_PTR(struct
55 : : acpi_table_header,
56 : : &facs));
57 : 13 : 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 : 949 : void acpi_tb_check_dsdt_header(void)
81 : : {
82 : :
83 : : /* Compare original length and checksum to current values */
84 : :
85 [ + - ]: 949 : if (acpi_gbl_original_dsdt_header.length != acpi_gbl_DSDT->length ||
86 [ - + ]: 949 : acpi_gbl_original_dsdt_header.checksum != acpi_gbl_DSDT->checksum) {
87 : 0 : ACPI_BIOS_ERROR((AE_INFO,
88 : : "The DSDT has been corrupted or replaced - "
89 : : "old, new headers below"));
90 : :
91 : 0 : acpi_tb_print_table_header(0, &acpi_gbl_original_dsdt_header);
92 : 0 : acpi_tb_print_table_header(0, acpi_gbl_DSDT);
93 : :
94 : 0 : 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 : 0 : acpi_gbl_original_dsdt_header.length = acpi_gbl_DSDT->length;
101 : 0 : acpi_gbl_original_dsdt_header.checksum =
102 : 0 : acpi_gbl_DSDT->checksum;
103 : : }
104 : 949 : }
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 : 0 : struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index)
121 : : {
122 : 0 : struct acpi_table_header *new_table;
123 : 0 : struct acpi_table_desc *table_desc;
124 : :
125 : 0 : table_desc = &acpi_gbl_root_table_list.tables[table_index];
126 : :
127 : 0 : new_table = ACPI_ALLOCATE(table_desc->length);
128 [ # # ]: 0 : if (!new_table) {
129 : 0 : ACPI_ERROR((AE_INFO, "Could not copy DSDT of length 0x%X",
130 : : table_desc->length));
131 : 0 : return (NULL);
132 : : }
133 : :
134 : 0 : memcpy(new_table, table_desc->pointer, table_desc->length);
135 : 0 : acpi_tb_uninstall_table(table_desc);
136 : :
137 : 0 : acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.
138 : 0 : tables[acpi_gbl_dsdt_index],
139 : : ACPI_PTR_TO_PHYSADDR(new_table),
140 : : ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
141 : : new_table);
142 : :
143 : 0 : ACPI_INFO(("Forced DSDT copy: length 0x%05X copied locally, original unmapped", new_table->length));
144 : :
145 : 0 : 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 : 39 : acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)
167 : : {
168 : 39 : u64 address64;
169 : :
170 : : /*
171 : : * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
172 : : * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
173 : : */
174 : 39 : if (table_entry_size == ACPI_RSDT_ENTRY_SIZE) {
175 : : /*
176 : : * 32-bit platform, RSDT: Return 32-bit table entry
177 : : * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
178 : : */
179 : 39 : return ((acpi_physical_address)
180 : 39 : (*ACPI_CAST_PTR(u32, table_entry)));
181 : : } else {
182 : : /*
183 : : * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
184 : : * 64-bit platform, XSDT: Move (unaligned) 64-bit to local,
185 : : * return 64-bit
186 : : */
187 : 0 : ACPI_MOVE_64_TO_64(&address64, table_entry);
188 : :
189 : : #if ACPI_MACHINE_WIDTH == 32
190 : : if (address64 > ACPI_UINT32_MAX) {
191 : :
192 : : /* Will truncate 64-bit address to 32 bits, issue warning */
193 : :
194 : : ACPI_BIOS_WARNING((AE_INFO,
195 : : "64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X),"
196 : : " truncating",
197 : : ACPI_FORMAT_UINT64(address64)));
198 : : }
199 : : #endif
200 : 0 : return ((acpi_physical_address)(address64));
201 : : }
202 : : }
203 : :
204 : : /*******************************************************************************
205 : : *
206 : : * FUNCTION: acpi_tb_parse_root_table
207 : : *
208 : : * PARAMETERS: rsdp_address - Pointer to the RSDP
209 : : *
210 : : * RETURN: Status
211 : : *
212 : : * DESCRIPTION: This function is called to parse the Root System Description
213 : : * Table (RSDT or XSDT)
214 : : *
215 : : * NOTE: Tables are mapped (not copied) for efficiency. The FACS must
216 : : * be mapped and cannot be copied because it contains the actual
217 : : * memory location of the ACPI Global Lock.
218 : : *
219 : : ******************************************************************************/
220 : :
221 : : acpi_status ACPI_INIT_FUNCTION
222 : 13 : acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
223 : : {
224 : 13 : struct acpi_table_rsdp *rsdp;
225 : 13 : u32 table_entry_size;
226 : 13 : u32 i;
227 : 13 : u32 table_count;
228 : 13 : struct acpi_table_header *table;
229 : 13 : acpi_physical_address address;
230 : 13 : u32 length;
231 : 13 : u8 *table_entry;
232 : 13 : acpi_status status;
233 : 13 : u32 table_index;
234 : :
235 : 13 : ACPI_FUNCTION_TRACE(tb_parse_root_table);
236 : :
237 : : /* Map the entire RSDP and extract the address of the RSDT or XSDT */
238 : :
239 : 13 : rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
240 [ + - ]: 13 : if (!rsdp) {
241 : : return_ACPI_STATUS(AE_NO_MEMORY);
242 : : }
243 : :
244 : 13 : acpi_tb_print_table_header(rsdp_address,
245 : : ACPI_CAST_PTR(struct acpi_table_header,
246 : : rsdp));
247 : :
248 : : /* Use XSDT if present and not overridden. Otherwise, use RSDT */
249 : :
250 [ - + ]: 13 : if ((rsdp->revision > 1) &&
251 [ # # # # ]: 0 : rsdp->xsdt_physical_address && !acpi_gbl_do_not_use_xsdt) {
252 : : /*
253 : : * RSDP contains an XSDT (64-bit physical addresses). We must use
254 : : * the XSDT if the revision is > 1 and the XSDT pointer is present,
255 : : * as per the ACPI specification.
256 : : */
257 : : address = (acpi_physical_address)rsdp->xsdt_physical_address;
258 : : table_entry_size = ACPI_XSDT_ENTRY_SIZE;
259 : : } else {
260 : : /* Root table is an RSDT (32-bit physical addresses) */
261 : :
262 : 13 : address = (acpi_physical_address)rsdp->rsdt_physical_address;
263 : 13 : table_entry_size = ACPI_RSDT_ENTRY_SIZE;
264 : : }
265 : :
266 : : /*
267 : : * It is not possible to map more than one entry in some environments,
268 : : * so unmap the RSDP here before mapping other tables
269 : : */
270 : 13 : acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
271 : :
272 : : /* Map the RSDT/XSDT table header to get the full table length */
273 : :
274 : 13 : table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
275 [ + - ]: 13 : if (!table) {
276 : : return_ACPI_STATUS(AE_NO_MEMORY);
277 : : }
278 : :
279 : 13 : acpi_tb_print_table_header(address, table);
280 : :
281 : : /*
282 : : * Validate length of the table, and map entire table.
283 : : * Minimum length table must contain at least one entry.
284 : : */
285 : 13 : length = table->length;
286 : 13 : acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
287 : :
288 [ - + ]: 13 : if (length < (sizeof(struct acpi_table_header) + table_entry_size)) {
289 : 0 : ACPI_BIOS_ERROR((AE_INFO,
290 : : "Invalid table length 0x%X in RSDT/XSDT",
291 : : length));
292 : 0 : return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
293 : : }
294 : :
295 : 13 : table = acpi_os_map_memory(address, length);
296 [ + - ]: 13 : if (!table) {
297 : : return_ACPI_STATUS(AE_NO_MEMORY);
298 : : }
299 : :
300 : : /* Validate the root table checksum */
301 : :
302 : 13 : status = acpi_tb_verify_checksum(table, length);
303 [ - + ]: 13 : if (ACPI_FAILURE(status)) {
304 : 0 : acpi_os_unmap_memory(table, length);
305 : 0 : return_ACPI_STATUS(status);
306 : : }
307 : :
308 : : /* Get the number of entries and pointer to first entry */
309 : :
310 : 13 : table_count = (u32)((table->length - sizeof(struct acpi_table_header)) /
311 : : table_entry_size);
312 : 13 : table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header));
313 : :
314 : : /* Initialize the root table array from the RSDT/XSDT */
315 : :
316 [ + + ]: 52 : for (i = 0; i < table_count; i++) {
317 : :
318 : : /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
319 : :
320 [ + - ]: 39 : address =
321 : : acpi_tb_get_root_table_entry(table_entry, table_entry_size);
322 : :
323 : : /* Skip NULL entries in RSDT/XSDT */
324 : :
325 [ - + ]: 39 : if (!address) {
326 : 0 : goto next_table;
327 : : }
328 : :
329 : 39 : status = acpi_tb_install_standard_table(address,
330 : : ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
331 : : FALSE, TRUE,
332 : : &table_index);
333 : :
334 [ - + ]: 39 : if (ACPI_SUCCESS(status) &&
335 [ + + ]: 39 : ACPI_COMPARE_NAMESEG(&acpi_gbl_root_table_list.
336 : : tables[table_index].signature,
337 : : ACPI_SIG_FADT)) {
338 : 13 : acpi_gbl_fadt_index = table_index;
339 : 13 : acpi_tb_parse_fadt();
340 : : }
341 : :
342 : 26 : next_table:
343 : :
344 : 39 : table_entry += table_entry_size;
345 : : }
346 : :
347 : 13 : acpi_os_unmap_memory(table, length);
348 : 13 : return_ACPI_STATUS(AE_OK);
349 : : }
350 : :
351 : : /*******************************************************************************
352 : : *
353 : : * FUNCTION: acpi_tb_get_table
354 : : *
355 : : * PARAMETERS: table_desc - Table descriptor
356 : : * out_table - Where the pointer to the table is returned
357 : : *
358 : : * RETURN: Status and pointer to the requested table
359 : : *
360 : : * DESCRIPTION: Increase a reference to a table descriptor and return the
361 : : * validated table pointer.
362 : : * If the table descriptor is an entry of the root table list,
363 : : * this API must be invoked with ACPI_MTX_TABLES acquired.
364 : : *
365 : : ******************************************************************************/
366 : :
367 : : acpi_status
368 : 286 : acpi_tb_get_table(struct acpi_table_desc *table_desc,
369 : : struct acpi_table_header **out_table)
370 : : {
371 : 286 : acpi_status status;
372 : :
373 : 286 : ACPI_FUNCTION_TRACE(acpi_tb_get_table);
374 : :
375 [ + + ]: 286 : if (table_desc->validation_count == 0) {
376 : :
377 : : /* Table need to be "VALIDATED" */
378 : :
379 : 234 : status = acpi_tb_validate_table(table_desc);
380 [ + - ]: 234 : if (ACPI_FAILURE(status)) {
381 : : return_ACPI_STATUS(status);
382 : : }
383 : : }
384 : :
385 [ + - ]: 286 : if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
386 : 286 : table_desc->validation_count++;
387 : :
388 : : /*
389 : : * Detect validation_count overflows to ensure that the warning
390 : : * message will only be printed once.
391 : : */
392 [ - + ]: 286 : if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) {
393 : 0 : ACPI_WARNING((AE_INFO,
394 : : "Table %p, Validation count overflows\n",
395 : : table_desc));
396 : : }
397 : : }
398 : :
399 : 286 : *out_table = table_desc->pointer;
400 : 286 : return_ACPI_STATUS(AE_OK);
401 : : }
402 : :
403 : : /*******************************************************************************
404 : : *
405 : : * FUNCTION: acpi_tb_put_table
406 : : *
407 : : * PARAMETERS: table_desc - Table descriptor
408 : : *
409 : : * RETURN: None
410 : : *
411 : : * DESCRIPTION: Decrease a reference to a table descriptor and release the
412 : : * validated table pointer if no references.
413 : : * If the table descriptor is an entry of the root table list,
414 : : * this API must be invoked with ACPI_MTX_TABLES acquired.
415 : : *
416 : : ******************************************************************************/
417 : :
418 : 169 : void acpi_tb_put_table(struct acpi_table_desc *table_desc)
419 : : {
420 : :
421 : 169 : ACPI_FUNCTION_TRACE(acpi_tb_put_table);
422 : :
423 [ + - ]: 169 : if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
424 : 169 : table_desc->validation_count--;
425 : :
426 : : /*
427 : : * Detect validation_count underflows to ensure that the warning
428 : : * message will only be printed once.
429 : : */
430 [ - + ]: 169 : if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) {
431 : 0 : ACPI_WARNING((AE_INFO,
432 : : "Table %p, Validation count underflows\n",
433 : : table_desc));
434 : 0 : return_VOID;
435 : : }
436 : : }
437 : :
438 [ + - ]: 169 : if (table_desc->validation_count == 0) {
439 : :
440 : : /* Table need to be "INVALIDATED" */
441 : :
442 : 169 : acpi_tb_invalidate_table(table_desc);
443 : : }
444 : :
445 : : return_VOID;
446 : : }
|