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
13 ACPI_MODULE_NAME("oslinuxtbl")
14 
15 #ifndef PATH_MAX
16 #define PATH_MAX 256
17 #endif
18 /* List of information about obtained ACPI tables */
19 typedef 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 
28 static acpi_status osl_table_initialize(void);
29 
30 static acpi_status
31 osl_table_name_from_file(char *filename, char *signature, u32 *instance);
32 
33 static acpi_status osl_add_table_to_list(char *signature, u32 instance);
34 
35 static acpi_status
36 osl_read_table_from_file(char *filename,
37 			 acpi_size file_offset,
38 			 struct acpi_table_header **table);
39 
40 static acpi_status
41 osl_map_table(acpi_size address,
42 	      char *signature, struct acpi_table_header **table);
43 
44 static void osl_unmap_table(struct acpi_table_header *table);
45 
46 static acpi_physical_address
47 osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword);
48 
49 static acpi_physical_address osl_find_rsdp_via_efi(void);
50 
51 static acpi_status osl_load_rsdp(void);
52 
53 static acpi_status osl_list_customized_tables(char *directory);
54 
55 static acpi_status
56 osl_get_customized_table(char *pathname,
57 			 char *signature,
58 			 u32 instance,
59 			 struct acpi_table_header **table,
60 			 acpi_physical_address *address);
61 
62 static acpi_status osl_list_bios_tables(void);
63 
64 static acpi_status
65 osl_get_bios_table(char *signature,
66 		   u32 instance,
67 		   struct acpi_table_header **table,
68 		   acpi_physical_address *address);
69 
70 static 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 
80 u8 gbl_dump_dynamic_tables = TRUE;
81 
82 /* Initialization flags */
83 
84 u8 gbl_table_list_initialized = FALSE;
85 
86 /* Local copies of main ACPI tables */
87 
88 struct acpi_table_rsdp gbl_rsdp;
89 struct acpi_table_fadt *gbl_fadt = NULL;
90 struct acpi_table_rsdt *gbl_rsdt = NULL;
91 struct acpi_table_xsdt *gbl_xsdt = NULL;
92 
93 /* Table addresses */
94 
95 acpi_physical_address gbl_fadt_address = 0;
96 acpi_physical_address gbl_rsdp_address = 0;
97 
98 /* Revision of RSD PTR */
99 
100 u8 gbl_revision = 0;
101 
102 struct osl_table_info *gbl_table_list_head = NULL;
103 u32 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 
osl_get_last_status(acpi_status default_status)117 static 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 
154 acpi_status
acpi_os_get_table_by_address(acpi_physical_address address,struct acpi_table_header ** table)155 acpi_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 
193 exit:
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 
218 acpi_status
acpi_os_get_table_by_name(char * signature,u32 instance,struct acpi_table_header ** table,acpi_physical_address * address)219 acpi_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 
osl_add_table_to_list(char * signature,u32 instance)277 static 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 
347 acpi_status
acpi_os_get_table_by_index(u32 index,struct acpi_table_header ** table,u32 * instance,acpi_physical_address * address)348 acpi_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 
401 static acpi_physical_address
osl_find_rsdp_via_efi_by_keyword(FILE * file,const char * keyword)402 osl_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 
osl_find_rsdp_via_efi(void)431 static 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 
osl_load_rsdp(void)461 static acpi_status osl_load_rsdp(void)
462 {
463 	struct acpi_table_header *mapped_table;
464 	u8 *rsdp_address;
465 	acpi_physical_address rsdp_base;
466 	acpi_size rsdp_size;
467 
468 	/* Get RSDP from memory */
469 
470 	rsdp_size = sizeof(struct acpi_table_rsdp);
471 	if (gbl_rsdp_base) {
472 		rsdp_base = gbl_rsdp_base;
473 	} else {
474 		rsdp_base = osl_find_rsdp_via_efi();
475 	}
476 
477 	if (!rsdp_base) {
478 		rsdp_base = ACPI_HI_RSDP_WINDOW_BASE;
479 		rsdp_size = ACPI_HI_RSDP_WINDOW_SIZE;
480 	}
481 
482 	rsdp_address = acpi_os_map_memory(rsdp_base, rsdp_size);
483 	if (!rsdp_address) {
484 		return (osl_get_last_status(AE_BAD_ADDRESS));
485 	}
486 
487 	/* Search low memory for the RSDP */
488 
489 	mapped_table = ACPI_CAST_PTR(struct acpi_table_header,
490 				     acpi_tb_scan_memory_for_rsdp(rsdp_address,
491 								  rsdp_size));
492 	if (!mapped_table) {
493 		acpi_os_unmap_memory(rsdp_address, rsdp_size);
494 		return (AE_NOT_FOUND);
495 	}
496 
497 	gbl_rsdp_address =
498 	    rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address);
499 
500 	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 
osl_can_use_xsdt(void)519 static u8 osl_can_use_xsdt(void)
520 {
521 	if (gbl_revision && !acpi_gbl_do_not_use_xsdt) {
522 		return (TRUE);
523 	} else {
524 		return (FALSE);
525 	}
526 }
527 
528 /******************************************************************************
529  *
530  * FUNCTION:    osl_table_initialize
531  *
532  * PARAMETERS:  None
533  *
534  * RETURN:      Status
535  *
536  * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
537  *              local variables. Main ACPI tables include RSDT, FADT, RSDT,
538  *              and/or XSDT.
539  *
540  *****************************************************************************/
541 
osl_table_initialize(void)542 static acpi_status osl_table_initialize(void)
543 {
544 	acpi_status status;
545 	acpi_physical_address address;
546 
547 	if (gbl_table_list_initialized) {
548 		return (AE_OK);
549 	}
550 
551 	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 
osl_list_bios_tables(void)686 static 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 
765 static acpi_status
osl_get_bios_table(char * signature,u32 instance,struct acpi_table_header ** table,acpi_physical_address * address)766 osl_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 
791 find_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 
954 exit_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 
977 exit:
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 
osl_list_customized_tables(char * directory)994 static 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 
1053 static acpi_status
osl_map_table(acpi_size address,char * signature,struct acpi_table_header ** table)1054 osl_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 
osl_unmap_table(struct acpi_table_header * table)1131 static 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 
1155 static acpi_status
osl_table_name_from_file(char * filename,char * signature,u32 * instance)1156 osl_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 
1195 static acpi_status
osl_read_table_from_file(char * filename,acpi_size file_offset,struct acpi_table_header ** table)1196 osl_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 
1280 exit:
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 
1306 static acpi_status
osl_get_customized_table(char * pathname,char * signature,u32 instance,struct acpi_table_header ** table,acpi_physical_address * address)1307 osl_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