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