1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /******************************************************************************* |
3 | * |
4 | * Module Name: rsdump - AML debugger support for resource structures. |
5 | * |
6 | ******************************************************************************/ |
7 | |
8 | #include <acpi/acpi.h> |
9 | #include "accommon.h" |
10 | #include "acresrc.h" |
11 | |
12 | #define _COMPONENT ACPI_RESOURCES |
13 | ACPI_MODULE_NAME("rsdump" ) |
14 | |
15 | /* |
16 | * All functions in this module are used by the AML Debugger only |
17 | */ |
18 | /* Local prototypes */ |
19 | static void acpi_rs_out_string(const char *title, const char *value); |
20 | |
21 | static void acpi_rs_out_integer8(const char *title, u8 value); |
22 | |
23 | static void acpi_rs_out_integer16(const char *title, u16 value); |
24 | |
25 | static void acpi_rs_out_integer32(const char *title, u32 value); |
26 | |
27 | static void acpi_rs_out_integer64(const char *title, u64 value); |
28 | |
29 | static void acpi_rs_out_title(const char *title); |
30 | |
31 | static void acpi_rs_dump_byte_list(u16 length, u8 *data); |
32 | |
33 | static void acpi_rs_dump_word_list(u16 length, u16 *data); |
34 | |
35 | static void acpi_rs_dump_dword_list(u8 length, u32 *data); |
36 | |
37 | static void acpi_rs_dump_short_byte_list(u8 length, u8 *data); |
38 | |
39 | static void |
40 | acpi_rs_dump_resource_source(struct acpi_resource_source *resource_source); |
41 | |
42 | static void |
43 | acpi_rs_dump_resource_label(char *title, |
44 | struct acpi_resource_label *resource_label); |
45 | |
46 | static void acpi_rs_dump_address_common(union acpi_resource_data *resource); |
47 | |
48 | static void |
49 | acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table); |
50 | |
51 | /******************************************************************************* |
52 | * |
53 | * FUNCTION: acpi_rs_dump_resource_list |
54 | * |
55 | * PARAMETERS: resource_list - Pointer to a resource descriptor list |
56 | * |
57 | * RETURN: None |
58 | * |
59 | * DESCRIPTION: Dispatches the structure to the correct dump routine. |
60 | * |
61 | ******************************************************************************/ |
62 | |
63 | void acpi_rs_dump_resource_list(struct acpi_resource *resource_list) |
64 | { |
65 | u32 count = 0; |
66 | u32 type; |
67 | |
68 | ACPI_FUNCTION_ENTRY(); |
69 | |
70 | /* Check if debug output enabled */ |
71 | |
72 | if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_RESOURCES, _COMPONENT)) { |
73 | return; |
74 | } |
75 | |
76 | /* Walk list and dump all resource descriptors (END_TAG terminates) */ |
77 | |
78 | do { |
79 | acpi_os_printf(format: "\n[%02X] " , count); |
80 | count++; |
81 | |
82 | /* Validate Type before dispatch */ |
83 | |
84 | type = resource_list->type; |
85 | if (type > ACPI_RESOURCE_TYPE_MAX) { |
86 | acpi_os_printf |
87 | (format: "Invalid descriptor type (%X) in resource list\n" , |
88 | resource_list->type); |
89 | return; |
90 | } else if (!resource_list->type) { |
91 | ACPI_ERROR((AE_INFO, "Invalid Zero Resource Type" )); |
92 | return; |
93 | } |
94 | |
95 | /* Sanity check the length. It must not be zero, or we loop forever */ |
96 | |
97 | if (!resource_list->length) { |
98 | acpi_os_printf |
99 | (format: "Invalid zero length descriptor in resource list\n" ); |
100 | return; |
101 | } |
102 | |
103 | /* Dump the resource descriptor */ |
104 | |
105 | if (type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { |
106 | acpi_rs_dump_descriptor(resource: &resource_list->data, |
107 | table: acpi_gbl_dump_serial_bus_dispatch |
108 | [resource_list->data. |
109 | common_serial_bus.type]); |
110 | } else { |
111 | acpi_rs_dump_descriptor(resource: &resource_list->data, |
112 | table: acpi_gbl_dump_resource_dispatch |
113 | [type]); |
114 | } |
115 | |
116 | /* Point to the next resource structure */ |
117 | |
118 | resource_list = ACPI_NEXT_RESOURCE(resource_list); |
119 | |
120 | /* Exit when END_TAG descriptor is reached */ |
121 | |
122 | } while (type != ACPI_RESOURCE_TYPE_END_TAG); |
123 | } |
124 | |
125 | /******************************************************************************* |
126 | * |
127 | * FUNCTION: acpi_rs_dump_irq_list |
128 | * |
129 | * PARAMETERS: route_table - Pointer to the routing table to dump. |
130 | * |
131 | * RETURN: None |
132 | * |
133 | * DESCRIPTION: Print IRQ routing table |
134 | * |
135 | ******************************************************************************/ |
136 | |
137 | void acpi_rs_dump_irq_list(u8 *route_table) |
138 | { |
139 | struct acpi_pci_routing_table *prt_element; |
140 | u8 count; |
141 | |
142 | ACPI_FUNCTION_ENTRY(); |
143 | |
144 | /* Check if debug output enabled */ |
145 | |
146 | if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_RESOURCES, _COMPONENT)) { |
147 | return; |
148 | } |
149 | |
150 | prt_element = ACPI_CAST_PTR(struct acpi_pci_routing_table, route_table); |
151 | |
152 | /* Dump all table elements, Exit on zero length element */ |
153 | |
154 | for (count = 0; prt_element->length; count++) { |
155 | acpi_os_printf(format: "\n[%02X] PCI IRQ Routing Table Package\n" , |
156 | count); |
157 | acpi_rs_dump_descriptor(resource: prt_element, table: acpi_rs_dump_prt); |
158 | |
159 | prt_element = ACPI_ADD_PTR(struct acpi_pci_routing_table, |
160 | prt_element, prt_element->length); |
161 | } |
162 | } |
163 | |
164 | /******************************************************************************* |
165 | * |
166 | * FUNCTION: acpi_rs_dump_descriptor |
167 | * |
168 | * PARAMETERS: resource - Buffer containing the resource |
169 | * table - Table entry to decode the resource |
170 | * |
171 | * RETURN: None |
172 | * |
173 | * DESCRIPTION: Dump a resource descriptor based on a dump table entry. |
174 | * |
175 | ******************************************************************************/ |
176 | |
177 | static void |
178 | acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table) |
179 | { |
180 | u8 *target = NULL; |
181 | u8 *previous_target; |
182 | const char *name; |
183 | u8 count; |
184 | |
185 | /* First table entry must contain the table length (# of table entries) */ |
186 | |
187 | count = table->offset; |
188 | |
189 | while (count) { |
190 | previous_target = target; |
191 | target = ACPI_ADD_PTR(u8, resource, table->offset); |
192 | name = table->name; |
193 | |
194 | switch (table->opcode) { |
195 | case ACPI_RSD_TITLE: |
196 | /* |
197 | * Optional resource title |
198 | */ |
199 | if (table->name) { |
200 | acpi_os_printf(format: "%s Resource\n" , name); |
201 | } |
202 | break; |
203 | |
204 | /* Strings */ |
205 | |
206 | case ACPI_RSD_LITERAL: |
207 | |
208 | acpi_rs_out_string(title: name, |
209 | ACPI_CAST_PTR(char, table->pointer)); |
210 | break; |
211 | |
212 | case ACPI_RSD_STRING: |
213 | |
214 | acpi_rs_out_string(title: name, ACPI_CAST_PTR(char, target)); |
215 | break; |
216 | |
217 | /* Data items, 8/16/32/64 bit */ |
218 | |
219 | case ACPI_RSD_UINT8: |
220 | |
221 | if (table->pointer) { |
222 | acpi_rs_out_string(title: name, |
223 | value: table->pointer[*target]); |
224 | } else { |
225 | acpi_rs_out_integer8(title: name, ACPI_GET8(target)); |
226 | } |
227 | break; |
228 | |
229 | case ACPI_RSD_UINT16: |
230 | |
231 | acpi_rs_out_integer16(title: name, ACPI_GET16(target)); |
232 | break; |
233 | |
234 | case ACPI_RSD_UINT32: |
235 | |
236 | acpi_rs_out_integer32(title: name, ACPI_GET32(target)); |
237 | break; |
238 | |
239 | case ACPI_RSD_UINT64: |
240 | |
241 | acpi_rs_out_integer64(title: name, ACPI_GET64(target)); |
242 | break; |
243 | |
244 | /* Flags: 1-bit and 2-bit flags supported */ |
245 | |
246 | case ACPI_RSD_1BITFLAG: |
247 | |
248 | acpi_rs_out_string(title: name, |
249 | value: table->pointer[*target & 0x01]); |
250 | break; |
251 | |
252 | case ACPI_RSD_2BITFLAG: |
253 | |
254 | acpi_rs_out_string(title: name, |
255 | value: table->pointer[*target & 0x03]); |
256 | break; |
257 | |
258 | case ACPI_RSD_3BITFLAG: |
259 | |
260 | acpi_rs_out_string(title: name, |
261 | value: table->pointer[*target & 0x07]); |
262 | break; |
263 | |
264 | case ACPI_RSD_6BITFLAG: |
265 | |
266 | acpi_rs_out_integer8(title: name, value: (ACPI_GET8(target) & 0x3F)); |
267 | break; |
268 | |
269 | case ACPI_RSD_SHORTLIST: |
270 | /* |
271 | * Short byte list (single line output) for DMA and IRQ resources |
272 | * Note: The list length is obtained from the previous table entry |
273 | */ |
274 | if (previous_target) { |
275 | acpi_rs_out_title(title: name); |
276 | acpi_rs_dump_short_byte_list(length: *previous_target, |
277 | data: target); |
278 | } |
279 | break; |
280 | |
281 | case ACPI_RSD_SHORTLISTX: |
282 | /* |
283 | * Short byte list (single line output) for GPIO vendor data |
284 | * Note: The list length is obtained from the previous table entry |
285 | */ |
286 | if (previous_target) { |
287 | acpi_rs_out_title(title: name); |
288 | acpi_rs_dump_short_byte_list(length: *previous_target, |
289 | data: * |
290 | (ACPI_CAST_INDIRECT_PTR |
291 | (u8, target))); |
292 | } |
293 | break; |
294 | |
295 | case ACPI_RSD_LONGLIST: |
296 | /* |
297 | * Long byte list for Vendor resource data |
298 | * Note: The list length is obtained from the previous table entry |
299 | */ |
300 | if (previous_target) { |
301 | acpi_rs_dump_byte_list(ACPI_GET16 |
302 | (previous_target), |
303 | data: target); |
304 | } |
305 | break; |
306 | |
307 | case ACPI_RSD_DWORDLIST: |
308 | /* |
309 | * Dword list for Extended Interrupt resources |
310 | * Note: The list length is obtained from the previous table entry |
311 | */ |
312 | if (previous_target) { |
313 | acpi_rs_dump_dword_list(length: *previous_target, |
314 | ACPI_CAST_PTR(u32, |
315 | target)); |
316 | } |
317 | break; |
318 | |
319 | case ACPI_RSD_WORDLIST: |
320 | /* |
321 | * Word list for GPIO Pin Table |
322 | * Note: The list length is obtained from the previous table entry |
323 | */ |
324 | if (previous_target) { |
325 | acpi_rs_dump_word_list(length: *previous_target, |
326 | data: *(ACPI_CAST_INDIRECT_PTR |
327 | (u16, target))); |
328 | } |
329 | break; |
330 | |
331 | case ACPI_RSD_ADDRESS: |
332 | /* |
333 | * Common flags for all Address resources |
334 | */ |
335 | acpi_rs_dump_address_common(ACPI_CAST_PTR |
336 | (union acpi_resource_data, |
337 | target)); |
338 | break; |
339 | |
340 | case ACPI_RSD_SOURCE: |
341 | /* |
342 | * Optional resource_source for Address resources |
343 | */ |
344 | acpi_rs_dump_resource_source(ACPI_CAST_PTR |
345 | (struct |
346 | acpi_resource_source, |
347 | target)); |
348 | break; |
349 | |
350 | case ACPI_RSD_LABEL: |
351 | /* |
352 | * resource_label |
353 | */ |
354 | acpi_rs_dump_resource_label(title: "Resource Label" , |
355 | ACPI_CAST_PTR(struct |
356 | acpi_resource_label, |
357 | target)); |
358 | break; |
359 | |
360 | case ACPI_RSD_SOURCE_LABEL: |
361 | /* |
362 | * resource_source_label |
363 | */ |
364 | acpi_rs_dump_resource_label(title: "Resource Source Label" , |
365 | ACPI_CAST_PTR(struct |
366 | acpi_resource_label, |
367 | target)); |
368 | break; |
369 | |
370 | default: |
371 | |
372 | acpi_os_printf(format: "**** Invalid table opcode [%X] ****\n" , |
373 | table->opcode); |
374 | return; |
375 | } |
376 | |
377 | table++; |
378 | count--; |
379 | } |
380 | } |
381 | |
382 | /******************************************************************************* |
383 | * |
384 | * FUNCTION: acpi_rs_dump_resource_source |
385 | * |
386 | * PARAMETERS: resource_source - Pointer to a Resource Source struct |
387 | * |
388 | * RETURN: None |
389 | * |
390 | * DESCRIPTION: Common routine for dumping the optional resource_source and the |
391 | * corresponding resource_source_index. |
392 | * |
393 | ******************************************************************************/ |
394 | |
395 | static void |
396 | acpi_rs_dump_resource_source(struct acpi_resource_source *resource_source) |
397 | { |
398 | ACPI_FUNCTION_ENTRY(); |
399 | |
400 | if (resource_source->index == 0xFF) { |
401 | return; |
402 | } |
403 | |
404 | acpi_rs_out_integer8(title: "Resource Source Index" , value: resource_source->index); |
405 | |
406 | acpi_rs_out_string(title: "Resource Source" , |
407 | value: resource_source->string_ptr ? |
408 | resource_source->string_ptr : "[Not Specified]" ); |
409 | } |
410 | |
411 | /******************************************************************************* |
412 | * |
413 | * FUNCTION: acpi_rs_dump_resource_label |
414 | * |
415 | * PARAMETERS: title - Title of the dumped resource field |
416 | * resource_label - Pointer to a Resource Label struct |
417 | * |
418 | * RETURN: None |
419 | * |
420 | * DESCRIPTION: Common routine for dumping the resource_label |
421 | * |
422 | ******************************************************************************/ |
423 | |
424 | static void |
425 | acpi_rs_dump_resource_label(char *title, |
426 | struct acpi_resource_label *resource_label) |
427 | { |
428 | ACPI_FUNCTION_ENTRY(); |
429 | |
430 | acpi_rs_out_string(title, |
431 | value: resource_label->string_ptr ? |
432 | resource_label->string_ptr : "[Not Specified]" ); |
433 | } |
434 | |
435 | /******************************************************************************* |
436 | * |
437 | * FUNCTION: acpi_rs_dump_address_common |
438 | * |
439 | * PARAMETERS: resource - Pointer to an internal resource descriptor |
440 | * |
441 | * RETURN: None |
442 | * |
443 | * DESCRIPTION: Dump the fields that are common to all Address resource |
444 | * descriptors |
445 | * |
446 | ******************************************************************************/ |
447 | |
448 | static void acpi_rs_dump_address_common(union acpi_resource_data *resource) |
449 | { |
450 | ACPI_FUNCTION_ENTRY(); |
451 | |
452 | /* Decode the type-specific flags */ |
453 | |
454 | switch (resource->address.resource_type) { |
455 | case ACPI_MEMORY_RANGE: |
456 | |
457 | acpi_rs_dump_descriptor(resource, table: acpi_rs_dump_memory_flags); |
458 | break; |
459 | |
460 | case ACPI_IO_RANGE: |
461 | |
462 | acpi_rs_dump_descriptor(resource, table: acpi_rs_dump_io_flags); |
463 | break; |
464 | |
465 | case ACPI_BUS_NUMBER_RANGE: |
466 | |
467 | acpi_rs_out_string(title: "Resource Type" , value: "Bus Number Range" ); |
468 | break; |
469 | |
470 | default: |
471 | |
472 | acpi_rs_out_integer8(title: "Resource Type" , |
473 | value: (u8) resource->address.resource_type); |
474 | break; |
475 | } |
476 | |
477 | /* Decode the general flags */ |
478 | |
479 | acpi_rs_dump_descriptor(resource, table: acpi_rs_dump_general_flags); |
480 | } |
481 | |
482 | /******************************************************************************* |
483 | * |
484 | * FUNCTION: acpi_rs_out* |
485 | * |
486 | * PARAMETERS: title - Name of the resource field |
487 | * value - Value of the resource field |
488 | * |
489 | * RETURN: None |
490 | * |
491 | * DESCRIPTION: Miscellaneous helper functions to consistently format the |
492 | * output of the resource dump routines |
493 | * |
494 | ******************************************************************************/ |
495 | |
496 | static void acpi_rs_out_string(const char *title, const char *value) |
497 | { |
498 | |
499 | acpi_os_printf(format: "%27s : %s" , title, value); |
500 | if (!*value) { |
501 | acpi_os_printf(format: "[NULL NAMESTRING]" ); |
502 | } |
503 | acpi_os_printf(format: "\n" ); |
504 | } |
505 | |
506 | static void acpi_rs_out_integer8(const char *title, u8 value) |
507 | { |
508 | acpi_os_printf(format: "%27s : %2.2X\n" , title, value); |
509 | } |
510 | |
511 | static void acpi_rs_out_integer16(const char *title, u16 value) |
512 | { |
513 | |
514 | acpi_os_printf(format: "%27s : %4.4X\n" , title, value); |
515 | } |
516 | |
517 | static void acpi_rs_out_integer32(const char *title, u32 value) |
518 | { |
519 | |
520 | acpi_os_printf(format: "%27s : %8.8X\n" , title, value); |
521 | } |
522 | |
523 | static void acpi_rs_out_integer64(const char *title, u64 value) |
524 | { |
525 | |
526 | acpi_os_printf(format: "%27s : %8.8X%8.8X\n" , title, ACPI_FORMAT_UINT64(value)); |
527 | } |
528 | |
529 | static void acpi_rs_out_title(const char *title) |
530 | { |
531 | |
532 | acpi_os_printf(format: "%27s : " , title); |
533 | } |
534 | |
535 | /******************************************************************************* |
536 | * |
537 | * FUNCTION: acpi_rs_dump*List |
538 | * |
539 | * PARAMETERS: length - Number of elements in the list |
540 | * data - Start of the list |
541 | * |
542 | * RETURN: None |
543 | * |
544 | * DESCRIPTION: Miscellaneous functions to dump lists of raw data |
545 | * |
546 | ******************************************************************************/ |
547 | |
548 | static void acpi_rs_dump_byte_list(u16 length, u8 * data) |
549 | { |
550 | u16 i; |
551 | |
552 | for (i = 0; i < length; i++) { |
553 | acpi_os_printf(format: "%25s%2.2X : %2.2X\n" , "Byte" , i, data[i]); |
554 | } |
555 | } |
556 | |
557 | static void acpi_rs_dump_short_byte_list(u8 length, u8 * data) |
558 | { |
559 | u8 i; |
560 | |
561 | for (i = 0; i < length; i++) { |
562 | acpi_os_printf(format: "%X " , data[i]); |
563 | } |
564 | |
565 | acpi_os_printf(format: "\n" ); |
566 | } |
567 | |
568 | static void acpi_rs_dump_dword_list(u8 length, u32 * data) |
569 | { |
570 | u8 i; |
571 | |
572 | for (i = 0; i < length; i++) { |
573 | acpi_os_printf(format: "%25s%2.2X : %8.8X\n" , "Dword" , i, data[i]); |
574 | } |
575 | } |
576 | |
577 | static void acpi_rs_dump_word_list(u16 length, u16 *data) |
578 | { |
579 | u16 i; |
580 | |
581 | for (i = 0; i < length; i++) { |
582 | acpi_os_printf(format: "%25s%2.2X : %4.4X\n" , "Word" , i, data[i]); |
583 | } |
584 | } |
585 | |