1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /******************************************************************************* |
3 | * |
4 | * Module Name: dbnames - Debugger commands for the acpi namespace |
5 | * |
6 | ******************************************************************************/ |
7 | |
8 | #include <acpi/acpi.h> |
9 | #include "accommon.h" |
10 | #include "acnamesp.h" |
11 | #include "acdebug.h" |
12 | #include "acpredef.h" |
13 | #include "acinterp.h" |
14 | |
15 | #define _COMPONENT ACPI_CA_DEBUGGER |
16 | ACPI_MODULE_NAME("dbnames" ) |
17 | |
18 | /* Local prototypes */ |
19 | static acpi_status |
20 | acpi_db_walk_and_match_name(acpi_handle obj_handle, |
21 | u32 nesting_level, |
22 | void *context, void **return_value); |
23 | |
24 | static acpi_status |
25 | acpi_db_walk_for_predefined_names(acpi_handle obj_handle, |
26 | u32 nesting_level, |
27 | void *context, void **return_value); |
28 | |
29 | static acpi_status |
30 | acpi_db_walk_for_specific_objects(acpi_handle obj_handle, |
31 | u32 nesting_level, |
32 | void *context, void **return_value); |
33 | |
34 | static acpi_status |
35 | acpi_db_walk_for_object_counts(acpi_handle obj_handle, |
36 | u32 nesting_level, |
37 | void *context, void **return_value); |
38 | |
39 | static acpi_status |
40 | acpi_db_integrity_walk(acpi_handle obj_handle, |
41 | u32 nesting_level, void *context, void **return_value); |
42 | |
43 | static acpi_status |
44 | acpi_db_walk_for_references(acpi_handle obj_handle, |
45 | u32 nesting_level, |
46 | void *context, void **return_value); |
47 | |
48 | static acpi_status |
49 | acpi_db_bus_walk(acpi_handle obj_handle, |
50 | u32 nesting_level, void *context, void **return_value); |
51 | |
52 | /* |
53 | * Arguments for the Objects command |
54 | * These object types map directly to the ACPI_TYPES |
55 | */ |
56 | static struct acpi_db_argument_info acpi_db_object_types[] = { |
57 | {"ANY" }, |
58 | {"INTEGERS" }, |
59 | {"STRINGS" }, |
60 | {"BUFFERS" }, |
61 | {"PACKAGES" }, |
62 | {"FIELDS" }, |
63 | {"DEVICES" }, |
64 | {"EVENTS" }, |
65 | {"METHODS" }, |
66 | {"MUTEXES" }, |
67 | {"REGIONS" }, |
68 | {"POWERRESOURCES" }, |
69 | {"PROCESSORS" }, |
70 | {"THERMALZONES" }, |
71 | {"BUFFERFIELDS" }, |
72 | {"DDBHANDLES" }, |
73 | {"DEBUG" }, |
74 | {"REGIONFIELDS" }, |
75 | {"BANKFIELDS" }, |
76 | {"INDEXFIELDS" }, |
77 | {"REFERENCES" }, |
78 | {"ALIASES" }, |
79 | {"METHODALIASES" }, |
80 | {"NOTIFY" }, |
81 | {"ADDRESSHANDLER" }, |
82 | {"RESOURCE" }, |
83 | {"RESOURCEFIELD" }, |
84 | {"SCOPES" }, |
85 | {NULL} /* Must be null terminated */ |
86 | }; |
87 | |
88 | /******************************************************************************* |
89 | * |
90 | * FUNCTION: acpi_db_set_scope |
91 | * |
92 | * PARAMETERS: name - New scope path |
93 | * |
94 | * RETURN: Status |
95 | * |
96 | * DESCRIPTION: Set the "current scope" as maintained by this utility. |
97 | * The scope is used as a prefix to ACPI paths. |
98 | * |
99 | ******************************************************************************/ |
100 | |
101 | void acpi_db_set_scope(char *name) |
102 | { |
103 | acpi_status status; |
104 | struct acpi_namespace_node *node; |
105 | |
106 | if (!name || name[0] == 0) { |
107 | acpi_os_printf(format: "Current scope: %s\n" , acpi_gbl_db_scope_buf); |
108 | return; |
109 | } |
110 | |
111 | acpi_db_prep_namestring(name); |
112 | |
113 | if (ACPI_IS_ROOT_PREFIX(name[0])) { |
114 | |
115 | /* Validate new scope from the root */ |
116 | |
117 | status = acpi_ns_get_node(prefix_node: acpi_gbl_root_node, external_pathname: name, |
118 | ACPI_NS_NO_UPSEARCH, out_node: &node); |
119 | if (ACPI_FAILURE(status)) { |
120 | goto error_exit; |
121 | } |
122 | |
123 | acpi_gbl_db_scope_buf[0] = 0; |
124 | } else { |
125 | /* Validate new scope relative to old scope */ |
126 | |
127 | status = acpi_ns_get_node(prefix_node: acpi_gbl_db_scope_node, external_pathname: name, |
128 | ACPI_NS_NO_UPSEARCH, out_node: &node); |
129 | if (ACPI_FAILURE(status)) { |
130 | goto error_exit; |
131 | } |
132 | } |
133 | |
134 | /* Build the final pathname */ |
135 | |
136 | if (acpi_ut_safe_strcat |
137 | (dest: acpi_gbl_db_scope_buf, dest_size: sizeof(acpi_gbl_db_scope_buf), source: name)) { |
138 | status = AE_BUFFER_OVERFLOW; |
139 | goto error_exit; |
140 | } |
141 | |
142 | if (acpi_ut_safe_strcat |
143 | (dest: acpi_gbl_db_scope_buf, dest_size: sizeof(acpi_gbl_db_scope_buf), source: "\\" )) { |
144 | status = AE_BUFFER_OVERFLOW; |
145 | goto error_exit; |
146 | } |
147 | |
148 | acpi_gbl_db_scope_node = node; |
149 | acpi_os_printf(format: "New scope: %s\n" , acpi_gbl_db_scope_buf); |
150 | return; |
151 | |
152 | error_exit: |
153 | |
154 | acpi_os_printf(format: "Could not attach scope: %s, %s\n" , |
155 | name, acpi_format_exception(exception: status)); |
156 | } |
157 | |
158 | /******************************************************************************* |
159 | * |
160 | * FUNCTION: acpi_db_dump_namespace |
161 | * |
162 | * PARAMETERS: start_arg - Node to begin namespace dump |
163 | * depth_arg - Maximum tree depth to be dumped |
164 | * |
165 | * RETURN: None |
166 | * |
167 | * DESCRIPTION: Dump entire namespace or a subtree. Each node is displayed |
168 | * with type and other information. |
169 | * |
170 | ******************************************************************************/ |
171 | |
172 | void acpi_db_dump_namespace(char *start_arg, char *depth_arg) |
173 | { |
174 | acpi_handle subtree_entry = acpi_gbl_root_node; |
175 | u32 max_depth = ACPI_UINT32_MAX; |
176 | |
177 | /* No argument given, just start at the root and dump entire namespace */ |
178 | |
179 | if (start_arg) { |
180 | subtree_entry = acpi_db_convert_to_node(in_string: start_arg); |
181 | if (!subtree_entry) { |
182 | return; |
183 | } |
184 | |
185 | /* Now we can check for the depth argument */ |
186 | |
187 | if (depth_arg) { |
188 | max_depth = strtoul(depth_arg, NULL, 0); |
189 | } |
190 | } |
191 | |
192 | acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
193 | |
194 | if (((struct acpi_namespace_node *)subtree_entry)->parent) { |
195 | acpi_os_printf(format: "ACPI Namespace (from %4.4s (%p) subtree):\n" , |
196 | ((struct acpi_namespace_node *)subtree_entry)-> |
197 | name.ascii, subtree_entry); |
198 | } else { |
199 | acpi_os_printf(format: "ACPI Namespace (from %s):\n" , |
200 | ACPI_NAMESPACE_ROOT); |
201 | } |
202 | |
203 | /* Display the subtree */ |
204 | |
205 | acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
206 | acpi_ns_dump_objects(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth, |
207 | ACPI_OWNER_ID_MAX, start_handle: subtree_entry); |
208 | acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
209 | } |
210 | |
211 | /******************************************************************************* |
212 | * |
213 | * FUNCTION: acpi_db_dump_namespace_paths |
214 | * |
215 | * PARAMETERS: None |
216 | * |
217 | * RETURN: None |
218 | * |
219 | * DESCRIPTION: Dump entire namespace with full object pathnames and object |
220 | * type information. Alternative to "namespace" command. |
221 | * |
222 | ******************************************************************************/ |
223 | |
224 | void acpi_db_dump_namespace_paths(void) |
225 | { |
226 | |
227 | acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
228 | acpi_os_printf(format: "ACPI Namespace (from root):\n" ); |
229 | |
230 | /* Display the entire namespace */ |
231 | |
232 | acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
233 | acpi_ns_dump_object_paths(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, |
234 | ACPI_UINT32_MAX, ACPI_OWNER_ID_MAX, |
235 | start_handle: acpi_gbl_root_node); |
236 | |
237 | acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
238 | } |
239 | |
240 | /******************************************************************************* |
241 | * |
242 | * FUNCTION: acpi_db_dump_namespace_by_owner |
243 | * |
244 | * PARAMETERS: owner_arg - Owner ID whose nodes will be displayed |
245 | * depth_arg - Maximum tree depth to be dumped |
246 | * |
247 | * RETURN: None |
248 | * |
249 | * DESCRIPTION: Dump elements of the namespace that are owned by the owner_id. |
250 | * |
251 | ******************************************************************************/ |
252 | |
253 | void acpi_db_dump_namespace_by_owner(char *owner_arg, char *depth_arg) |
254 | { |
255 | acpi_handle subtree_entry = acpi_gbl_root_node; |
256 | u32 max_depth = ACPI_UINT32_MAX; |
257 | acpi_owner_id owner_id; |
258 | |
259 | owner_id = (acpi_owner_id)strtoul(owner_arg, NULL, 0); |
260 | |
261 | /* Now we can check for the depth argument */ |
262 | |
263 | if (depth_arg) { |
264 | max_depth = strtoul(depth_arg, NULL, 0); |
265 | } |
266 | |
267 | acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
268 | acpi_os_printf(format: "ACPI Namespace by owner %X:\n" , owner_id); |
269 | |
270 | /* Display the subtree */ |
271 | |
272 | acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
273 | acpi_ns_dump_objects(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth, |
274 | owner_id, start_handle: subtree_entry); |
275 | acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
276 | } |
277 | |
278 | /******************************************************************************* |
279 | * |
280 | * FUNCTION: acpi_db_walk_and_match_name |
281 | * |
282 | * PARAMETERS: Callback from walk_namespace |
283 | * |
284 | * RETURN: Status |
285 | * |
286 | * DESCRIPTION: Find a particular name/names within the namespace. Wildcards |
287 | * are supported -- '?' matches any character. |
288 | * |
289 | ******************************************************************************/ |
290 | |
291 | static acpi_status |
292 | acpi_db_walk_and_match_name(acpi_handle obj_handle, |
293 | u32 nesting_level, |
294 | void *context, void **return_value) |
295 | { |
296 | acpi_status status; |
297 | char *requested_name = (char *)context; |
298 | u32 i; |
299 | struct acpi_buffer buffer; |
300 | struct acpi_walk_info info; |
301 | |
302 | /* Check for a name match */ |
303 | |
304 | for (i = 0; i < 4; i++) { |
305 | |
306 | /* Wildcard support */ |
307 | |
308 | if ((requested_name[i] != '?') && |
309 | (requested_name[i] != ((struct acpi_namespace_node *) |
310 | obj_handle)->name.ascii[i])) { |
311 | |
312 | /* No match, just exit */ |
313 | |
314 | return (AE_OK); |
315 | } |
316 | } |
317 | |
318 | /* Get the full pathname to this object */ |
319 | |
320 | buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
321 | status = acpi_ns_handle_to_pathname(target_handle: obj_handle, buffer: &buffer, TRUE); |
322 | if (ACPI_FAILURE(status)) { |
323 | acpi_os_printf(format: "Could Not get pathname for object %p\n" , |
324 | obj_handle); |
325 | } else { |
326 | info.count = 0; |
327 | info.owner_id = ACPI_OWNER_ID_MAX; |
328 | info.debug_level = ACPI_UINT32_MAX; |
329 | info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT; |
330 | |
331 | acpi_os_printf(format: "%32s" , (char *)buffer.pointer); |
332 | (void)acpi_ns_dump_one_object(obj_handle, level: nesting_level, context: &info, |
333 | NULL); |
334 | ACPI_FREE(buffer.pointer); |
335 | } |
336 | |
337 | return (AE_OK); |
338 | } |
339 | |
340 | /******************************************************************************* |
341 | * |
342 | * FUNCTION: acpi_db_find_name_in_namespace |
343 | * |
344 | * PARAMETERS: name_arg - The 4-character ACPI name to find. |
345 | * wildcards are supported. |
346 | * |
347 | * RETURN: None |
348 | * |
349 | * DESCRIPTION: Search the namespace for a given name (with wildcards) |
350 | * |
351 | ******************************************************************************/ |
352 | |
353 | acpi_status acpi_db_find_name_in_namespace(char *name_arg) |
354 | { |
355 | char acpi_name[5] = "____" ; |
356 | char *acpi_name_ptr = acpi_name; |
357 | |
358 | if (strlen(name_arg) > ACPI_NAMESEG_SIZE) { |
359 | acpi_os_printf(format: "Name must be no longer than 4 characters\n" ); |
360 | return (AE_OK); |
361 | } |
362 | |
363 | /* Pad out name with underscores as necessary to create a 4-char name */ |
364 | |
365 | acpi_ut_strupr(src_string: name_arg); |
366 | while (*name_arg) { |
367 | *acpi_name_ptr = *name_arg; |
368 | acpi_name_ptr++; |
369 | name_arg++; |
370 | } |
371 | |
372 | /* Walk the namespace from the root */ |
373 | |
374 | (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
375 | ACPI_UINT32_MAX, descending_callback: acpi_db_walk_and_match_name, |
376 | NULL, context: acpi_name, NULL); |
377 | |
378 | acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
379 | return (AE_OK); |
380 | } |
381 | |
382 | /******************************************************************************* |
383 | * |
384 | * FUNCTION: acpi_db_walk_for_predefined_names |
385 | * |
386 | * PARAMETERS: Callback from walk_namespace |
387 | * |
388 | * RETURN: Status |
389 | * |
390 | * DESCRIPTION: Detect and display predefined ACPI names (names that start with |
391 | * an underscore) |
392 | * |
393 | ******************************************************************************/ |
394 | |
395 | static acpi_status |
396 | acpi_db_walk_for_predefined_names(acpi_handle obj_handle, |
397 | u32 nesting_level, |
398 | void *context, void **return_value) |
399 | { |
400 | struct acpi_namespace_node *node = |
401 | (struct acpi_namespace_node *)obj_handle; |
402 | u32 *count = (u32 *)context; |
403 | const union acpi_predefined_info *predefined; |
404 | const union acpi_predefined_info *package = NULL; |
405 | char *pathname; |
406 | char string_buffer[48]; |
407 | |
408 | predefined = acpi_ut_match_predefined_method(name: node->name.ascii); |
409 | if (!predefined) { |
410 | return (AE_OK); |
411 | } |
412 | |
413 | pathname = acpi_ns_get_normalized_pathname(node, TRUE); |
414 | if (!pathname) { |
415 | return (AE_OK); |
416 | } |
417 | |
418 | /* If method returns a package, the info is in the next table entry */ |
419 | |
420 | if (predefined->info.expected_btypes & ACPI_RTYPE_PACKAGE) { |
421 | package = predefined + 1; |
422 | } |
423 | |
424 | acpi_ut_get_expected_return_types(buffer: string_buffer, |
425 | expected_btypes: predefined->info.expected_btypes); |
426 | |
427 | acpi_os_printf(format: "%-32s Arguments %X, Return Types: %s" , pathname, |
428 | METHOD_GET_ARG_COUNT(predefined->info.argument_list), |
429 | string_buffer); |
430 | |
431 | if (package) { |
432 | acpi_os_printf(format: " (PkgType %2.2X, ObjType %2.2X, Count %2.2X)" , |
433 | package->ret_info.type, |
434 | package->ret_info.object_type1, |
435 | package->ret_info.count1); |
436 | } |
437 | |
438 | acpi_os_printf(format: "\n" ); |
439 | |
440 | /* Check that the declared argument count matches the ACPI spec */ |
441 | |
442 | acpi_ns_check_acpi_compliance(pathname, node, predefined); |
443 | |
444 | ACPI_FREE(pathname); |
445 | (*count)++; |
446 | return (AE_OK); |
447 | } |
448 | |
449 | /******************************************************************************* |
450 | * |
451 | * FUNCTION: acpi_db_check_predefined_names |
452 | * |
453 | * PARAMETERS: None |
454 | * |
455 | * RETURN: None |
456 | * |
457 | * DESCRIPTION: Validate all predefined names in the namespace |
458 | * |
459 | ******************************************************************************/ |
460 | |
461 | void acpi_db_check_predefined_names(void) |
462 | { |
463 | u32 count = 0; |
464 | |
465 | /* Search all nodes in namespace */ |
466 | |
467 | (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
468 | ACPI_UINT32_MAX, |
469 | descending_callback: acpi_db_walk_for_predefined_names, NULL, |
470 | context: (void *)&count, NULL); |
471 | |
472 | acpi_os_printf(format: "Found %u predefined names in the namespace\n" , count); |
473 | } |
474 | |
475 | /******************************************************************************* |
476 | * |
477 | * FUNCTION: acpi_db_walk_for_object_counts |
478 | * |
479 | * PARAMETERS: Callback from walk_namespace |
480 | * |
481 | * RETURN: Status |
482 | * |
483 | * DESCRIPTION: Display short info about objects in the namespace |
484 | * |
485 | ******************************************************************************/ |
486 | |
487 | static acpi_status |
488 | acpi_db_walk_for_object_counts(acpi_handle obj_handle, |
489 | u32 nesting_level, |
490 | void *context, void **return_value) |
491 | { |
492 | struct acpi_object_info *info = (struct acpi_object_info *)context; |
493 | struct acpi_namespace_node *node = |
494 | (struct acpi_namespace_node *)obj_handle; |
495 | |
496 | if (node->type > ACPI_TYPE_NS_NODE_MAX) { |
497 | acpi_os_printf(format: "[%4.4s]: Unknown object type %X\n" , |
498 | node->name.ascii, node->type); |
499 | } else { |
500 | info->types[node->type]++; |
501 | } |
502 | |
503 | return (AE_OK); |
504 | } |
505 | |
506 | /******************************************************************************* |
507 | * |
508 | * FUNCTION: acpi_db_walk_for_fields |
509 | * |
510 | * PARAMETERS: Callback from walk_namespace |
511 | * |
512 | * RETURN: Status |
513 | * |
514 | * DESCRIPTION: Display short info about objects in the namespace |
515 | * |
516 | ******************************************************************************/ |
517 | |
518 | static acpi_status |
519 | acpi_db_walk_for_fields(acpi_handle obj_handle, |
520 | u32 nesting_level, void *context, void **return_value) |
521 | { |
522 | union acpi_object *ret_value; |
523 | struct acpi_region_walk_info *info = |
524 | (struct acpi_region_walk_info *)context; |
525 | struct acpi_buffer buffer; |
526 | acpi_status status; |
527 | struct acpi_namespace_node *node = acpi_ns_validate_handle(handle: obj_handle); |
528 | |
529 | if (!node) { |
530 | return (AE_OK); |
531 | } |
532 | if (node->object->field.region_obj->region.space_id != |
533 | info->address_space_id) { |
534 | return (AE_OK); |
535 | } |
536 | |
537 | info->count++; |
538 | |
539 | /* Get and display the full pathname to this object */ |
540 | |
541 | buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
542 | status = acpi_ns_handle_to_pathname(target_handle: obj_handle, buffer: &buffer, TRUE); |
543 | if (ACPI_FAILURE(status)) { |
544 | acpi_os_printf(format: "Could Not get pathname for object %p\n" , |
545 | obj_handle); |
546 | return (AE_OK); |
547 | } |
548 | |
549 | acpi_os_printf(format: "%s " , (char *)buffer.pointer); |
550 | ACPI_FREE(buffer.pointer); |
551 | |
552 | buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
553 | status = acpi_evaluate_object(object: obj_handle, NULL, NULL, return_object_buffer: &buffer); |
554 | if (ACPI_FAILURE(status)) { |
555 | acpi_os_printf(format: "Could Not evaluate object %p\n" , |
556 | obj_handle); |
557 | return (AE_OK); |
558 | } |
559 | /* |
560 | * Since this is a field unit, surround the output in braces |
561 | */ |
562 | acpi_os_printf(format: "{" ); |
563 | |
564 | ret_value = (union acpi_object *)buffer.pointer; |
565 | switch (ret_value->type) { |
566 | case ACPI_TYPE_INTEGER: |
567 | |
568 | acpi_os_printf(format: "%8.8X%8.8X" , |
569 | ACPI_FORMAT_UINT64(ret_value->integer.value)); |
570 | break; |
571 | |
572 | case ACPI_TYPE_BUFFER: |
573 | |
574 | acpi_ut_dump_buffer(buffer: ret_value->buffer.pointer, |
575 | count: ret_value->buffer.length, |
576 | DB_DISPLAY_DATA_ONLY | DB_BYTE_DISPLAY, offset: 0); |
577 | break; |
578 | |
579 | default: |
580 | |
581 | break; |
582 | } |
583 | acpi_os_printf(format: "}\n" ); |
584 | |
585 | ACPI_FREE(buffer.pointer); |
586 | |
587 | return (AE_OK); |
588 | } |
589 | |
590 | /******************************************************************************* |
591 | * |
592 | * FUNCTION: acpi_db_walk_for_specific_objects |
593 | * |
594 | * PARAMETERS: Callback from walk_namespace |
595 | * |
596 | * RETURN: Status |
597 | * |
598 | * DESCRIPTION: Display short info about objects in the namespace |
599 | * |
600 | ******************************************************************************/ |
601 | |
602 | static acpi_status |
603 | acpi_db_walk_for_specific_objects(acpi_handle obj_handle, |
604 | u32 nesting_level, |
605 | void *context, void **return_value) |
606 | { |
607 | struct acpi_walk_info *info = (struct acpi_walk_info *)context; |
608 | struct acpi_buffer buffer; |
609 | acpi_status status; |
610 | |
611 | info->count++; |
612 | |
613 | /* Get and display the full pathname to this object */ |
614 | |
615 | buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
616 | status = acpi_ns_handle_to_pathname(target_handle: obj_handle, buffer: &buffer, TRUE); |
617 | if (ACPI_FAILURE(status)) { |
618 | acpi_os_printf(format: "Could Not get pathname for object %p\n" , |
619 | obj_handle); |
620 | return (AE_OK); |
621 | } |
622 | |
623 | acpi_os_printf(format: "%32s" , (char *)buffer.pointer); |
624 | ACPI_FREE(buffer.pointer); |
625 | |
626 | /* Dump short info about the object */ |
627 | |
628 | (void)acpi_ns_dump_one_object(obj_handle, level: nesting_level, context: info, NULL); |
629 | return (AE_OK); |
630 | } |
631 | |
632 | /******************************************************************************* |
633 | * |
634 | * FUNCTION: acpi_db_display_objects |
635 | * |
636 | * PARAMETERS: obj_type_arg - Type of object to display |
637 | * display_count_arg - Max depth to display |
638 | * |
639 | * RETURN: None |
640 | * |
641 | * DESCRIPTION: Display objects in the namespace of the requested type |
642 | * |
643 | ******************************************************************************/ |
644 | |
645 | acpi_status acpi_db_display_objects(char *obj_type_arg, char *display_count_arg) |
646 | { |
647 | struct acpi_walk_info info; |
648 | acpi_object_type type; |
649 | struct acpi_object_info *object_info; |
650 | u32 i; |
651 | u32 total_objects = 0; |
652 | |
653 | /* No argument means display summary/count of all object types */ |
654 | |
655 | if (!obj_type_arg) { |
656 | object_info = |
657 | ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_object_info)); |
658 | |
659 | if (!object_info) |
660 | return (AE_NO_MEMORY); |
661 | |
662 | /* Walk the namespace from the root */ |
663 | |
664 | (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
665 | ACPI_UINT32_MAX, |
666 | descending_callback: acpi_db_walk_for_object_counts, NULL, |
667 | context: (void *)object_info, NULL); |
668 | |
669 | acpi_os_printf(format: "\nSummary of namespace objects:\n\n" ); |
670 | |
671 | for (i = 0; i < ACPI_TOTAL_TYPES; i++) { |
672 | acpi_os_printf(format: "%8u %s\n" , object_info->types[i], |
673 | acpi_ut_get_type_name(type: i)); |
674 | |
675 | total_objects += object_info->types[i]; |
676 | } |
677 | |
678 | acpi_os_printf(format: "\n%8u Total namespace objects\n\n" , |
679 | total_objects); |
680 | |
681 | ACPI_FREE(object_info); |
682 | return (AE_OK); |
683 | } |
684 | |
685 | /* Get the object type */ |
686 | |
687 | type = acpi_db_match_argument(user_argument: obj_type_arg, arguments: acpi_db_object_types); |
688 | if (type == ACPI_TYPE_NOT_FOUND) { |
689 | acpi_os_printf(format: "Invalid or unsupported argument\n" ); |
690 | return (AE_OK); |
691 | } |
692 | |
693 | acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
694 | acpi_os_printf |
695 | (format: "Objects of type [%s] defined in the current ACPI Namespace:\n" , |
696 | acpi_ut_get_type_name(type)); |
697 | |
698 | acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
699 | |
700 | info.count = 0; |
701 | info.owner_id = ACPI_OWNER_ID_MAX; |
702 | info.debug_level = ACPI_UINT32_MAX; |
703 | info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT; |
704 | |
705 | /* Walk the namespace from the root */ |
706 | |
707 | (void)acpi_walk_namespace(type, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, |
708 | descending_callback: acpi_db_walk_for_specific_objects, NULL, |
709 | context: (void *)&info, NULL); |
710 | |
711 | acpi_os_printf |
712 | (format: "\nFound %u objects of type [%s] in the current ACPI Namespace\n" , |
713 | info.count, acpi_ut_get_type_name(type)); |
714 | |
715 | acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
716 | return (AE_OK); |
717 | } |
718 | |
719 | /******************************************************************************* |
720 | * |
721 | * FUNCTION: acpi_db_display_fields |
722 | * |
723 | * PARAMETERS: obj_type_arg - Type of object to display |
724 | * display_count_arg - Max depth to display |
725 | * |
726 | * RETURN: None |
727 | * |
728 | * DESCRIPTION: Display objects in the namespace of the requested type |
729 | * |
730 | ******************************************************************************/ |
731 | |
732 | acpi_status acpi_db_display_fields(u32 address_space_id) |
733 | { |
734 | struct acpi_region_walk_info info; |
735 | |
736 | info.count = 0; |
737 | info.owner_id = ACPI_OWNER_ID_MAX; |
738 | info.debug_level = ACPI_UINT32_MAX; |
739 | info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT; |
740 | info.address_space_id = address_space_id; |
741 | |
742 | /* Walk the namespace from the root */ |
743 | |
744 | (void)acpi_walk_namespace(ACPI_TYPE_LOCAL_REGION_FIELD, |
745 | ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, |
746 | descending_callback: acpi_db_walk_for_fields, NULL, context: (void *)&info, |
747 | NULL); |
748 | |
749 | return (AE_OK); |
750 | } |
751 | |
752 | /******************************************************************************* |
753 | * |
754 | * FUNCTION: acpi_db_integrity_walk |
755 | * |
756 | * PARAMETERS: Callback from walk_namespace |
757 | * |
758 | * RETURN: Status |
759 | * |
760 | * DESCRIPTION: Examine one NS node for valid values. |
761 | * |
762 | ******************************************************************************/ |
763 | |
764 | static acpi_status |
765 | acpi_db_integrity_walk(acpi_handle obj_handle, |
766 | u32 nesting_level, void *context, void **return_value) |
767 | { |
768 | struct acpi_integrity_info *info = |
769 | (struct acpi_integrity_info *)context; |
770 | struct acpi_namespace_node *node = |
771 | (struct acpi_namespace_node *)obj_handle; |
772 | union acpi_operand_object *object; |
773 | u8 alias = TRUE; |
774 | |
775 | info->nodes++; |
776 | |
777 | /* Verify the NS node, and dereference aliases */ |
778 | |
779 | while (alias) { |
780 | if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) { |
781 | acpi_os_printf |
782 | (format: "Invalid Descriptor Type for Node %p [%s] - " |
783 | "is %2.2X should be %2.2X\n" , node, |
784 | acpi_ut_get_descriptor_name(object: node), |
785 | ACPI_GET_DESCRIPTOR_TYPE(node), |
786 | ACPI_DESC_TYPE_NAMED); |
787 | return (AE_OK); |
788 | } |
789 | |
790 | if ((node->type == ACPI_TYPE_LOCAL_ALIAS) || |
791 | (node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { |
792 | node = (struct acpi_namespace_node *)node->object; |
793 | } else { |
794 | alias = FALSE; |
795 | } |
796 | } |
797 | |
798 | if (node->type > ACPI_TYPE_LOCAL_MAX) { |
799 | acpi_os_printf(format: "Invalid Object Type for Node %p, Type = %X\n" , |
800 | node, node->type); |
801 | return (AE_OK); |
802 | } |
803 | |
804 | if (!acpi_ut_valid_nameseg(signature: node->name.ascii)) { |
805 | acpi_os_printf(format: "Invalid AcpiName for Node %p\n" , node); |
806 | return (AE_OK); |
807 | } |
808 | |
809 | object = acpi_ns_get_attached_object(node); |
810 | if (object) { |
811 | info->objects++; |
812 | if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) { |
813 | acpi_os_printf |
814 | (format: "Invalid Descriptor Type for Object %p [%s]\n" , |
815 | object, acpi_ut_get_descriptor_name(object)); |
816 | } |
817 | } |
818 | |
819 | return (AE_OK); |
820 | } |
821 | |
822 | /******************************************************************************* |
823 | * |
824 | * FUNCTION: acpi_db_check_integrity |
825 | * |
826 | * PARAMETERS: None |
827 | * |
828 | * RETURN: None |
829 | * |
830 | * DESCRIPTION: Check entire namespace for data structure integrity |
831 | * |
832 | ******************************************************************************/ |
833 | |
834 | void acpi_db_check_integrity(void) |
835 | { |
836 | struct acpi_integrity_info info = { 0, 0 }; |
837 | |
838 | /* Search all nodes in namespace */ |
839 | |
840 | (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
841 | ACPI_UINT32_MAX, descending_callback: acpi_db_integrity_walk, NULL, |
842 | context: (void *)&info, NULL); |
843 | |
844 | acpi_os_printf(format: "Verified %u namespace nodes with %u Objects\n" , |
845 | info.nodes, info.objects); |
846 | } |
847 | |
848 | /******************************************************************************* |
849 | * |
850 | * FUNCTION: acpi_db_walk_for_references |
851 | * |
852 | * PARAMETERS: Callback from walk_namespace |
853 | * |
854 | * RETURN: Status |
855 | * |
856 | * DESCRIPTION: Check if this namespace object refers to the target object |
857 | * that is passed in as the context value. |
858 | * |
859 | * Note: Currently doesn't check subobjects within the Node's object |
860 | * |
861 | ******************************************************************************/ |
862 | |
863 | static acpi_status |
864 | acpi_db_walk_for_references(acpi_handle obj_handle, |
865 | u32 nesting_level, |
866 | void *context, void **return_value) |
867 | { |
868 | union acpi_operand_object *obj_desc = |
869 | (union acpi_operand_object *)context; |
870 | struct acpi_namespace_node *node = |
871 | (struct acpi_namespace_node *)obj_handle; |
872 | |
873 | /* Check for match against the namespace node itself */ |
874 | |
875 | if (node == (void *)obj_desc) { |
876 | acpi_os_printf(format: "Object is a Node [%4.4s]\n" , |
877 | acpi_ut_get_node_name(object: node)); |
878 | } |
879 | |
880 | /* Check for match against the object attached to the node */ |
881 | |
882 | if (acpi_ns_get_attached_object(node) == obj_desc) { |
883 | acpi_os_printf(format: "Reference at Node->Object %p [%4.4s]\n" , |
884 | node, acpi_ut_get_node_name(object: node)); |
885 | } |
886 | |
887 | return (AE_OK); |
888 | } |
889 | |
890 | /******************************************************************************* |
891 | * |
892 | * FUNCTION: acpi_db_find_references |
893 | * |
894 | * PARAMETERS: object_arg - String with hex value of the object |
895 | * |
896 | * RETURN: None |
897 | * |
898 | * DESCRIPTION: Search namespace for all references to the input object |
899 | * |
900 | ******************************************************************************/ |
901 | |
902 | void acpi_db_find_references(char *object_arg) |
903 | { |
904 | union acpi_operand_object *obj_desc; |
905 | acpi_size address; |
906 | |
907 | /* Convert string to object pointer */ |
908 | |
909 | address = strtoul(object_arg, NULL, 16); |
910 | obj_desc = ACPI_TO_POINTER(address); |
911 | |
912 | /* Search all nodes in namespace */ |
913 | |
914 | (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
915 | ACPI_UINT32_MAX, descending_callback: acpi_db_walk_for_references, |
916 | NULL, context: (void *)obj_desc, NULL); |
917 | } |
918 | |
919 | /******************************************************************************* |
920 | * |
921 | * FUNCTION: acpi_db_bus_walk |
922 | * |
923 | * PARAMETERS: Callback from walk_namespace |
924 | * |
925 | * RETURN: Status |
926 | * |
927 | * DESCRIPTION: Display info about device objects that have a corresponding |
928 | * _PRT method. |
929 | * |
930 | ******************************************************************************/ |
931 | |
932 | static acpi_status |
933 | acpi_db_bus_walk(acpi_handle obj_handle, |
934 | u32 nesting_level, void *context, void **return_value) |
935 | { |
936 | struct acpi_namespace_node *node = |
937 | (struct acpi_namespace_node *)obj_handle; |
938 | acpi_status status; |
939 | struct acpi_buffer buffer; |
940 | struct acpi_namespace_node *temp_node; |
941 | struct acpi_device_info *info; |
942 | u32 i; |
943 | |
944 | if ((node->type != ACPI_TYPE_DEVICE) && |
945 | (node->type != ACPI_TYPE_PROCESSOR)) { |
946 | return (AE_OK); |
947 | } |
948 | |
949 | /* Exit if there is no _PRT under this device */ |
950 | |
951 | status = acpi_get_handle(parent: node, METHOD_NAME__PRT, |
952 | ACPI_CAST_PTR(acpi_handle, &temp_node)); |
953 | if (ACPI_FAILURE(status)) { |
954 | return (AE_OK); |
955 | } |
956 | |
957 | /* Get the full path to this device object */ |
958 | |
959 | buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
960 | status = acpi_ns_handle_to_pathname(target_handle: obj_handle, buffer: &buffer, TRUE); |
961 | if (ACPI_FAILURE(status)) { |
962 | acpi_os_printf(format: "Could Not get pathname for object %p\n" , |
963 | obj_handle); |
964 | return (AE_OK); |
965 | } |
966 | |
967 | status = acpi_get_object_info(object: obj_handle, return_buffer: &info); |
968 | if (ACPI_FAILURE(status)) { |
969 | return (AE_OK); |
970 | } |
971 | |
972 | /* Display the full path */ |
973 | |
974 | acpi_os_printf(format: "%-32s Type %X" , (char *)buffer.pointer, node->type); |
975 | ACPI_FREE(buffer.pointer); |
976 | |
977 | if (info->flags & ACPI_PCI_ROOT_BRIDGE) { |
978 | acpi_os_printf(format: " - Is PCI Root Bridge" ); |
979 | } |
980 | acpi_os_printf(format: "\n" ); |
981 | |
982 | /* _PRT info */ |
983 | |
984 | acpi_os_printf(format: "_PRT: %p\n" , temp_node); |
985 | |
986 | /* Dump _ADR, _HID, _UID, _CID */ |
987 | |
988 | if (info->valid & ACPI_VALID_ADR) { |
989 | acpi_os_printf(format: "_ADR: %8.8X%8.8X\n" , |
990 | ACPI_FORMAT_UINT64(info->address)); |
991 | } else { |
992 | acpi_os_printf(format: "_ADR: <Not Present>\n" ); |
993 | } |
994 | |
995 | if (info->valid & ACPI_VALID_HID) { |
996 | acpi_os_printf(format: "_HID: %s\n" , info->hardware_id.string); |
997 | } else { |
998 | acpi_os_printf(format: "_HID: <Not Present>\n" ); |
999 | } |
1000 | |
1001 | if (info->valid & ACPI_VALID_UID) { |
1002 | acpi_os_printf(format: "_UID: %s\n" , info->unique_id.string); |
1003 | } else { |
1004 | acpi_os_printf(format: "_UID: <Not Present>\n" ); |
1005 | } |
1006 | |
1007 | if (info->valid & ACPI_VALID_CID) { |
1008 | for (i = 0; i < info->compatible_id_list.count; i++) { |
1009 | acpi_os_printf(format: "_CID: %s\n" , |
1010 | info->compatible_id_list.ids[i].string); |
1011 | } |
1012 | } else { |
1013 | acpi_os_printf(format: "_CID: <Not Present>\n" ); |
1014 | } |
1015 | |
1016 | ACPI_FREE(info); |
1017 | return (AE_OK); |
1018 | } |
1019 | |
1020 | /******************************************************************************* |
1021 | * |
1022 | * FUNCTION: acpi_db_get_bus_info |
1023 | * |
1024 | * PARAMETERS: None |
1025 | * |
1026 | * RETURN: None |
1027 | * |
1028 | * DESCRIPTION: Display info about system buses. |
1029 | * |
1030 | ******************************************************************************/ |
1031 | |
1032 | void acpi_db_get_bus_info(void) |
1033 | { |
1034 | /* Search all nodes in namespace */ |
1035 | |
1036 | (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
1037 | ACPI_UINT32_MAX, descending_callback: acpi_db_bus_walk, NULL, NULL, |
1038 | NULL); |
1039 | } |
1040 | |