File Index
Files and directories
Sign in
FILE

apdump.c

File preview with syntax highlighting.

linux-6.19.14/tools/power/acpi/tools/acpidump/apdump.c C
  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
 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		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
107u32 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
142static int
143ap_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
191int 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
249int 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
293int 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
366int 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
402exit:
403	ACPI_FREE(table);
404	return (table_status);
405}
~/ Read-only file preview.