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