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