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 
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 
ap_is_valid_header(struct acpi_table_header * table)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 
ap_is_valid_checksum(struct acpi_table_header * table)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 	}
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 
ap_get_table_length(struct acpi_table_header * table)106 u32 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 
141 static int
ap_dump_table_buffer(struct acpi_table_header * table,u32 instance,acpi_physical_address address)142 ap_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 
ap_dump_all_tables(void)190 int 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 
ap_dump_table_by_address(char * ascii_address)248 int 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 
ap_dump_table_by_name(char * signature)292 int 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 
ap_dump_table_from_file(char * pathname)365 int 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 
401 exit:
402 	ACPI_FREE(table);
403 	return (table_status);
404 }
405