/******************************************************************************* * * Module Name: dbcmds - debug commands and output routines * $Revision: 1.1.1.1 $ * ******************************************************************************/ /* * Copyright (C) 2000, 2001 R. Byron Moore * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "acpi.h" #include "acparser.h" #include "acdispat.h" #include "amlcode.h" #include "acnamesp.h" #include "acparser.h" #include "acevents.h" #include "acinterp.h" #include "acdebug.h" #include "actables.h" #include "acresrc.h" #ifdef ENABLE_DEBUGGER #define _COMPONENT ACPI_DEBUGGER MODULE_NAME ("dbcmds") /* * Arguments for the Objects command * These object types map directly to the ACPI_TYPES */ ARGUMENT_INFO acpi_db_object_types [] = { {"ANY"}, {"NUMBERS"}, {"STRINGS"}, {"BUFFERS"}, {"PACKAGES"}, {"FIELDS"}, {"DEVICES"}, {"EVENTS"}, {"METHODS"}, {"MUTEXES"}, {"REGIONS"}, {"POWERRESOURCES"}, {"PROCESSORS"}, {"THERMALZONES"}, {"BUFFERFIELDS"}, {"DDBHANDLES"}, {NULL} /* Must be null terminated */ }; /******************************************************************************* * * FUNCTION: Acpi_db_walk_for_references * * PARAMETERS: Callback from Walk_namespace * * RETURN: Status * * DESCRIPTION: Check if this namespace object refers to the target object * that is passed in as the context value. * ******************************************************************************/ acpi_status acpi_db_walk_for_references ( acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value) { acpi_operand_object *obj_desc = (acpi_operand_object *) context; acpi_namespace_node *node = (acpi_namespace_node *) obj_handle; /* Check for match against the namespace node itself */ if (node == (void *) obj_desc) { acpi_os_printf ("Object is a Node [%4.4s]\n", &node->name); } /* Check for match against the object attached to the node */ if (node->object == obj_desc) { acpi_os_printf ("Reference at Node->Object %p [%4.4s]\n", node, &node->name); } /* Check first child for a match */ /* TBD: [Investigate] probably now obsolete with new datastructure */ if (node->child == (void *) obj_desc) { acpi_os_printf ("Reference at Node->Child %p [%4.4s]\n", node, &node->name); } return (AE_OK); } /******************************************************************************* * * FUNCTION: Acpi_db_find_references * * PARAMETERS: Object_arg - String with hex value of the object * * RETURN: None * * DESCRIPTION: Search namespace for all references to the input object * ******************************************************************************/ void acpi_db_find_references ( NATIVE_CHAR *object_arg) { acpi_operand_object *obj_desc; /* Convert string to object pointer */ obj_desc = (acpi_operand_object *) STRTOUL (object_arg, NULL, 16); /* Search all nodes in namespace */ acpi_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, acpi_db_walk_for_references, (void *) obj_desc, NULL); } /******************************************************************************* * * FUNCTION: Acpi_db_display_locks * * PARAMETERS: None * * RETURN: None * * DESCRIPTION: Display information about internal mutexes. * ******************************************************************************/ void acpi_db_display_locks (void) { u32 i; for (i = 0; i < MAX_MTX; i++) { acpi_os_printf ("%26s : %s\n", acpi_ut_get_mutex_name (i), acpi_gbl_acpi_mutex_info[i].owner_id == ACPI_MUTEX_NOT_ACQUIRED ? "Locked" : "Unlocked"); } } /******************************************************************************* * * FUNCTION: Acpi_db_display_table_info * * PARAMETERS: Table_arg - String with name of table to be displayed * * RETURN: None * * DESCRIPTION: Display information about loaded tables. Current * implementation displays all loaded tables. * ******************************************************************************/ void acpi_db_display_table_info ( NATIVE_CHAR *table_arg) { u32 i; for (i = 0; i < NUM_ACPI_TABLES; i++) { if (acpi_gbl_acpi_tables[i].pointer) { acpi_os_printf ("%s at %p length %X\n", acpi_gbl_acpi_table_data[i].name, acpi_gbl_acpi_tables[i].pointer, acpi_gbl_acpi_tables[i].length); } } } /******************************************************************************* * * FUNCTION: Acpi_db_unload_acpi_table * * PARAMETERS: Table_arg - Name of the table to be unloaded * Instance_arg - Which instance of the table to unload (if * there are multiple tables of the same type) * * RETURN: Nonde * * DESCRIPTION: Unload an ACPI table. * Instance is not implemented * ******************************************************************************/ void acpi_db_unload_acpi_table ( NATIVE_CHAR *table_arg, NATIVE_CHAR *instance_arg) { u32 i; acpi_status status; /* Search all tables for the target type */ for (i = 0; i < NUM_ACPI_TABLES; i++) { if (!STRNCMP (table_arg, acpi_gbl_acpi_table_data[i].signature, acpi_gbl_acpi_table_data[i].sig_length)) { /* Found the table, unload it */ status = acpi_unload_table (i); if (ACPI_SUCCESS (status)) { acpi_os_printf ("[%s] unloaded and uninstalled\n", table_arg); } else { acpi_os_printf ("%s, while unloading [%s]\n", acpi_format_exception (status), table_arg); } return; } } acpi_os_printf ("Unknown table type [%s]\n", table_arg); } /******************************************************************************* * * FUNCTION: Acpi_db_set_method_breakpoint * * PARAMETERS: Location - AML offset of breakpoint * Walk_state - Current walk info * Op - Current Op (from parse walk) * * RETURN: None * * DESCRIPTION: Set a breakpoint in a control method at the specified * AML offset * ******************************************************************************/ void acpi_db_set_method_breakpoint ( NATIVE_CHAR *location, acpi_walk_state *walk_state, acpi_parse_object *op) { u32 address; if (!op) { acpi_os_printf ("There is no method currently executing\n"); return; } /* Get and verify the breakpoint address */ address = STRTOUL (location, NULL, 16); if (address <= op->aml_offset) { acpi_os_printf ("Breakpoint %X is beyond current address %X\n", address, op->aml_offset); } /* Save breakpoint in current walk */ walk_state->method_breakpoint = address; acpi_os_printf ("Breakpoint set at AML offset %X\n", address); } /******************************************************************************* * * FUNCTION: Acpi_db_set_method_call_breakpoint * * PARAMETERS: Op - Current Op (from parse walk) * * RETURN: None * * DESCRIPTION: Set a breakpoint in a control method at the specified * AML offset * ******************************************************************************/ void acpi_db_set_method_call_breakpoint ( acpi_parse_object *op) { if (!op) { acpi_os_printf ("There is no method currently executing\n"); return; } acpi_gbl_step_to_next_call = TRUE; } /******************************************************************************* * * FUNCTION: Acpi_db_disassemble_aml * * PARAMETERS: Statements - Number of statements to disassemble * Op - Current Op (from parse walk) * * RETURN: None * * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number * of statements specified. * ******************************************************************************/ void acpi_db_disassemble_aml ( NATIVE_CHAR *statements, acpi_parse_object *op) { u32 num_statements = 8; if (!op) { acpi_os_printf ("There is no method currently executing\n"); return; } if (statements) { num_statements = STRTOUL (statements, NULL, 0); } acpi_db_display_op (NULL, op, num_statements); } /******************************************************************************* * * FUNCTION: Acpi_db_dump_namespace * * PARAMETERS: Start_arg - Node to begin namespace dump * Depth_arg - Maximum tree depth to be dumped * * RETURN: None * * DESCRIPTION: Dump entire namespace or a subtree. Each node is displayed * with type and other information. * ******************************************************************************/ void acpi_db_dump_namespace ( NATIVE_CHAR *start_arg, NATIVE_CHAR *depth_arg) { acpi_handle subtree_entry = acpi_gbl_root_node; u32 max_depth = ACPI_UINT32_MAX; /* No argument given, just start at the root and dump entire namespace */ if (start_arg) { /* Check if numeric argument, must be a Node */ if ((start_arg[0] >= 0x30) && (start_arg[0] <= 0x39)) { subtree_entry = (acpi_handle) STRTOUL (start_arg, NULL, 16); if (!acpi_os_readable (subtree_entry, sizeof (acpi_namespace_node))) { acpi_os_printf ("Address %p is invalid in this address space\n", subtree_entry); return; } if (!VALID_DESCRIPTOR_TYPE ((subtree_entry), ACPI_DESC_TYPE_NAMED)) { acpi_os_printf ("Address %p is not a valid Named object\n", subtree_entry); return; } } /* Alpha argument */ else { /* The parameter is a name string that must be resolved to a Named obj*/ subtree_entry = acpi_db_local_ns_lookup (start_arg); if (!subtree_entry) { subtree_entry = acpi_gbl_root_node; } } /* Now we can check for the depth argument */ if (depth_arg) { max_depth = STRTOUL (depth_arg, NULL, 0); } } acpi_db_set_output_destination (DB_DUPLICATE_OUTPUT); acpi_os_printf ("ACPI Namespace (from %p subtree):\n", subtree_entry); /* Display the subtree */ acpi_db_set_output_destination (DB_REDIRECTABLE_OUTPUT); acpi_ns_dump_objects (ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth, ACPI_UINT32_MAX, subtree_entry); acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); } /******************************************************************************* * * FUNCTION: Acpi_db_dump_namespace_by_owner * * PARAMETERS: Owner_arg - Owner ID whose nodes will be displayed * Depth_arg - Maximum tree depth to be dumped * * RETURN: None * * DESCRIPTION: Dump elements of the namespace that are owned by the Owner_id. * ******************************************************************************/ void acpi_db_dump_namespace_by_owner ( NATIVE_CHAR *owner_arg, NATIVE_CHAR *depth_arg) { acpi_handle subtree_entry = acpi_gbl_root_node; u32 max_depth = ACPI_UINT32_MAX; u16 owner_id; owner_id = (u16) STRTOUL (owner_arg, NULL, 0); /* Now we can check for the depth argument */ if (depth_arg) { max_depth = STRTOUL (depth_arg, NULL, 0); } acpi_db_set_output_destination (DB_DUPLICATE_OUTPUT); acpi_os_printf ("ACPI Namespace by owner %X:\n", owner_id); /* Display the subtree */ acpi_db_set_output_destination (DB_REDIRECTABLE_OUTPUT); acpi_ns_dump_objects (ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth, owner_id, subtree_entry); acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); } /******************************************************************************* * * FUNCTION: Acpi_db_send_notify * * PARAMETERS: Name - Name of ACPI object to send the notify to * Value - Value of the notify to send. * * RETURN: None * * DESCRIPTION: Send an ACPI notification. The value specified is sent to the * named object as an ACPI notify. * ******************************************************************************/ void acpi_db_send_notify ( NATIVE_CHAR *name, u32 value) { acpi_namespace_node *node; /* Translate name to an Named object */ node = acpi_db_local_ns_lookup (name); if (!node) { return; } /* Decode Named object type */ switch (node->type) { case ACPI_TYPE_DEVICE: case ACPI_TYPE_THERMAL: /* Send the notify */ acpi_ev_queue_notify_request (node, value); break; default: acpi_os_printf ("Named object is not a device or a thermal object\n"); break; } } /******************************************************************************* * * FUNCTION: Acpi_db_set_method_data * * PARAMETERS: Type_arg - L for local, A for argument * Index_arg - which one * Value_arg - Value to set. * * RETURN: None * * DESCRIPTION: Set a local or argument for the running control method. * NOTE: only object supported is Number. * ******************************************************************************/ void acpi_db_set_method_data ( NATIVE_CHAR *type_arg, NATIVE_CHAR *index_arg, NATIVE_CHAR *value_arg) { NATIVE_CHAR type; u32 index; u32 value; acpi_walk_state *walk_state; acpi_operand_object *obj_desc; /* Validate Type_arg */ STRUPR (type_arg); type = type_arg[0]; if ((type != 'L') && (type != 'A')) { acpi_os_printf ("Invalid SET operand: %s\n", type_arg); return; } /* Get the index and value */ index = STRTOUL (index_arg, NULL, 16); value = STRTOUL (value_arg, NULL, 16); walk_state = acpi_ds_get_current_walk_state (acpi_gbl_current_walk_list); if (!walk_state) { acpi_os_printf ("There is no method currently executing\n"); return; } /* Create and initialize the new object */ obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); if (!obj_desc) { acpi_os_printf ("Could not create an internal object\n"); return; } obj_desc->integer.value = value; /* Store the new object into the target */ switch (type) { case 'A': /* Set a method argument */ if (index > MTH_NUM_ARGS) { acpi_os_printf ("Arg%d - Invalid argument name\n", index); return; } acpi_ds_store_object_to_local (AML_ARG_OP, index, obj_desc, walk_state); obj_desc = walk_state->arguments[index].object; acpi_os_printf ("Arg%d: ", index); acpi_db_display_internal_object (obj_desc, walk_state); break; case 'L': /* Set a method local */ if (index > MTH_NUM_LOCALS) { acpi_os_printf ("Local%d - Invalid local variable name\n", index); return; } acpi_ds_store_object_to_local (AML_LOCAL_OP, index, obj_desc, walk_state); obj_desc = walk_state->local_variables[index].object; acpi_os_printf ("Local%d: ", index); acpi_db_display_internal_object (obj_desc, walk_state); break; default: break; } } /******************************************************************************* * * FUNCTION: Acpi_db_walk_for_specific_objects * * PARAMETERS: Callback from Walk_namespace * * RETURN: Status * * DESCRIPTION: Display short info about objects in the namespace * ******************************************************************************/ acpi_status acpi_db_walk_for_specific_objects ( acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value) { acpi_operand_object *obj_desc; acpi_status status; u32 buf_size; NATIVE_CHAR buffer[64]; obj_desc = ((acpi_namespace_node *)obj_handle)->object; buf_size = sizeof (buffer) / sizeof (*buffer); /* Get and display the full pathname to this object */ status = acpi_ns_handle_to_pathname (obj_handle, &buf_size, buffer); if (ACPI_FAILURE (status)) { acpi_os_printf ("Could Not get pathname for object %p\n", obj_handle); return (AE_OK); } acpi_os_printf ("%32s", buffer); /* Display short information about the object */ if (obj_desc) { switch (obj_desc->common.type) { case ACPI_TYPE_METHOD: acpi_os_printf (" #Args %d Concurrency %X", obj_desc->method.param_count, obj_desc->method.concurrency); break; case ACPI_TYPE_INTEGER: acpi_os_printf (" Value %X", obj_desc->integer.value); break; case ACPI_TYPE_STRING: acpi_os_printf (" \"%s\"", obj_desc->string.pointer); break; case ACPI_TYPE_REGION: acpi_os_printf (" Space_id %X Address %X Length %X", obj_desc->region.space_id, obj_desc->region.address, obj_desc->region.length); break; case ACPI_TYPE_PACKAGE: acpi_os_printf (" #Elements %X", obj_desc->package.count); break; case ACPI_TYPE_BUFFER: acpi_os_printf (" Length %X", obj_desc->buffer.length); break; } } acpi_os_printf ("\n"); return (AE_OK); } /******************************************************************************* * * FUNCTION: Acpi_db_display_objects * * PARAMETERS: Obj_type_arg - Type of object to display * Display_count_arg - Max depth to display * * RETURN: None * * DESCRIPTION: Display objects in the namespace of the requested type * ******************************************************************************/ acpi_status acpi_db_display_objects ( NATIVE_CHAR *obj_type_arg, NATIVE_CHAR *display_count_arg) { acpi_object_type8 type; /* Get the object type */ type = acpi_db_match_argument (obj_type_arg, acpi_db_object_types); if (type == ACPI_TYPE_NOT_FOUND) { acpi_os_printf ("Invalid or unsupported argument\n"); return (AE_OK); } acpi_db_set_output_destination (DB_DUPLICATE_OUTPUT); acpi_os_printf ("Objects of type [%s] defined in the current ACPI Namespace: \n", acpi_ut_get_type_name (type)); acpi_db_set_output_destination (DB_REDIRECTABLE_OUTPUT); /* Walk the namespace from the root */ acpi_walk_namespace (type, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, acpi_db_walk_for_specific_objects, (void *) &type, NULL); acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); return (AE_OK); } /******************************************************************************* * * FUNCTION: Acpi_db_walk_and_match_name * * PARAMETERS: Callback from Walk_namespace * * RETURN: Status * * DESCRIPTION: Find a particular name/names within the namespace. Wildcards * are supported -- '?' matches any character. * ******************************************************************************/ acpi_status acpi_db_walk_and_match_name ( acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value) { acpi_status status; NATIVE_CHAR *requested_name = (NATIVE_CHAR *) context; u32 i; u32 buf_size; NATIVE_CHAR buffer[96]; /* Check for a name match */ for (i = 0; i < 4; i++) { /* Wildcard support */ if ((requested_name[i] != '?') && (requested_name[i] != ((NATIVE_CHAR *) (&((acpi_namespace_node *) obj_handle)->name))[i])) { /* No match, just exit */ return (AE_OK); } } /* Get the full pathname to this object */ buf_size = sizeof (buffer) / sizeof (*buffer); status = acpi_ns_handle_to_pathname (obj_handle, &buf_size, buffer); if (ACPI_FAILURE (status)) { acpi_os_printf ("Could Not get pathname for object %p\n", obj_handle); } else { acpi_os_printf ("%32s (%p) - %s\n", buffer, obj_handle, acpi_ut_get_type_name (((acpi_namespace_node *) obj_handle)->type)); } return (AE_OK); } /******************************************************************************* * * FUNCTION: Acpi_db_find_name_in_namespace * * PARAMETERS: Name_arg - The 4-character ACPI name to find. * wildcards are supported. * * RETURN: None * * DESCRIPTION: Search the namespace for a given name (with wildcards) * ******************************************************************************/ acpi_status acpi_db_find_name_in_namespace ( NATIVE_CHAR *name_arg) { if (STRLEN (name_arg) > 4) { acpi_os_printf ("Name must be no longer than 4 characters\n"); return (AE_OK); } /* Walk the namespace from the root */ acpi_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, acpi_db_walk_and_match_name, name_arg, NULL); acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); return (AE_OK); } /******************************************************************************* * * FUNCTION: Acpi_db_set_scope * * PARAMETERS: Name - New scope path * * RETURN: Status * * DESCRIPTION: Set the "current scope" as maintained by this utility. * The scope is used as a prefix to ACPI paths. * ******************************************************************************/ void acpi_db_set_scope ( NATIVE_CHAR *name) { if (!name || name[0] == 0) { acpi_os_printf ("Current scope: %s\n", acpi_gbl_db_scope_buf); return; } acpi_db_prep_namestring (name); /* TBD: [Future] Validate scope here */ if (name[0] == '\\') { STRCPY (acpi_gbl_db_scope_buf, name); STRCAT (acpi_gbl_db_scope_buf, "\\"); } else { STRCAT (acpi_gbl_db_scope_buf, name); STRCAT (acpi_gbl_db_scope_buf, "\\"); } acpi_os_printf ("New scope: %s\n", acpi_gbl_db_scope_buf); } /******************************************************************************* * * FUNCTION: Acpi_db_display_resources * * PARAMETERS: Object_arg - String with hex value of the object * * RETURN: None * * DESCRIPTION: * ******************************************************************************/ void acpi_db_display_resources ( NATIVE_CHAR *object_arg) { #ifndef _IA16 acpi_operand_object *obj_desc; acpi_status status; acpi_buffer return_obj; acpi_db_set_output_destination (DB_REDIRECTABLE_OUTPUT); /* Convert string to object pointer */ obj_desc = (acpi_operand_object *) STRTOUL (object_arg, NULL, 16); /* Prepare for a return object of arbitrary size */ return_obj.pointer = acpi_gbl_db_buffer; return_obj.length = ACPI_DEBUG_BUFFER_SIZE; /* _PRT */ acpi_os_printf ("Evaluating _PRT\n"); status = acpi_evaluate_object (obj_desc, "_PRT", NULL, &return_obj); if (ACPI_FAILURE (status)) { acpi_os_printf ("Could not obtain _PRT: %s\n", acpi_format_exception (status)); goto get_crs; } return_obj.pointer = acpi_gbl_db_buffer; return_obj.length = ACPI_DEBUG_BUFFER_SIZE; status = acpi_get_irq_routing_table (obj_desc, &return_obj); if (ACPI_FAILURE (status)) { acpi_os_printf ("Get_irq_routing_table failed: %s\n", acpi_format_exception (status)); } else { acpi_rs_dump_irq_list ((u8 *) acpi_gbl_db_buffer); } /* _CRS */ get_crs: acpi_os_printf ("Evaluating _CRS\n"); return_obj.pointer = acpi_gbl_db_buffer; return_obj.length = ACPI_DEBUG_BUFFER_SIZE; status = acpi_evaluate_object (obj_desc, "_CRS", NULL, &return_obj); if (ACPI_FAILURE (status)) { acpi_os_printf ("Could not obtain _CRS: %s\n", acpi_format_exception (status)); goto get_prs; } return_obj.pointer = acpi_gbl_db_buffer; return_obj.length = ACPI_DEBUG_BUFFER_SIZE; status = acpi_get_current_resources (obj_desc, &return_obj); if (ACPI_FAILURE (status)) { acpi_os_printf ("Acpi_get_current_resources failed: %s\n", acpi_format_exception (status)); } else { acpi_rs_dump_resource_list ((acpi_resource *) acpi_gbl_db_buffer); } /* _PRS */ get_prs: acpi_os_printf ("Evaluating _PRS\n"); return_obj.pointer = acpi_gbl_db_buffer; return_obj.length = ACPI_DEBUG_BUFFER_SIZE; status = acpi_evaluate_object (obj_desc, "_PRS", NULL, &return_obj); if (ACPI_FAILURE (status)) { acpi_os_printf ("Could not obtain _PRS: %s\n", acpi_format_exception (status)); goto cleanup; } return_obj.pointer = acpi_gbl_db_buffer; return_obj.length = ACPI_DEBUG_BUFFER_SIZE; status = acpi_get_possible_resources (obj_desc, &return_obj); if (ACPI_FAILURE (status)) { acpi_os_printf ("Acpi_get_possible_resources failed: %s\n", acpi_format_exception (status)); } else { acpi_rs_dump_resource_list ((acpi_resource *) acpi_gbl_db_buffer); } cleanup: acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); return; #endif } #endif /* ENABLE_DEBUGGER */