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