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 | acpi_evaluate_object(object: obj_handle, NULL, NULL, return_object_buffer: &buffer); |
554 | |
555 | /* |
556 | * Since this is a field unit, surround the output in braces |
557 | */ |
558 | acpi_os_printf(format: "{" ); |
559 | |
560 | ret_value = (union acpi_object *)buffer.pointer; |
561 | switch (ret_value->type) { |
562 | case ACPI_TYPE_INTEGER: |
563 | |
564 | acpi_os_printf(format: "%8.8X%8.8X" , |
565 | ACPI_FORMAT_UINT64(ret_value->integer.value)); |
566 | break; |
567 | |
568 | case ACPI_TYPE_BUFFER: |
569 | |
570 | acpi_ut_dump_buffer(buffer: ret_value->buffer.pointer, |
571 | count: ret_value->buffer.length, |
572 | DB_DISPLAY_DATA_ONLY | DB_BYTE_DISPLAY, offset: 0); |
573 | break; |
574 | |
575 | default: |
576 | |
577 | break; |
578 | } |
579 | acpi_os_printf(format: "}\n" ); |
580 | |
581 | ACPI_FREE(buffer.pointer); |
582 | |
583 | return (AE_OK); |
584 | } |
585 | |
586 | /******************************************************************************* |
587 | * |
588 | * FUNCTION: acpi_db_walk_for_specific_objects |
589 | * |
590 | * PARAMETERS: Callback from walk_namespace |
591 | * |
592 | * RETURN: Status |
593 | * |
594 | * DESCRIPTION: Display short info about objects in the namespace |
595 | * |
596 | ******************************************************************************/ |
597 | |
598 | static acpi_status |
599 | acpi_db_walk_for_specific_objects(acpi_handle obj_handle, |
600 | u32 nesting_level, |
601 | void *context, void **return_value) |
602 | { |
603 | struct acpi_walk_info *info = (struct acpi_walk_info *)context; |
604 | struct acpi_buffer buffer; |
605 | acpi_status status; |
606 | |
607 | info->count++; |
608 | |
609 | /* Get and display the full pathname to this object */ |
610 | |
611 | buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
612 | status = acpi_ns_handle_to_pathname(target_handle: obj_handle, buffer: &buffer, TRUE); |
613 | if (ACPI_FAILURE(status)) { |
614 | acpi_os_printf(format: "Could Not get pathname for object %p\n" , |
615 | obj_handle); |
616 | return (AE_OK); |
617 | } |
618 | |
619 | acpi_os_printf(format: "%32s" , (char *)buffer.pointer); |
620 | ACPI_FREE(buffer.pointer); |
621 | |
622 | /* Dump short info about the object */ |
623 | |
624 | (void)acpi_ns_dump_one_object(obj_handle, level: nesting_level, context: info, NULL); |
625 | return (AE_OK); |
626 | } |
627 | |
628 | /******************************************************************************* |
629 | * |
630 | * FUNCTION: acpi_db_display_objects |
631 | * |
632 | * PARAMETERS: obj_type_arg - Type of object to display |
633 | * display_count_arg - Max depth to display |
634 | * |
635 | * RETURN: None |
636 | * |
637 | * DESCRIPTION: Display objects in the namespace of the requested type |
638 | * |
639 | ******************************************************************************/ |
640 | |
641 | acpi_status acpi_db_display_objects(char *obj_type_arg, char *display_count_arg) |
642 | { |
643 | struct acpi_walk_info info; |
644 | acpi_object_type type; |
645 | struct acpi_object_info *object_info; |
646 | u32 i; |
647 | u32 total_objects = 0; |
648 | |
649 | /* No argument means display summary/count of all object types */ |
650 | |
651 | if (!obj_type_arg) { |
652 | object_info = |
653 | ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_object_info)); |
654 | |
655 | if (!object_info) |
656 | return (AE_NO_MEMORY); |
657 | |
658 | /* Walk the namespace from the root */ |
659 | |
660 | (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
661 | ACPI_UINT32_MAX, |
662 | descending_callback: acpi_db_walk_for_object_counts, NULL, |
663 | context: (void *)object_info, NULL); |
664 | |
665 | acpi_os_printf(format: "\nSummary of namespace objects:\n\n" ); |
666 | |
667 | for (i = 0; i < ACPI_TOTAL_TYPES; i++) { |
668 | acpi_os_printf(format: "%8u %s\n" , object_info->types[i], |
669 | acpi_ut_get_type_name(type: i)); |
670 | |
671 | total_objects += object_info->types[i]; |
672 | } |
673 | |
674 | acpi_os_printf(format: "\n%8u Total namespace objects\n\n" , |
675 | total_objects); |
676 | |
677 | ACPI_FREE(object_info); |
678 | return (AE_OK); |
679 | } |
680 | |
681 | /* Get the object type */ |
682 | |
683 | type = acpi_db_match_argument(user_argument: obj_type_arg, arguments: acpi_db_object_types); |
684 | if (type == ACPI_TYPE_NOT_FOUND) { |
685 | acpi_os_printf(format: "Invalid or unsupported argument\n" ); |
686 | return (AE_OK); |
687 | } |
688 | |
689 | acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
690 | acpi_os_printf |
691 | (format: "Objects of type [%s] defined in the current ACPI Namespace:\n" , |
692 | acpi_ut_get_type_name(type)); |
693 | |
694 | acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
695 | |
696 | info.count = 0; |
697 | info.owner_id = ACPI_OWNER_ID_MAX; |
698 | info.debug_level = ACPI_UINT32_MAX; |
699 | info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT; |
700 | |
701 | /* Walk the namespace from the root */ |
702 | |
703 | (void)acpi_walk_namespace(type, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, |
704 | descending_callback: acpi_db_walk_for_specific_objects, NULL, |
705 | context: (void *)&info, NULL); |
706 | |
707 | acpi_os_printf |
708 | (format: "\nFound %u objects of type [%s] in the current ACPI Namespace\n" , |
709 | info.count, acpi_ut_get_type_name(type)); |
710 | |
711 | acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
712 | return (AE_OK); |
713 | } |
714 | |
715 | /******************************************************************************* |
716 | * |
717 | * FUNCTION: acpi_db_display_fields |
718 | * |
719 | * PARAMETERS: obj_type_arg - Type of object to display |
720 | * display_count_arg - Max depth to display |
721 | * |
722 | * RETURN: None |
723 | * |
724 | * DESCRIPTION: Display objects in the namespace of the requested type |
725 | * |
726 | ******************************************************************************/ |
727 | |
728 | acpi_status acpi_db_display_fields(u32 address_space_id) |
729 | { |
730 | struct acpi_region_walk_info info; |
731 | |
732 | info.count = 0; |
733 | info.owner_id = ACPI_OWNER_ID_MAX; |
734 | info.debug_level = ACPI_UINT32_MAX; |
735 | info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT; |
736 | info.address_space_id = address_space_id; |
737 | |
738 | /* Walk the namespace from the root */ |
739 | |
740 | (void)acpi_walk_namespace(ACPI_TYPE_LOCAL_REGION_FIELD, |
741 | ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, |
742 | descending_callback: acpi_db_walk_for_fields, NULL, context: (void *)&info, |
743 | NULL); |
744 | |
745 | return (AE_OK); |
746 | } |
747 | |
748 | /******************************************************************************* |
749 | * |
750 | * FUNCTION: acpi_db_integrity_walk |
751 | * |
752 | * PARAMETERS: Callback from walk_namespace |
753 | * |
754 | * RETURN: Status |
755 | * |
756 | * DESCRIPTION: Examine one NS node for valid values. |
757 | * |
758 | ******************************************************************************/ |
759 | |
760 | static acpi_status |
761 | acpi_db_integrity_walk(acpi_handle obj_handle, |
762 | u32 nesting_level, void *context, void **return_value) |
763 | { |
764 | struct acpi_integrity_info *info = |
765 | (struct acpi_integrity_info *)context; |
766 | struct acpi_namespace_node *node = |
767 | (struct acpi_namespace_node *)obj_handle; |
768 | union acpi_operand_object *object; |
769 | u8 alias = TRUE; |
770 | |
771 | info->nodes++; |
772 | |
773 | /* Verify the NS node, and dereference aliases */ |
774 | |
775 | while (alias) { |
776 | if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) { |
777 | acpi_os_printf |
778 | (format: "Invalid Descriptor Type for Node %p [%s] - " |
779 | "is %2.2X should be %2.2X\n" , node, |
780 | acpi_ut_get_descriptor_name(object: node), |
781 | ACPI_GET_DESCRIPTOR_TYPE(node), |
782 | ACPI_DESC_TYPE_NAMED); |
783 | return (AE_OK); |
784 | } |
785 | |
786 | if ((node->type == ACPI_TYPE_LOCAL_ALIAS) || |
787 | (node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { |
788 | node = (struct acpi_namespace_node *)node->object; |
789 | } else { |
790 | alias = FALSE; |
791 | } |
792 | } |
793 | |
794 | if (node->type > ACPI_TYPE_LOCAL_MAX) { |
795 | acpi_os_printf(format: "Invalid Object Type for Node %p, Type = %X\n" , |
796 | node, node->type); |
797 | return (AE_OK); |
798 | } |
799 | |
800 | if (!acpi_ut_valid_nameseg(signature: node->name.ascii)) { |
801 | acpi_os_printf(format: "Invalid AcpiName for Node %p\n" , node); |
802 | return (AE_OK); |
803 | } |
804 | |
805 | object = acpi_ns_get_attached_object(node); |
806 | if (object) { |
807 | info->objects++; |
808 | if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) { |
809 | acpi_os_printf |
810 | (format: "Invalid Descriptor Type for Object %p [%s]\n" , |
811 | object, acpi_ut_get_descriptor_name(object)); |
812 | } |
813 | } |
814 | |
815 | return (AE_OK); |
816 | } |
817 | |
818 | /******************************************************************************* |
819 | * |
820 | * FUNCTION: acpi_db_check_integrity |
821 | * |
822 | * PARAMETERS: None |
823 | * |
824 | * RETURN: None |
825 | * |
826 | * DESCRIPTION: Check entire namespace for data structure integrity |
827 | * |
828 | ******************************************************************************/ |
829 | |
830 | void acpi_db_check_integrity(void) |
831 | { |
832 | struct acpi_integrity_info info = { 0, 0 }; |
833 | |
834 | /* Search all nodes in namespace */ |
835 | |
836 | (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
837 | ACPI_UINT32_MAX, descending_callback: acpi_db_integrity_walk, NULL, |
838 | context: (void *)&info, NULL); |
839 | |
840 | acpi_os_printf(format: "Verified %u namespace nodes with %u Objects\n" , |
841 | info.nodes, info.objects); |
842 | } |
843 | |
844 | /******************************************************************************* |
845 | * |
846 | * FUNCTION: acpi_db_walk_for_references |
847 | * |
848 | * PARAMETERS: Callback from walk_namespace |
849 | * |
850 | * RETURN: Status |
851 | * |
852 | * DESCRIPTION: Check if this namespace object refers to the target object |
853 | * that is passed in as the context value. |
854 | * |
855 | * Note: Currently doesn't check subobjects within the Node's object |
856 | * |
857 | ******************************************************************************/ |
858 | |
859 | static acpi_status |
860 | acpi_db_walk_for_references(acpi_handle obj_handle, |
861 | u32 nesting_level, |
862 | void *context, void **return_value) |
863 | { |
864 | union acpi_operand_object *obj_desc = |
865 | (union acpi_operand_object *)context; |
866 | struct acpi_namespace_node *node = |
867 | (struct acpi_namespace_node *)obj_handle; |
868 | |
869 | /* Check for match against the namespace node itself */ |
870 | |
871 | if (node == (void *)obj_desc) { |
872 | acpi_os_printf(format: "Object is a Node [%4.4s]\n" , |
873 | acpi_ut_get_node_name(object: node)); |
874 | } |
875 | |
876 | /* Check for match against the object attached to the node */ |
877 | |
878 | if (acpi_ns_get_attached_object(node) == obj_desc) { |
879 | acpi_os_printf(format: "Reference at Node->Object %p [%4.4s]\n" , |
880 | node, acpi_ut_get_node_name(object: node)); |
881 | } |
882 | |
883 | return (AE_OK); |
884 | } |
885 | |
886 | /******************************************************************************* |
887 | * |
888 | * FUNCTION: acpi_db_find_references |
889 | * |
890 | * PARAMETERS: object_arg - String with hex value of the object |
891 | * |
892 | * RETURN: None |
893 | * |
894 | * DESCRIPTION: Search namespace for all references to the input object |
895 | * |
896 | ******************************************************************************/ |
897 | |
898 | void acpi_db_find_references(char *object_arg) |
899 | { |
900 | union acpi_operand_object *obj_desc; |
901 | acpi_size address; |
902 | |
903 | /* Convert string to object pointer */ |
904 | |
905 | address = strtoul(object_arg, NULL, 16); |
906 | obj_desc = ACPI_TO_POINTER(address); |
907 | |
908 | /* Search all nodes in namespace */ |
909 | |
910 | (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
911 | ACPI_UINT32_MAX, descending_callback: acpi_db_walk_for_references, |
912 | NULL, context: (void *)obj_desc, NULL); |
913 | } |
914 | |
915 | /******************************************************************************* |
916 | * |
917 | * FUNCTION: acpi_db_bus_walk |
918 | * |
919 | * PARAMETERS: Callback from walk_namespace |
920 | * |
921 | * RETURN: Status |
922 | * |
923 | * DESCRIPTION: Display info about device objects that have a corresponding |
924 | * _PRT method. |
925 | * |
926 | ******************************************************************************/ |
927 | |
928 | static acpi_status |
929 | acpi_db_bus_walk(acpi_handle obj_handle, |
930 | u32 nesting_level, void *context, void **return_value) |
931 | { |
932 | struct acpi_namespace_node *node = |
933 | (struct acpi_namespace_node *)obj_handle; |
934 | acpi_status status; |
935 | struct acpi_buffer buffer; |
936 | struct acpi_namespace_node *temp_node; |
937 | struct acpi_device_info *info; |
938 | u32 i; |
939 | |
940 | if ((node->type != ACPI_TYPE_DEVICE) && |
941 | (node->type != ACPI_TYPE_PROCESSOR)) { |
942 | return (AE_OK); |
943 | } |
944 | |
945 | /* Exit if there is no _PRT under this device */ |
946 | |
947 | status = acpi_get_handle(parent: node, METHOD_NAME__PRT, |
948 | ACPI_CAST_PTR(acpi_handle, &temp_node)); |
949 | if (ACPI_FAILURE(status)) { |
950 | return (AE_OK); |
951 | } |
952 | |
953 | /* Get the full path to this device object */ |
954 | |
955 | buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
956 | status = acpi_ns_handle_to_pathname(target_handle: obj_handle, buffer: &buffer, TRUE); |
957 | if (ACPI_FAILURE(status)) { |
958 | acpi_os_printf(format: "Could Not get pathname for object %p\n" , |
959 | obj_handle); |
960 | return (AE_OK); |
961 | } |
962 | |
963 | status = acpi_get_object_info(object: obj_handle, return_buffer: &info); |
964 | if (ACPI_FAILURE(status)) { |
965 | return (AE_OK); |
966 | } |
967 | |
968 | /* Display the full path */ |
969 | |
970 | acpi_os_printf(format: "%-32s Type %X" , (char *)buffer.pointer, node->type); |
971 | ACPI_FREE(buffer.pointer); |
972 | |
973 | if (info->flags & ACPI_PCI_ROOT_BRIDGE) { |
974 | acpi_os_printf(format: " - Is PCI Root Bridge" ); |
975 | } |
976 | acpi_os_printf(format: "\n" ); |
977 | |
978 | /* _PRT info */ |
979 | |
980 | acpi_os_printf(format: "_PRT: %p\n" , temp_node); |
981 | |
982 | /* Dump _ADR, _HID, _UID, _CID */ |
983 | |
984 | if (info->valid & ACPI_VALID_ADR) { |
985 | acpi_os_printf(format: "_ADR: %8.8X%8.8X\n" , |
986 | ACPI_FORMAT_UINT64(info->address)); |
987 | } else { |
988 | acpi_os_printf(format: "_ADR: <Not Present>\n" ); |
989 | } |
990 | |
991 | if (info->valid & ACPI_VALID_HID) { |
992 | acpi_os_printf(format: "_HID: %s\n" , info->hardware_id.string); |
993 | } else { |
994 | acpi_os_printf(format: "_HID: <Not Present>\n" ); |
995 | } |
996 | |
997 | if (info->valid & ACPI_VALID_UID) { |
998 | acpi_os_printf(format: "_UID: %s\n" , info->unique_id.string); |
999 | } else { |
1000 | acpi_os_printf(format: "_UID: <Not Present>\n" ); |
1001 | } |
1002 | |
1003 | if (info->valid & ACPI_VALID_CID) { |
1004 | for (i = 0; i < info->compatible_id_list.count; i++) { |
1005 | acpi_os_printf(format: "_CID: %s\n" , |
1006 | info->compatible_id_list.ids[i].string); |
1007 | } |
1008 | } else { |
1009 | acpi_os_printf(format: "_CID: <Not Present>\n" ); |
1010 | } |
1011 | |
1012 | ACPI_FREE(info); |
1013 | return (AE_OK); |
1014 | } |
1015 | |
1016 | /******************************************************************************* |
1017 | * |
1018 | * FUNCTION: acpi_db_get_bus_info |
1019 | * |
1020 | * PARAMETERS: None |
1021 | * |
1022 | * RETURN: None |
1023 | * |
1024 | * DESCRIPTION: Display info about system buses. |
1025 | * |
1026 | ******************************************************************************/ |
1027 | |
1028 | void acpi_db_get_bus_info(void) |
1029 | { |
1030 | /* Search all nodes in namespace */ |
1031 | |
1032 | (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
1033 | ACPI_UINT32_MAX, descending_callback: acpi_db_bus_walk, NULL, NULL, |
1034 | NULL); |
1035 | } |
1036 | |