diff options
Diffstat (limited to 'tools/power/acpi/os_specific/service_layers/oslinuxtbl.c')
-rw-r--r-- | tools/power/acpi/os_specific/service_layers/oslinuxtbl.c | 1329 |
1 files changed, 1329 insertions, 0 deletions
diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c new file mode 100644 index 000000000000..28c52008e854 --- /dev/null +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c | |||
@@ -0,0 +1,1329 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables | ||
4 | * | ||
5 | *****************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2014, 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 "acpidump.h" | ||
45 | |||
46 | #define _COMPONENT ACPI_OS_SERVICES | ||
47 | ACPI_MODULE_NAME("oslinuxtbl") | ||
48 | |||
49 | #ifndef PATH_MAX | ||
50 | #define PATH_MAX 256 | ||
51 | #endif | ||
52 | /* List of information about obtained ACPI tables */ | ||
53 | typedef struct osl_table_info { | ||
54 | struct osl_table_info *next; | ||
55 | u32 instance; | ||
56 | char signature[ACPI_NAME_SIZE]; | ||
57 | |||
58 | } osl_table_info; | ||
59 | |||
60 | /* Local prototypes */ | ||
61 | |||
62 | static acpi_status osl_table_initialize(void); | ||
63 | |||
64 | static acpi_status | ||
65 | osl_table_name_from_file(char *filename, char *signature, u32 *instance); | ||
66 | |||
67 | static acpi_status osl_add_table_to_list(char *signature, u32 instance); | ||
68 | |||
69 | static acpi_status | ||
70 | osl_read_table_from_file(char *filename, | ||
71 | acpi_size file_offset, | ||
72 | char *signature, struct acpi_table_header **table); | ||
73 | |||
74 | static acpi_status | ||
75 | osl_map_table(acpi_size address, | ||
76 | char *signature, struct acpi_table_header **table); | ||
77 | |||
78 | static void osl_unmap_table(struct acpi_table_header *table); | ||
79 | |||
80 | static acpi_physical_address osl_find_rsdp_via_efi(void); | ||
81 | |||
82 | static acpi_status osl_load_rsdp(void); | ||
83 | |||
84 | static acpi_status osl_list_customized_tables(char *directory); | ||
85 | |||
86 | static acpi_status | ||
87 | osl_get_customized_table(char *pathname, | ||
88 | char *signature, | ||
89 | u32 instance, | ||
90 | struct acpi_table_header **table, | ||
91 | acpi_physical_address * address); | ||
92 | |||
93 | static acpi_status osl_list_bios_tables(void); | ||
94 | |||
95 | static acpi_status | ||
96 | osl_get_bios_table(char *signature, | ||
97 | u32 instance, | ||
98 | struct acpi_table_header **table, | ||
99 | acpi_physical_address * address); | ||
100 | |||
101 | static acpi_status osl_get_last_status(acpi_status default_status); | ||
102 | |||
103 | /* File locations */ | ||
104 | |||
105 | #define DYNAMIC_TABLE_DIR "/sys/firmware/acpi/tables/dynamic" | ||
106 | #define STATIC_TABLE_DIR "/sys/firmware/acpi/tables" | ||
107 | #define EFI_SYSTAB "/sys/firmware/efi/systab" | ||
108 | |||
109 | /* Should we get dynamically loaded SSDTs from DYNAMIC_TABLE_DIR? */ | ||
110 | |||
111 | u8 gbl_dump_dynamic_tables = TRUE; | ||
112 | |||
113 | /* Initialization flags */ | ||
114 | |||
115 | u8 gbl_table_list_initialized = FALSE; | ||
116 | |||
117 | /* Local copies of main ACPI tables */ | ||
118 | |||
119 | struct acpi_table_rsdp gbl_rsdp; | ||
120 | struct acpi_table_fadt *gbl_fadt = NULL; | ||
121 | struct acpi_table_rsdt *gbl_rsdt = NULL; | ||
122 | struct acpi_table_xsdt *gbl_xsdt = NULL; | ||
123 | |||
124 | /* Table addresses */ | ||
125 | |||
126 | acpi_physical_address gbl_fadt_address = 0; | ||
127 | acpi_physical_address gbl_rsdp_address = 0; | ||
128 | |||
129 | /* Revision of RSD PTR */ | ||
130 | |||
131 | u8 gbl_revision = 0; | ||
132 | |||
133 | struct osl_table_info *gbl_table_list_head = NULL; | ||
134 | u32 gbl_table_count = 0; | ||
135 | |||
136 | /****************************************************************************** | ||
137 | * | ||
138 | * FUNCTION: osl_get_last_status | ||
139 | * | ||
140 | * PARAMETERS: default_status - Default error status to return | ||
141 | * | ||
142 | * RETURN: Status; Converted from errno. | ||
143 | * | ||
144 | * DESCRIPTION: Get last errno and conver it to acpi_status. | ||
145 | * | ||
146 | *****************************************************************************/ | ||
147 | |||
148 | static acpi_status osl_get_last_status(acpi_status default_status) | ||
149 | { | ||
150 | |||
151 | switch (errno) { | ||
152 | case EACCES: | ||
153 | case EPERM: | ||
154 | |||
155 | return (AE_ACCESS); | ||
156 | |||
157 | case ENOENT: | ||
158 | |||
159 | return (AE_NOT_FOUND); | ||
160 | |||
161 | case ENOMEM: | ||
162 | |||
163 | return (AE_NO_MEMORY); | ||
164 | |||
165 | default: | ||
166 | |||
167 | return (default_status); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | /****************************************************************************** | ||
172 | * | ||
173 | * FUNCTION: acpi_os_get_table_by_address | ||
174 | * | ||
175 | * PARAMETERS: address - Physical address of the ACPI table | ||
176 | * table - Where a pointer to the table is returned | ||
177 | * | ||
178 | * RETURN: Status; Table buffer is returned if AE_OK. | ||
179 | * AE_NOT_FOUND: A valid table was not found at the address | ||
180 | * | ||
181 | * DESCRIPTION: Get an ACPI table via a physical memory address. | ||
182 | * | ||
183 | *****************************************************************************/ | ||
184 | |||
185 | acpi_status | ||
186 | acpi_os_get_table_by_address(acpi_physical_address address, | ||
187 | struct acpi_table_header ** table) | ||
188 | { | ||
189 | u32 table_length; | ||
190 | struct acpi_table_header *mapped_table; | ||
191 | struct acpi_table_header *local_table = NULL; | ||
192 | acpi_status status = AE_OK; | ||
193 | |||
194 | /* Get main ACPI tables from memory on first invocation of this function */ | ||
195 | |||
196 | status = osl_table_initialize(); | ||
197 | if (ACPI_FAILURE(status)) { | ||
198 | return (status); | ||
199 | } | ||
200 | |||
201 | /* Map the table and validate it */ | ||
202 | |||
203 | status = osl_map_table(address, NULL, &mapped_table); | ||
204 | if (ACPI_FAILURE(status)) { | ||
205 | return (status); | ||
206 | } | ||
207 | |||
208 | /* Copy table to local buffer and return it */ | ||
209 | |||
210 | table_length = ap_get_table_length(mapped_table); | ||
211 | if (table_length == 0) { | ||
212 | status = AE_BAD_HEADER; | ||
213 | goto exit; | ||
214 | } | ||
215 | |||
216 | local_table = calloc(1, table_length); | ||
217 | if (!local_table) { | ||
218 | status = AE_NO_MEMORY; | ||
219 | goto exit; | ||
220 | } | ||
221 | |||
222 | ACPI_MEMCPY(local_table, mapped_table, table_length); | ||
223 | |||
224 | exit: | ||
225 | osl_unmap_table(mapped_table); | ||
226 | *table = local_table; | ||
227 | return (status); | ||
228 | } | ||
229 | |||
230 | /****************************************************************************** | ||
231 | * | ||
232 | * FUNCTION: acpi_os_get_table_by_name | ||
233 | * | ||
234 | * PARAMETERS: signature - ACPI Signature for desired table. Must be | ||
235 | * a null terminated 4-character string. | ||
236 | * instance - Multiple table support for SSDT/UEFI (0...n) | ||
237 | * Must be 0 for other tables. | ||
238 | * table - Where a pointer to the table is returned | ||
239 | * address - Where the table physical address is returned | ||
240 | * | ||
241 | * RETURN: Status; Table buffer and physical address returned if AE_OK. | ||
242 | * AE_LIMIT: Instance is beyond valid limit | ||
243 | * AE_NOT_FOUND: A table with the signature was not found | ||
244 | * | ||
245 | * NOTE: Assumes the input signature is uppercase. | ||
246 | * | ||
247 | *****************************************************************************/ | ||
248 | |||
249 | acpi_status | ||
250 | acpi_os_get_table_by_name(char *signature, | ||
251 | u32 instance, | ||
252 | struct acpi_table_header ** table, | ||
253 | acpi_physical_address * address) | ||
254 | { | ||
255 | acpi_status status; | ||
256 | |||
257 | /* Get main ACPI tables from memory on first invocation of this function */ | ||
258 | |||
259 | status = osl_table_initialize(); | ||
260 | if (ACPI_FAILURE(status)) { | ||
261 | return (status); | ||
262 | } | ||
263 | |||
264 | /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */ | ||
265 | |||
266 | if (!gbl_dump_customized_tables) { | ||
267 | |||
268 | /* Attempt to get the table from the memory */ | ||
269 | |||
270 | status = | ||
271 | osl_get_bios_table(signature, instance, table, address); | ||
272 | } else { | ||
273 | /* Attempt to get the table from the static directory */ | ||
274 | |||
275 | status = osl_get_customized_table(STATIC_TABLE_DIR, signature, | ||
276 | instance, table, address); | ||
277 | } | ||
278 | |||
279 | if (ACPI_FAILURE(status) && status == AE_LIMIT) { | ||
280 | if (gbl_dump_dynamic_tables) { | ||
281 | |||
282 | /* Attempt to get a dynamic table */ | ||
283 | |||
284 | status = | ||
285 | osl_get_customized_table(DYNAMIC_TABLE_DIR, | ||
286 | signature, instance, table, | ||
287 | address); | ||
288 | } | ||
289 | } | ||
290 | |||
291 | return (status); | ||
292 | } | ||
293 | |||
294 | /****************************************************************************** | ||
295 | * | ||
296 | * FUNCTION: osl_add_table_to_list | ||
297 | * | ||
298 | * PARAMETERS: signature - Table signature | ||
299 | * instance - Table instance | ||
300 | * | ||
301 | * RETURN: Status; Successfully added if AE_OK. | ||
302 | * AE_NO_MEMORY: Memory allocation error | ||
303 | * | ||
304 | * DESCRIPTION: Insert a table structure into OSL table list. | ||
305 | * | ||
306 | *****************************************************************************/ | ||
307 | |||
308 | static acpi_status osl_add_table_to_list(char *signature, u32 instance) | ||
309 | { | ||
310 | struct osl_table_info *new_info; | ||
311 | struct osl_table_info *next; | ||
312 | u32 next_instance = 0; | ||
313 | u8 found = FALSE; | ||
314 | |||
315 | new_info = calloc(1, sizeof(struct osl_table_info)); | ||
316 | if (!new_info) { | ||
317 | return (AE_NO_MEMORY); | ||
318 | } | ||
319 | |||
320 | ACPI_MOVE_NAME(new_info->signature, signature); | ||
321 | |||
322 | if (!gbl_table_list_head) { | ||
323 | gbl_table_list_head = new_info; | ||
324 | } else { | ||
325 | next = gbl_table_list_head; | ||
326 | while (1) { | ||
327 | if (ACPI_COMPARE_NAME(next->signature, signature)) { | ||
328 | if (next->instance == instance) { | ||
329 | found = TRUE; | ||
330 | } | ||
331 | if (next->instance >= next_instance) { | ||
332 | next_instance = next->instance + 1; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | if (!next->next) { | ||
337 | break; | ||
338 | } | ||
339 | next = next->next; | ||
340 | } | ||
341 | next->next = new_info; | ||
342 | } | ||
343 | |||
344 | if (found) { | ||
345 | if (instance) { | ||
346 | fprintf(stderr, | ||
347 | "%4.4s: Warning unmatched table instance %d, expected %d\n", | ||
348 | signature, instance, next_instance); | ||
349 | } | ||
350 | instance = next_instance; | ||
351 | } | ||
352 | |||
353 | new_info->instance = instance; | ||
354 | gbl_table_count++; | ||
355 | |||
356 | return (AE_OK); | ||
357 | } | ||
358 | |||
359 | /****************************************************************************** | ||
360 | * | ||
361 | * FUNCTION: acpi_os_get_table_by_index | ||
362 | * | ||
363 | * PARAMETERS: index - Which table to get | ||
364 | * table - Where a pointer to the table is returned | ||
365 | * instance - Where a pointer to the table instance no. is | ||
366 | * returned | ||
367 | * address - Where the table physical address is returned | ||
368 | * | ||
369 | * RETURN: Status; Table buffer and physical address returned if AE_OK. | ||
370 | * AE_LIMIT: Index is beyond valid limit | ||
371 | * | ||
372 | * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns | ||
373 | * AE_LIMIT when an invalid index is reached. Index is not | ||
374 | * necessarily an index into the RSDT/XSDT. | ||
375 | * | ||
376 | *****************************************************************************/ | ||
377 | |||
378 | acpi_status | ||
379 | acpi_os_get_table_by_index(u32 index, | ||
380 | struct acpi_table_header ** table, | ||
381 | u32 *instance, acpi_physical_address * address) | ||
382 | { | ||
383 | struct osl_table_info *info; | ||
384 | acpi_status status; | ||
385 | u32 i; | ||
386 | |||
387 | /* Get main ACPI tables from memory on first invocation of this function */ | ||
388 | |||
389 | status = osl_table_initialize(); | ||
390 | if (ACPI_FAILURE(status)) { | ||
391 | return (status); | ||
392 | } | ||
393 | |||
394 | /* Validate Index */ | ||
395 | |||
396 | if (index >= gbl_table_count) { | ||
397 | return (AE_LIMIT); | ||
398 | } | ||
399 | |||
400 | /* Point to the table list entry specified by the Index argument */ | ||
401 | |||
402 | info = gbl_table_list_head; | ||
403 | for (i = 0; i < index; i++) { | ||
404 | info = info->next; | ||
405 | } | ||
406 | |||
407 | /* Now we can just get the table via the signature */ | ||
408 | |||
409 | status = acpi_os_get_table_by_name(info->signature, info->instance, | ||
410 | table, address); | ||
411 | |||
412 | if (ACPI_SUCCESS(status)) { | ||
413 | *instance = info->instance; | ||
414 | } | ||
415 | return (status); | ||
416 | } | ||
417 | |||
418 | /****************************************************************************** | ||
419 | * | ||
420 | * FUNCTION: osl_find_rsdp_via_efi | ||
421 | * | ||
422 | * PARAMETERS: None | ||
423 | * | ||
424 | * RETURN: RSDP address if found | ||
425 | * | ||
426 | * DESCRIPTION: Find RSDP address via EFI. | ||
427 | * | ||
428 | *****************************************************************************/ | ||
429 | |||
430 | static acpi_physical_address osl_find_rsdp_via_efi(void) | ||
431 | { | ||
432 | FILE *file; | ||
433 | char buffer[80]; | ||
434 | unsigned long address = 0; | ||
435 | |||
436 | file = fopen(EFI_SYSTAB, "r"); | ||
437 | if (file) { | ||
438 | while (fgets(buffer, 80, file)) { | ||
439 | if (sscanf(buffer, "ACPI20=0x%lx", &address) == 1) { | ||
440 | break; | ||
441 | } | ||
442 | } | ||
443 | fclose(file); | ||
444 | } | ||
445 | |||
446 | return ((acpi_physical_address) (address)); | ||
447 | } | ||
448 | |||
449 | /****************************************************************************** | ||
450 | * | ||
451 | * FUNCTION: osl_load_rsdp | ||
452 | * | ||
453 | * PARAMETERS: None | ||
454 | * | ||
455 | * RETURN: Status | ||
456 | * | ||
457 | * DESCRIPTION: Scan and load RSDP. | ||
458 | * | ||
459 | *****************************************************************************/ | ||
460 | |||
461 | static acpi_status osl_load_rsdp(void) | ||
462 | { | ||
463 | struct acpi_table_header *mapped_table; | ||
464 | u8 *rsdp_address; | ||
465 | acpi_physical_address rsdp_base; | ||
466 | acpi_size rsdp_size; | ||
467 | |||
468 | /* Get RSDP from memory */ | ||
469 | |||
470 | rsdp_size = sizeof(struct acpi_table_rsdp); | ||
471 | if (gbl_rsdp_base) { | ||
472 | rsdp_base = gbl_rsdp_base; | ||
473 | } else { | ||
474 | rsdp_base = osl_find_rsdp_via_efi(); | ||
475 | } | ||
476 | |||
477 | if (!rsdp_base) { | ||
478 | rsdp_base = ACPI_HI_RSDP_WINDOW_BASE; | ||
479 | rsdp_size = ACPI_HI_RSDP_WINDOW_SIZE; | ||
480 | } | ||
481 | |||
482 | rsdp_address = acpi_os_map_memory(rsdp_base, rsdp_size); | ||
483 | if (!rsdp_address) { | ||
484 | return (osl_get_last_status(AE_BAD_ADDRESS)); | ||
485 | } | ||
486 | |||
487 | /* Search low memory for the RSDP */ | ||
488 | |||
489 | mapped_table = ACPI_CAST_PTR(struct acpi_table_header, | ||
490 | acpi_tb_scan_memory_for_rsdp(rsdp_address, | ||
491 | rsdp_size)); | ||
492 | if (!mapped_table) { | ||
493 | acpi_os_unmap_memory(rsdp_address, rsdp_size); | ||
494 | return (AE_NOT_FOUND); | ||
495 | } | ||
496 | |||
497 | gbl_rsdp_address = | ||
498 | rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address); | ||
499 | |||
500 | ACPI_MEMCPY(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp)); | ||
501 | acpi_os_unmap_memory(rsdp_address, rsdp_size); | ||
502 | |||
503 | return (AE_OK); | ||
504 | } | ||
505 | |||
506 | /****************************************************************************** | ||
507 | * | ||
508 | * FUNCTION: osl_can_use_xsdt | ||
509 | * | ||
510 | * PARAMETERS: None | ||
511 | * | ||
512 | * RETURN: TRUE if XSDT is allowed to be used. | ||
513 | * | ||
514 | * DESCRIPTION: This function collects logic that can be used to determine if | ||
515 | * XSDT should be used instead of RSDT. | ||
516 | * | ||
517 | *****************************************************************************/ | ||
518 | |||
519 | static u8 osl_can_use_xsdt(void) | ||
520 | { | ||
521 | if (gbl_revision && !acpi_gbl_do_not_use_xsdt) { | ||
522 | return (TRUE); | ||
523 | } else { | ||
524 | return (FALSE); | ||
525 | } | ||
526 | } | ||
527 | |||
528 | /****************************************************************************** | ||
529 | * | ||
530 | * FUNCTION: osl_table_initialize | ||
531 | * | ||
532 | * PARAMETERS: None | ||
533 | * | ||
534 | * RETURN: Status | ||
535 | * | ||
536 | * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to | ||
537 | * local variables. Main ACPI tables include RSDT, FADT, RSDT, | ||
538 | * and/or XSDT. | ||
539 | * | ||
540 | *****************************************************************************/ | ||
541 | |||
542 | static acpi_status osl_table_initialize(void) | ||
543 | { | ||
544 | acpi_status status; | ||
545 | acpi_physical_address address; | ||
546 | |||
547 | if (gbl_table_list_initialized) { | ||
548 | return (AE_OK); | ||
549 | } | ||
550 | |||
551 | /* Get RSDP from memory */ | ||
552 | |||
553 | status = osl_load_rsdp(); | ||
554 | if (ACPI_FAILURE(status)) { | ||
555 | return (status); | ||
556 | } | ||
557 | |||
558 | /* Get XSDT from memory */ | ||
559 | |||
560 | if (gbl_rsdp.revision && !gbl_do_not_dump_xsdt) { | ||
561 | if (gbl_xsdt) { | ||
562 | free(gbl_xsdt); | ||
563 | gbl_xsdt = NULL; | ||
564 | } | ||
565 | |||
566 | gbl_revision = 2; | ||
567 | status = osl_get_bios_table(ACPI_SIG_XSDT, 0, | ||
568 | ACPI_CAST_PTR(struct | ||
569 | acpi_table_header *, | ||
570 | &gbl_xsdt), &address); | ||
571 | if (ACPI_FAILURE(status)) { | ||
572 | return (status); | ||
573 | } | ||
574 | } | ||
575 | |||
576 | /* Get RSDT from memory */ | ||
577 | |||
578 | if (gbl_rsdp.rsdt_physical_address) { | ||
579 | if (gbl_rsdt) { | ||
580 | free(gbl_rsdt); | ||
581 | gbl_rsdt = NULL; | ||
582 | } | ||
583 | |||
584 | status = osl_get_bios_table(ACPI_SIG_RSDT, 0, | ||
585 | ACPI_CAST_PTR(struct | ||
586 | acpi_table_header *, | ||
587 | &gbl_rsdt), &address); | ||
588 | if (ACPI_FAILURE(status)) { | ||
589 | return (status); | ||
590 | } | ||
591 | } | ||
592 | |||
593 | /* Get FADT from memory */ | ||
594 | |||
595 | if (gbl_fadt) { | ||
596 | free(gbl_fadt); | ||
597 | gbl_fadt = NULL; | ||
598 | } | ||
599 | |||
600 | status = osl_get_bios_table(ACPI_SIG_FADT, 0, | ||
601 | ACPI_CAST_PTR(struct acpi_table_header *, | ||
602 | &gbl_fadt), | ||
603 | &gbl_fadt_address); | ||
604 | if (ACPI_FAILURE(status)) { | ||
605 | return (status); | ||
606 | } | ||
607 | |||
608 | if (!gbl_dump_customized_tables) { | ||
609 | |||
610 | /* Add mandatory tables to global table list first */ | ||
611 | |||
612 | status = osl_add_table_to_list(ACPI_RSDP_NAME, 0); | ||
613 | if (ACPI_FAILURE(status)) { | ||
614 | return (status); | ||
615 | } | ||
616 | |||
617 | status = osl_add_table_to_list(ACPI_SIG_RSDT, 0); | ||
618 | if (ACPI_FAILURE(status)) { | ||
619 | return (status); | ||
620 | } | ||
621 | |||
622 | if (gbl_revision == 2) { | ||
623 | status = osl_add_table_to_list(ACPI_SIG_XSDT, 0); | ||
624 | if (ACPI_FAILURE(status)) { | ||
625 | return (status); | ||
626 | } | ||
627 | } | ||
628 | |||
629 | status = osl_add_table_to_list(ACPI_SIG_DSDT, 0); | ||
630 | if (ACPI_FAILURE(status)) { | ||
631 | return (status); | ||
632 | } | ||
633 | |||
634 | status = osl_add_table_to_list(ACPI_SIG_FACS, 0); | ||
635 | if (ACPI_FAILURE(status)) { | ||
636 | return (status); | ||
637 | } | ||
638 | |||
639 | /* Add all tables found in the memory */ | ||
640 | |||
641 | status = osl_list_bios_tables(); | ||
642 | if (ACPI_FAILURE(status)) { | ||
643 | return (status); | ||
644 | } | ||
645 | } else { | ||
646 | /* Add all tables found in the static directory */ | ||
647 | |||
648 | status = osl_list_customized_tables(STATIC_TABLE_DIR); | ||
649 | if (ACPI_FAILURE(status)) { | ||
650 | return (status); | ||
651 | } | ||
652 | } | ||
653 | |||
654 | if (gbl_dump_dynamic_tables) { | ||
655 | |||
656 | /* Add all dynamically loaded tables in the dynamic directory */ | ||
657 | |||
658 | status = osl_list_customized_tables(DYNAMIC_TABLE_DIR); | ||
659 | if (ACPI_FAILURE(status)) { | ||
660 | return (status); | ||
661 | } | ||
662 | } | ||
663 | |||
664 | gbl_table_list_initialized = TRUE; | ||
665 | return (AE_OK); | ||
666 | } | ||
667 | |||
668 | /****************************************************************************** | ||
669 | * | ||
670 | * FUNCTION: osl_list_bios_tables | ||
671 | * | ||
672 | * PARAMETERS: None | ||
673 | * | ||
674 | * RETURN: Status; Table list is initialized if AE_OK. | ||
675 | * | ||
676 | * DESCRIPTION: Add ACPI tables to the table list from memory. | ||
677 | * | ||
678 | * NOTE: This works on Linux as table customization does not modify the | ||
679 | * addresses stored in RSDP/RSDT/XSDT/FADT. | ||
680 | * | ||
681 | *****************************************************************************/ | ||
682 | |||
683 | static acpi_status osl_list_bios_tables(void) | ||
684 | { | ||
685 | struct acpi_table_header *mapped_table = NULL; | ||
686 | u8 *table_data; | ||
687 | u8 number_of_tables; | ||
688 | u8 item_size; | ||
689 | acpi_physical_address table_address = 0; | ||
690 | acpi_status status = AE_OK; | ||
691 | u32 i; | ||
692 | |||
693 | if (osl_can_use_xsdt()) { | ||
694 | item_size = sizeof(u64); | ||
695 | table_data = | ||
696 | ACPI_CAST8(gbl_xsdt) + sizeof(struct acpi_table_header); | ||
697 | number_of_tables = | ||
698 | (u8)((gbl_xsdt->header.length - | ||
699 | sizeof(struct acpi_table_header)) | ||
700 | / item_size); | ||
701 | } else { /* Use RSDT if XSDT is not available */ | ||
702 | |||
703 | item_size = sizeof(u32); | ||
704 | table_data = | ||
705 | ACPI_CAST8(gbl_rsdt) + sizeof(struct acpi_table_header); | ||
706 | number_of_tables = | ||
707 | (u8)((gbl_rsdt->header.length - | ||
708 | sizeof(struct acpi_table_header)) | ||
709 | / item_size); | ||
710 | } | ||
711 | |||
712 | /* Search RSDT/XSDT for the requested table */ | ||
713 | |||
714 | for (i = 0; i < number_of_tables; ++i, table_data += item_size) { | ||
715 | if (osl_can_use_xsdt()) { | ||
716 | table_address = | ||
717 | (acpi_physical_address) (*ACPI_CAST64(table_data)); | ||
718 | } else { | ||
719 | table_address = | ||
720 | (acpi_physical_address) (*ACPI_CAST32(table_data)); | ||
721 | } | ||
722 | |||
723 | /* Skip NULL entries in RSDT/XSDT */ | ||
724 | |||
725 | if (!table_address) { | ||
726 | continue; | ||
727 | } | ||
728 | |||
729 | status = osl_map_table(table_address, NULL, &mapped_table); | ||
730 | if (ACPI_FAILURE(status)) { | ||
731 | return (status); | ||
732 | } | ||
733 | |||
734 | osl_add_table_to_list(mapped_table->signature, 0); | ||
735 | osl_unmap_table(mapped_table); | ||
736 | } | ||
737 | |||
738 | return (AE_OK); | ||
739 | } | ||
740 | |||
741 | /****************************************************************************** | ||
742 | * | ||
743 | * FUNCTION: osl_get_bios_table | ||
744 | * | ||
745 | * PARAMETERS: signature - ACPI Signature for common table. Must be | ||
746 | * a null terminated 4-character string. | ||
747 | * instance - Multiple table support for SSDT/UEFI (0...n) | ||
748 | * Must be 0 for other tables. | ||
749 | * table - Where a pointer to the table is returned | ||
750 | * address - Where the table physical address is returned | ||
751 | * | ||
752 | * RETURN: Status; Table buffer and physical address returned if AE_OK. | ||
753 | * AE_LIMIT: Instance is beyond valid limit | ||
754 | * AE_NOT_FOUND: A table with the signature was not found | ||
755 | * | ||
756 | * DESCRIPTION: Get a BIOS provided ACPI table | ||
757 | * | ||
758 | * NOTE: Assumes the input signature is uppercase. | ||
759 | * | ||
760 | *****************************************************************************/ | ||
761 | |||
762 | static acpi_status | ||
763 | osl_get_bios_table(char *signature, | ||
764 | u32 instance, | ||
765 | struct acpi_table_header **table, | ||
766 | acpi_physical_address * address) | ||
767 | { | ||
768 | struct acpi_table_header *local_table = NULL; | ||
769 | struct acpi_table_header *mapped_table = NULL; | ||
770 | u8 *table_data; | ||
771 | u8 number_of_tables; | ||
772 | u8 item_size; | ||
773 | u32 current_instance = 0; | ||
774 | acpi_physical_address table_address = 0; | ||
775 | u32 table_length = 0; | ||
776 | acpi_status status = AE_OK; | ||
777 | u32 i; | ||
778 | |||
779 | /* Handle special tables whose addresses are not in RSDT/XSDT */ | ||
780 | |||
781 | if (ACPI_COMPARE_NAME(signature, ACPI_RSDP_NAME) || | ||
782 | ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT) || | ||
783 | ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT) || | ||
784 | ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT) || | ||
785 | ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { | ||
786 | if (instance > 0) { | ||
787 | return (AE_LIMIT); | ||
788 | } | ||
789 | |||
790 | /* | ||
791 | * Get the appropriate address, either 32-bit or 64-bit. Be very | ||
792 | * careful about the FADT length and validate table addresses. | ||
793 | * Note: The 64-bit addresses have priority. | ||
794 | */ | ||
795 | if (ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT)) { | ||
796 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_XDSDT) && | ||
797 | gbl_fadt->Xdsdt) { | ||
798 | table_address = | ||
799 | (acpi_physical_address) gbl_fadt->Xdsdt; | ||
800 | } else | ||
801 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_DSDT) | ||
802 | && gbl_fadt->dsdt) { | ||
803 | table_address = | ||
804 | (acpi_physical_address) gbl_fadt->dsdt; | ||
805 | } | ||
806 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { | ||
807 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_XFACS) && | ||
808 | gbl_fadt->Xfacs) { | ||
809 | table_address = | ||
810 | (acpi_physical_address) gbl_fadt->Xfacs; | ||
811 | } else | ||
812 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_FACS) | ||
813 | && gbl_fadt->facs) { | ||
814 | table_address = | ||
815 | (acpi_physical_address) gbl_fadt->facs; | ||
816 | } | ||
817 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) { | ||
818 | if (!gbl_revision) { | ||
819 | return (AE_BAD_SIGNATURE); | ||
820 | } | ||
821 | table_address = | ||
822 | (acpi_physical_address) gbl_rsdp. | ||
823 | xsdt_physical_address; | ||
824 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) { | ||
825 | table_address = | ||
826 | (acpi_physical_address) gbl_rsdp. | ||
827 | rsdt_physical_address; | ||
828 | } else { | ||
829 | table_address = | ||
830 | (acpi_physical_address) gbl_rsdp_address; | ||
831 | signature = ACPI_SIG_RSDP; | ||
832 | } | ||
833 | |||
834 | /* Now we can get the requested special table */ | ||
835 | |||
836 | status = osl_map_table(table_address, signature, &mapped_table); | ||
837 | if (ACPI_FAILURE(status)) { | ||
838 | return (status); | ||
839 | } | ||
840 | |||
841 | table_length = ap_get_table_length(mapped_table); | ||
842 | } else { /* Case for a normal ACPI table */ | ||
843 | |||
844 | if (osl_can_use_xsdt()) { | ||
845 | item_size = sizeof(u64); | ||
846 | table_data = | ||
847 | ACPI_CAST8(gbl_xsdt) + | ||
848 | sizeof(struct acpi_table_header); | ||
849 | number_of_tables = | ||
850 | (u8)((gbl_xsdt->header.length - | ||
851 | sizeof(struct acpi_table_header)) | ||
852 | / item_size); | ||
853 | } else { /* Use RSDT if XSDT is not available */ | ||
854 | |||
855 | item_size = sizeof(u32); | ||
856 | table_data = | ||
857 | ACPI_CAST8(gbl_rsdt) + | ||
858 | sizeof(struct acpi_table_header); | ||
859 | number_of_tables = | ||
860 | (u8)((gbl_rsdt->header.length - | ||
861 | sizeof(struct acpi_table_header)) | ||
862 | / item_size); | ||
863 | } | ||
864 | |||
865 | /* Search RSDT/XSDT for the requested table */ | ||
866 | |||
867 | for (i = 0; i < number_of_tables; ++i, table_data += item_size) { | ||
868 | if (osl_can_use_xsdt()) { | ||
869 | table_address = | ||
870 | (acpi_physical_address) (*ACPI_CAST64 | ||
871 | (table_data)); | ||
872 | } else { | ||
873 | table_address = | ||
874 | (acpi_physical_address) (*ACPI_CAST32 | ||
875 | (table_data)); | ||
876 | } | ||
877 | |||
878 | /* Skip NULL entries in RSDT/XSDT */ | ||
879 | |||
880 | if (!table_address) { | ||
881 | continue; | ||
882 | } | ||
883 | |||
884 | status = | ||
885 | osl_map_table(table_address, NULL, &mapped_table); | ||
886 | if (ACPI_FAILURE(status)) { | ||
887 | return (status); | ||
888 | } | ||
889 | table_length = mapped_table->length; | ||
890 | |||
891 | /* Does this table match the requested signature? */ | ||
892 | |||
893 | if (!ACPI_COMPARE_NAME | ||
894 | (mapped_table->signature, signature)) { | ||
895 | osl_unmap_table(mapped_table); | ||
896 | mapped_table = NULL; | ||
897 | continue; | ||
898 | } | ||
899 | |||
900 | /* Match table instance (for SSDT/UEFI tables) */ | ||
901 | |||
902 | if (current_instance != instance) { | ||
903 | osl_unmap_table(mapped_table); | ||
904 | mapped_table = NULL; | ||
905 | current_instance++; | ||
906 | continue; | ||
907 | } | ||
908 | |||
909 | break; | ||
910 | } | ||
911 | } | ||
912 | |||
913 | if (!mapped_table) { | ||
914 | return (AE_LIMIT); | ||
915 | } | ||
916 | |||
917 | if (table_length == 0) { | ||
918 | status = AE_BAD_HEADER; | ||
919 | goto exit; | ||
920 | } | ||
921 | |||
922 | /* Copy table to local buffer and return it */ | ||
923 | |||
924 | local_table = calloc(1, table_length); | ||
925 | if (!local_table) { | ||
926 | status = AE_NO_MEMORY; | ||
927 | goto exit; | ||
928 | } | ||
929 | |||
930 | ACPI_MEMCPY(local_table, mapped_table, table_length); | ||
931 | *address = table_address; | ||
932 | *table = local_table; | ||
933 | |||
934 | exit: | ||
935 | osl_unmap_table(mapped_table); | ||
936 | return (status); | ||
937 | } | ||
938 | |||
939 | /****************************************************************************** | ||
940 | * | ||
941 | * FUNCTION: osl_list_customized_tables | ||
942 | * | ||
943 | * PARAMETERS: directory - Directory that contains the tables | ||
944 | * | ||
945 | * RETURN: Status; Table list is initialized if AE_OK. | ||
946 | * | ||
947 | * DESCRIPTION: Add ACPI tables to the table list from a directory. | ||
948 | * | ||
949 | *****************************************************************************/ | ||
950 | |||
951 | static acpi_status osl_list_customized_tables(char *directory) | ||
952 | { | ||
953 | void *table_dir; | ||
954 | u32 instance; | ||
955 | char temp_name[ACPI_NAME_SIZE]; | ||
956 | char *filename; | ||
957 | acpi_status status = AE_OK; | ||
958 | |||
959 | /* Open the requested directory */ | ||
960 | |||
961 | table_dir = acpi_os_open_directory(directory, "*", REQUEST_FILE_ONLY); | ||
962 | if (!table_dir) { | ||
963 | return (osl_get_last_status(AE_NOT_FOUND)); | ||
964 | } | ||
965 | |||
966 | /* Examine all entries in this directory */ | ||
967 | |||
968 | while ((filename = acpi_os_get_next_filename(table_dir))) { | ||
969 | |||
970 | /* Extract table name and instance number */ | ||
971 | |||
972 | status = | ||
973 | osl_table_name_from_file(filename, temp_name, &instance); | ||
974 | |||
975 | /* Ignore meaningless files */ | ||
976 | |||
977 | if (ACPI_FAILURE(status)) { | ||
978 | continue; | ||
979 | } | ||
980 | |||
981 | /* Add new info node to global table list */ | ||
982 | |||
983 | status = osl_add_table_to_list(temp_name, instance); | ||
984 | if (ACPI_FAILURE(status)) { | ||
985 | break; | ||
986 | } | ||
987 | } | ||
988 | |||
989 | acpi_os_close_directory(table_dir); | ||
990 | return (status); | ||
991 | } | ||
992 | |||
993 | /****************************************************************************** | ||
994 | * | ||
995 | * FUNCTION: osl_map_table | ||
996 | * | ||
997 | * PARAMETERS: address - Address of the table in memory | ||
998 | * signature - Optional ACPI Signature for desired table. | ||
999 | * Null terminated 4-character string. | ||
1000 | * table - Where a pointer to the mapped table is | ||
1001 | * returned | ||
1002 | * | ||
1003 | * RETURN: Status; Mapped table is returned if AE_OK. | ||
1004 | * AE_NOT_FOUND: A valid table was not found at the address | ||
1005 | * | ||
1006 | * DESCRIPTION: Map entire ACPI table into caller's address space. | ||
1007 | * | ||
1008 | *****************************************************************************/ | ||
1009 | |||
1010 | static acpi_status | ||
1011 | osl_map_table(acpi_size address, | ||
1012 | char *signature, struct acpi_table_header **table) | ||
1013 | { | ||
1014 | struct acpi_table_header *mapped_table; | ||
1015 | u32 length; | ||
1016 | |||
1017 | if (!address) { | ||
1018 | return (AE_BAD_ADDRESS); | ||
1019 | } | ||
1020 | |||
1021 | /* | ||
1022 | * Map the header so we can get the table length. | ||
1023 | * Use sizeof (struct acpi_table_header) as: | ||
1024 | * 1. it is bigger than 24 to include RSDP->Length | ||
1025 | * 2. it is smaller than sizeof (struct acpi_table_rsdp) | ||
1026 | */ | ||
1027 | mapped_table = | ||
1028 | acpi_os_map_memory(address, sizeof(struct acpi_table_header)); | ||
1029 | if (!mapped_table) { | ||
1030 | fprintf(stderr, "Could not map table header at 0x%8.8X%8.8X\n", | ||
1031 | ACPI_FORMAT_UINT64(address)); | ||
1032 | return (osl_get_last_status(AE_BAD_ADDRESS)); | ||
1033 | } | ||
1034 | |||
1035 | /* If specified, signature must match */ | ||
1036 | |||
1037 | if (signature) { | ||
1038 | if (ACPI_VALIDATE_RSDP_SIG(signature)) { | ||
1039 | if (!ACPI_VALIDATE_RSDP_SIG(mapped_table->signature)) { | ||
1040 | acpi_os_unmap_memory(mapped_table, | ||
1041 | sizeof(struct | ||
1042 | acpi_table_header)); | ||
1043 | return (AE_BAD_SIGNATURE); | ||
1044 | } | ||
1045 | } else | ||
1046 | if (!ACPI_COMPARE_NAME(signature, mapped_table->signature)) | ||
1047 | { | ||
1048 | acpi_os_unmap_memory(mapped_table, | ||
1049 | sizeof(struct acpi_table_header)); | ||
1050 | return (AE_BAD_SIGNATURE); | ||
1051 | } | ||
1052 | } | ||
1053 | |||
1054 | /* Map the entire table */ | ||
1055 | |||
1056 | length = ap_get_table_length(mapped_table); | ||
1057 | acpi_os_unmap_memory(mapped_table, sizeof(struct acpi_table_header)); | ||
1058 | if (length == 0) { | ||
1059 | return (AE_BAD_HEADER); | ||
1060 | } | ||
1061 | |||
1062 | mapped_table = acpi_os_map_memory(address, length); | ||
1063 | if (!mapped_table) { | ||
1064 | fprintf(stderr, | ||
1065 | "Could not map table at 0x%8.8X%8.8X length %8.8X\n", | ||
1066 | ACPI_FORMAT_UINT64(address), length); | ||
1067 | return (osl_get_last_status(AE_INVALID_TABLE_LENGTH)); | ||
1068 | } | ||
1069 | |||
1070 | (void)ap_is_valid_checksum(mapped_table); | ||
1071 | |||
1072 | *table = mapped_table; | ||
1073 | return (AE_OK); | ||
1074 | } | ||
1075 | |||
1076 | /****************************************************************************** | ||
1077 | * | ||
1078 | * FUNCTION: osl_unmap_table | ||
1079 | * | ||
1080 | * PARAMETERS: table - A pointer to the mapped table | ||
1081 | * | ||
1082 | * RETURN: None | ||
1083 | * | ||
1084 | * DESCRIPTION: Unmap entire ACPI table. | ||
1085 | * | ||
1086 | *****************************************************************************/ | ||
1087 | |||
1088 | static void osl_unmap_table(struct acpi_table_header *table) | ||
1089 | { | ||
1090 | if (table) { | ||
1091 | acpi_os_unmap_memory(table, ap_get_table_length(table)); | ||
1092 | } | ||
1093 | } | ||
1094 | |||
1095 | /****************************************************************************** | ||
1096 | * | ||
1097 | * FUNCTION: osl_table_name_from_file | ||
1098 | * | ||
1099 | * PARAMETERS: filename - File that contains the desired table | ||
1100 | * signature - Pointer to 4-character buffer to store | ||
1101 | * extracted table signature. | ||
1102 | * instance - Pointer to integer to store extracted | ||
1103 | * table instance number. | ||
1104 | * | ||
1105 | * RETURN: Status; Table name is extracted if AE_OK. | ||
1106 | * | ||
1107 | * DESCRIPTION: Extract table signature and instance number from a table file | ||
1108 | * name. | ||
1109 | * | ||
1110 | *****************************************************************************/ | ||
1111 | |||
1112 | static acpi_status | ||
1113 | osl_table_name_from_file(char *filename, char *signature, u32 *instance) | ||
1114 | { | ||
1115 | |||
1116 | /* Ignore meaningless files */ | ||
1117 | |||
1118 | if (strlen(filename) < ACPI_NAME_SIZE) { | ||
1119 | return (AE_BAD_SIGNATURE); | ||
1120 | } | ||
1121 | |||
1122 | /* Extract instance number */ | ||
1123 | |||
1124 | if (isdigit((int)filename[ACPI_NAME_SIZE])) { | ||
1125 | sscanf(&filename[ACPI_NAME_SIZE], "%d", instance); | ||
1126 | } else if (strlen(filename) != ACPI_NAME_SIZE) { | ||
1127 | return (AE_BAD_SIGNATURE); | ||
1128 | } else { | ||
1129 | *instance = 0; | ||
1130 | } | ||
1131 | |||
1132 | /* Extract signature */ | ||
1133 | |||
1134 | ACPI_MOVE_NAME(signature, filename); | ||
1135 | return (AE_OK); | ||
1136 | } | ||
1137 | |||
1138 | /****************************************************************************** | ||
1139 | * | ||
1140 | * FUNCTION: osl_read_table_from_file | ||
1141 | * | ||
1142 | * PARAMETERS: filename - File that contains the desired table | ||
1143 | * file_offset - Offset of the table in file | ||
1144 | * signature - Optional ACPI Signature for desired table. | ||
1145 | * A null terminated 4-character string. | ||
1146 | * table - Where a pointer to the table is returned | ||
1147 | * | ||
1148 | * RETURN: Status; Table buffer is returned if AE_OK. | ||
1149 | * | ||
1150 | * DESCRIPTION: Read a ACPI table from a file. | ||
1151 | * | ||
1152 | *****************************************************************************/ | ||
1153 | |||
1154 | static acpi_status | ||
1155 | osl_read_table_from_file(char *filename, | ||
1156 | acpi_size file_offset, | ||
1157 | char *signature, struct acpi_table_header **table) | ||
1158 | { | ||
1159 | FILE *table_file; | ||
1160 | struct acpi_table_header header; | ||
1161 | struct acpi_table_header *local_table = NULL; | ||
1162 | u32 table_length; | ||
1163 | s32 count; | ||
1164 | acpi_status status = AE_OK; | ||
1165 | |||
1166 | /* Open the file */ | ||
1167 | |||
1168 | table_file = fopen(filename, "rb"); | ||
1169 | if (table_file == NULL) { | ||
1170 | fprintf(stderr, "Could not open table file: %s\n", filename); | ||
1171 | return (osl_get_last_status(AE_NOT_FOUND)); | ||
1172 | } | ||
1173 | |||
1174 | fseek(table_file, file_offset, SEEK_SET); | ||
1175 | |||
1176 | /* Read the Table header to get the table length */ | ||
1177 | |||
1178 | count = fread(&header, 1, sizeof(struct acpi_table_header), table_file); | ||
1179 | if (count != sizeof(struct acpi_table_header)) { | ||
1180 | fprintf(stderr, "Could not read table header: %s\n", filename); | ||
1181 | status = AE_BAD_HEADER; | ||
1182 | goto exit; | ||
1183 | } | ||
1184 | |||
1185 | /* If signature is specified, it must match the table */ | ||
1186 | |||
1187 | if (signature) { | ||
1188 | if (ACPI_VALIDATE_RSDP_SIG(signature)) { | ||
1189 | if (!ACPI_VALIDATE_RSDP_SIG(header.signature)) { | ||
1190 | fprintf(stderr, | ||
1191 | "Incorrect RSDP signature: found %8.8s\n", | ||
1192 | header.signature); | ||
1193 | status = AE_BAD_SIGNATURE; | ||
1194 | goto exit; | ||
1195 | } | ||
1196 | } else if (!ACPI_COMPARE_NAME(signature, header.signature)) { | ||
1197 | fprintf(stderr, | ||
1198 | "Incorrect signature: Expecting %4.4s, found %4.4s\n", | ||
1199 | signature, header.signature); | ||
1200 | status = AE_BAD_SIGNATURE; | ||
1201 | goto exit; | ||
1202 | } | ||
1203 | } | ||
1204 | |||
1205 | table_length = ap_get_table_length(&header); | ||
1206 | if (table_length == 0) { | ||
1207 | status = AE_BAD_HEADER; | ||
1208 | goto exit; | ||
1209 | } | ||
1210 | |||
1211 | /* Read the entire table into a local buffer */ | ||
1212 | |||
1213 | local_table = calloc(1, table_length); | ||
1214 | if (!local_table) { | ||
1215 | fprintf(stderr, | ||
1216 | "%4.4s: Could not allocate buffer for table of length %X\n", | ||
1217 | header.signature, table_length); | ||
1218 | status = AE_NO_MEMORY; | ||
1219 | goto exit; | ||
1220 | } | ||
1221 | |||
1222 | fseek(table_file, file_offset, SEEK_SET); | ||
1223 | |||
1224 | count = fread(local_table, 1, table_length, table_file); | ||
1225 | if (count != table_length) { | ||
1226 | fprintf(stderr, "%4.4s: Could not read table content\n", | ||
1227 | header.signature); | ||
1228 | status = AE_INVALID_TABLE_LENGTH; | ||
1229 | goto exit; | ||
1230 | } | ||
1231 | |||
1232 | /* Validate checksum */ | ||
1233 | |||
1234 | (void)ap_is_valid_checksum(local_table); | ||
1235 | |||
1236 | exit: | ||
1237 | fclose(table_file); | ||
1238 | *table = local_table; | ||
1239 | return (status); | ||
1240 | } | ||
1241 | |||
1242 | /****************************************************************************** | ||
1243 | * | ||
1244 | * FUNCTION: osl_get_customized_table | ||
1245 | * | ||
1246 | * PARAMETERS: pathname - Directory to find Linux customized table | ||
1247 | * signature - ACPI Signature for desired table. Must be | ||
1248 | * a null terminated 4-character string. | ||
1249 | * instance - Multiple table support for SSDT/UEFI (0...n) | ||
1250 | * Must be 0 for other tables. | ||
1251 | * table - Where a pointer to the table is returned | ||
1252 | * address - Where the table physical address is returned | ||
1253 | * | ||
1254 | * RETURN: Status; Table buffer is returned if AE_OK. | ||
1255 | * AE_LIMIT: Instance is beyond valid limit | ||
1256 | * AE_NOT_FOUND: A table with the signature was not found | ||
1257 | * | ||
1258 | * DESCRIPTION: Get an OS customized table. | ||
1259 | * | ||
1260 | *****************************************************************************/ | ||
1261 | |||
1262 | static acpi_status | ||
1263 | osl_get_customized_table(char *pathname, | ||
1264 | char *signature, | ||
1265 | u32 instance, | ||
1266 | struct acpi_table_header **table, | ||
1267 | acpi_physical_address * address) | ||
1268 | { | ||
1269 | void *table_dir; | ||
1270 | u32 current_instance = 0; | ||
1271 | char temp_name[ACPI_NAME_SIZE]; | ||
1272 | char table_filename[PATH_MAX]; | ||
1273 | char *filename; | ||
1274 | acpi_status status; | ||
1275 | |||
1276 | /* Open the directory for customized tables */ | ||
1277 | |||
1278 | table_dir = acpi_os_open_directory(pathname, "*", REQUEST_FILE_ONLY); | ||
1279 | if (!table_dir) { | ||
1280 | return (osl_get_last_status(AE_NOT_FOUND)); | ||
1281 | } | ||
1282 | |||
1283 | /* Attempt to find the table in the directory */ | ||
1284 | |||
1285 | while ((filename = acpi_os_get_next_filename(table_dir))) { | ||
1286 | |||
1287 | /* Ignore meaningless files */ | ||
1288 | |||
1289 | if (!ACPI_COMPARE_NAME(filename, signature)) { | ||
1290 | continue; | ||
1291 | } | ||
1292 | |||
1293 | /* Extract table name and instance number */ | ||
1294 | |||
1295 | status = | ||
1296 | osl_table_name_from_file(filename, temp_name, | ||
1297 | ¤t_instance); | ||
1298 | |||
1299 | /* Ignore meaningless files */ | ||
1300 | |||
1301 | if (ACPI_FAILURE(status) || current_instance != instance) { | ||
1302 | continue; | ||
1303 | } | ||
1304 | |||
1305 | /* Create the table pathname */ | ||
1306 | |||
1307 | if (instance != 0) { | ||
1308 | sprintf(table_filename, "%s/%4.4s%d", pathname, | ||
1309 | temp_name, instance); | ||
1310 | } else { | ||
1311 | sprintf(table_filename, "%s/%4.4s", pathname, | ||
1312 | temp_name); | ||
1313 | } | ||
1314 | break; | ||
1315 | } | ||
1316 | |||
1317 | acpi_os_close_directory(table_dir); | ||
1318 | |||
1319 | if (!filename) { | ||
1320 | return (AE_LIMIT); | ||
1321 | } | ||
1322 | |||
1323 | /* There is no physical address saved for customized tables, use zero */ | ||
1324 | |||
1325 | *address = 0; | ||
1326 | status = osl_read_table_from_file(table_filename, 0, NULL, table); | ||
1327 | |||
1328 | return (status); | ||
1329 | } | ||