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