xref: /openbmc/linux/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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 					     &current_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