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
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 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
ap_get_table_length(struct acpi_table_header * table)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
ap_dump_table_buffer(struct acpi_table_header * table,u32 instance,acpi_physical_address address)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
ap_dump_all_tables(void)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
ap_dump_table_by_address(char * ascii_address)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
ap_dump_table_by_name(char * signature)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
ap_dump_table_from_file(char * pathname)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