1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/******************************************************************************
3 *
4 * Module Name: apdump - Dump routines for ACPI tables (acpidump)
5 *
6 * Copyright (C) 2000 - 2023, Intel Corp.
7 *
8 *****************************************************************************/
9
10#include "acpidump.h"
11
12/* Local prototypes */
13
14static int
15ap_dump_table_buffer(struct acpi_table_header *table,
16		     u32 instance, acpi_physical_address address);
17
18/******************************************************************************
19 *
20 * FUNCTION:    ap_is_valid_header
21 *
22 * PARAMETERS:  table               - Pointer to table to be validated
23 *
24 * RETURN:      TRUE if the header appears to be valid. FALSE otherwise
25 *
26 * DESCRIPTION: Check for a valid ACPI table header
27 *
28 ******************************************************************************/
29
30u8 ap_is_valid_header(struct acpi_table_header *table)
31{
32
33	if (!ACPI_VALIDATE_RSDP_SIG(table->signature)) {
34
35		/* Make sure signature is all ASCII and a valid ACPI name */
36
37		if (!acpi_ut_valid_nameseg(table->signature)) {
38			fprintf(stderr,
39				"Table signature (0x%8.8X) is invalid\n",
40				*(u32 *)table->signature);
41			return (FALSE);
42		}
43
44		/* Check for minimum table length */
45
46		if (table->length < sizeof(struct acpi_table_header)) {
47			fprintf(stderr, "Table length (0x%8.8X) is invalid\n",
48				table->length);
49			return (FALSE);
50		}
51	}
52
53	return (TRUE);
54}
55
56/******************************************************************************
57 *
58 * FUNCTION:    ap_is_valid_checksum
59 *
60 * PARAMETERS:  table               - Pointer to table to be validated
61 *
62 * RETURN:      TRUE if the checksum appears to be valid. FALSE otherwise.
63 *
64 * DESCRIPTION: Check for a valid ACPI table checksum.
65 *
66 ******************************************************************************/
67
68u8 ap_is_valid_checksum(struct acpi_table_header *table)
69{
70	acpi_status status;
71	struct acpi_table_rsdp *rsdp;
72
73	if (ACPI_VALIDATE_RSDP_SIG(table->signature)) {
74		/*
75		 * Checksum for RSDP.
76		 * Note: Other checksums are computed during the table dump.
77		 */
78		rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table);
79		status = acpi_tb_validate_rsdp(rsdp);
80	} else {
81		/* We don't have to check for a CDAT here, since CDAT is not in the RSDT/XSDT */
82
83		status = acpi_ut_verify_checksum(table, table->length);
84	}
85
86	if (ACPI_FAILURE(status)) {
87		fprintf(stderr, "%4.4s: Warning: wrong checksum in table\n",
88			table->signature);
89	}
90
91	return (AE_OK);
92}
93
94/******************************************************************************
95 *
96 * FUNCTION:    ap_get_table_length
97 *
98 * PARAMETERS:  table               - Pointer to the table
99 *
100 * RETURN:      Table length
101 *
102 * DESCRIPTION: Obtain table length according to table signature.
103 *
104 ******************************************************************************/
105
106u32 ap_get_table_length(struct acpi_table_header *table)
107{
108	struct acpi_table_rsdp *rsdp;
109
110	/* Check if table is valid */
111
112	if (!ap_is_valid_header(table)) {
113		return (0);
114	}
115
116	if (ACPI_VALIDATE_RSDP_SIG(table->signature)) {
117		rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table);
118		return (acpi_tb_get_rsdp_length(rsdp));
119	}
120
121	/* Normal ACPI table */
122
123	return (table->length);
124}
125
126/******************************************************************************
127 *
128 * FUNCTION:    ap_dump_table_buffer
129 *
130 * PARAMETERS:  table               - ACPI table to be dumped
131 *              instance            - ACPI table instance no. to be dumped
132 *              address             - Physical address of the table
133 *
134 * RETURN:      None
135 *
136 * DESCRIPTION: Dump an ACPI table in standard ASCII hex format, with a
137 *              header that is compatible with the acpi_xtract utility.
138 *
139 ******************************************************************************/
140
141static int
142ap_dump_table_buffer(struct acpi_table_header *table,
143		     u32 instance, acpi_physical_address address)
144{
145	u32 table_length;
146
147	table_length = ap_get_table_length(table);
148
149	/* Print only the header if requested */
150
151	if (gbl_summary_mode) {
152		acpi_tb_print_table_header(address, table);
153		return (0);
154	}
155
156	/* Dump to binary file if requested */
157
158	if (gbl_binary_mode) {
159		return (ap_write_to_binary_file(table, instance));
160	}
161
162	/*
163	 * Dump the table with header for use with acpixtract utility.
164	 * Note: simplest to just always emit a 64-bit address. acpi_xtract
165	 * utility can handle this.
166	 */
167	fprintf(gbl_output_file, "%4.4s @ 0x%8.8X%8.8X\n",
168		table->signature, ACPI_FORMAT_UINT64(address));
169
170	acpi_ut_dump_buffer_to_file(gbl_output_file,
171				    ACPI_CAST_PTR(u8, table), table_length,
172				    DB_BYTE_DISPLAY, 0);
173	fprintf(gbl_output_file, "\n");
174	return (0);
175}
176
177/******************************************************************************
178 *
179 * FUNCTION:    ap_dump_all_tables
180 *
181 * PARAMETERS:  None
182 *
183 * RETURN:      Status
184 *
185 * DESCRIPTION: Get all tables from the RSDT/XSDT (or at least all of the
186 *              tables that we can possibly get).
187 *
188 ******************************************************************************/
189
190int ap_dump_all_tables(void)
191{
192	struct acpi_table_header *table;
193	u32 instance = 0;
194	acpi_physical_address address;
195	acpi_status status;
196	int table_status;
197	u32 i;
198
199	/* Get and dump all available ACPI tables */
200
201	for (i = 0; i < AP_MAX_ACPI_FILES; i++) {
202		status =
203		    acpi_os_get_table_by_index(i, &table, &instance, &address);
204		if (ACPI_FAILURE(status)) {
205
206			/* AE_LIMIT means that no more tables are available */
207
208			if (status == AE_LIMIT) {
209				return (0);
210			} else if (i == 0) {
211				fprintf(stderr,
212					"Could not get ACPI tables, %s\n",
213					acpi_format_exception(status));
214				return (-1);
215			} else {
216				fprintf(stderr,
217					"Could not get ACPI table at index %u, %s\n",
218					i, acpi_format_exception(status));
219				continue;
220			}
221		}
222
223		table_status = ap_dump_table_buffer(table, instance, address);
224		ACPI_FREE(table);
225
226		if (table_status) {
227			break;
228		}
229	}
230
231	/* Something seriously bad happened if the loop terminates here */
232
233	return (-1);
234}
235
236/******************************************************************************
237 *
238 * FUNCTION:    ap_dump_table_by_address
239 *
240 * PARAMETERS:  ascii_address       - Address for requested ACPI table
241 *
242 * RETURN:      Status
243 *
244 * DESCRIPTION: Get an ACPI table via a physical address and dump it.
245 *
246 ******************************************************************************/
247
248int ap_dump_table_by_address(char *ascii_address)
249{
250	acpi_physical_address address;
251	struct acpi_table_header *table;
252	acpi_status status;
253	int table_status;
254	u64 long_address;
255
256	/* Convert argument to an integer physical address */
257
258	status = acpi_ut_strtoul64(ascii_address, &long_address);
259	if (ACPI_FAILURE(status)) {
260		fprintf(stderr, "%s: Could not convert to a physical address\n",
261			ascii_address);
262		return (-1);
263	}
264
265	address = (acpi_physical_address)long_address;
266	status = acpi_os_get_table_by_address(address, &table);
267	if (ACPI_FAILURE(status)) {
268		fprintf(stderr, "Could not get table at 0x%8.8X%8.8X, %s\n",
269			ACPI_FORMAT_UINT64(address),
270			acpi_format_exception(status));
271		return (-1);
272	}
273
274	table_status = ap_dump_table_buffer(table, 0, address);
275	ACPI_FREE(table);
276	return (table_status);
277}
278
279/******************************************************************************
280 *
281 * FUNCTION:    ap_dump_table_by_name
282 *
283 * PARAMETERS:  signature           - Requested ACPI table signature
284 *
285 * RETURN:      Status
286 *
287 * DESCRIPTION: Get an ACPI table via a signature and dump it. Handles
288 *              multiple tables with the same signature (SSDTs).
289 *
290 ******************************************************************************/
291
292int ap_dump_table_by_name(char *signature)
293{
294	char local_signature[ACPI_NAMESEG_SIZE + 1];
295	u32 instance;
296	struct acpi_table_header *table;
297	acpi_physical_address address;
298	acpi_status status;
299	int table_status;
300
301	if (strlen(signature) != ACPI_NAMESEG_SIZE) {
302		fprintf(stderr,
303			"Invalid table signature [%s]: must be exactly 4 characters\n",
304			signature);
305		return (-1);
306	}
307
308	/* Table signatures are expected to be uppercase */
309
310	strcpy(local_signature, signature);
311	acpi_ut_strupr(local_signature);
312
313	/* To be friendly, handle tables whose signatures do not match the name */
314
315	if (ACPI_COMPARE_NAMESEG(local_signature, "FADT")) {
316		strcpy(local_signature, ACPI_SIG_FADT);
317	} else if (ACPI_COMPARE_NAMESEG(local_signature, "MADT")) {
318		strcpy(local_signature, ACPI_SIG_MADT);
319	}
320
321	/* Dump all instances of this signature (to handle multiple SSDTs) */
322
323	for (instance = 0; instance < AP_MAX_ACPI_FILES; instance++) {
324		status = acpi_os_get_table_by_name(local_signature, instance,
325						   &table, &address);
326		if (ACPI_FAILURE(status)) {
327
328			/* AE_LIMIT means that no more tables are available */
329
330			if (status == AE_LIMIT) {
331				return (0);
332			}
333
334			fprintf(stderr,
335				"Could not get ACPI table with signature [%s], %s\n",
336				local_signature, acpi_format_exception(status));
337			return (-1);
338		}
339
340		table_status = ap_dump_table_buffer(table, instance, address);
341		ACPI_FREE(table);
342
343		if (table_status) {
344			break;
345		}
346	}
347
348	/* Something seriously bad happened if the loop terminates here */
349
350	return (-1);
351}
352
353/******************************************************************************
354 *
355 * FUNCTION:    ap_dump_table_from_file
356 *
357 * PARAMETERS:  pathname            - File containing the binary ACPI table
358 *
359 * RETURN:      Status
360 *
361 * DESCRIPTION: Dump an ACPI table from a binary file
362 *
363 ******************************************************************************/
364
365int ap_dump_table_from_file(char *pathname)
366{
367	struct acpi_table_header *table;
368	u32 file_size = 0;
369	int table_status = -1;
370
371	/* Get the entire ACPI table from the file */
372
373	table = ap_get_table_from_file(pathname, &file_size);
374	if (!table) {
375		return (-1);
376	}
377
378	if (!acpi_ut_valid_nameseg(table->signature)) {
379		fprintf(stderr,
380			"No valid ACPI signature was found in input file %s\n",
381			pathname);
382	}
383
384	/* File must be at least as long as the table length */
385
386	if (table->length > file_size) {
387		fprintf(stderr,
388			"Table length (0x%X) is too large for input file (0x%X) %s\n",
389			table->length, file_size, pathname);
390		goto exit;
391	}
392
393	if (gbl_verbose_mode) {
394		fprintf(stderr,
395			"Input file:  %s contains table [%4.4s], 0x%X (%u) bytes\n",
396			pathname, table->signature, file_size, file_size);
397	}
398
399	table_status = ap_dump_table_buffer(table, 0, 0);
400
401exit:
402	ACPI_FREE(table);
403	return (table_status);
404}
405