195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2506f57ddSLv Zheng /******************************************************************************
3506f57ddSLv Zheng *
4506f57ddSLv Zheng * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables
5506f57ddSLv Zheng *
6*612c2932SBob Moore * Copyright (C) 2000 - 2023, Intel Corp.
7506f57ddSLv Zheng *
895857638SErik Schmauss *****************************************************************************/
9506f57ddSLv Zheng
10506f57ddSLv Zheng #include "acpidump.h"
11506f57ddSLv Zheng
12506f57ddSLv Zheng #define _COMPONENT ACPI_OS_SERVICES
13506f57ddSLv Zheng ACPI_MODULE_NAME("oslinuxtbl")
14506f57ddSLv Zheng
15506f57ddSLv Zheng #ifndef PATH_MAX
16506f57ddSLv Zheng #define PATH_MAX 256
17506f57ddSLv Zheng #endif
18506f57ddSLv Zheng /* List of information about obtained ACPI tables */
19506f57ddSLv Zheng typedef struct osl_table_info {
20506f57ddSLv Zheng struct osl_table_info *next;
21506f57ddSLv Zheng u32 instance;
2232786755SBob Moore char signature[ACPI_NAMESEG_SIZE];
23506f57ddSLv Zheng
24506f57ddSLv Zheng } osl_table_info;
25506f57ddSLv Zheng
26506f57ddSLv Zheng /* Local prototypes */
27506f57ddSLv Zheng
28506f57ddSLv Zheng static acpi_status osl_table_initialize(void);
29506f57ddSLv Zheng
30506f57ddSLv Zheng static acpi_status
31506f57ddSLv Zheng osl_table_name_from_file(char *filename, char *signature, u32 *instance);
32506f57ddSLv Zheng
33506f57ddSLv Zheng static acpi_status osl_add_table_to_list(char *signature, u32 instance);
34506f57ddSLv Zheng
35506f57ddSLv Zheng static acpi_status
36506f57ddSLv Zheng osl_read_table_from_file(char *filename,
37506f57ddSLv Zheng acpi_size file_offset,
38d82faa08SBob Moore struct acpi_table_header **table);
39506f57ddSLv Zheng
40506f57ddSLv Zheng static acpi_status
41506f57ddSLv Zheng osl_map_table(acpi_size address,
42506f57ddSLv Zheng char *signature, struct acpi_table_header **table);
43506f57ddSLv Zheng
44506f57ddSLv Zheng static void osl_unmap_table(struct acpi_table_header *table);
45506f57ddSLv Zheng
46890fbfa0SLv Zheng static acpi_physical_address
47890fbfa0SLv Zheng osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword);
48890fbfa0SLv Zheng
49506f57ddSLv Zheng static acpi_physical_address osl_find_rsdp_via_efi(void);
50506f57ddSLv Zheng
51506f57ddSLv Zheng static acpi_status osl_load_rsdp(void);
52506f57ddSLv Zheng
53506f57ddSLv Zheng static acpi_status osl_list_customized_tables(char *directory);
54506f57ddSLv Zheng
55506f57ddSLv Zheng static acpi_status
56506f57ddSLv Zheng osl_get_customized_table(char *pathname,
57506f57ddSLv Zheng char *signature,
58506f57ddSLv Zheng u32 instance,
59506f57ddSLv Zheng struct acpi_table_header **table,
60506f57ddSLv Zheng acpi_physical_address *address);
61506f57ddSLv Zheng
62506f57ddSLv Zheng static acpi_status osl_list_bios_tables(void);
63506f57ddSLv Zheng
64506f57ddSLv Zheng static acpi_status
65506f57ddSLv Zheng osl_get_bios_table(char *signature,
66506f57ddSLv Zheng u32 instance,
67506f57ddSLv Zheng struct acpi_table_header **table,
68506f57ddSLv Zheng acpi_physical_address *address);
69506f57ddSLv Zheng
70506f57ddSLv Zheng static acpi_status osl_get_last_status(acpi_status default_status);
71506f57ddSLv Zheng
72506f57ddSLv Zheng /* File locations */
73506f57ddSLv Zheng
74506f57ddSLv Zheng #define DYNAMIC_TABLE_DIR "/sys/firmware/acpi/tables/dynamic"
75506f57ddSLv Zheng #define STATIC_TABLE_DIR "/sys/firmware/acpi/tables"
76506f57ddSLv Zheng #define EFI_SYSTAB "/sys/firmware/efi/systab"
77506f57ddSLv Zheng
78506f57ddSLv Zheng /* Should we get dynamically loaded SSDTs from DYNAMIC_TABLE_DIR? */
79506f57ddSLv Zheng
80506f57ddSLv Zheng u8 gbl_dump_dynamic_tables = TRUE;
81506f57ddSLv Zheng
82506f57ddSLv Zheng /* Initialization flags */
83506f57ddSLv Zheng
84506f57ddSLv Zheng u8 gbl_table_list_initialized = FALSE;
85506f57ddSLv Zheng
86506f57ddSLv Zheng /* Local copies of main ACPI tables */
87506f57ddSLv Zheng
88506f57ddSLv Zheng struct acpi_table_rsdp gbl_rsdp;
89506f57ddSLv Zheng struct acpi_table_fadt *gbl_fadt = NULL;
90506f57ddSLv Zheng struct acpi_table_rsdt *gbl_rsdt = NULL;
91506f57ddSLv Zheng struct acpi_table_xsdt *gbl_xsdt = NULL;
92506f57ddSLv Zheng
93506f57ddSLv Zheng /* Table addresses */
94506f57ddSLv Zheng
95506f57ddSLv Zheng acpi_physical_address gbl_fadt_address = 0;
96506f57ddSLv Zheng acpi_physical_address gbl_rsdp_address = 0;
97506f57ddSLv Zheng
98506f57ddSLv Zheng /* Revision of RSD PTR */
99506f57ddSLv Zheng
100506f57ddSLv Zheng u8 gbl_revision = 0;
101506f57ddSLv Zheng
102506f57ddSLv Zheng struct osl_table_info *gbl_table_list_head = NULL;
103506f57ddSLv Zheng u32 gbl_table_count = 0;
104506f57ddSLv Zheng
105506f57ddSLv Zheng /******************************************************************************
106506f57ddSLv Zheng *
107506f57ddSLv Zheng * FUNCTION: osl_get_last_status
108506f57ddSLv Zheng *
109506f57ddSLv Zheng * PARAMETERS: default_status - Default error status to return
110506f57ddSLv Zheng *
111506f57ddSLv Zheng * RETURN: Status; Converted from errno.
112506f57ddSLv Zheng *
113465e490dSColin Ian King * DESCRIPTION: Get last errno and convert it to acpi_status.
114506f57ddSLv Zheng *
115506f57ddSLv Zheng *****************************************************************************/
116506f57ddSLv Zheng
osl_get_last_status(acpi_status default_status)117506f57ddSLv Zheng static acpi_status osl_get_last_status(acpi_status default_status)
118506f57ddSLv Zheng {
119506f57ddSLv Zheng
120506f57ddSLv Zheng switch (errno) {
121506f57ddSLv Zheng case EACCES:
122506f57ddSLv Zheng case EPERM:
123506f57ddSLv Zheng
124506f57ddSLv Zheng return (AE_ACCESS);
125506f57ddSLv Zheng
126506f57ddSLv Zheng case ENOENT:
127506f57ddSLv Zheng
128506f57ddSLv Zheng return (AE_NOT_FOUND);
129506f57ddSLv Zheng
130506f57ddSLv Zheng case ENOMEM:
131506f57ddSLv Zheng
132506f57ddSLv Zheng return (AE_NO_MEMORY);
133506f57ddSLv Zheng
134506f57ddSLv Zheng default:
135506f57ddSLv Zheng
136506f57ddSLv Zheng return (default_status);
137506f57ddSLv Zheng }
138506f57ddSLv Zheng }
139506f57ddSLv Zheng
140506f57ddSLv Zheng /******************************************************************************
141506f57ddSLv Zheng *
142506f57ddSLv Zheng * FUNCTION: acpi_os_get_table_by_address
143506f57ddSLv Zheng *
144506f57ddSLv Zheng * PARAMETERS: address - Physical address of the ACPI table
145506f57ddSLv Zheng * table - Where a pointer to the table is returned
146506f57ddSLv Zheng *
147506f57ddSLv Zheng * RETURN: Status; Table buffer is returned if AE_OK.
148506f57ddSLv Zheng * AE_NOT_FOUND: A valid table was not found at the address
149506f57ddSLv Zheng *
150506f57ddSLv Zheng * DESCRIPTION: Get an ACPI table via a physical memory address.
151506f57ddSLv Zheng *
152506f57ddSLv Zheng *****************************************************************************/
153506f57ddSLv Zheng
154506f57ddSLv Zheng acpi_status
acpi_os_get_table_by_address(acpi_physical_address address,struct acpi_table_header ** table)155506f57ddSLv Zheng acpi_os_get_table_by_address(acpi_physical_address address,
156506f57ddSLv Zheng struct acpi_table_header **table)
157506f57ddSLv Zheng {
158506f57ddSLv Zheng u32 table_length;
159506f57ddSLv Zheng struct acpi_table_header *mapped_table;
160506f57ddSLv Zheng struct acpi_table_header *local_table = NULL;
161506f57ddSLv Zheng acpi_status status = AE_OK;
162506f57ddSLv Zheng
163506f57ddSLv Zheng /* Get main ACPI tables from memory on first invocation of this function */
164506f57ddSLv Zheng
165506f57ddSLv Zheng status = osl_table_initialize();
166506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
167506f57ddSLv Zheng return (status);
168506f57ddSLv Zheng }
169506f57ddSLv Zheng
170506f57ddSLv Zheng /* Map the table and validate it */
171506f57ddSLv Zheng
172506f57ddSLv Zheng status = osl_map_table(address, NULL, &mapped_table);
173506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
174506f57ddSLv Zheng return (status);
175506f57ddSLv Zheng }
176506f57ddSLv Zheng
177506f57ddSLv Zheng /* Copy table to local buffer and return it */
178506f57ddSLv Zheng
179506f57ddSLv Zheng table_length = ap_get_table_length(mapped_table);
180506f57ddSLv Zheng if (table_length == 0) {
181506f57ddSLv Zheng status = AE_BAD_HEADER;
182506f57ddSLv Zheng goto exit;
183506f57ddSLv Zheng }
184506f57ddSLv Zheng
185506f57ddSLv Zheng local_table = calloc(1, table_length);
186506f57ddSLv Zheng if (!local_table) {
187506f57ddSLv Zheng status = AE_NO_MEMORY;
188506f57ddSLv Zheng goto exit;
189506f57ddSLv Zheng }
190506f57ddSLv Zheng
1914fa4616eSBob Moore memcpy(local_table, mapped_table, table_length);
192506f57ddSLv Zheng
193506f57ddSLv Zheng exit:
194506f57ddSLv Zheng osl_unmap_table(mapped_table);
195506f57ddSLv Zheng *table = local_table;
196506f57ddSLv Zheng return (status);
197506f57ddSLv Zheng }
198506f57ddSLv Zheng
199506f57ddSLv Zheng /******************************************************************************
200506f57ddSLv Zheng *
201506f57ddSLv Zheng * FUNCTION: acpi_os_get_table_by_name
202506f57ddSLv Zheng *
203506f57ddSLv Zheng * PARAMETERS: signature - ACPI Signature for desired table. Must be
204506f57ddSLv Zheng * a null terminated 4-character string.
205506f57ddSLv Zheng * instance - Multiple table support for SSDT/UEFI (0...n)
206506f57ddSLv Zheng * Must be 0 for other tables.
207506f57ddSLv Zheng * table - Where a pointer to the table is returned
208506f57ddSLv Zheng * address - Where the table physical address is returned
209506f57ddSLv Zheng *
210506f57ddSLv Zheng * RETURN: Status; Table buffer and physical address returned if AE_OK.
211506f57ddSLv Zheng * AE_LIMIT: Instance is beyond valid limit
212506f57ddSLv Zheng * AE_NOT_FOUND: A table with the signature was not found
213506f57ddSLv Zheng *
214506f57ddSLv Zheng * NOTE: Assumes the input signature is uppercase.
215506f57ddSLv Zheng *
216506f57ddSLv Zheng *****************************************************************************/
217506f57ddSLv Zheng
218506f57ddSLv Zheng acpi_status
acpi_os_get_table_by_name(char * signature,u32 instance,struct acpi_table_header ** table,acpi_physical_address * address)219506f57ddSLv Zheng acpi_os_get_table_by_name(char *signature,
220506f57ddSLv Zheng u32 instance,
221506f57ddSLv Zheng struct acpi_table_header **table,
222506f57ddSLv Zheng acpi_physical_address *address)
223506f57ddSLv Zheng {
224506f57ddSLv Zheng acpi_status status;
225506f57ddSLv Zheng
226506f57ddSLv Zheng /* Get main ACPI tables from memory on first invocation of this function */
227506f57ddSLv Zheng
228506f57ddSLv Zheng status = osl_table_initialize();
229506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
230506f57ddSLv Zheng return (status);
231506f57ddSLv Zheng }
232506f57ddSLv Zheng
233506f57ddSLv Zheng /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */
234506f57ddSLv Zheng
235506f57ddSLv Zheng if (!gbl_dump_customized_tables) {
236506f57ddSLv Zheng
237506f57ddSLv Zheng /* Attempt to get the table from the memory */
238506f57ddSLv Zheng
239506f57ddSLv Zheng status =
240506f57ddSLv Zheng osl_get_bios_table(signature, instance, table, address);
241506f57ddSLv Zheng } else {
242506f57ddSLv Zheng /* Attempt to get the table from the static directory */
243506f57ddSLv Zheng
244506f57ddSLv Zheng status = osl_get_customized_table(STATIC_TABLE_DIR, signature,
245506f57ddSLv Zheng instance, table, address);
246506f57ddSLv Zheng }
247506f57ddSLv Zheng
248506f57ddSLv Zheng if (ACPI_FAILURE(status) && status == AE_LIMIT) {
249506f57ddSLv Zheng if (gbl_dump_dynamic_tables) {
250506f57ddSLv Zheng
251506f57ddSLv Zheng /* Attempt to get a dynamic table */
252506f57ddSLv Zheng
253506f57ddSLv Zheng status =
254506f57ddSLv Zheng osl_get_customized_table(DYNAMIC_TABLE_DIR,
255506f57ddSLv Zheng signature, instance, table,
256506f57ddSLv Zheng address);
257506f57ddSLv Zheng }
258506f57ddSLv Zheng }
259506f57ddSLv Zheng
260506f57ddSLv Zheng return (status);
261506f57ddSLv Zheng }
262506f57ddSLv Zheng
263506f57ddSLv Zheng /******************************************************************************
264506f57ddSLv Zheng *
265506f57ddSLv Zheng * FUNCTION: osl_add_table_to_list
266506f57ddSLv Zheng *
267506f57ddSLv Zheng * PARAMETERS: signature - Table signature
268506f57ddSLv Zheng * instance - Table instance
269506f57ddSLv Zheng *
270506f57ddSLv Zheng * RETURN: Status; Successfully added if AE_OK.
271506f57ddSLv Zheng * AE_NO_MEMORY: Memory allocation error
272506f57ddSLv Zheng *
273506f57ddSLv Zheng * DESCRIPTION: Insert a table structure into OSL table list.
274506f57ddSLv Zheng *
275506f57ddSLv Zheng *****************************************************************************/
276506f57ddSLv Zheng
osl_add_table_to_list(char * signature,u32 instance)277506f57ddSLv Zheng static acpi_status osl_add_table_to_list(char *signature, u32 instance)
278506f57ddSLv Zheng {
279506f57ddSLv Zheng struct osl_table_info *new_info;
280506f57ddSLv Zheng struct osl_table_info *next;
281506f57ddSLv Zheng u32 next_instance = 0;
282506f57ddSLv Zheng u8 found = FALSE;
283506f57ddSLv Zheng
284506f57ddSLv Zheng new_info = calloc(1, sizeof(struct osl_table_info));
285506f57ddSLv Zheng if (!new_info) {
286506f57ddSLv Zheng return (AE_NO_MEMORY);
287506f57ddSLv Zheng }
288506f57ddSLv Zheng
289a3ce7a8eSBob Moore ACPI_COPY_NAMESEG(new_info->signature, signature);
290506f57ddSLv Zheng
291506f57ddSLv Zheng if (!gbl_table_list_head) {
292506f57ddSLv Zheng gbl_table_list_head = new_info;
293506f57ddSLv Zheng } else {
294506f57ddSLv Zheng next = gbl_table_list_head;
295506f57ddSLv Zheng while (1) {
2965599fb69SBob Moore if (ACPI_COMPARE_NAMESEG(next->signature, signature)) {
297506f57ddSLv Zheng if (next->instance == instance) {
298506f57ddSLv Zheng found = TRUE;
299506f57ddSLv Zheng }
300506f57ddSLv Zheng if (next->instance >= next_instance) {
301506f57ddSLv Zheng next_instance = next->instance + 1;
302506f57ddSLv Zheng }
303506f57ddSLv Zheng }
304506f57ddSLv Zheng
305506f57ddSLv Zheng if (!next->next) {
306506f57ddSLv Zheng break;
307506f57ddSLv Zheng }
308506f57ddSLv Zheng next = next->next;
309506f57ddSLv Zheng }
310506f57ddSLv Zheng next->next = new_info;
311506f57ddSLv Zheng }
312506f57ddSLv Zheng
313506f57ddSLv Zheng if (found) {
314506f57ddSLv Zheng if (instance) {
315506f57ddSLv Zheng fprintf(stderr,
316506f57ddSLv Zheng "%4.4s: Warning unmatched table instance %d, expected %d\n",
317506f57ddSLv Zheng signature, instance, next_instance);
318506f57ddSLv Zheng }
319506f57ddSLv Zheng instance = next_instance;
320506f57ddSLv Zheng }
321506f57ddSLv Zheng
322506f57ddSLv Zheng new_info->instance = instance;
323506f57ddSLv Zheng gbl_table_count++;
324506f57ddSLv Zheng
325506f57ddSLv Zheng return (AE_OK);
326506f57ddSLv Zheng }
327506f57ddSLv Zheng
328506f57ddSLv Zheng /******************************************************************************
329506f57ddSLv Zheng *
330506f57ddSLv Zheng * FUNCTION: acpi_os_get_table_by_index
331506f57ddSLv Zheng *
332506f57ddSLv Zheng * PARAMETERS: index - Which table to get
333506f57ddSLv Zheng * table - Where a pointer to the table is returned
334506f57ddSLv Zheng * instance - Where a pointer to the table instance no. is
335506f57ddSLv Zheng * returned
336506f57ddSLv Zheng * address - Where the table physical address is returned
337506f57ddSLv Zheng *
338506f57ddSLv Zheng * RETURN: Status; Table buffer and physical address returned if AE_OK.
339506f57ddSLv Zheng * AE_LIMIT: Index is beyond valid limit
340506f57ddSLv Zheng *
341506f57ddSLv Zheng * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
342506f57ddSLv Zheng * AE_LIMIT when an invalid index is reached. Index is not
343506f57ddSLv Zheng * necessarily an index into the RSDT/XSDT.
344506f57ddSLv Zheng *
345506f57ddSLv Zheng *****************************************************************************/
346506f57ddSLv Zheng
347506f57ddSLv Zheng acpi_status
acpi_os_get_table_by_index(u32 index,struct acpi_table_header ** table,u32 * instance,acpi_physical_address * address)348506f57ddSLv Zheng acpi_os_get_table_by_index(u32 index,
349506f57ddSLv Zheng struct acpi_table_header **table,
350506f57ddSLv Zheng u32 *instance, acpi_physical_address *address)
351506f57ddSLv Zheng {
352506f57ddSLv Zheng struct osl_table_info *info;
353506f57ddSLv Zheng acpi_status status;
354506f57ddSLv Zheng u32 i;
355506f57ddSLv Zheng
356506f57ddSLv Zheng /* Get main ACPI tables from memory on first invocation of this function */
357506f57ddSLv Zheng
358506f57ddSLv Zheng status = osl_table_initialize();
359506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
360506f57ddSLv Zheng return (status);
361506f57ddSLv Zheng }
362506f57ddSLv Zheng
363506f57ddSLv Zheng /* Validate Index */
364506f57ddSLv Zheng
365506f57ddSLv Zheng if (index >= gbl_table_count) {
366506f57ddSLv Zheng return (AE_LIMIT);
367506f57ddSLv Zheng }
368506f57ddSLv Zheng
369506f57ddSLv Zheng /* Point to the table list entry specified by the Index argument */
370506f57ddSLv Zheng
371506f57ddSLv Zheng info = gbl_table_list_head;
372506f57ddSLv Zheng for (i = 0; i < index; i++) {
373506f57ddSLv Zheng info = info->next;
374506f57ddSLv Zheng }
375506f57ddSLv Zheng
376506f57ddSLv Zheng /* Now we can just get the table via the signature */
377506f57ddSLv Zheng
378506f57ddSLv Zheng status = acpi_os_get_table_by_name(info->signature, info->instance,
379506f57ddSLv Zheng table, address);
380506f57ddSLv Zheng
381506f57ddSLv Zheng if (ACPI_SUCCESS(status)) {
382506f57ddSLv Zheng *instance = info->instance;
383506f57ddSLv Zheng }
384506f57ddSLv Zheng return (status);
385506f57ddSLv Zheng }
386506f57ddSLv Zheng
387506f57ddSLv Zheng /******************************************************************************
388506f57ddSLv Zheng *
389890fbfa0SLv Zheng * FUNCTION: osl_find_rsdp_via_efi_by_keyword
390890fbfa0SLv Zheng *
391890fbfa0SLv Zheng * PARAMETERS: keyword - Character string indicating ACPI GUID version
392890fbfa0SLv Zheng * in the EFI table
393890fbfa0SLv Zheng *
394890fbfa0SLv Zheng * RETURN: RSDP address if found
395890fbfa0SLv Zheng *
396890fbfa0SLv Zheng * DESCRIPTION: Find RSDP address via EFI using keyword indicating the ACPI
397890fbfa0SLv Zheng * GUID version.
398890fbfa0SLv Zheng *
399890fbfa0SLv Zheng *****************************************************************************/
400890fbfa0SLv Zheng
401890fbfa0SLv Zheng static acpi_physical_address
osl_find_rsdp_via_efi_by_keyword(FILE * file,const char * keyword)402890fbfa0SLv Zheng osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword)
403890fbfa0SLv Zheng {
404890fbfa0SLv Zheng char buffer[80];
405890fbfa0SLv Zheng unsigned long long address = 0;
406890fbfa0SLv Zheng char format[32];
407890fbfa0SLv Zheng
408890fbfa0SLv Zheng snprintf(format, 32, "%s=%s", keyword, "%llx");
409890fbfa0SLv Zheng fseek(file, 0, SEEK_SET);
410890fbfa0SLv Zheng while (fgets(buffer, 80, file)) {
411890fbfa0SLv Zheng if (sscanf(buffer, format, &address) == 1) {
412890fbfa0SLv Zheng break;
413890fbfa0SLv Zheng }
414890fbfa0SLv Zheng }
415890fbfa0SLv Zheng
416890fbfa0SLv Zheng return ((acpi_physical_address)(address));
417890fbfa0SLv Zheng }
418890fbfa0SLv Zheng
419890fbfa0SLv Zheng /******************************************************************************
420890fbfa0SLv Zheng *
421506f57ddSLv Zheng * FUNCTION: osl_find_rsdp_via_efi
422506f57ddSLv Zheng *
423506f57ddSLv Zheng * PARAMETERS: None
424506f57ddSLv Zheng *
425506f57ddSLv Zheng * RETURN: RSDP address if found
426506f57ddSLv Zheng *
427506f57ddSLv Zheng * DESCRIPTION: Find RSDP address via EFI.
428506f57ddSLv Zheng *
429506f57ddSLv Zheng *****************************************************************************/
430506f57ddSLv Zheng
osl_find_rsdp_via_efi(void)431506f57ddSLv Zheng static acpi_physical_address osl_find_rsdp_via_efi(void)
432506f57ddSLv Zheng {
433506f57ddSLv Zheng FILE *file;
434890fbfa0SLv Zheng acpi_physical_address address = 0;
435506f57ddSLv Zheng
436506f57ddSLv Zheng file = fopen(EFI_SYSTAB, "r");
437506f57ddSLv Zheng if (file) {
438890fbfa0SLv Zheng address = osl_find_rsdp_via_efi_by_keyword(file, "ACPI20");
439890fbfa0SLv Zheng if (!address) {
440890fbfa0SLv Zheng address =
441890fbfa0SLv Zheng osl_find_rsdp_via_efi_by_keyword(file, "ACPI");
442506f57ddSLv Zheng }
443506f57ddSLv Zheng fclose(file);
444506f57ddSLv Zheng }
445506f57ddSLv Zheng
446890fbfa0SLv Zheng return (address);
447506f57ddSLv Zheng }
448506f57ddSLv Zheng
449506f57ddSLv Zheng /******************************************************************************
450506f57ddSLv Zheng *
451506f57ddSLv Zheng * FUNCTION: osl_load_rsdp
452506f57ddSLv Zheng *
453506f57ddSLv Zheng * PARAMETERS: None
454506f57ddSLv Zheng *
455506f57ddSLv Zheng * RETURN: Status
456506f57ddSLv Zheng *
457506f57ddSLv Zheng * DESCRIPTION: Scan and load RSDP.
458506f57ddSLv Zheng *
459506f57ddSLv Zheng *****************************************************************************/
460506f57ddSLv Zheng
osl_load_rsdp(void)461506f57ddSLv Zheng static acpi_status osl_load_rsdp(void)
462506f57ddSLv Zheng {
463506f57ddSLv Zheng struct acpi_table_header *mapped_table;
464506f57ddSLv Zheng u8 *rsdp_address;
465506f57ddSLv Zheng acpi_physical_address rsdp_base;
466506f57ddSLv Zheng acpi_size rsdp_size;
467506f57ddSLv Zheng
468506f57ddSLv Zheng /* Get RSDP from memory */
469506f57ddSLv Zheng
470506f57ddSLv Zheng rsdp_size = sizeof(struct acpi_table_rsdp);
471506f57ddSLv Zheng if (gbl_rsdp_base) {
472506f57ddSLv Zheng rsdp_base = gbl_rsdp_base;
473506f57ddSLv Zheng } else {
474506f57ddSLv Zheng rsdp_base = osl_find_rsdp_via_efi();
475506f57ddSLv Zheng }
476506f57ddSLv Zheng
477506f57ddSLv Zheng if (!rsdp_base) {
478506f57ddSLv Zheng rsdp_base = ACPI_HI_RSDP_WINDOW_BASE;
479506f57ddSLv Zheng rsdp_size = ACPI_HI_RSDP_WINDOW_SIZE;
480506f57ddSLv Zheng }
481506f57ddSLv Zheng
482506f57ddSLv Zheng rsdp_address = acpi_os_map_memory(rsdp_base, rsdp_size);
483506f57ddSLv Zheng if (!rsdp_address) {
484506f57ddSLv Zheng return (osl_get_last_status(AE_BAD_ADDRESS));
485506f57ddSLv Zheng }
486506f57ddSLv Zheng
487506f57ddSLv Zheng /* Search low memory for the RSDP */
488506f57ddSLv Zheng
489506f57ddSLv Zheng mapped_table = ACPI_CAST_PTR(struct acpi_table_header,
490506f57ddSLv Zheng acpi_tb_scan_memory_for_rsdp(rsdp_address,
491506f57ddSLv Zheng rsdp_size));
492506f57ddSLv Zheng if (!mapped_table) {
493506f57ddSLv Zheng acpi_os_unmap_memory(rsdp_address, rsdp_size);
494506f57ddSLv Zheng return (AE_NOT_FOUND);
495506f57ddSLv Zheng }
496506f57ddSLv Zheng
497506f57ddSLv Zheng gbl_rsdp_address =
498506f57ddSLv Zheng rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address);
499506f57ddSLv Zheng
5004fa4616eSBob Moore memcpy(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp));
501506f57ddSLv Zheng acpi_os_unmap_memory(rsdp_address, rsdp_size);
502506f57ddSLv Zheng
503506f57ddSLv Zheng return (AE_OK);
504506f57ddSLv Zheng }
505506f57ddSLv Zheng
506506f57ddSLv Zheng /******************************************************************************
507506f57ddSLv Zheng *
508c7932267SLv Zheng * FUNCTION: osl_can_use_xsdt
509c7932267SLv Zheng *
510c7932267SLv Zheng * PARAMETERS: None
511c7932267SLv Zheng *
512c7932267SLv Zheng * RETURN: TRUE if XSDT is allowed to be used.
513c7932267SLv Zheng *
514c7932267SLv Zheng * DESCRIPTION: This function collects logic that can be used to determine if
515c7932267SLv Zheng * XSDT should be used instead of RSDT.
516c7932267SLv Zheng *
517c7932267SLv Zheng *****************************************************************************/
518c7932267SLv Zheng
osl_can_use_xsdt(void)519c7932267SLv Zheng static u8 osl_can_use_xsdt(void)
520c7932267SLv Zheng {
521c7932267SLv Zheng if (gbl_revision && !acpi_gbl_do_not_use_xsdt) {
522c7932267SLv Zheng return (TRUE);
523c7932267SLv Zheng } else {
524c7932267SLv Zheng return (FALSE);
525c7932267SLv Zheng }
526c7932267SLv Zheng }
527c7932267SLv Zheng
528c7932267SLv Zheng /******************************************************************************
529c7932267SLv Zheng *
530506f57ddSLv Zheng * FUNCTION: osl_table_initialize
531506f57ddSLv Zheng *
532506f57ddSLv Zheng * PARAMETERS: None
533506f57ddSLv Zheng *
534506f57ddSLv Zheng * RETURN: Status
535506f57ddSLv Zheng *
536506f57ddSLv Zheng * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
537506f57ddSLv Zheng * local variables. Main ACPI tables include RSDT, FADT, RSDT,
538506f57ddSLv Zheng * and/or XSDT.
539506f57ddSLv Zheng *
540506f57ddSLv Zheng *****************************************************************************/
541506f57ddSLv Zheng
osl_table_initialize(void)542506f57ddSLv Zheng static acpi_status osl_table_initialize(void)
543506f57ddSLv Zheng {
544506f57ddSLv Zheng acpi_status status;
545506f57ddSLv Zheng acpi_physical_address address;
546506f57ddSLv Zheng
547506f57ddSLv Zheng if (gbl_table_list_initialized) {
548506f57ddSLv Zheng return (AE_OK);
549506f57ddSLv Zheng }
550506f57ddSLv Zheng
551428394dfSLv Zheng if (!gbl_dump_customized_tables) {
552428394dfSLv Zheng
553506f57ddSLv Zheng /* Get RSDP from memory */
554506f57ddSLv Zheng
555506f57ddSLv Zheng status = osl_load_rsdp();
556506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
557506f57ddSLv Zheng return (status);
558506f57ddSLv Zheng }
559506f57ddSLv Zheng
560506f57ddSLv Zheng /* Get XSDT from memory */
561506f57ddSLv Zheng
562c7932267SLv Zheng if (gbl_rsdp.revision && !gbl_do_not_dump_xsdt) {
563506f57ddSLv Zheng if (gbl_xsdt) {
564506f57ddSLv Zheng free(gbl_xsdt);
565506f57ddSLv Zheng gbl_xsdt = NULL;
566506f57ddSLv Zheng }
567506f57ddSLv Zheng
568506f57ddSLv Zheng gbl_revision = 2;
569506f57ddSLv Zheng status = osl_get_bios_table(ACPI_SIG_XSDT, 0,
570506f57ddSLv Zheng ACPI_CAST_PTR(struct
571428394dfSLv Zheng acpi_table_header
572428394dfSLv Zheng *, &gbl_xsdt),
573428394dfSLv Zheng &address);
574506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
575506f57ddSLv Zheng return (status);
576506f57ddSLv Zheng }
577506f57ddSLv Zheng }
578506f57ddSLv Zheng
579506f57ddSLv Zheng /* Get RSDT from memory */
580506f57ddSLv Zheng
581506f57ddSLv Zheng if (gbl_rsdp.rsdt_physical_address) {
582506f57ddSLv Zheng if (gbl_rsdt) {
583506f57ddSLv Zheng free(gbl_rsdt);
584506f57ddSLv Zheng gbl_rsdt = NULL;
585506f57ddSLv Zheng }
586506f57ddSLv Zheng
587506f57ddSLv Zheng status = osl_get_bios_table(ACPI_SIG_RSDT, 0,
588506f57ddSLv Zheng ACPI_CAST_PTR(struct
589428394dfSLv Zheng acpi_table_header
590428394dfSLv Zheng *, &gbl_rsdt),
591428394dfSLv Zheng &address);
592506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
593506f57ddSLv Zheng return (status);
594506f57ddSLv Zheng }
595506f57ddSLv Zheng }
596506f57ddSLv Zheng
597506f57ddSLv Zheng /* Get FADT from memory */
598506f57ddSLv Zheng
599506f57ddSLv Zheng if (gbl_fadt) {
600506f57ddSLv Zheng free(gbl_fadt);
601506f57ddSLv Zheng gbl_fadt = NULL;
602506f57ddSLv Zheng }
603506f57ddSLv Zheng
604506f57ddSLv Zheng status = osl_get_bios_table(ACPI_SIG_FADT, 0,
605428394dfSLv Zheng ACPI_CAST_PTR(struct
606428394dfSLv Zheng acpi_table_header *,
607506f57ddSLv Zheng &gbl_fadt),
608506f57ddSLv Zheng &gbl_fadt_address);
609506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
610506f57ddSLv Zheng return (status);
611506f57ddSLv Zheng }
612506f57ddSLv Zheng
613506f57ddSLv Zheng /* Add mandatory tables to global table list first */
614506f57ddSLv Zheng
615506f57ddSLv Zheng status = osl_add_table_to_list(ACPI_RSDP_NAME, 0);
616506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
617506f57ddSLv Zheng return (status);
618506f57ddSLv Zheng }
619506f57ddSLv Zheng
620506f57ddSLv Zheng status = osl_add_table_to_list(ACPI_SIG_RSDT, 0);
621506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
622506f57ddSLv Zheng return (status);
623506f57ddSLv Zheng }
624506f57ddSLv Zheng
625506f57ddSLv Zheng if (gbl_revision == 2) {
626506f57ddSLv Zheng status = osl_add_table_to_list(ACPI_SIG_XSDT, 0);
627506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
628506f57ddSLv Zheng return (status);
629506f57ddSLv Zheng }
630506f57ddSLv Zheng }
631506f57ddSLv Zheng
632506f57ddSLv Zheng status = osl_add_table_to_list(ACPI_SIG_DSDT, 0);
633506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
634506f57ddSLv Zheng return (status);
635506f57ddSLv Zheng }
636506f57ddSLv Zheng
637506f57ddSLv Zheng status = osl_add_table_to_list(ACPI_SIG_FACS, 0);
638506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
639506f57ddSLv Zheng return (status);
640506f57ddSLv Zheng }
641506f57ddSLv Zheng
642506f57ddSLv Zheng /* Add all tables found in the memory */
643506f57ddSLv Zheng
644506f57ddSLv Zheng status = osl_list_bios_tables();
645506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
646506f57ddSLv Zheng return (status);
647506f57ddSLv Zheng }
648506f57ddSLv Zheng } else {
649506f57ddSLv Zheng /* Add all tables found in the static directory */
650506f57ddSLv Zheng
651506f57ddSLv Zheng status = osl_list_customized_tables(STATIC_TABLE_DIR);
652506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
653506f57ddSLv Zheng return (status);
654506f57ddSLv Zheng }
655506f57ddSLv Zheng }
656506f57ddSLv Zheng
657506f57ddSLv Zheng if (gbl_dump_dynamic_tables) {
658506f57ddSLv Zheng
659506f57ddSLv Zheng /* Add all dynamically loaded tables in the dynamic directory */
660506f57ddSLv Zheng
661506f57ddSLv Zheng status = osl_list_customized_tables(DYNAMIC_TABLE_DIR);
662506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
663506f57ddSLv Zheng return (status);
664506f57ddSLv Zheng }
665506f57ddSLv Zheng }
666506f57ddSLv Zheng
667506f57ddSLv Zheng gbl_table_list_initialized = TRUE;
668506f57ddSLv Zheng return (AE_OK);
669506f57ddSLv Zheng }
670506f57ddSLv Zheng
671506f57ddSLv Zheng /******************************************************************************
672506f57ddSLv Zheng *
673506f57ddSLv Zheng * FUNCTION: osl_list_bios_tables
674506f57ddSLv Zheng *
675506f57ddSLv Zheng * PARAMETERS: None
676506f57ddSLv Zheng *
677506f57ddSLv Zheng * RETURN: Status; Table list is initialized if AE_OK.
678506f57ddSLv Zheng *
679506f57ddSLv Zheng * DESCRIPTION: Add ACPI tables to the table list from memory.
680506f57ddSLv Zheng *
681506f57ddSLv Zheng * NOTE: This works on Linux as table customization does not modify the
682506f57ddSLv Zheng * addresses stored in RSDP/RSDT/XSDT/FADT.
683506f57ddSLv Zheng *
684506f57ddSLv Zheng *****************************************************************************/
685506f57ddSLv Zheng
osl_list_bios_tables(void)686506f57ddSLv Zheng static acpi_status osl_list_bios_tables(void)
687506f57ddSLv Zheng {
688506f57ddSLv Zheng struct acpi_table_header *mapped_table = NULL;
689506f57ddSLv Zheng u8 *table_data;
690506f57ddSLv Zheng u8 number_of_tables;
691506f57ddSLv Zheng u8 item_size;
692506f57ddSLv Zheng acpi_physical_address table_address = 0;
693506f57ddSLv Zheng acpi_status status = AE_OK;
694506f57ddSLv Zheng u32 i;
695506f57ddSLv Zheng
696c7932267SLv Zheng if (osl_can_use_xsdt()) {
697506f57ddSLv Zheng item_size = sizeof(u64);
698506f57ddSLv Zheng table_data =
699506f57ddSLv Zheng ACPI_CAST8(gbl_xsdt) + sizeof(struct acpi_table_header);
700506f57ddSLv Zheng number_of_tables =
701506f57ddSLv Zheng (u8)((gbl_xsdt->header.length -
702506f57ddSLv Zheng sizeof(struct acpi_table_header))
703506f57ddSLv Zheng / item_size);
704506f57ddSLv Zheng } else { /* Use RSDT if XSDT is not available */
705506f57ddSLv Zheng
706506f57ddSLv Zheng item_size = sizeof(u32);
707506f57ddSLv Zheng table_data =
708506f57ddSLv Zheng ACPI_CAST8(gbl_rsdt) + sizeof(struct acpi_table_header);
709506f57ddSLv Zheng number_of_tables =
710506f57ddSLv Zheng (u8)((gbl_rsdt->header.length -
711506f57ddSLv Zheng sizeof(struct acpi_table_header))
712506f57ddSLv Zheng / item_size);
713506f57ddSLv Zheng }
714506f57ddSLv Zheng
715506f57ddSLv Zheng /* Search RSDT/XSDT for the requested table */
716506f57ddSLv Zheng
717506f57ddSLv Zheng for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
718c7932267SLv Zheng if (osl_can_use_xsdt()) {
719506f57ddSLv Zheng table_address =
720506f57ddSLv Zheng (acpi_physical_address)(*ACPI_CAST64(table_data));
721506f57ddSLv Zheng } else {
722506f57ddSLv Zheng table_address =
723506f57ddSLv Zheng (acpi_physical_address)(*ACPI_CAST32(table_data));
724506f57ddSLv Zheng }
725506f57ddSLv Zheng
7260f929fbfSLv Zheng /* Skip NULL entries in RSDT/XSDT */
7270f929fbfSLv Zheng
72803c5b6b0SLv Zheng if (table_address == 0) {
7290f929fbfSLv Zheng continue;
7300f929fbfSLv Zheng }
7310f929fbfSLv Zheng
732506f57ddSLv Zheng status = osl_map_table(table_address, NULL, &mapped_table);
733506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
734506f57ddSLv Zheng return (status);
735506f57ddSLv Zheng }
736506f57ddSLv Zheng
737506f57ddSLv Zheng osl_add_table_to_list(mapped_table->signature, 0);
738506f57ddSLv Zheng osl_unmap_table(mapped_table);
739506f57ddSLv Zheng }
740506f57ddSLv Zheng
741506f57ddSLv Zheng return (AE_OK);
742506f57ddSLv Zheng }
743506f57ddSLv Zheng
744506f57ddSLv Zheng /******************************************************************************
745506f57ddSLv Zheng *
746506f57ddSLv Zheng * FUNCTION: osl_get_bios_table
747506f57ddSLv Zheng *
748506f57ddSLv Zheng * PARAMETERS: signature - ACPI Signature for common table. Must be
749506f57ddSLv Zheng * a null terminated 4-character string.
750506f57ddSLv Zheng * instance - Multiple table support for SSDT/UEFI (0...n)
751506f57ddSLv Zheng * Must be 0 for other tables.
752506f57ddSLv Zheng * table - Where a pointer to the table is returned
753506f57ddSLv Zheng * address - Where the table physical address is returned
754506f57ddSLv Zheng *
755506f57ddSLv Zheng * RETURN: Status; Table buffer and physical address returned if AE_OK.
756506f57ddSLv Zheng * AE_LIMIT: Instance is beyond valid limit
757506f57ddSLv Zheng * AE_NOT_FOUND: A table with the signature was not found
758506f57ddSLv Zheng *
759506f57ddSLv Zheng * DESCRIPTION: Get a BIOS provided ACPI table
760506f57ddSLv Zheng *
761506f57ddSLv Zheng * NOTE: Assumes the input signature is uppercase.
762506f57ddSLv Zheng *
763506f57ddSLv Zheng *****************************************************************************/
764506f57ddSLv Zheng
765506f57ddSLv Zheng static acpi_status
osl_get_bios_table(char * signature,u32 instance,struct acpi_table_header ** table,acpi_physical_address * address)766506f57ddSLv Zheng osl_get_bios_table(char *signature,
767506f57ddSLv Zheng u32 instance,
768506f57ddSLv Zheng struct acpi_table_header **table,
769506f57ddSLv Zheng acpi_physical_address *address)
770506f57ddSLv Zheng {
771506f57ddSLv Zheng struct acpi_table_header *local_table = NULL;
772506f57ddSLv Zheng struct acpi_table_header *mapped_table = NULL;
773506f57ddSLv Zheng u8 *table_data;
774506f57ddSLv Zheng u8 number_of_tables;
775506f57ddSLv Zheng u8 item_size;
776506f57ddSLv Zheng u32 current_instance = 0;
77703c5b6b0SLv Zheng acpi_physical_address table_address;
77803c5b6b0SLv Zheng acpi_physical_address first_table_address = 0;
779506f57ddSLv Zheng u32 table_length = 0;
780506f57ddSLv Zheng acpi_status status = AE_OK;
781506f57ddSLv Zheng u32 i;
782506f57ddSLv Zheng
783506f57ddSLv Zheng /* Handle special tables whose addresses are not in RSDT/XSDT */
784506f57ddSLv Zheng
7855599fb69SBob Moore if (ACPI_COMPARE_NAMESEG(signature, ACPI_RSDP_NAME) ||
7865599fb69SBob Moore ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_RSDT) ||
7875599fb69SBob Moore ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_XSDT) ||
7885599fb69SBob Moore ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_DSDT) ||
7895599fb69SBob Moore ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_FACS)) {
79003c5b6b0SLv Zheng
79103c5b6b0SLv Zheng find_next_instance:
79203c5b6b0SLv Zheng
79303c5b6b0SLv Zheng table_address = 0;
7942947c1d5SLv Zheng
795506f57ddSLv Zheng /*
796506f57ddSLv Zheng * Get the appropriate address, either 32-bit or 64-bit. Be very
797506f57ddSLv Zheng * careful about the FADT length and validate table addresses.
798506f57ddSLv Zheng * Note: The 64-bit addresses have priority.
799506f57ddSLv Zheng */
8005599fb69SBob Moore if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_DSDT)) {
80103c5b6b0SLv Zheng if (current_instance < 2) {
80203c5b6b0SLv Zheng if ((gbl_fadt->header.length >=
80303c5b6b0SLv Zheng MIN_FADT_FOR_XDSDT) && gbl_fadt->Xdsdt
80403c5b6b0SLv Zheng && current_instance == 0) {
805506f57ddSLv Zheng table_address =
80603c5b6b0SLv Zheng (acpi_physical_address)gbl_fadt->
80703c5b6b0SLv Zheng Xdsdt;
808506f57ddSLv Zheng } else
80903c5b6b0SLv Zheng if ((gbl_fadt->header.length >=
81003c5b6b0SLv Zheng MIN_FADT_FOR_DSDT)
81103c5b6b0SLv Zheng && gbl_fadt->dsdt !=
81203c5b6b0SLv Zheng first_table_address) {
813506f57ddSLv Zheng table_address =
81403c5b6b0SLv Zheng (acpi_physical_address)gbl_fadt->
81503c5b6b0SLv Zheng dsdt;
81603c5b6b0SLv Zheng }
817506f57ddSLv Zheng }
8185599fb69SBob Moore } else if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_FACS)) {
81903c5b6b0SLv Zheng if (current_instance < 2) {
82003c5b6b0SLv Zheng if ((gbl_fadt->header.length >=
82103c5b6b0SLv Zheng MIN_FADT_FOR_XFACS) && gbl_fadt->Xfacs
82203c5b6b0SLv Zheng && current_instance == 0) {
823506f57ddSLv Zheng table_address =
82403c5b6b0SLv Zheng (acpi_physical_address)gbl_fadt->
82503c5b6b0SLv Zheng Xfacs;
826506f57ddSLv Zheng } else
82703c5b6b0SLv Zheng if ((gbl_fadt->header.length >=
82803c5b6b0SLv Zheng MIN_FADT_FOR_FACS)
82903c5b6b0SLv Zheng && gbl_fadt->facs !=
83003c5b6b0SLv Zheng first_table_address) {
831506f57ddSLv Zheng table_address =
83203c5b6b0SLv Zheng (acpi_physical_address)gbl_fadt->
83303c5b6b0SLv Zheng facs;
83403c5b6b0SLv Zheng }
835506f57ddSLv Zheng }
8365599fb69SBob Moore } else if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_XSDT)) {
837506f57ddSLv Zheng if (!gbl_revision) {
838506f57ddSLv Zheng return (AE_BAD_SIGNATURE);
839506f57ddSLv Zheng }
84003c5b6b0SLv Zheng if (current_instance == 0) {
841506f57ddSLv Zheng table_address =
842506f57ddSLv Zheng (acpi_physical_address)gbl_rsdp.
843506f57ddSLv Zheng xsdt_physical_address;
84403c5b6b0SLv Zheng }
8455599fb69SBob Moore } else if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_RSDT)) {
84603c5b6b0SLv Zheng if (current_instance == 0) {
847506f57ddSLv Zheng table_address =
848506f57ddSLv Zheng (acpi_physical_address)gbl_rsdp.
849506f57ddSLv Zheng rsdt_physical_address;
85003c5b6b0SLv Zheng }
851506f57ddSLv Zheng } else {
85203c5b6b0SLv Zheng if (current_instance == 0) {
85303c5b6b0SLv Zheng table_address =
85403c5b6b0SLv Zheng (acpi_physical_address)gbl_rsdp_address;
855506f57ddSLv Zheng signature = ACPI_SIG_RSDP;
856506f57ddSLv Zheng }
85703c5b6b0SLv Zheng }
85803c5b6b0SLv Zheng
85903c5b6b0SLv Zheng if (table_address == 0) {
86003c5b6b0SLv Zheng goto exit_find_table;
86103c5b6b0SLv Zheng }
862506f57ddSLv Zheng
863506f57ddSLv Zheng /* Now we can get the requested special table */
864506f57ddSLv Zheng
865506f57ddSLv Zheng status = osl_map_table(table_address, signature, &mapped_table);
866506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
867506f57ddSLv Zheng return (status);
868506f57ddSLv Zheng }
869506f57ddSLv Zheng
870506f57ddSLv Zheng table_length = ap_get_table_length(mapped_table);
87103c5b6b0SLv Zheng if (first_table_address == 0) {
87203c5b6b0SLv Zheng first_table_address = table_address;
87303c5b6b0SLv Zheng }
87403c5b6b0SLv Zheng
87503c5b6b0SLv Zheng /* Match table instance */
87603c5b6b0SLv Zheng
87703c5b6b0SLv Zheng if (current_instance != instance) {
87803c5b6b0SLv Zheng osl_unmap_table(mapped_table);
87903c5b6b0SLv Zheng mapped_table = NULL;
88003c5b6b0SLv Zheng current_instance++;
88103c5b6b0SLv Zheng goto find_next_instance;
88203c5b6b0SLv Zheng }
883506f57ddSLv Zheng } else { /* Case for a normal ACPI table */
884506f57ddSLv Zheng
885c7932267SLv Zheng if (osl_can_use_xsdt()) {
886506f57ddSLv Zheng item_size = sizeof(u64);
887506f57ddSLv Zheng table_data =
888506f57ddSLv Zheng ACPI_CAST8(gbl_xsdt) +
889506f57ddSLv Zheng sizeof(struct acpi_table_header);
890506f57ddSLv Zheng number_of_tables =
891506f57ddSLv Zheng (u8)((gbl_xsdt->header.length -
892506f57ddSLv Zheng sizeof(struct acpi_table_header))
893506f57ddSLv Zheng / item_size);
894506f57ddSLv Zheng } else { /* Use RSDT if XSDT is not available */
895506f57ddSLv Zheng
896506f57ddSLv Zheng item_size = sizeof(u32);
897506f57ddSLv Zheng table_data =
898506f57ddSLv Zheng ACPI_CAST8(gbl_rsdt) +
899506f57ddSLv Zheng sizeof(struct acpi_table_header);
900506f57ddSLv Zheng number_of_tables =
901506f57ddSLv Zheng (u8)((gbl_rsdt->header.length -
902506f57ddSLv Zheng sizeof(struct acpi_table_header))
903506f57ddSLv Zheng / item_size);
904506f57ddSLv Zheng }
905506f57ddSLv Zheng
906506f57ddSLv Zheng /* Search RSDT/XSDT for the requested table */
907506f57ddSLv Zheng
908506f57ddSLv Zheng for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
909c7932267SLv Zheng if (osl_can_use_xsdt()) {
910506f57ddSLv Zheng table_address =
911506f57ddSLv Zheng (acpi_physical_address)(*ACPI_CAST64
912506f57ddSLv Zheng (table_data));
913506f57ddSLv Zheng } else {
914506f57ddSLv Zheng table_address =
915506f57ddSLv Zheng (acpi_physical_address)(*ACPI_CAST32
916506f57ddSLv Zheng (table_data));
917506f57ddSLv Zheng }
918506f57ddSLv Zheng
9190f929fbfSLv Zheng /* Skip NULL entries in RSDT/XSDT */
9200f929fbfSLv Zheng
92103c5b6b0SLv Zheng if (table_address == 0) {
9220f929fbfSLv Zheng continue;
9230f929fbfSLv Zheng }
9240f929fbfSLv Zheng
925506f57ddSLv Zheng status =
926506f57ddSLv Zheng osl_map_table(table_address, NULL, &mapped_table);
927506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
928506f57ddSLv Zheng return (status);
929506f57ddSLv Zheng }
930506f57ddSLv Zheng table_length = mapped_table->length;
931506f57ddSLv Zheng
932506f57ddSLv Zheng /* Does this table match the requested signature? */
933506f57ddSLv Zheng
9345599fb69SBob Moore if (!ACPI_COMPARE_NAMESEG
935506f57ddSLv Zheng (mapped_table->signature, signature)) {
936506f57ddSLv Zheng osl_unmap_table(mapped_table);
937506f57ddSLv Zheng mapped_table = NULL;
938506f57ddSLv Zheng continue;
939506f57ddSLv Zheng }
940506f57ddSLv Zheng
941506f57ddSLv Zheng /* Match table instance (for SSDT/UEFI tables) */
942506f57ddSLv Zheng
943506f57ddSLv Zheng if (current_instance != instance) {
944506f57ddSLv Zheng osl_unmap_table(mapped_table);
945506f57ddSLv Zheng mapped_table = NULL;
946506f57ddSLv Zheng current_instance++;
947506f57ddSLv Zheng continue;
948506f57ddSLv Zheng }
949506f57ddSLv Zheng
950506f57ddSLv Zheng break;
951506f57ddSLv Zheng }
952506f57ddSLv Zheng }
953506f57ddSLv Zheng
95403c5b6b0SLv Zheng exit_find_table:
95503c5b6b0SLv Zheng
956506f57ddSLv Zheng if (!mapped_table) {
957506f57ddSLv Zheng return (AE_LIMIT);
958506f57ddSLv Zheng }
959506f57ddSLv Zheng
960506f57ddSLv Zheng if (table_length == 0) {
961506f57ddSLv Zheng status = AE_BAD_HEADER;
962506f57ddSLv Zheng goto exit;
963506f57ddSLv Zheng }
964506f57ddSLv Zheng
965506f57ddSLv Zheng /* Copy table to local buffer and return it */
966506f57ddSLv Zheng
967506f57ddSLv Zheng local_table = calloc(1, table_length);
968506f57ddSLv Zheng if (!local_table) {
969506f57ddSLv Zheng status = AE_NO_MEMORY;
970506f57ddSLv Zheng goto exit;
971506f57ddSLv Zheng }
972506f57ddSLv Zheng
9734fa4616eSBob Moore memcpy(local_table, mapped_table, table_length);
974506f57ddSLv Zheng *address = table_address;
975506f57ddSLv Zheng *table = local_table;
976506f57ddSLv Zheng
977506f57ddSLv Zheng exit:
978506f57ddSLv Zheng osl_unmap_table(mapped_table);
979506f57ddSLv Zheng return (status);
980506f57ddSLv Zheng }
981506f57ddSLv Zheng
982506f57ddSLv Zheng /******************************************************************************
983506f57ddSLv Zheng *
984506f57ddSLv Zheng * FUNCTION: osl_list_customized_tables
985506f57ddSLv Zheng *
986506f57ddSLv Zheng * PARAMETERS: directory - Directory that contains the tables
987506f57ddSLv Zheng *
988506f57ddSLv Zheng * RETURN: Status; Table list is initialized if AE_OK.
989506f57ddSLv Zheng *
990506f57ddSLv Zheng * DESCRIPTION: Add ACPI tables to the table list from a directory.
991506f57ddSLv Zheng *
992506f57ddSLv Zheng *****************************************************************************/
993506f57ddSLv Zheng
osl_list_customized_tables(char * directory)994506f57ddSLv Zheng static acpi_status osl_list_customized_tables(char *directory)
995506f57ddSLv Zheng {
996506f57ddSLv Zheng void *table_dir;
997506f57ddSLv Zheng u32 instance;
99832786755SBob Moore char temp_name[ACPI_NAMESEG_SIZE];
999506f57ddSLv Zheng char *filename;
1000506f57ddSLv Zheng acpi_status status = AE_OK;
1001506f57ddSLv Zheng
1002506f57ddSLv Zheng /* Open the requested directory */
1003506f57ddSLv Zheng
1004506f57ddSLv Zheng table_dir = acpi_os_open_directory(directory, "*", REQUEST_FILE_ONLY);
1005506f57ddSLv Zheng if (!table_dir) {
1006506f57ddSLv Zheng return (osl_get_last_status(AE_NOT_FOUND));
1007506f57ddSLv Zheng }
1008506f57ddSLv Zheng
1009506f57ddSLv Zheng /* Examine all entries in this directory */
1010506f57ddSLv Zheng
1011506f57ddSLv Zheng while ((filename = acpi_os_get_next_filename(table_dir))) {
1012506f57ddSLv Zheng
1013506f57ddSLv Zheng /* Extract table name and instance number */
1014506f57ddSLv Zheng
1015506f57ddSLv Zheng status =
1016506f57ddSLv Zheng osl_table_name_from_file(filename, temp_name, &instance);
1017506f57ddSLv Zheng
1018506f57ddSLv Zheng /* Ignore meaningless files */
1019506f57ddSLv Zheng
1020506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
1021506f57ddSLv Zheng continue;
1022506f57ddSLv Zheng }
1023506f57ddSLv Zheng
1024506f57ddSLv Zheng /* Add new info node to global table list */
1025506f57ddSLv Zheng
1026506f57ddSLv Zheng status = osl_add_table_to_list(temp_name, instance);
1027506f57ddSLv Zheng if (ACPI_FAILURE(status)) {
1028506f57ddSLv Zheng break;
1029506f57ddSLv Zheng }
1030506f57ddSLv Zheng }
1031506f57ddSLv Zheng
1032506f57ddSLv Zheng acpi_os_close_directory(table_dir);
1033506f57ddSLv Zheng return (status);
1034506f57ddSLv Zheng }
1035506f57ddSLv Zheng
1036506f57ddSLv Zheng /******************************************************************************
1037506f57ddSLv Zheng *
1038506f57ddSLv Zheng * FUNCTION: osl_map_table
1039506f57ddSLv Zheng *
1040506f57ddSLv Zheng * PARAMETERS: address - Address of the table in memory
1041506f57ddSLv Zheng * signature - Optional ACPI Signature for desired table.
1042506f57ddSLv Zheng * Null terminated 4-character string.
1043506f57ddSLv Zheng * table - Where a pointer to the mapped table is
1044506f57ddSLv Zheng * returned
1045506f57ddSLv Zheng *
1046506f57ddSLv Zheng * RETURN: Status; Mapped table is returned if AE_OK.
1047506f57ddSLv Zheng * AE_NOT_FOUND: A valid table was not found at the address
1048506f57ddSLv Zheng *
1049506f57ddSLv Zheng * DESCRIPTION: Map entire ACPI table into caller's address space.
1050506f57ddSLv Zheng *
1051506f57ddSLv Zheng *****************************************************************************/
1052506f57ddSLv Zheng
1053506f57ddSLv Zheng static acpi_status
osl_map_table(acpi_size address,char * signature,struct acpi_table_header ** table)1054506f57ddSLv Zheng osl_map_table(acpi_size address,
1055506f57ddSLv Zheng char *signature, struct acpi_table_header **table)
1056506f57ddSLv Zheng {
1057506f57ddSLv Zheng struct acpi_table_header *mapped_table;
1058506f57ddSLv Zheng u32 length;
1059506f57ddSLv Zheng
1060506f57ddSLv Zheng if (!address) {
1061506f57ddSLv Zheng return (AE_BAD_ADDRESS);
1062506f57ddSLv Zheng }
1063506f57ddSLv Zheng
1064506f57ddSLv Zheng /*
1065506f57ddSLv Zheng * Map the header so we can get the table length.
1066506f57ddSLv Zheng * Use sizeof (struct acpi_table_header) as:
1067506f57ddSLv Zheng * 1. it is bigger than 24 to include RSDP->Length
1068506f57ddSLv Zheng * 2. it is smaller than sizeof (struct acpi_table_rsdp)
1069506f57ddSLv Zheng */
1070506f57ddSLv Zheng mapped_table =
1071506f57ddSLv Zheng acpi_os_map_memory(address, sizeof(struct acpi_table_header));
1072506f57ddSLv Zheng if (!mapped_table) {
1073506f57ddSLv Zheng fprintf(stderr, "Could not map table header at 0x%8.8X%8.8X\n",
1074506f57ddSLv Zheng ACPI_FORMAT_UINT64(address));
1075506f57ddSLv Zheng return (osl_get_last_status(AE_BAD_ADDRESS));
1076506f57ddSLv Zheng }
1077506f57ddSLv Zheng
1078506f57ddSLv Zheng /* If specified, signature must match */
1079506f57ddSLv Zheng
1080d63f3790SLv Zheng if (signature) {
1081d63f3790SLv Zheng if (ACPI_VALIDATE_RSDP_SIG(signature)) {
1082d63f3790SLv Zheng if (!ACPI_VALIDATE_RSDP_SIG(mapped_table->signature)) {
1083d63f3790SLv Zheng acpi_os_unmap_memory(mapped_table,
1084d63f3790SLv Zheng sizeof(struct
1085d63f3790SLv Zheng acpi_table_header));
1086d63f3790SLv Zheng return (AE_BAD_SIGNATURE);
1087d63f3790SLv Zheng }
1088d63f3790SLv Zheng } else
10895599fb69SBob Moore if (!ACPI_COMPARE_NAMESEG
10905599fb69SBob Moore (signature, mapped_table->signature)) {
1091506f57ddSLv Zheng acpi_os_unmap_memory(mapped_table,
1092506f57ddSLv Zheng sizeof(struct acpi_table_header));
1093506f57ddSLv Zheng return (AE_BAD_SIGNATURE);
1094506f57ddSLv Zheng }
1095d63f3790SLv Zheng }
1096506f57ddSLv Zheng
1097506f57ddSLv Zheng /* Map the entire table */
1098506f57ddSLv Zheng
1099506f57ddSLv Zheng length = ap_get_table_length(mapped_table);
1100506f57ddSLv Zheng acpi_os_unmap_memory(mapped_table, sizeof(struct acpi_table_header));
1101506f57ddSLv Zheng if (length == 0) {
1102506f57ddSLv Zheng return (AE_BAD_HEADER);
1103506f57ddSLv Zheng }
1104506f57ddSLv Zheng
1105506f57ddSLv Zheng mapped_table = acpi_os_map_memory(address, length);
1106506f57ddSLv Zheng if (!mapped_table) {
1107506f57ddSLv Zheng fprintf(stderr,
1108506f57ddSLv Zheng "Could not map table at 0x%8.8X%8.8X length %8.8X\n",
1109506f57ddSLv Zheng ACPI_FORMAT_UINT64(address), length);
1110506f57ddSLv Zheng return (osl_get_last_status(AE_INVALID_TABLE_LENGTH));
1111506f57ddSLv Zheng }
1112506f57ddSLv Zheng
1113506f57ddSLv Zheng (void)ap_is_valid_checksum(mapped_table);
1114506f57ddSLv Zheng
1115506f57ddSLv Zheng *table = mapped_table;
1116506f57ddSLv Zheng return (AE_OK);
1117506f57ddSLv Zheng }
1118506f57ddSLv Zheng
1119506f57ddSLv Zheng /******************************************************************************
1120506f57ddSLv Zheng *
1121506f57ddSLv Zheng * FUNCTION: osl_unmap_table
1122506f57ddSLv Zheng *
1123506f57ddSLv Zheng * PARAMETERS: table - A pointer to the mapped table
1124506f57ddSLv Zheng *
1125506f57ddSLv Zheng * RETURN: None
1126506f57ddSLv Zheng *
1127506f57ddSLv Zheng * DESCRIPTION: Unmap entire ACPI table.
1128506f57ddSLv Zheng *
1129506f57ddSLv Zheng *****************************************************************************/
1130506f57ddSLv Zheng
osl_unmap_table(struct acpi_table_header * table)1131506f57ddSLv Zheng static void osl_unmap_table(struct acpi_table_header *table)
1132506f57ddSLv Zheng {
1133506f57ddSLv Zheng if (table) {
1134506f57ddSLv Zheng acpi_os_unmap_memory(table, ap_get_table_length(table));
1135506f57ddSLv Zheng }
1136506f57ddSLv Zheng }
1137506f57ddSLv Zheng
1138506f57ddSLv Zheng /******************************************************************************
1139506f57ddSLv Zheng *
1140506f57ddSLv Zheng * FUNCTION: osl_table_name_from_file
1141506f57ddSLv Zheng *
1142506f57ddSLv Zheng * PARAMETERS: filename - File that contains the desired table
1143506f57ddSLv Zheng * signature - Pointer to 4-character buffer to store
1144506f57ddSLv Zheng * extracted table signature.
1145506f57ddSLv Zheng * instance - Pointer to integer to store extracted
1146506f57ddSLv Zheng * table instance number.
1147506f57ddSLv Zheng *
1148506f57ddSLv Zheng * RETURN: Status; Table name is extracted if AE_OK.
1149506f57ddSLv Zheng *
1150506f57ddSLv Zheng * DESCRIPTION: Extract table signature and instance number from a table file
1151506f57ddSLv Zheng * name.
1152506f57ddSLv Zheng *
1153506f57ddSLv Zheng *****************************************************************************/
1154506f57ddSLv Zheng
1155506f57ddSLv Zheng static acpi_status
osl_table_name_from_file(char * filename,char * signature,u32 * instance)1156506f57ddSLv Zheng osl_table_name_from_file(char *filename, char *signature, u32 *instance)
1157506f57ddSLv Zheng {
1158506f57ddSLv Zheng
1159506f57ddSLv Zheng /* Ignore meaningless files */
1160506f57ddSLv Zheng
116132786755SBob Moore if (strlen(filename) < ACPI_NAMESEG_SIZE) {
1162506f57ddSLv Zheng return (AE_BAD_SIGNATURE);
1163506f57ddSLv Zheng }
1164506f57ddSLv Zheng
1165506f57ddSLv Zheng /* Extract instance number */
1166506f57ddSLv Zheng
116732786755SBob Moore if (isdigit((int)filename[ACPI_NAMESEG_SIZE])) {
116832786755SBob Moore sscanf(&filename[ACPI_NAMESEG_SIZE], "%u", instance);
116932786755SBob Moore } else if (strlen(filename) != ACPI_NAMESEG_SIZE) {
1170506f57ddSLv Zheng return (AE_BAD_SIGNATURE);
1171506f57ddSLv Zheng } else {
1172506f57ddSLv Zheng *instance = 0;
1173506f57ddSLv Zheng }
1174506f57ddSLv Zheng
1175506f57ddSLv Zheng /* Extract signature */
1176506f57ddSLv Zheng
1177a3ce7a8eSBob Moore ACPI_COPY_NAMESEG(signature, filename);
1178506f57ddSLv Zheng return (AE_OK);
1179506f57ddSLv Zheng }
1180506f57ddSLv Zheng
1181506f57ddSLv Zheng /******************************************************************************
1182506f57ddSLv Zheng *
1183506f57ddSLv Zheng * FUNCTION: osl_read_table_from_file
1184506f57ddSLv Zheng *
1185506f57ddSLv Zheng * PARAMETERS: filename - File that contains the desired table
1186506f57ddSLv Zheng * file_offset - Offset of the table in file
1187506f57ddSLv Zheng * table - Where a pointer to the table is returned
1188506f57ddSLv Zheng *
1189506f57ddSLv Zheng * RETURN: Status; Table buffer is returned if AE_OK.
1190506f57ddSLv Zheng *
1191506f57ddSLv Zheng * DESCRIPTION: Read a ACPI table from a file.
1192506f57ddSLv Zheng *
1193506f57ddSLv Zheng *****************************************************************************/
1194506f57ddSLv Zheng
1195506f57ddSLv Zheng static acpi_status
osl_read_table_from_file(char * filename,acpi_size file_offset,struct acpi_table_header ** table)1196506f57ddSLv Zheng osl_read_table_from_file(char *filename,
1197506f57ddSLv Zheng acpi_size file_offset,
1198d82faa08SBob Moore struct acpi_table_header **table)
1199506f57ddSLv Zheng {
1200506f57ddSLv Zheng FILE *table_file;
1201506f57ddSLv Zheng struct acpi_table_header header;
1202506f57ddSLv Zheng struct acpi_table_header *local_table = NULL;
1203506f57ddSLv Zheng u32 table_length;
1204506f57ddSLv Zheng s32 count;
1205506f57ddSLv Zheng acpi_status status = AE_OK;
1206506f57ddSLv Zheng
1207506f57ddSLv Zheng /* Open the file */
1208506f57ddSLv Zheng
1209506f57ddSLv Zheng table_file = fopen(filename, "rb");
1210506f57ddSLv Zheng if (table_file == NULL) {
1211506f57ddSLv Zheng fprintf(stderr, "Could not open table file: %s\n", filename);
1212506f57ddSLv Zheng return (osl_get_last_status(AE_NOT_FOUND));
1213506f57ddSLv Zheng }
1214506f57ddSLv Zheng
1215506f57ddSLv Zheng fseek(table_file, file_offset, SEEK_SET);
1216506f57ddSLv Zheng
1217506f57ddSLv Zheng /* Read the Table header to get the table length */
1218506f57ddSLv Zheng
1219506f57ddSLv Zheng count = fread(&header, 1, sizeof(struct acpi_table_header), table_file);
1220506f57ddSLv Zheng if (count != sizeof(struct acpi_table_header)) {
1221506f57ddSLv Zheng fprintf(stderr, "Could not read table header: %s\n", filename);
1222506f57ddSLv Zheng status = AE_BAD_HEADER;
1223506f57ddSLv Zheng goto exit;
1224506f57ddSLv Zheng }
1225506f57ddSLv Zheng
1226d82faa08SBob Moore #ifdef ACPI_OBSOLETE_FUNCTIONS
1227d82faa08SBob Moore
1228506f57ddSLv Zheng /* If signature is specified, it must match the table */
1229506f57ddSLv Zheng
1230d63f3790SLv Zheng if (signature) {
1231d63f3790SLv Zheng if (ACPI_VALIDATE_RSDP_SIG(signature)) {
1232d63f3790SLv Zheng if (!ACPI_VALIDATE_RSDP_SIG(header.signature)) {
1233d63f3790SLv Zheng fprintf(stderr,
1234d63f3790SLv Zheng "Incorrect RSDP signature: found %8.8s\n",
1235d63f3790SLv Zheng header.signature);
1236d63f3790SLv Zheng status = AE_BAD_SIGNATURE;
1237d63f3790SLv Zheng goto exit;
1238d63f3790SLv Zheng }
12395599fb69SBob Moore } else if (!ACPI_COMPARE_NAMESEG(signature, header.signature)) {
1240506f57ddSLv Zheng fprintf(stderr,
1241506f57ddSLv Zheng "Incorrect signature: Expecting %4.4s, found %4.4s\n",
1242506f57ddSLv Zheng signature, header.signature);
1243506f57ddSLv Zheng status = AE_BAD_SIGNATURE;
1244506f57ddSLv Zheng goto exit;
1245506f57ddSLv Zheng }
1246d63f3790SLv Zheng }
1247d82faa08SBob Moore #endif
1248506f57ddSLv Zheng
1249506f57ddSLv Zheng table_length = ap_get_table_length(&header);
1250506f57ddSLv Zheng if (table_length == 0) {
1251506f57ddSLv Zheng status = AE_BAD_HEADER;
1252506f57ddSLv Zheng goto exit;
1253506f57ddSLv Zheng }
1254506f57ddSLv Zheng
1255506f57ddSLv Zheng /* Read the entire table into a local buffer */
1256506f57ddSLv Zheng
1257506f57ddSLv Zheng local_table = calloc(1, table_length);
1258506f57ddSLv Zheng if (!local_table) {
1259506f57ddSLv Zheng fprintf(stderr,
1260506f57ddSLv Zheng "%4.4s: Could not allocate buffer for table of length %X\n",
1261506f57ddSLv Zheng header.signature, table_length);
1262506f57ddSLv Zheng status = AE_NO_MEMORY;
1263506f57ddSLv Zheng goto exit;
1264506f57ddSLv Zheng }
1265506f57ddSLv Zheng
1266506f57ddSLv Zheng fseek(table_file, file_offset, SEEK_SET);
1267506f57ddSLv Zheng
1268d87a2b75SLv Zheng count = fread(local_table, 1, table_length, table_file);
1269d87a2b75SLv Zheng if (count != table_length) {
1270506f57ddSLv Zheng fprintf(stderr, "%4.4s: Could not read table content\n",
1271506f57ddSLv Zheng header.signature);
1272506f57ddSLv Zheng status = AE_INVALID_TABLE_LENGTH;
1273506f57ddSLv Zheng goto exit;
1274506f57ddSLv Zheng }
1275506f57ddSLv Zheng
1276506f57ddSLv Zheng /* Validate checksum */
1277506f57ddSLv Zheng
1278506f57ddSLv Zheng (void)ap_is_valid_checksum(local_table);
1279506f57ddSLv Zheng
1280506f57ddSLv Zheng exit:
1281506f57ddSLv Zheng fclose(table_file);
1282506f57ddSLv Zheng *table = local_table;
1283506f57ddSLv Zheng return (status);
1284506f57ddSLv Zheng }
1285506f57ddSLv Zheng
1286506f57ddSLv Zheng /******************************************************************************
1287506f57ddSLv Zheng *
1288506f57ddSLv Zheng * FUNCTION: osl_get_customized_table
1289506f57ddSLv Zheng *
1290506f57ddSLv Zheng * PARAMETERS: pathname - Directory to find Linux customized table
1291506f57ddSLv Zheng * signature - ACPI Signature for desired table. Must be
1292506f57ddSLv Zheng * a null terminated 4-character string.
1293506f57ddSLv Zheng * instance - Multiple table support for SSDT/UEFI (0...n)
1294506f57ddSLv Zheng * Must be 0 for other tables.
1295506f57ddSLv Zheng * table - Where a pointer to the table is returned
1296506f57ddSLv Zheng * address - Where the table physical address is returned
1297506f57ddSLv Zheng *
1298506f57ddSLv Zheng * RETURN: Status; Table buffer is returned if AE_OK.
1299506f57ddSLv Zheng * AE_LIMIT: Instance is beyond valid limit
1300506f57ddSLv Zheng * AE_NOT_FOUND: A table with the signature was not found
1301506f57ddSLv Zheng *
1302506f57ddSLv Zheng * DESCRIPTION: Get an OS customized table.
1303506f57ddSLv Zheng *
1304506f57ddSLv Zheng *****************************************************************************/
1305506f57ddSLv Zheng
1306506f57ddSLv Zheng static acpi_status
osl_get_customized_table(char * pathname,char * signature,u32 instance,struct acpi_table_header ** table,acpi_physical_address * address)1307506f57ddSLv Zheng osl_get_customized_table(char *pathname,
1308506f57ddSLv Zheng char *signature,
1309506f57ddSLv Zheng u32 instance,
1310506f57ddSLv Zheng struct acpi_table_header **table,
1311506f57ddSLv Zheng acpi_physical_address *address)
1312506f57ddSLv Zheng {
1313506f57ddSLv Zheng void *table_dir;
1314506f57ddSLv Zheng u32 current_instance = 0;
131532786755SBob Moore char temp_name[ACPI_NAMESEG_SIZE];
1316506f57ddSLv Zheng char table_filename[PATH_MAX];
1317506f57ddSLv Zheng char *filename;
1318506f57ddSLv Zheng acpi_status status;
1319506f57ddSLv Zheng
1320506f57ddSLv Zheng /* Open the directory for customized tables */
1321506f57ddSLv Zheng
1322506f57ddSLv Zheng table_dir = acpi_os_open_directory(pathname, "*", REQUEST_FILE_ONLY);
1323506f57ddSLv Zheng if (!table_dir) {
1324506f57ddSLv Zheng return (osl_get_last_status(AE_NOT_FOUND));
1325506f57ddSLv Zheng }
1326506f57ddSLv Zheng
1327506f57ddSLv Zheng /* Attempt to find the table in the directory */
1328506f57ddSLv Zheng
1329506f57ddSLv Zheng while ((filename = acpi_os_get_next_filename(table_dir))) {
1330506f57ddSLv Zheng
1331506f57ddSLv Zheng /* Ignore meaningless files */
1332506f57ddSLv Zheng
13335599fb69SBob Moore if (!ACPI_COMPARE_NAMESEG(filename, signature)) {
1334506f57ddSLv Zheng continue;
1335506f57ddSLv Zheng }
1336506f57ddSLv Zheng
1337506f57ddSLv Zheng /* Extract table name and instance number */
1338506f57ddSLv Zheng
1339506f57ddSLv Zheng status =
1340506f57ddSLv Zheng osl_table_name_from_file(filename, temp_name,
1341506f57ddSLv Zheng ¤t_instance);
1342506f57ddSLv Zheng
1343506f57ddSLv Zheng /* Ignore meaningless files */
1344506f57ddSLv Zheng
1345506f57ddSLv Zheng if (ACPI_FAILURE(status) || current_instance != instance) {
1346506f57ddSLv Zheng continue;
1347506f57ddSLv Zheng }
1348506f57ddSLv Zheng
1349506f57ddSLv Zheng /* Create the table pathname */
1350506f57ddSLv Zheng
1351506f57ddSLv Zheng if (instance != 0) {
1352506f57ddSLv Zheng sprintf(table_filename, "%s/%4.4s%d", pathname,
1353506f57ddSLv Zheng temp_name, instance);
1354506f57ddSLv Zheng } else {
1355506f57ddSLv Zheng sprintf(table_filename, "%s/%4.4s", pathname,
1356506f57ddSLv Zheng temp_name);
1357506f57ddSLv Zheng }
1358506f57ddSLv Zheng break;
1359506f57ddSLv Zheng }
1360506f57ddSLv Zheng
1361506f57ddSLv Zheng acpi_os_close_directory(table_dir);
1362506f57ddSLv Zheng
1363506f57ddSLv Zheng if (!filename) {
1364506f57ddSLv Zheng return (AE_LIMIT);
1365506f57ddSLv Zheng }
1366506f57ddSLv Zheng
1367506f57ddSLv Zheng /* There is no physical address saved for customized tables, use zero */
1368506f57ddSLv Zheng
1369506f57ddSLv Zheng *address = 0;
1370d82faa08SBob Moore status = osl_read_table_from_file(table_filename, 0, table);
1371506f57ddSLv Zheng
1372506f57ddSLv Zheng return (status);
1373506f57ddSLv Zheng }
1374