Commit 095c03ba authored by Andy Grover's avatar Andy Grover

ACPI: Remove interpreter debugger and kdb directories. These ultimately

didn't prove useful enough to be used on a regular basis.
parent a2fa7607
#
# Makefile for all Linux ACPI interpreter subdirectories
#
obj-$(CONFIG_ACPI_INTERPRETER) := $(patsubst %.c,%.o,$(wildcard *.c))
EXTRA_CFLAGS += $(ACPI_CFLAGS)
include $(TOPDIR)/Rules.make
/*******************************************************************************
*
* Module Name: dbcmds - debug commands and output routines
* $Revision: 87 $
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2002, 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 "acdispat.h"
#include "amlcode.h"
#include "acnamesp.h"
#include "acevents.h"
#include "acdebug.h"
#include "acresrc.h"
#include "acdisasm.h"
#ifdef ACPI_DEBUGGER
#define _COMPONENT ACPI_CA_DEBUGGER
ACPI_MODULE_NAME ("dbcmds")
/*
* Arguments for the Objects command
* These object types map directly to the ACPI_TYPES
*/
static 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.
*
* Note: Currently doesn't check subobjects within the Node's object
*
******************************************************************************/
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.ascii);
}
/* Check for match against the object attached to the node */
if (acpi_ns_get_attached_object (node) == obj_desc) {
acpi_os_printf ("Reference at Node->Object %p [%4.4s]\n", node, node->name.ascii);
}
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_TO_POINTER (ACPI_STRTOUL (object_arg, NULL, 16));
/* Search all nodes in namespace */
(void) 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 (!ACPI_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 = ACPI_STRTOUL (location, NULL, 16);
if (address <= op->common.aml_offset) {
acpi_os_printf ("Breakpoint %X is beyond current address %X\n", address, op->common.aml_offset);
}
/* Save breakpoint in current walk */
walk_state->user_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 = ACPI_STRTOUL (statements, NULL, 0);
}
acpi_dm_disassemble (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_TO_POINTER (ACPI_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 (ACPI_GET_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 = ACPI_STRTOUL (depth_arg, NULL, 0);
}
}
acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT);
acpi_os_printf ("ACPI Namespace (from %p subtree):\n", subtree_entry);
/* Display the subtree */
acpi_db_set_output_destination (ACPI_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 (ACPI_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) ACPI_STRTOUL (owner_arg, NULL, 0);
/* Now we can check for the depth argument */
if (depth_arg) {
max_depth = ACPI_STRTOUL (depth_arg, NULL, 0);
}
acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT);
acpi_os_printf ("ACPI Namespace by owner %X:\n", owner_id);
/* Display the subtree */
acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT);
acpi_ns_dump_objects (ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth, owner_id, subtree_entry);
acpi_db_set_output_destination (ACPI_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;
acpi_status status;
/* 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 */
status = acpi_ev_queue_notify_request (node, value);
if (ACPI_FAILURE (status)) {
acpi_os_printf ("Could not queue notify\n");
}
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;
acpi_status status;
/* Validate Type_arg */
ACPI_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 = ACPI_STRTOUL (index_arg, NULL, 16);
value = ACPI_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_MAX_ARG) {
acpi_os_printf ("Arg%d - Invalid argument name\n", index);
return;
}
status = acpi_ds_store_object_to_local (AML_ARG_OP, index, obj_desc, walk_state);
if (ACPI_FAILURE (status)) {
return;
}
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_MAX_LOCAL) {
acpi_os_printf ("Local%d - Invalid local variable name\n", index);
return;
}
status = acpi_ds_store_object_to_local (AML_LOCAL_OP, index, obj_desc, walk_state);
if (ACPI_FAILURE (status)) {
return;
}
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;
acpi_buffer buffer;
obj_desc = acpi_ns_get_attached_object ((acpi_namespace_node *) obj_handle);
/* Get and display the full pathname to this object */
buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
status = acpi_ns_handle_to_pathname (obj_handle, &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.pointer);
ACPI_MEM_FREE (buffer.pointer);
/* Display short information about the object */
if (obj_desc) {
switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
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;
default:
/* Ignore other object types */
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_type 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 (ACPI_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 (ACPI_DB_REDIRECTABLE_OUTPUT);
/* Walk the namespace from the root */
(void) acpi_walk_namespace (type, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
acpi_db_walk_for_specific_objects, (void *) &type, NULL);
acpi_db_set_output_destination (ACPI_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;
acpi_buffer buffer;
/* Check for a name match */
for (i = 0; i < 4; i++) {
/* Wildcard support */
if ((requested_name[i] != '?') &&
(requested_name[i] != ((acpi_namespace_node *) obj_handle)->name.ascii[i])) {
/* No match, just exit */
return (AE_OK);
}
}
/* Get the full pathname to this object */
buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
status = acpi_ns_handle_to_pathname (obj_handle, &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.pointer, obj_handle,
acpi_ut_get_type_name (((acpi_namespace_node *) obj_handle)->type));
ACPI_MEM_FREE (buffer.pointer);
}
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 (ACPI_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 */
(void) 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 (ACPI_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)
{
acpi_status status;
acpi_namespace_node *node;
if (!name || name[0] == 0) {
acpi_os_printf ("Current scope: %s\n", acpi_gbl_db_scope_buf);
return;
}
acpi_db_prep_namestring (name);
if (name[0] == '\\') {
/* Validate new scope from the root */
status = acpi_ns_get_node_by_path (name, acpi_gbl_root_node, ACPI_NS_NO_UPSEARCH, &node);
if (ACPI_FAILURE (status)) {
goto error_exit;
}
ACPI_STRCPY (acpi_gbl_db_scope_buf, name);
ACPI_STRCAT (acpi_gbl_db_scope_buf, "\\");
}
else {
/* Validate new scope relative to old scope */
status = acpi_ns_get_node_by_path (name, acpi_gbl_db_scope_node, ACPI_NS_NO_UPSEARCH, &node);
if (ACPI_FAILURE (status)) {
goto error_exit;
}
ACPI_STRCAT (acpi_gbl_db_scope_buf, name);
ACPI_STRCAT (acpi_gbl_db_scope_buf, "\\");
}
acpi_gbl_db_scope_node = node;
acpi_os_printf ("New scope: %s\n", acpi_gbl_db_scope_buf);
return;
error_exit:
acpi_os_printf ("Could not attach scope: %s, %s\n", name, acpi_format_exception (status));
}
/*******************************************************************************
*
* 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)
{
#if ACPI_MACHINE_WIDTH != 16
acpi_operand_object *obj_desc;
acpi_status status;
acpi_buffer return_obj;
acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT);
acpi_dbg_level |= ACPI_LV_RESOURCES;
/* Convert string to object pointer */
obj_desc = ACPI_TO_POINTER (ACPI_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));
goto get_prs;
}
else {
acpi_rs_dump_resource_list (ACPI_CAST_PTR (acpi_resource, acpi_gbl_db_buffer));
}
status = acpi_set_current_resources (obj_desc, &return_obj);
if (ACPI_FAILURE (status)) {
acpi_os_printf ("Acpi_set_current_resources failed: %s\n", acpi_format_exception (status));
goto get_prs;
}
/* _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_CAST_PTR (acpi_resource, acpi_gbl_db_buffer));
}
cleanup:
acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
return;
#endif
}
typedef struct
{
u32 nodes;
u32 objects;
} ACPI_INTEGRITY_INFO;
/*******************************************************************************
*
* FUNCTION: Acpi_db_integrity_walk
*
* PARAMETERS: Callback from Walk_namespace
*
* RETURN: Status
*
* DESCRIPTION: Examine one NS node for valid values.
*
******************************************************************************/
acpi_status
acpi_db_integrity_walk (
acpi_handle obj_handle,
u32 nesting_level,
void *context,
void **return_value)
{
ACPI_INTEGRITY_INFO *info = (ACPI_INTEGRITY_INFO *) context;
acpi_namespace_node *node = (acpi_namespace_node *) obj_handle;
acpi_operand_object *object;
info->nodes++;
if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
acpi_os_printf ("Invalid Descriptor Type for Node %p, Type = %X\n",
node, ACPI_GET_DESCRIPTOR_TYPE (node));
}
if (node->type > INTERNAL_TYPE_MAX) {
acpi_os_printf ("Invalid Object Type for Node %p, Type = %X\n",
node, node->type);
}
if (!acpi_ut_valid_acpi_name (node->name.integer)) {
acpi_os_printf ("Invalid Acpi_name for Node %p\n", node);
}
object = acpi_ns_get_attached_object (node);
if (object) {
info->objects++;
if (ACPI_GET_DESCRIPTOR_TYPE (object) != ACPI_DESC_TYPE_OPERAND) {
acpi_os_printf ("Invalid Descriptor Type for Object %p, Type = %X\n",
object, ACPI_GET_DESCRIPTOR_TYPE (object));
}
}
return (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_check_integrity
*
* PARAMETERS: None
*
* RETURN: None
*
* DESCRIPTION: Check entire namespace for data structure integrity
*
******************************************************************************/
void
acpi_db_check_integrity (void)
{
ACPI_INTEGRITY_INFO info = {0,0};
/* Search all nodes in namespace */
(void) acpi_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
acpi_db_integrity_walk, (void *) &info, NULL);
acpi_os_printf ("Verified %d namespace nodes with %d Objects\n", info.nodes, info.objects);
}
#endif /* ACPI_DEBUGGER */
/*******************************************************************************
*
* Module Name: dbdisply - debug display commands
* $Revision: 78 $
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2002, 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 "amlcode.h"
#include "acdispat.h"
#include "acnamesp.h"
#include "acparser.h"
#include "acinterp.h"
#include "acdebug.h"
#ifdef ACPI_DEBUGGER
#define _COMPONENT ACPI_CA_DEBUGGER
ACPI_MODULE_NAME ("dbdisply")
/******************************************************************************
*
* FUNCTION: Acpi_db_get_pointer
*
* PARAMETERS: Target - Pointer to string to be converted
*
* RETURN: Converted pointer
*
* DESCRIPTION: Convert an ascii pointer value to a real value
*
*****************************************************************************/
void *
acpi_db_get_pointer (
void *target)
{
void *obj_ptr;
#if ACPI_MACHINE_WIDTH == 16
#include <stdio.h>
/* Have to handle 16-bit pointers of the form segment:offset */
if (!sscanf (target, "%p", &obj_ptr)) {
acpi_os_printf ("Invalid pointer: %s\n", target);
return (NULL);
}
#else
/* Simple flat pointer */
obj_ptr = ACPI_TO_POINTER (ACPI_STRTOUL (target, NULL, 16));
#endif
return (obj_ptr);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_dump_parser_descriptor
*
* PARAMETERS: Op - A parser Op descriptor
*
* RETURN: None
*
* DESCRIPTION: Display a formatted parser object
*
******************************************************************************/
void
acpi_db_dump_parser_descriptor (
acpi_parse_object *op)
{
const acpi_opcode_info *info;
info = acpi_ps_get_opcode_info (op->common.aml_opcode);
acpi_os_printf ("Parser Op Descriptor:\n");
acpi_os_printf ("%20.20s : %4.4X\n", "Opcode", op->common.aml_opcode);
ACPI_DEBUG_ONLY_MEMBERS (acpi_os_printf ("%20.20s : %s\n", "Opcode Name", info->name));
acpi_os_printf ("%20.20s : %p\n", "Value/Arg_list", op->common.value.arg);
acpi_os_printf ("%20.20s : %p\n", "Parent", op->common.parent);
acpi_os_printf ("%20.20s : %p\n", "Next_op", op->common.next);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_decode_and_display_object
*
* PARAMETERS: Target - String with object to be displayed. Names
* and hex pointers are supported.
* Output_type - Byte, Word, Dword, or Qword (B|W|D|Q)
*
* RETURN: None
*
* DESCRIPTION: Display a formatted ACPI object
*
******************************************************************************/
void
acpi_db_decode_and_display_object (
NATIVE_CHAR *target,
NATIVE_CHAR *output_type)
{
void *obj_ptr;
acpi_namespace_node *node;
acpi_operand_object *obj_desc;
u32 display = DB_BYTE_DISPLAY;
NATIVE_CHAR buffer[80];
acpi_buffer ret_buf;
acpi_status status;
u32 size;
if (!target) {
return;
}
/* Decode the output type */
if (output_type) {
ACPI_STRUPR (output_type);
if (output_type[0] == 'W') {
display = DB_WORD_DISPLAY;
}
else if (output_type[0] == 'D') {
display = DB_DWORD_DISPLAY;
}
else if (output_type[0] == 'Q') {
display = DB_QWORD_DISPLAY;
}
}
ret_buf.length = sizeof (buffer);
ret_buf.pointer = buffer;
/* Differentiate between a number and a name */
if ((target[0] >= 0x30) && (target[0] <= 0x39)) {
obj_ptr = acpi_db_get_pointer (target);
if (!acpi_os_readable (obj_ptr, 16)) {
acpi_os_printf ("Address %p is invalid in this address space\n", obj_ptr);
return;
}
/* Decode the object type */
switch (ACPI_GET_DESCRIPTOR_TYPE (obj_ptr)) {
case ACPI_DESC_TYPE_NAMED:
/* This is a namespace Node */
if (!acpi_os_readable (obj_ptr, sizeof (acpi_namespace_node))) {
acpi_os_printf ("Cannot read entire Named object at address %p\n", obj_ptr);
return;
}
node = obj_ptr;
goto dump_nte;
case ACPI_DESC_TYPE_OPERAND:
/* This is a ACPI OPERAND OBJECT */
if (!acpi_os_readable (obj_ptr, sizeof (acpi_operand_object))) {
acpi_os_printf ("Cannot read entire ACPI object at address %p\n", obj_ptr);
return;
}
acpi_ut_dump_buffer (obj_ptr, sizeof (acpi_operand_object), display, ACPI_UINT32_MAX);
acpi_ex_dump_object_descriptor (obj_ptr, 1);
break;
case ACPI_DESC_TYPE_PARSER:
/* This is a Parser Op object */
if (!acpi_os_readable (obj_ptr, sizeof (acpi_parse_object))) {
acpi_os_printf ("Cannot read entire Parser object at address %p\n", obj_ptr);
return;
}
acpi_ut_dump_buffer (obj_ptr, sizeof (acpi_parse_object), display, ACPI_UINT32_MAX);
acpi_db_dump_parser_descriptor ((acpi_parse_object *) obj_ptr);
break;
default:
/* Is not a recognizeable object */
size = 16;
if (acpi_os_readable (obj_ptr, 64)) {
size = 64;
}
/* Just dump some memory */
acpi_ut_dump_buffer (obj_ptr, size, display, ACPI_UINT32_MAX);
break;
}
return;
}
/* The parameter is a name string that must be resolved to a Named obj */
node = acpi_db_local_ns_lookup (target);
if (!node) {
return;
}
dump_nte:
/* Now dump the Named obj */
status = acpi_get_name (node, ACPI_FULL_PATHNAME, &ret_buf);
if (ACPI_FAILURE (status)) {
acpi_os_printf ("Could not convert name to pathname\n");
}
else {
acpi_os_printf ("Object (%p) Pathname: %s\n", node, ret_buf.pointer);
}
if (!acpi_os_readable (node, sizeof (acpi_namespace_node))) {
acpi_os_printf ("Invalid Named object at address %p\n", node);
return;
}
acpi_ut_dump_buffer ((void *) node, sizeof (acpi_namespace_node), display, ACPI_UINT32_MAX);
acpi_ex_dump_node (node, 1);
obj_desc = acpi_ns_get_attached_object (node);
if (obj_desc) {
acpi_os_printf ("\nAttached Object (%p):\n", obj_desc);
if (!acpi_os_readable (obj_desc, sizeof (acpi_operand_object))) {
acpi_os_printf ("Invalid internal ACPI Object at address %p\n", obj_desc);
return;
}
acpi_ut_dump_buffer ((void *) obj_desc, sizeof (acpi_operand_object), display, ACPI_UINT32_MAX);
acpi_ex_dump_object_descriptor (obj_desc, 1);
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_decode_internal_object
*
* PARAMETERS: Obj_desc - Object to be displayed
*
* RETURN: None
*
* DESCRIPTION: Short display of an internal object. Numbers and Strings.
*
******************************************************************************/
void
acpi_db_decode_internal_object (
acpi_operand_object *obj_desc)
{
u32 i;
if (!obj_desc) {
acpi_os_printf (" Uninitialized\n");
return;
}
if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) {
acpi_os_printf ("%p", obj_desc);
return;
}
acpi_os_printf (" %s", acpi_ut_get_object_type_name (obj_desc));
switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
case ACPI_TYPE_INTEGER:
acpi_os_printf (" %8.8X%8.8X", ACPI_HIDWORD (obj_desc->integer.value),
ACPI_LODWORD (obj_desc->integer.value));
break;
case ACPI_TYPE_STRING:
acpi_os_printf ("(%d) \"%.24s",
obj_desc->string.length, obj_desc->string.pointer);
if (obj_desc->string.length > 24)
{
acpi_os_printf ("...");
}
else
{
acpi_os_printf ("\"");
}
break;
case ACPI_TYPE_BUFFER:
acpi_os_printf ("(%d)", obj_desc->buffer.length);
for (i = 0; (i < 8) && (i < obj_desc->buffer.length); i++) {
acpi_os_printf (" %2.2X", obj_desc->buffer.pointer[i]);
}
break;
default:
acpi_os_printf ("%p", obj_desc);
break;
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_decode_node
*
* PARAMETERS: Node - Object to be displayed
*
* RETURN: None
*
* DESCRIPTION: Short display of a namespace node
*
******************************************************************************/
void
acpi_db_decode_node (
acpi_namespace_node *node)
{
acpi_os_printf ("<Node> Name %4.4s Type-%s",
node->name.ascii, acpi_ut_get_type_name (node->type));
if (node->flags & ANOBJ_METHOD_ARG) {
acpi_os_printf (" [Method Arg]");
}
if (node->flags & ANOBJ_METHOD_LOCAL) {
acpi_os_printf (" [Method Local]");
}
acpi_db_decode_internal_object (acpi_ns_get_attached_object (node));
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_display_internal_object
*
* PARAMETERS: Obj_desc - Object to be displayed
* Walk_state - Current walk state
*
* RETURN: None
*
* DESCRIPTION: Short display of an internal object
*
******************************************************************************/
void
acpi_db_display_internal_object (
acpi_operand_object *obj_desc,
acpi_walk_state *walk_state)
{
u8 type;
acpi_os_printf ("%p ", obj_desc);
if (!obj_desc) {
acpi_os_printf ("<Null_obj>\n");
return;
}
/* Decode the object type */
switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) {
case ACPI_DESC_TYPE_PARSER:
acpi_os_printf ("<Parser> ");
break;
case ACPI_DESC_TYPE_NAMED:
acpi_db_decode_node ((acpi_namespace_node *) obj_desc);
break;
case ACPI_DESC_TYPE_OPERAND:
type = ACPI_GET_OBJECT_TYPE (obj_desc);
if (type > INTERNAL_TYPE_MAX) {
acpi_os_printf (" Type %hX [Invalid Type]", type);
return;
}
/* Decode the ACPI object type */
switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
case INTERNAL_TYPE_REFERENCE:
switch (obj_desc->reference.opcode) {
case AML_LOCAL_OP:
acpi_os_printf ("[Local%d] ", obj_desc->reference.offset);
if (walk_state) {
obj_desc = walk_state->local_variables[obj_desc->reference.offset].object;
acpi_os_printf ("%p", obj_desc);
acpi_db_decode_internal_object (obj_desc);
}
break;
case AML_ARG_OP:
acpi_os_printf ("[Arg%d] ", obj_desc->reference.offset);
if (walk_state) {
obj_desc = walk_state->arguments[obj_desc->reference.offset].object;
acpi_os_printf ("%p", obj_desc);
acpi_db_decode_internal_object (obj_desc);
}
break;
case AML_DEBUG_OP:
acpi_os_printf ("[Debug] ");
break;
case AML_INDEX_OP:
acpi_os_printf ("[Index] ");
acpi_db_decode_internal_object (obj_desc->reference.object);
break;
case AML_REF_OF_OP:
acpi_os_printf ("[Reference] ");
/* Reference can be to a Node or an Operand object */
switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc->reference.object)) {
case ACPI_DESC_TYPE_NAMED:
acpi_db_decode_node (obj_desc->reference.object);
break;
case ACPI_DESC_TYPE_OPERAND:
acpi_db_decode_internal_object (obj_desc->reference.object);
break;
default:
break;
}
break;
default:
acpi_os_printf ("Unknown Reference opcode %X\n",
obj_desc->reference.opcode);
break;
}
break;
default:
acpi_os_printf ("<Obj> ");
acpi_os_printf (" ");
acpi_db_decode_internal_object (obj_desc);
break;
}
break;
default:
acpi_os_printf ("<Not a valid ACPI Object Descriptor> ");
break;
}
acpi_os_printf ("\n");
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_display_method_info
*
* PARAMETERS: Start_op - Root of the control method parse tree
*
* RETURN: None
*
* DESCRIPTION: Display information about the current method
*
******************************************************************************/
void
acpi_db_display_method_info (
acpi_parse_object *start_op)
{
acpi_walk_state *walk_state;
acpi_operand_object *obj_desc;
acpi_namespace_node *node;
acpi_parse_object *root_op;
acpi_parse_object *op;
const acpi_opcode_info *op_info;
u32 num_ops = 0;
u32 num_operands = 0;
u32 num_operators = 0;
u32 num_remaining_ops = 0;
u32 num_remaining_operands = 0;
u32 num_remaining_operators = 0;
u32 num_args;
u32 concurrency;
u8 count_remaining = FALSE;
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;
}
obj_desc = walk_state->method_desc;
node = walk_state->method_node;
num_args = obj_desc->method.param_count;
concurrency = obj_desc->method.concurrency;
acpi_os_printf ("Currently executing control method is [%4.4s]\n", node->name.ascii);
acpi_os_printf ("%X arguments, max concurrency = %X\n", num_args, concurrency);
root_op = start_op;
while (root_op->common.parent) {
root_op = root_op->common.parent;
}
op = root_op;
while (op) {
if (op == start_op) {
count_remaining = TRUE;
}
num_ops++;
if (count_remaining) {
num_remaining_ops++;
}
/* Decode the opcode */
op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
switch (op_info->class) {
case AML_CLASS_ARGUMENT:
if (count_remaining) {
num_remaining_operands++;
}
num_operands++;
break;
case AML_CLASS_UNKNOWN:
/* Bad opcode or ASCII character */
continue;
default:
if (count_remaining) {
num_remaining_operators++;
}
num_operators++;
break;
}
op = acpi_ps_get_depth_next (start_op, op);
}
acpi_os_printf ("Method contains: %X AML Opcodes - %X Operators, %X Operands\n",
num_ops, num_operators, num_operands);
acpi_os_printf ("Remaining to execute: %X AML Opcodes - %X Operators, %X Operands\n",
num_remaining_ops, num_remaining_operators, num_remaining_operands);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_display_locals
*
* PARAMETERS: None
*
* RETURN: None
*
* DESCRIPTION: Display all locals for the currently running control method
*
******************************************************************************/
void
acpi_db_display_locals (void)
{
u32 i;
acpi_walk_state *walk_state;
acpi_operand_object *obj_desc;
acpi_namespace_node *node;
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;
}
obj_desc = walk_state->method_desc;
node = walk_state->method_node;
acpi_os_printf ("Local Variables for method [%4.4s]:\n", node->name.ascii);
for (i = 0; i < MTH_NUM_LOCALS; i++) {
obj_desc = walk_state->local_variables[i].object;
acpi_os_printf ("Local%d: ", i);
acpi_db_display_internal_object (obj_desc, walk_state);
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_display_arguments
*
* PARAMETERS: None
*
* RETURN: None
*
* DESCRIPTION: Display all arguments for the currently running control method
*
******************************************************************************/
void
acpi_db_display_arguments (void)
{
u32 i;
acpi_walk_state *walk_state;
acpi_operand_object *obj_desc;
u32 num_args;
u32 concurrency;
acpi_namespace_node *node;
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;
}
obj_desc = walk_state->method_desc;
node = walk_state->method_node;
num_args = obj_desc->method.param_count;
concurrency = obj_desc->method.concurrency;
acpi_os_printf ("Method [%4.4s] has %X arguments, max concurrency = %X\n",
node->name.ascii, num_args, concurrency);
for (i = 0; i < num_args; i++) {
obj_desc = walk_state->arguments[i].object;
acpi_os_printf ("Arg%d: ", i);
acpi_db_display_internal_object (obj_desc, walk_state);
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_display_results
*
* PARAMETERS: None
*
* RETURN: None
*
* DESCRIPTION: Display current contents of a method result stack
*
******************************************************************************/
void
acpi_db_display_results (void)
{
u32 i;
acpi_walk_state *walk_state;
acpi_operand_object *obj_desc;
u32 num_results = 0;
acpi_namespace_node *node;
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;
}
obj_desc = walk_state->method_desc;
node = walk_state->method_node;
if (walk_state->results) {
num_results = walk_state->results->results.num_results;
}
acpi_os_printf ("Method [%4.4s] has %X stacked result objects\n",
node->name.ascii, num_results);
for (i = 0; i < num_results; i++) {
obj_desc = walk_state->results->results.obj_desc[i];
acpi_os_printf ("Result%d: ", i);
acpi_db_display_internal_object (obj_desc, walk_state);
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_display_calling_tree
*
* PARAMETERS: None
*
* RETURN: None
*
* DESCRIPTION: Display current calling tree of nested control methods
*
******************************************************************************/
void
acpi_db_display_calling_tree (void)
{
acpi_walk_state *walk_state;
acpi_namespace_node *node;
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;
}
node = walk_state->method_node;
acpi_os_printf ("Current Control Method Call Tree\n");
while (walk_state) {
node = walk_state->method_node;
acpi_os_printf (" [%4.4s]\n", node->name.ascii);
walk_state = walk_state->next;
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_display_result_object
*
* PARAMETERS: Obj_desc - Object to be displayed
* Walk_state - Current walk state
*
* RETURN: None
*
* DESCRIPTION: Display the result of an AML opcode
*
* Note: Curently only displays the result object if we are single stepping.
* However, this output may be useful in other contexts and could be enabled
* to do so if needed.
*
******************************************************************************/
void
acpi_db_display_result_object (
acpi_operand_object *obj_desc,
acpi_walk_state *walk_state)
{
/* Only display if single stepping */
if (!acpi_gbl_cm_single_step) {
return;
}
acpi_os_printf ("Result_obj: ");
acpi_db_display_internal_object (obj_desc, walk_state);
acpi_os_printf ("\n");
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_display_argument_object
*
* PARAMETERS: Obj_desc - Object to be displayed
* Walk_state - Current walk state
*
* RETURN: None
*
* DESCRIPTION: Display the result of an AML opcode
*
******************************************************************************/
void
acpi_db_display_argument_object (
acpi_operand_object *obj_desc,
acpi_walk_state *walk_state)
{
if (!acpi_gbl_cm_single_step) {
return;
}
acpi_os_printf ("Arg_obj: ");
acpi_db_display_internal_object (obj_desc, walk_state);
}
#endif /* ACPI_DEBUGGER */
/*******************************************************************************
*
* Module Name: dbexec - debugger control method execution
* $Revision: 44 $
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2002, 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 "acdebug.h"
#ifdef ACPI_DEBUGGER
#define _COMPONENT ACPI_CA_DEBUGGER
ACPI_MODULE_NAME ("dbexec")
static acpi_db_method_info acpi_gbl_db_method_info;
/*******************************************************************************
*
* FUNCTION: Acpi_db_execute_method
*
* PARAMETERS: Info - Valid info segment
* Return_obj - Where to put return object
*
* RETURN: Status
*
* DESCRIPTION: Execute a control method.
*
******************************************************************************/
acpi_status
acpi_db_execute_method (
acpi_db_method_info *info,
acpi_buffer *return_obj)
{
acpi_status status;
acpi_object_list param_objects;
acpi_object params[MTH_NUM_ARGS];
u32 i;
if (acpi_gbl_db_output_to_file && !acpi_dbg_level) {
acpi_os_printf ("Warning: debug output is not enabled!\n");
}
/* Are there arguments to the method? */
if (info->args && info->args[0]) {
for (i = 0; info->args[i] && i < MTH_NUM_ARGS; i++) {
params[i].type = ACPI_TYPE_INTEGER;
params[i].integer.value = ACPI_STRTOUL (info->args[i], NULL, 16);
}
param_objects.pointer = params;
param_objects.count = i;
}
else {
/* Setup default parameters */
params[0].type = ACPI_TYPE_INTEGER;
params[0].integer.value = 0x01020304;
params[1].type = ACPI_TYPE_STRING;
params[1].string.length = 12;
params[1].string.pointer = "AML Debugger";
param_objects.pointer = params;
param_objects.count = 2;
}
/* Prepare for a return object of arbitrary size */
return_obj->pointer = acpi_gbl_db_buffer;
return_obj->length = ACPI_DEBUG_BUFFER_SIZE;
/* Do the actual method execution */
status = acpi_evaluate_object (NULL, info->pathname, &param_objects, return_obj);
acpi_gbl_cm_single_step = FALSE;
acpi_gbl_method_executing = FALSE;
return (status);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_execute_setup
*
* PARAMETERS: Info - Valid method info
*
* RETURN: Status
*
* DESCRIPTION: Setup info segment prior to method execution
*
******************************************************************************/
void
acpi_db_execute_setup (
acpi_db_method_info *info)
{
/* Catenate the current scope to the supplied name */
info->pathname[0] = 0;
if ((info->name[0] != '\\') &&
(info->name[0] != '/')) {
ACPI_STRCAT (info->pathname, acpi_gbl_db_scope_buf);
}
ACPI_STRCAT (info->pathname, info->name);
acpi_db_prep_namestring (info->pathname);
acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT);
acpi_os_printf ("Executing %s\n", info->pathname);
if (info->flags & EX_SINGLE_STEP) {
acpi_gbl_cm_single_step = TRUE;
acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
}
else {
/* No single step, allow redirection to a file */
acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT);
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_get_outstanding_allocations
*
* PARAMETERS: None
*
* RETURN: Current global allocation count minus cache entries
*
* DESCRIPTION: Determine the current number of "outstanding" allocations --
* those allocations that have not been freed and also are not
* in one of the various object caches.
*
******************************************************************************/
u32
acpi_db_get_outstanding_allocations (
void)
{
u32 outstanding = 0;
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
u32 i;
for (i = ACPI_MEM_LIST_FIRST_CACHE_LIST; i < ACPI_NUM_MEM_LISTS; i++) {
outstanding += (acpi_gbl_memory_lists[i].total_allocated -
acpi_gbl_memory_lists[i].total_freed -
acpi_gbl_memory_lists[i].cache_depth);
}
#endif
return (outstanding);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_execute
*
* PARAMETERS: Name - Name of method to execute
* Args - Parameters to the method
* Flags - single step/no single step
*
* RETURN: Status
*
* DESCRIPTION: Execute a control method. Name is relative to the current
* scope.
*
******************************************************************************/
void
acpi_db_execute (
NATIVE_CHAR *name,
NATIVE_CHAR **args,
u32 flags)
{
acpi_status status;
acpi_buffer return_obj;
#ifdef ACPI_DEBUG_OUTPUT
u32 previous_allocations;
u32 allocations;
/* Memory allocation tracking */
previous_allocations = acpi_db_get_outstanding_allocations ();
#endif
acpi_gbl_db_method_info.name = name;
acpi_gbl_db_method_info.args = args;
acpi_gbl_db_method_info.flags = flags;
return_obj.pointer = NULL;
return_obj.length = ACPI_ALLOCATE_BUFFER;
acpi_db_execute_setup (&acpi_gbl_db_method_info);
status = acpi_db_execute_method (&acpi_gbl_db_method_info, &return_obj);
/*
* Allow any handlers in separate threads to complete.
* (Such as Notify handlers invoked from AML executed above).
*/
acpi_os_sleep (0, 10);
#ifdef ACPI_DEBUG_OUTPUT
/* Memory allocation tracking */
allocations = acpi_db_get_outstanding_allocations () - previous_allocations;
acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT);
if (allocations > 0) {
acpi_os_printf ("Outstanding: %ld allocations after execution\n",
allocations);
}
#endif
if (ACPI_FAILURE (status)) {
acpi_os_printf ("Execution of %s failed with status %s\n",
acpi_gbl_db_method_info.pathname, acpi_format_exception (status));
}
else {
/* Display a return object, if any */
if (return_obj.length) {
acpi_os_printf ("Execution of %s returned object %p Buflen %X\n",
acpi_gbl_db_method_info.pathname, return_obj.pointer, return_obj.length);
acpi_db_dump_object (return_obj.pointer, 1);
}
else {
acpi_os_printf ("No return object from execution of %s\n",
acpi_gbl_db_method_info.pathname);
}
}
acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_method_thread
*
* PARAMETERS: Context - Execution info segment
*
* RETURN: None
*
* DESCRIPTION: Debugger execute thread. Waits for a command line, then
* simply dispatches it.
*
******************************************************************************/
void ACPI_SYSTEM_XFACE
acpi_db_method_thread (
void *context)
{
acpi_status status;
acpi_db_method_info *info = context;
u32 i;
acpi_buffer return_obj;
for (i = 0; i < info->num_loops; i++) {
status = acpi_db_execute_method (info, &return_obj);
if (ACPI_SUCCESS (status)) {
if (return_obj.length) {
acpi_os_printf ("Execution of %s returned object %p Buflen %X\n",
info->pathname, return_obj.pointer, return_obj.length);
acpi_db_dump_object (return_obj.pointer, 1);
}
}
}
/* Signal our completion */
status = acpi_os_signal_semaphore (info->thread_gate, 1);
if (ACPI_FAILURE (status)) {
acpi_os_printf ("Could not signal debugger semaphore\n");
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_create_execution_threads
*
* PARAMETERS: Num_threads_arg - Number of threads to create
* Num_loops_arg - Loop count for the thread(s)
* Method_name_arg - Control method to execute
*
* RETURN: None
*
* DESCRIPTION: Create threads to execute method(s)
*
******************************************************************************/
void
acpi_db_create_execution_threads (
NATIVE_CHAR *num_threads_arg,
NATIVE_CHAR *num_loops_arg,
NATIVE_CHAR *method_name_arg)
{
acpi_status status;
u32 num_threads;
u32 num_loops;
u32 i;
acpi_handle thread_gate;
/* Get the arguments */
num_threads = ACPI_STRTOUL (num_threads_arg, NULL, 0);
num_loops = ACPI_STRTOUL (num_loops_arg, NULL, 0);
if (!num_threads || !num_loops) {
acpi_os_printf ("Bad argument: Threads %X, Loops %X\n", num_threads, num_loops);
return;
}
/* Create the synchronization semaphore */
status = acpi_os_create_semaphore (1, 0, &thread_gate);
if (ACPI_FAILURE (status)) {
acpi_os_printf ("Could not create semaphore, %s\n", acpi_format_exception (status));
return;
}
/* Setup the context to be passed to each thread */
acpi_gbl_db_method_info.name = method_name_arg;
acpi_gbl_db_method_info.args = NULL;
acpi_gbl_db_method_info.flags = 0;
acpi_gbl_db_method_info.num_loops = num_loops;
acpi_gbl_db_method_info.thread_gate = thread_gate;
acpi_db_execute_setup (&acpi_gbl_db_method_info);
/* Create the threads */
acpi_os_printf ("Creating %X threads to execute %X times each\n", num_threads, num_loops);
for (i = 0; i < (num_threads); i++) {
status = acpi_os_queue_for_execution (OSD_PRIORITY_MED, acpi_db_method_thread, &acpi_gbl_db_method_info);
if (ACPI_FAILURE (status)) {
break;
}
}
/* Wait for all threads to complete */
i = num_threads;
while (i) /* Brain damage for OSD implementations that only support wait of 1 unit */ {
status = acpi_os_wait_semaphore (thread_gate, 1, WAIT_FOREVER);
i--;
}
/* Cleanup and exit */
(void) acpi_os_delete_semaphore (thread_gate);
acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT);
acpi_os_printf ("All threads (%X) have completed\n", num_threads);
acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
}
#endif /* ACPI_DEBUGGER */
/*******************************************************************************
*
* Module Name: dbfileio - Debugger file I/O commands. These can't usually
* be used when running the debugger in Ring 0 (Kernel mode)
* $Revision: 68 $
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2002, 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 "acdebug.h"
#include "acnamesp.h"
#include "actables.h"
#if (defined ACPI_DEBUGGER || defined ACPI_DISASSEMBLER)
#define _COMPONENT ACPI_CA_DEBUGGER
ACPI_MODULE_NAME ("dbfileio")
/*
* NOTE: this is here for lack of a better place. It is used in all
* flavors of the debugger, need LCD file
*/
#ifdef ACPI_APPLICATION
#include <stdio.h>
FILE *acpi_gbl_debug_file = NULL;
#endif
acpi_table_header *acpi_gbl_db_table_ptr = NULL;
/*******************************************************************************
*
* FUNCTION: Acpi_db_match_argument
*
* PARAMETERS: User_argument - User command line
* Arguments - Array of commands to match against
*
* RETURN: Index into command array or ACPI_TYPE_NOT_FOUND if not found
*
* DESCRIPTION: Search command array for a command match
*
******************************************************************************/
acpi_object_type
acpi_db_match_argument (
NATIVE_CHAR *user_argument,
ARGUMENT_INFO *arguments)
{
u32 i;
if (!user_argument || user_argument[0] == 0) {
return (ACPI_TYPE_NOT_FOUND);
}
for (i = 0; arguments[i].name; i++) {
if (ACPI_STRSTR (arguments[i].name, user_argument) == arguments[i].name) {
return (i);
}
}
/* Argument not recognized */
return (ACPI_TYPE_NOT_FOUND);
}
#ifdef ACPI_DEBUGGER
/*******************************************************************************
*
* FUNCTION: Acpi_db_close_debug_file
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: If open, close the current debug output file
*
******************************************************************************/
void
acpi_db_close_debug_file (
void)
{
#ifdef ACPI_APPLICATION
if (acpi_gbl_debug_file) {
fclose (acpi_gbl_debug_file);
acpi_gbl_debug_file = NULL;
acpi_gbl_db_output_to_file = FALSE;
acpi_os_printf ("Debug output file %s closed\n", acpi_gbl_db_debug_filename);
}
#endif
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_open_debug_file
*
* PARAMETERS: Name - Filename to open
*
* RETURN: Status
*
* DESCRIPTION: Open a file where debug output will be directed.
*
******************************************************************************/
void
acpi_db_open_debug_file (
NATIVE_CHAR *name)
{
#ifdef ACPI_APPLICATION
acpi_db_close_debug_file ();
acpi_gbl_debug_file = fopen (name, "w+");
if (acpi_gbl_debug_file) {
acpi_os_printf ("Debug output file %s opened\n", name);
ACPI_STRCPY (acpi_gbl_db_debug_filename, name);
acpi_gbl_db_output_to_file = TRUE;
}
else {
acpi_os_printf ("Could not open debug file %s\n", name);
}
#endif
}
#endif
#ifdef ACPI_APPLICATION
/*******************************************************************************
*
* FUNCTION: Acpi_db_load_table
*
* PARAMETERS: fp - File that contains table
* Table_ptr - Return value, buffer with table
* Table_lenght - Return value, length of table
*
* RETURN: Status
*
* DESCRIPTION: Load the DSDT from the file pointer
*
******************************************************************************/
static acpi_status
acpi_db_load_table(
FILE *fp,
acpi_table_header **table_ptr,
u32 *table_length)
{
acpi_table_header table_header;
u8 *aml_start;
u32 aml_length;
u32 actual;
acpi_status status;
/* Read the table header */
if (fread (&table_header, 1, sizeof (table_header), fp) != sizeof (acpi_table_header)) {
acpi_os_printf ("Couldn't read the table header\n");
return (AE_BAD_SIGNATURE);
}
/* Validate the table header/length */
status = acpi_tb_validate_table_header (&table_header);
if ((ACPI_FAILURE (status)) ||
(table_header.length > 0x800000)) /* 8 Mbyte should be enough */ {
acpi_os_printf ("Table header is invalid!\n");
return (AE_ERROR);
}
/* We only support a limited number of table types */
if (ACPI_STRNCMP ((char *) table_header.signature, DSDT_SIG, 4) &&
ACPI_STRNCMP ((char *) table_header.signature, PSDT_SIG, 4) &&
ACPI_STRNCMP ((char *) table_header.signature, SSDT_SIG, 4)) {
acpi_os_printf ("Table signature is invalid\n");
ACPI_DUMP_BUFFER (&table_header, sizeof (acpi_table_header));
return (AE_ERROR);
}
/* Allocate a buffer for the table */
*table_length = table_header.length;
*table_ptr = acpi_os_allocate ((size_t) *table_length);
if (!*table_ptr) {
acpi_os_printf ("Could not allocate memory for ACPI table %4.4s (size=%X)\n",
table_header.signature, table_header.length);
return (AE_NO_MEMORY);
}
aml_start = (u8 *) *table_ptr + sizeof (table_header);
aml_length = *table_length - sizeof (table_header);
/* Copy the header to the buffer */
ACPI_MEMCPY (*table_ptr, &table_header, sizeof (table_header));
/* Get the rest of the table */
actual = fread (aml_start, 1, (size_t) aml_length, fp);
if (actual == aml_length) {
return (AE_OK);
}
if (actual > 0) {
acpi_os_printf ("Warning - reading table, asked for %X got %X\n", aml_length, actual);
return (AE_OK);
}
acpi_os_printf ("Error - could not read the table file\n");
acpi_os_free (*table_ptr);
*table_ptr = NULL;
*table_length = 0;
return (AE_ERROR);
}
#endif
/*******************************************************************************
*
* FUNCTION: Ae_local_load_table
*
* PARAMETERS: Table_ptr - pointer to a buffer containing the entire
* table to be loaded
*
* RETURN: Status
*
* DESCRIPTION: This function is called to load a table from the caller's
* buffer. The buffer must contain an entire ACPI Table including
* a valid header. The header fields will be verified, and if it
* is determined that the table is invalid, the call will fail.
*
* If the call fails an appropriate status will be returned.
*
******************************************************************************/
acpi_status
ae_local_load_table (
acpi_table_header *table_ptr)
{
acpi_status status;
acpi_table_desc table_info;
ACPI_FUNCTION_TRACE ("Ae_local_load_table");
if (!table_ptr) {
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
table_info.pointer = table_ptr;
status = acpi_tb_recognize_table (&table_info, ACPI_TABLE_SECONDARY);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
/* Install the new table into the local data structures */
status = acpi_tb_install_table (&table_info);
if (ACPI_FAILURE (status)) {
/* Free table allocated by Acpi_tb_get_table */
acpi_tb_delete_single_table (&table_info);
return_ACPI_STATUS (status);
}
#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
status = acpi_ns_load_table (table_info.installed_desc, acpi_gbl_root_node);
if (ACPI_FAILURE (status)) {
/* Uninstall table and free the buffer */
acpi_tb_delete_acpi_table (ACPI_TABLE_DSDT);
return_ACPI_STATUS (status);
}
#endif
return_ACPI_STATUS (status);
}
#ifdef ACPI_APPLICATION
acpi_status
acpi_db_get_acpi_table (
NATIVE_CHAR *filename)
{
FILE *fp;
u32 table_length;
acpi_status status;
/* Open the file */
fp = fopen (filename, "rb");
if (!fp) {
acpi_os_printf ("Could not open file %s\n", filename);
return (AE_ERROR);
}
/* Get the entire file */
fprintf (stderr, "Loading Acpi table from file %s\n", filename);
status = acpi_db_load_table (fp, &acpi_gbl_db_table_ptr, &table_length);
fclose(fp);
if (ACPI_FAILURE (status)) {
acpi_os_printf ("Couldn't get table from the file\n");
return (status);
}
return (AE_OK);
}
#endif
/*******************************************************************************
*
* FUNCTION: Acpi_db_load_acpi_table
*
* PARAMETERS: Filname - File where table is located
*
* RETURN: Status
*
* DESCRIPTION: Load an ACPI table from a file
*
******************************************************************************/
acpi_status
acpi_db_load_acpi_table (
NATIVE_CHAR *filename) {
#ifdef ACPI_APPLICATION
acpi_status status;
status = acpi_db_get_acpi_table (filename);
if (ACPI_FAILURE (status)) {
return (status);
}
/* Attempt to recognize and install the table */
status = ae_local_load_table (acpi_gbl_db_table_ptr);
if (ACPI_FAILURE (status)) {
if (status == AE_ALREADY_EXISTS) {
acpi_os_printf ("Table %4.4s is already installed\n",
acpi_gbl_db_table_ptr->signature);
}
else {
acpi_os_printf ("Could not install table, %s\n",
acpi_format_exception (status));
}
return (status);
}
fprintf (stderr, "Acpi table [%4.4s] successfully installed and loaded\n",
acpi_gbl_db_table_ptr->signature);
acpi_gbl_acpi_hardware_present = FALSE;
#endif /* ACPI_APPLICATION */
return (AE_OK);
}
#endif /* ACPI_DEBUGGER */
/******************************************************************************
*
* Module Name: dbhistry - debugger HISTORY command
* $Revision: 25 $
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2002, 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 "acdebug.h"
#ifdef ACPI_DEBUGGER
#define _COMPONENT ACPI_CA_DEBUGGER
ACPI_MODULE_NAME ("dbhistry")
#define HI_NO_HISTORY 0
#define HI_RECORD_HISTORY 1
#define HISTORY_SIZE 20
typedef struct history_info
{
NATIVE_CHAR command[80];
u32 cmd_num;
} HISTORY_INFO;
static HISTORY_INFO acpi_gbl_history_buffer[HISTORY_SIZE];
static u16 acpi_gbl_lo_history = 0;
static u16 acpi_gbl_num_history = 0;
static u16 acpi_gbl_next_history_index = 0;
static u32 acpi_gbl_next_cmd_num = 1;
/*******************************************************************************
*
* FUNCTION: Acpi_db_add_to_history
*
* PARAMETERS: Command_line - Command to add
*
* RETURN: None
*
* DESCRIPTION: Add a command line to the history buffer.
*
******************************************************************************/
void
acpi_db_add_to_history (
NATIVE_CHAR *command_line)
{
/* Put command into the next available slot */
ACPI_STRCPY (acpi_gbl_history_buffer[acpi_gbl_next_history_index].command, command_line);
acpi_gbl_history_buffer[acpi_gbl_next_history_index].cmd_num = acpi_gbl_next_cmd_num;
/* Adjust indexes */
if ((acpi_gbl_num_history == HISTORY_SIZE) &&
(acpi_gbl_next_history_index == acpi_gbl_lo_history)) {
acpi_gbl_lo_history++;
if (acpi_gbl_lo_history >= HISTORY_SIZE) {
acpi_gbl_lo_history = 0;
}
}
acpi_gbl_next_history_index++;
if (acpi_gbl_next_history_index >= HISTORY_SIZE) {
acpi_gbl_next_history_index = 0;
}
acpi_gbl_next_cmd_num++;
if (acpi_gbl_num_history < HISTORY_SIZE) {
acpi_gbl_num_history++;
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_display_history
*
* PARAMETERS: None
*
* RETURN: None
*
* DESCRIPTION: Display the contents of the history buffer
*
******************************************************************************/
void
acpi_db_display_history (void)
{
NATIVE_UINT i;
u16 history_index;
history_index = acpi_gbl_lo_history;
/* Dump entire history buffer */
for (i = 0; i < acpi_gbl_num_history; i++) {
acpi_os_printf ("%ld %s\n", acpi_gbl_history_buffer[history_index].cmd_num,
acpi_gbl_history_buffer[history_index].command);
history_index++;
if (history_index >= HISTORY_SIZE) {
history_index = 0;
}
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_get_from_history
*
* PARAMETERS: Command_num_arg - String containing the number of the
* command to be retrieved
*
* RETURN: None
*
* DESCRIPTION: Get a command from the history buffer
*
******************************************************************************/
NATIVE_CHAR *
acpi_db_get_from_history (
NATIVE_CHAR *command_num_arg)
{
NATIVE_UINT i;
u16 history_index;
u32 cmd_num;
if (command_num_arg == NULL) {
cmd_num = acpi_gbl_next_cmd_num - 1;
}
else {
cmd_num = ACPI_STRTOUL (command_num_arg, NULL, 0);
}
/* Search history buffer */
history_index = acpi_gbl_lo_history;
for (i = 0; i < acpi_gbl_num_history; i++) {
if (acpi_gbl_history_buffer[history_index].cmd_num == cmd_num) {
/* Found the commnad, return it */
return (acpi_gbl_history_buffer[history_index].command);
}
history_index++;
if (history_index >= HISTORY_SIZE) {
history_index = 0;
}
}
acpi_os_printf ("Invalid history number: %d\n", history_index);
return (NULL);
}
#endif /* ACPI_DEBUGGER */
/*******************************************************************************
*
* Module Name: dbinput - user front-end to the AML debugger
* $Revision: 87 $
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2002, 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 "acdebug.h"
#ifdef ACPI_DEBUGGER
#define _COMPONENT ACPI_CA_DEBUGGER
ACPI_MODULE_NAME ("dbinput")
/*
* Top-level debugger commands.
*
* This list of commands must match the string table below it
*/
enum acpi_ex_debugger_commands
{
CMD_NOT_FOUND = 0,
CMD_NULL,
CMD_ALLOCATIONS,
CMD_ARGS,
CMD_ARGUMENTS,
CMD_BREAKPOINT,
CMD_CALL,
CMD_CLOSE,
CMD_DEBUG,
CMD_DUMP,
CMD_ENABLEACPI,
CMD_EVENT,
CMD_EXECUTE,
CMD_EXIT,
CMD_FIND,
CMD_GO,
CMD_HELP,
CMD_HELP2,
CMD_HISTORY,
CMD_HISTORY_EXE,
CMD_HISTORY_LAST,
CMD_INFORMATION,
CMD_INTEGRITY,
CMD_INTO,
CMD_LEVEL,
CMD_LIST,
CMD_LOAD,
CMD_LOCALS,
CMD_LOCKS,
CMD_METHODS,
CMD_NAMESPACE,
CMD_NOTIFY,
CMD_OBJECT,
CMD_OPEN,
CMD_OWNER,
CMD_PREFIX,
CMD_QUIT,
CMD_REFERENCES,
CMD_RESOURCES,
CMD_RESULTS,
CMD_SET,
CMD_STATS,
CMD_STOP,
CMD_TABLES,
CMD_TERMINATE,
CMD_THREADS,
CMD_TREE,
CMD_UNLOAD
};
#define CMD_FIRST_VALID 2
static const COMMAND_INFO acpi_gbl_db_commands[] =
{ {"<NOT FOUND>", 0},
{"<NULL>", 0},
{"ALLOCATIONS", 0},
{"ARGS", 0},
{"ARGUMENTS", 0},
{"BREAKPOINT", 1},
{"CALL", 0},
{"CLOSE", 0},
{"DEBUG", 1},
{"DUMP", 1},
{"ENABLEACPI", 0},
{"EVENT", 1},
{"EXECUTE", 1},
{"EXIT", 0},
{"FIND", 1},
{"GO", 0},
{"HELP", 0},
{"?", 0},
{"HISTORY", 0},
{"!", 1},
{"!!", 0},
{"INFORMATION", 0},
{"INTEGRITY", 0},
{"INTO", 0},
{"LEVEL", 0},
{"LIST", 0},
{"LOAD", 1},
{"LOCALS", 0},
{"LOCKS", 0},
{"METHODS", 0},
{"NAMESPACE", 0},
{"NOTIFY", 2},
{"OBJECT", 1},
{"OPEN", 1},
{"OWNER", 1},
{"PREFIX", 0},
{"QUIT", 0},
{"REFERENCES", 1},
{"RESOURCES", 1},
{"RESULTS", 0},
{"SET", 3},
{"STATS", 0},
{"STOP", 0},
{"TABLES", 0},
{"TERMINATE", 0},
{"THREADS", 3},
{"TREE", 0},
{"UNLOAD", 1},
{NULL, 0}
};
/*******************************************************************************
*
* FUNCTION: Acpi_db_display_help
*
* PARAMETERS: Help_type - Subcommand (optional)
*
* RETURN: None
*
* DESCRIPTION: Print a usage message.
*
******************************************************************************/
void
acpi_db_display_help (
NATIVE_CHAR *help_type)
{
/* No parameter, just give the overview */
if (!help_type)
{
acpi_os_printf ("ACPI CA Debugger Commands\n\n");
acpi_os_printf ("The following classes of commands are available. Help is available for\n");
acpi_os_printf ("each class by entering \"Help <Class_name>\"\n\n");
acpi_os_printf (" [GENERAL] General-Purpose Commands\n");
acpi_os_printf (" [NAMESPACE] Namespace Access Commands\n");
acpi_os_printf (" [METHOD] Control Method Execution Commands\n");
acpi_os_printf (" [FILE] File I/O Commands\n");
return;
}
/*
* Parameter is the command class
*
* The idea here is to keep each class of commands smaller than a screenful
*/
switch (help_type[0])
{
case 'G':
acpi_os_printf ("\nGeneral-Purpose Commands\n\n");
acpi_os_printf ("Allocations Display list of current memory allocations\n");
acpi_os_printf ("Dump <Address>|<Namepath>\n");
acpi_os_printf (" [Byte|Word|Dword|Qword] Display ACPI objects or memory\n");
acpi_os_printf ("Enable_acpi Enable ACPI (hardware) mode\n");
acpi_os_printf ("Help This help screen\n");
acpi_os_printf ("History Display command history buffer\n");
acpi_os_printf ("Level [<Debug_level>] [console] Get/Set debug level for file or console\n");
acpi_os_printf ("Locks Current status of internal mutexes\n");
acpi_os_printf ("Quit or Exit Exit this command\n");
acpi_os_printf ("Stats [Allocations|Memory|Misc\n");
acpi_os_printf (" |Objects|Tables] Display namespace and memory statistics\n");
acpi_os_printf ("Tables Display info about loaded ACPI tables\n");
acpi_os_printf ("Unload <Table_sig> [Instance] Unload an ACPI table\n");
acpi_os_printf ("! <Command_number> Execute command from history buffer\n");
acpi_os_printf ("!! Execute last command again\n");
return;
case 'N':
acpi_os_printf ("\nNamespace Access Commands\n\n");
acpi_os_printf ("Debug <Namepath> [Arguments] Single Step a control method\n");
acpi_os_printf ("Event <F|G> <Value> Generate Acpi_event (Fixed/GPE)\n");
acpi_os_printf ("Execute <Namepath> [Arguments] Execute control method\n");
acpi_os_printf ("Find <Name> (? is wildcard) Find ACPI name(s) with wildcards\n");
acpi_os_printf ("Method Display list of loaded control methods\n");
acpi_os_printf ("Namespace [<Addr>|<Path>] [Depth] Display loaded namespace tree/subtree\n");
acpi_os_printf ("Notify <Name_path> <Value> Send a notification\n");
acpi_os_printf ("Objects <Object_type> Display all objects of the given type\n");
acpi_os_printf ("Owner <Owner_id> [Depth] Display loaded namespace by object owner\n");
acpi_os_printf ("Prefix [<Name_path>] Set or Get current execution prefix\n");
acpi_os_printf ("References <Addr> Find all references to object at addr\n");
acpi_os_printf ("Resources xxx Get and display resources\n");
acpi_os_printf ("Terminate Delete namespace and all internal objects\n");
acpi_os_printf ("Thread <Threads><Loops><Name_path> Spawn threads to execute method(s)\n");
return;
case 'M':
acpi_os_printf ("\nControl Method Execution Commands\n\n");
acpi_os_printf ("Arguments (or Args) Display method arguments\n");
acpi_os_printf ("Breakpoint <Aml_offset> Set an AML execution breakpoint\n");
acpi_os_printf ("Call Run to next control method invocation\n");
acpi_os_printf ("Go Allow method to run to completion\n");
acpi_os_printf ("Information Display info about the current method\n");
acpi_os_printf ("Into Step into (not over) a method call\n");
acpi_os_printf ("List [# of Aml Opcodes] Display method ASL statements\n");
acpi_os_printf ("Locals Display method local variables\n");
acpi_os_printf ("Results Display method result stack\n");
acpi_os_printf ("Set <A|L> <#> <Value> Set method data (Arguments/Locals)\n");
acpi_os_printf ("Stop Terminate control method\n");
acpi_os_printf ("Tree Display control method calling tree\n");
acpi_os_printf ("<Enter> Single step next AML opcode (over calls)\n");
return;
case 'F':
acpi_os_printf ("\nFile I/O Commands\n\n");
acpi_os_printf ("Close Close debug output file\n");
acpi_os_printf ("Open <Output Filename> Open a file for debug output\n");
acpi_os_printf ("Load <Input Filename> Load ACPI table from a file\n");
return;
default:
acpi_os_printf ("Unrecognized Command Class: %X\n", help_type);
return;
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_get_next_token
*
* PARAMETERS: String - Command buffer
* Next - Return value, end of next token
*
* RETURN: Pointer to the start of the next token.
*
* DESCRIPTION: Command line parsing. Get the next token on the command line
*
******************************************************************************/
NATIVE_CHAR *
acpi_db_get_next_token (
NATIVE_CHAR *string,
NATIVE_CHAR **next)
{
NATIVE_CHAR *start;
/* At end of buffer? */
if (!string || !(*string))
{
return (NULL);
}
/* Get rid of any spaces at the beginning */
if (*string == ' ')
{
while (*string && (*string == ' '))
{
string++;
}
if (!(*string))
{
return (NULL);
}
}
start = string;
/* Find end of token */
while (*string && (*string != ' '))
{
string++;
}
if (!(*string))
{
*next = NULL;
}
else
{
*string = 0;
*next = string + 1;
}
return (start);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_get_line
*
* PARAMETERS: Input_buffer - Command line buffer
*
* RETURN: None
*
* DESCRIPTION: Get the next command line from the user. Gets entire line
* up to the next newline
*
******************************************************************************/
u32
acpi_db_get_line (
NATIVE_CHAR *input_buffer)
{
u32 i;
u32 count;
NATIVE_CHAR *next;
NATIVE_CHAR *this;
ACPI_STRCPY (acpi_gbl_db_parsed_buf, input_buffer);
ACPI_STRUPR (acpi_gbl_db_parsed_buf);
this = acpi_gbl_db_parsed_buf;
for (i = 0; i < ACPI_DEBUGGER_MAX_ARGS; i++)
{
acpi_gbl_db_args[i] = acpi_db_get_next_token (this, &next);
if (!acpi_gbl_db_args[i])
{
break;
}
this = next;
}
/* Uppercase the actual command */
if (acpi_gbl_db_args[0])
{
ACPI_STRUPR (acpi_gbl_db_args[0]);
}
count = i;
if (count)
{
count--; /* Number of args only */
}
return (count);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_match_command
*
* PARAMETERS: User_command - User command line
*
* RETURN: Index into command array, -1 if not found
*
* DESCRIPTION: Search command array for a command match
*
******************************************************************************/
u32
acpi_db_match_command (
NATIVE_CHAR *user_command)
{
u32 i;
if (!user_command || user_command[0] == 0)
{
return (CMD_NULL);
}
for (i = CMD_FIRST_VALID; acpi_gbl_db_commands[i].name; i++)
{
if (ACPI_STRSTR (acpi_gbl_db_commands[i].name, user_command) ==
acpi_gbl_db_commands[i].name)
{
return (i);
}
}
/* Command not recognized */
return (CMD_NOT_FOUND);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_command_dispatch
*
* PARAMETERS: Input_buffer - Command line buffer
* Walk_state - Current walk
* Op - Current (executing) parse op
*
* RETURN: Status
*
* DESCRIPTION: Command dispatcher. Called from two places:
*
******************************************************************************/
acpi_status
acpi_db_command_dispatch (
NATIVE_CHAR *input_buffer,
acpi_walk_state *walk_state,
acpi_parse_object *op)
{
u32 temp;
u32 command_index;
u32 param_count;
NATIVE_CHAR *command_line;
acpi_status status = AE_CTRL_TRUE;
/* If Acpi_terminate has been called, terminate this thread */
if (acpi_gbl_db_terminate_threads)
{
return (AE_CTRL_TERMINATE);
}
param_count = acpi_db_get_line (input_buffer);
command_index = acpi_db_match_command (acpi_gbl_db_args[0]);
temp = 0;
/* Verify that we have the minimum number of params */
if (param_count < acpi_gbl_db_commands[command_index].min_args)
{
acpi_os_printf ("%d parameters entered, [%s] requires %d parameters\n",
param_count, acpi_gbl_db_commands[command_index].name, acpi_gbl_db_commands[command_index].min_args);
return (AE_CTRL_TRUE);
}
/* Decode and dispatch the command */
switch (command_index)
{
case CMD_NULL:
if (op)
{
return (AE_OK);
}
break;
case CMD_ALLOCATIONS:
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
acpi_ut_dump_allocations ((u32) -1, NULL);
#endif
break;
case CMD_ARGS:
case CMD_ARGUMENTS:
acpi_db_display_arguments ();
break;
case CMD_BREAKPOINT:
acpi_db_set_method_breakpoint (acpi_gbl_db_args[1], walk_state, op);
break;
case CMD_CALL:
acpi_db_set_method_call_breakpoint (op);
status = AE_OK;
break;
case CMD_CLOSE:
acpi_db_close_debug_file ();
break;
case CMD_DEBUG:
acpi_db_execute (acpi_gbl_db_args[1], &acpi_gbl_db_args[2], EX_SINGLE_STEP);
break;
case CMD_DUMP:
acpi_db_decode_and_display_object (acpi_gbl_db_args[1], acpi_gbl_db_args[2]);
break;
case CMD_ENABLEACPI:
status = acpi_enable();
if (ACPI_FAILURE(status))
{
acpi_os_printf("Acpi_enable failed (Status=%X)\n", status);
return (status);
}
break;
case CMD_EVENT:
acpi_os_printf ("Event command not implemented\n");
break;
case CMD_EXECUTE:
acpi_db_execute (acpi_gbl_db_args[1], &acpi_gbl_db_args[2], EX_NO_SINGLE_STEP);
break;
case CMD_FIND:
status = acpi_db_find_name_in_namespace (acpi_gbl_db_args[1]);
break;
case CMD_GO:
acpi_gbl_cm_single_step = FALSE;
return (AE_OK);
case CMD_HELP:
case CMD_HELP2:
acpi_db_display_help (acpi_gbl_db_args[1]);
break;
case CMD_HISTORY:
acpi_db_display_history ();
break;
case CMD_HISTORY_EXE:
command_line = acpi_db_get_from_history (acpi_gbl_db_args[1]);
if (!command_line)
{
return (AE_CTRL_TRUE);
}
status = acpi_db_command_dispatch (command_line, walk_state, op);
if (ACPI_SUCCESS (status))
{
status = AE_CTRL_TRUE;
}
return (status);
case CMD_HISTORY_LAST:
command_line = acpi_db_get_from_history (NULL);
if (!command_line)
{
return (AE_CTRL_TRUE);
}
status = acpi_db_command_dispatch (command_line, walk_state, op);
if (ACPI_SUCCESS (status))
{
status = AE_CTRL_TRUE;
}
return (status);
case CMD_INFORMATION:
acpi_db_display_method_info (op);
break;
case CMD_INTEGRITY:
acpi_db_check_integrity ();
break;
case CMD_INTO:
if (op)
{
acpi_gbl_cm_single_step = TRUE;
return (AE_OK);
}
break;
case CMD_LEVEL:
if (param_count == 0)
{
acpi_os_printf ("Current debug level for file output is: %8.8lX\n", acpi_gbl_db_debug_level);
acpi_os_printf ("Current debug level for console output is: %8.8lX\n", acpi_gbl_db_console_debug_level);
}
else if (param_count == 2)
{
temp = acpi_gbl_db_console_debug_level;
acpi_gbl_db_console_debug_level = ACPI_STRTOUL (acpi_gbl_db_args[1], NULL, 16);
acpi_os_printf ("Debug Level for console output was %8.8lX, now %8.8lX\n", temp, acpi_gbl_db_console_debug_level);
}
else
{
temp = acpi_gbl_db_debug_level;
acpi_gbl_db_debug_level = ACPI_STRTOUL (acpi_gbl_db_args[1], NULL, 16);
acpi_os_printf ("Debug Level for file output was %8.8lX, now %8.8lX\n", temp, acpi_gbl_db_debug_level);
}
break;
case CMD_LIST:
acpi_db_disassemble_aml (acpi_gbl_db_args[1], op);
break;
case CMD_LOAD:
status = acpi_db_load_acpi_table (acpi_gbl_db_args[1]);
if (ACPI_FAILURE (status))
{
return (status);
}
break;
case CMD_LOCKS:
acpi_db_display_locks ();
break;
case CMD_LOCALS:
acpi_db_display_locals ();
break;
case CMD_METHODS:
status = acpi_db_display_objects ("METHOD", acpi_gbl_db_args[1]);
break;
case CMD_NAMESPACE:
acpi_db_dump_namespace (acpi_gbl_db_args[1], acpi_gbl_db_args[2]);
break;
case CMD_NOTIFY:
temp = ACPI_STRTOUL (acpi_gbl_db_args[2], NULL, 0);
acpi_db_send_notify (acpi_gbl_db_args[1], temp);
break;
case CMD_OBJECT:
ACPI_STRUPR (acpi_gbl_db_args[1]);
status = acpi_db_display_objects (acpi_gbl_db_args[1], acpi_gbl_db_args[2]);
break;
case CMD_OPEN:
acpi_db_open_debug_file (acpi_gbl_db_args[1]);
break;
case CMD_OWNER:
acpi_db_dump_namespace_by_owner (acpi_gbl_db_args[1], acpi_gbl_db_args[2]);
break;
case CMD_PREFIX:
acpi_db_set_scope (acpi_gbl_db_args[1]);
break;
case CMD_REFERENCES:
acpi_db_find_references (acpi_gbl_db_args[1]);
break;
case CMD_RESOURCES:
acpi_db_display_resources (acpi_gbl_db_args[1]);
break;
case CMD_RESULTS:
acpi_db_display_results ();
break;
case CMD_SET:
acpi_db_set_method_data (acpi_gbl_db_args[1], acpi_gbl_db_args[2], acpi_gbl_db_args[3]);
break;
case CMD_STATS:
status = acpi_db_display_statistics (acpi_gbl_db_args[1]);
break;
case CMD_STOP:
return (AE_NOT_IMPLEMENTED);
case CMD_TABLES:
acpi_db_display_table_info (acpi_gbl_db_args[1]);
break;
case CMD_TERMINATE:
acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT);
acpi_ut_subsystem_shutdown ();
/* TBD: [Restructure] Need some way to re-initialize without re-creating the semaphores! */
/* Acpi_initialize (NULL); */
break;
case CMD_THREADS:
acpi_db_create_execution_threads (acpi_gbl_db_args[1], acpi_gbl_db_args[2], acpi_gbl_db_args[3]);
break;
case CMD_TREE:
acpi_db_display_calling_tree ();
break;
case CMD_UNLOAD:
acpi_db_unload_acpi_table (acpi_gbl_db_args[1], acpi_gbl_db_args[2]);
break;
case CMD_EXIT:
case CMD_QUIT:
if (op)
{
acpi_os_printf ("Method execution terminated\n");
return (AE_CTRL_TERMINATE);
}
if (!acpi_gbl_db_output_to_file)
{
acpi_dbg_level = DEBUG_DEFAULT;
}
/* Shutdown */
/* Acpi_ut_subsystem_shutdown (); */
acpi_db_close_debug_file ();
acpi_gbl_db_terminate_threads = TRUE;
return (AE_CTRL_TERMINATE);
case CMD_NOT_FOUND:
default:
acpi_os_printf ("Unknown Command\n");
return (AE_CTRL_TRUE);
}
/* Add all commands that come here to the history buffer */
acpi_db_add_to_history (input_buffer);
return (status);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_execute_thread
*
* PARAMETERS: Context - Not used
*
* RETURN: None
*
* DESCRIPTION: Debugger execute thread. Waits for a command line, then
* simply dispatches it.
*
******************************************************************************/
void ACPI_SYSTEM_XFACE
acpi_db_execute_thread (
void *context)
{
acpi_status status = AE_OK;
acpi_status Mstatus;
while (status != AE_CTRL_TERMINATE)
{
acpi_gbl_method_executing = FALSE;
acpi_gbl_step_to_next_call = FALSE;
Mstatus = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_READY);
if (ACPI_FAILURE (Mstatus))
{
return;
}
status = acpi_db_command_dispatch (acpi_gbl_db_line_buf, NULL, NULL);
Mstatus = acpi_ut_release_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE);
if (ACPI_FAILURE (Mstatus))
{
return;
}
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_single_thread
*
* PARAMETERS: None
*
* RETURN: None
*
* DESCRIPTION: Debugger execute thread. Waits for a command line, then
* simply dispatches it.
*
******************************************************************************/
void
acpi_db_single_thread (
void)
{
acpi_gbl_method_executing = FALSE;
acpi_gbl_step_to_next_call = FALSE;
(void) acpi_db_command_dispatch (acpi_gbl_db_line_buf, NULL, NULL);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_user_commands
*
* PARAMETERS: Prompt - User prompt (depends on mode)
* Op - Current executing parse op
*
* RETURN: None
*
* DESCRIPTION: Command line execution for the AML debugger. Commands are
* matched and dispatched here.
*
******************************************************************************/
acpi_status
acpi_db_user_commands (
NATIVE_CHAR prompt,
acpi_parse_object *op)
{
acpi_status status = AE_OK;
/* TBD: [Restructure] Need a separate command line buffer for step mode */
while (!acpi_gbl_db_terminate_threads)
{
/* Force output to console until a command is entered */
acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
/* Different prompt if method is executing */
if (!acpi_gbl_method_executing)
{
acpi_os_printf ("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
}
else
{
acpi_os_printf ("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
}
/* Get the user input line */
(void) acpi_os_get_line (acpi_gbl_db_line_buf);
/* Check for single or multithreaded debug */
if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED)
{
/*
* Signal the debug thread that we have a command to execute,
* and wait for the command to complete.
*/
status = acpi_ut_release_mutex (ACPI_MTX_DEBUG_CMD_READY);
if (ACPI_FAILURE (status))
{
return (status);
}
status = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE);
if (ACPI_FAILURE (status))
{
return (status);
}
}
else
{
/* Just call to the command line interpreter */
acpi_db_single_thread ();
}
}
/*
* Only this thread (the original thread) should actually terminate the subsystem,
* because all the semaphores are deleted during termination
*/
status = acpi_terminate ();
return (status);
}
#endif /* ACPI_DEBUGGER */
/*******************************************************************************
*
* Module Name: dbstats - Generation and display of ACPI table statistics
* $Revision: 61 $
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2002, 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 <acdebug.h>
#include <acnamesp.h>
#ifdef ACPI_DEBUGGER
#define _COMPONENT ACPI_CA_DEBUGGER
ACPI_MODULE_NAME ("dbstats")
/*
* Statistics subcommands
*/
static ARGUMENT_INFO acpi_db_stat_types [] =
{ {"ALLOCATIONS"},
{"OBJECTS"},
{"MEMORY"},
{"MISC"},
{"TABLES"},
{"SIZES"},
{"STACK"},
{NULL} /* Must be null terminated */
};
#define CMD_STAT_ALLOCATIONS 0
#define CMD_STAT_OBJECTS 1
#define CMD_STAT_MEMORY 2
#define CMD_STAT_MISC 3
#define CMD_STAT_TABLES 4
#define CMD_STAT_SIZES 5
#define CMD_STAT_STACK 6
/*******************************************************************************
*
* FUNCTION: Acpi_db_enumerate_object
*
* PARAMETERS: Obj_desc - Object to be counted
*
* RETURN: None
*
* DESCRIPTION: Add this object to the global counts, by object type.
* Limited recursion handles subobjects and packages, and this
* is probably acceptable within the AML debugger only.
*
******************************************************************************/
void
acpi_db_enumerate_object (
acpi_operand_object *obj_desc)
{
u32 i;
if (!obj_desc)
{
return;
}
/* Enumerate this object first */
acpi_gbl_num_objects++;
if (ACPI_GET_OBJECT_TYPE (obj_desc) > INTERNAL_TYPE_NODE_MAX)
{
acpi_gbl_obj_type_count_misc++;
}
else
{
acpi_gbl_obj_type_count [ACPI_GET_OBJECT_TYPE (obj_desc)]++;
}
/* Count the sub-objects */
switch (ACPI_GET_OBJECT_TYPE (obj_desc))
{
case ACPI_TYPE_PACKAGE:
for (i = 0; i < obj_desc->package.count; i++)
{
acpi_db_enumerate_object (obj_desc->package.elements[i]);
}
break;
case ACPI_TYPE_DEVICE:
acpi_db_enumerate_object (obj_desc->device.sys_handler);
acpi_db_enumerate_object (obj_desc->device.drv_handler);
acpi_db_enumerate_object (obj_desc->device.addr_handler);
break;
case ACPI_TYPE_BUFFER_FIELD:
if (acpi_ns_get_secondary_object (obj_desc))
{
acpi_gbl_obj_type_count [ACPI_TYPE_BUFFER_FIELD]++;
}
break;
case ACPI_TYPE_REGION:
acpi_gbl_obj_type_count [INTERNAL_TYPE_REGION_FIELD ]++;
acpi_db_enumerate_object (obj_desc->region.addr_handler);
break;
case ACPI_TYPE_POWER:
acpi_db_enumerate_object (obj_desc->power_resource.sys_handler);
acpi_db_enumerate_object (obj_desc->power_resource.drv_handler);
break;
case ACPI_TYPE_PROCESSOR:
acpi_db_enumerate_object (obj_desc->processor.sys_handler);
acpi_db_enumerate_object (obj_desc->processor.drv_handler);
acpi_db_enumerate_object (obj_desc->processor.addr_handler);
break;
case ACPI_TYPE_THERMAL:
acpi_db_enumerate_object (obj_desc->thermal_zone.sys_handler);
acpi_db_enumerate_object (obj_desc->thermal_zone.drv_handler);
acpi_db_enumerate_object (obj_desc->thermal_zone.addr_handler);
break;
default:
break;
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_classify_one_object
*
* PARAMETERS: Callback for Walk_namespace
*
* RETURN: Status
*
* DESCRIPTION: Enumerate both the object descriptor (including subobjects) and
* the parent namespace node.
*
******************************************************************************/
acpi_status
acpi_db_classify_one_object (
acpi_handle obj_handle,
u32 nesting_level,
void *context,
void **return_value)
{
acpi_namespace_node *node;
acpi_operand_object *obj_desc;
u32 type;
acpi_gbl_num_nodes++;
node = (acpi_namespace_node *) obj_handle;
obj_desc = acpi_ns_get_attached_object (node);
acpi_db_enumerate_object (obj_desc);
type = node->type;
if (type > INTERNAL_TYPE_NODE_MAX)
{
acpi_gbl_node_type_count_misc++;
}
else
{
acpi_gbl_node_type_count [type]++;
}
return AE_OK;
/* TBD: These need to be counted during the initial parsing phase */
/*
if (Acpi_ps_is_named_op (Op->Opcode))
{
Num_nodes++;
}
if (Is_method)
{
Num_method_elements++;
}
Num_grammar_elements++;
Op = Acpi_ps_get_depth_next (Root, Op);
Size_of_parse_tree = (Num_grammar_elements - Num_method_elements) * (u32) sizeof (acpi_parse_object);
Size_of_method_trees = Num_method_elements * (u32) sizeof (acpi_parse_object);
Size_of_node_entries = Num_nodes * (u32) sizeof (acpi_namespace_node);
Size_of_acpi_objects = Num_nodes * (u32) sizeof (acpi_operand_object);
*/
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_count_namespace_objects
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: Count and classify the entire namespace, including all
* namespace nodes and attached objects.
*
******************************************************************************/
void
acpi_db_count_namespace_objects (
void)
{
u32 i;
acpi_gbl_num_nodes = 0;
acpi_gbl_num_objects = 0;
acpi_gbl_obj_type_count_misc = 0;
for (i = 0; i < (INTERNAL_TYPE_NODE_MAX -1); i++)
{
acpi_gbl_obj_type_count [i] = 0;
acpi_gbl_node_type_count [i] = 0;
}
(void) acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
FALSE, acpi_db_classify_one_object, NULL, NULL);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_display_statistics
*
* PARAMETERS: Type_arg - Subcommand
*
* RETURN: Status
*
* DESCRIPTION: Display various statistics
*
******************************************************************************/
acpi_status
acpi_db_display_statistics (
NATIVE_CHAR *type_arg)
{
u32 i;
u32 type;
u32 size;
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
u32 outstanding;
#endif
if (!acpi_gbl_DSDT)
{
acpi_os_printf ("*** Warning: There is no DSDT loaded\n");
}
if (!type_arg)
{
acpi_os_printf ("The following subcommands are available:\n ALLOCATIONS, OBJECTS, MEMORY, MISC, SIZES, TABLES\n");
return (AE_OK);
}
ACPI_STRUPR (type_arg);
type = acpi_db_match_argument (type_arg, acpi_db_stat_types);
if (type == (u32) -1)
{
acpi_os_printf ("Invalid or unsupported argument\n");
return (AE_OK);
}
switch (type)
{
case CMD_STAT_ALLOCATIONS:
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
acpi_ut_dump_allocation_info ();
#endif
break;
case CMD_STAT_TABLES:
acpi_os_printf ("ACPI Table Information:\n\n");
if (acpi_gbl_DSDT)
{
acpi_os_printf ("DSDT Length:................% 7ld (%X)\n", acpi_gbl_DSDT->length, acpi_gbl_DSDT->length);
}
break;
case CMD_STAT_OBJECTS:
acpi_db_count_namespace_objects ();
acpi_os_printf ("\nObjects defined in the current namespace:\n\n");
acpi_os_printf ("%16.16s % 10.10s % 10.10s\n", "ACPI_TYPE", "NODES", "OBJECTS");
for (i = 0; i < INTERNAL_TYPE_NODE_MAX; i++)
{
acpi_os_printf ("%16.16s % 10ld% 10ld\n", acpi_ut_get_type_name (i),
acpi_gbl_node_type_count [i], acpi_gbl_obj_type_count [i]);
}
acpi_os_printf ("%16.16s % 10ld% 10ld\n", "Misc/Unknown",
acpi_gbl_node_type_count_misc, acpi_gbl_obj_type_count_misc);
acpi_os_printf ("%16.16s % 10ld% 10ld\n", "TOTALS:",
acpi_gbl_num_nodes, acpi_gbl_num_objects);
break;
case CMD_STAT_MEMORY:
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
acpi_os_printf ("\n----Object and Cache Statistics---------------------------------------------\n");
for (i = 0; i < ACPI_NUM_MEM_LISTS; i++)
{
acpi_os_printf ("\n%s\n", acpi_gbl_memory_lists[i].list_name);
if (acpi_gbl_memory_lists[i].max_cache_depth > 0)
{
acpi_os_printf (" Cache: [Depth Max Avail Size] % 7d % 7d % 7d % 7d B\n",
acpi_gbl_memory_lists[i].cache_depth,
acpi_gbl_memory_lists[i].max_cache_depth,
acpi_gbl_memory_lists[i].max_cache_depth - acpi_gbl_memory_lists[i].cache_depth,
(acpi_gbl_memory_lists[i].cache_depth * acpi_gbl_memory_lists[i].object_size));
acpi_os_printf (" Cache: [Requests Hits Misses Obj_size] % 7d % 7d % 7d % 7d B\n",
acpi_gbl_memory_lists[i].cache_requests,
acpi_gbl_memory_lists[i].cache_hits,
acpi_gbl_memory_lists[i].cache_requests - acpi_gbl_memory_lists[i].cache_hits,
acpi_gbl_memory_lists[i].object_size);
}
outstanding = acpi_gbl_memory_lists[i].total_allocated -
acpi_gbl_memory_lists[i].total_freed -
acpi_gbl_memory_lists[i].cache_depth;
if (acpi_gbl_memory_lists[i].object_size)
{
size = ACPI_ROUND_UP_TO_1K (outstanding * acpi_gbl_memory_lists[i].object_size);
}
else
{
size = ACPI_ROUND_UP_TO_1K (acpi_gbl_memory_lists[i].current_total_size);
}
acpi_os_printf (" Mem: [Alloc Free Outstanding Size] % 7d % 7d % 7d % 7d Kb\n",
acpi_gbl_memory_lists[i].total_allocated,
acpi_gbl_memory_lists[i].total_freed,
outstanding, size);
}
#endif
break;
case CMD_STAT_MISC:
acpi_os_printf ("\nMiscellaneous Statistics:\n\n");
acpi_os_printf ("Calls to Acpi_ps_find:.. ........% 7ld\n", acpi_gbl_ps_find_count);
acpi_os_printf ("Calls to Acpi_ns_lookup:..........% 7ld\n", acpi_gbl_ns_lookup_count);
acpi_os_printf ("\n");
acpi_os_printf ("Mutex usage:\n\n");
for (i = 0; i < NUM_MTX; i++)
{
acpi_os_printf ("%-28s: % 7ld\n", acpi_ut_get_mutex_name (i), acpi_gbl_acpi_mutex_info[i].use_count);
}
break;
case CMD_STAT_SIZES:
acpi_os_printf ("\nInternal object sizes:\n\n");
acpi_os_printf ("Common %3d\n", sizeof (ACPI_OBJECT_COMMON));
acpi_os_printf ("Number %3d\n", sizeof (ACPI_OBJECT_INTEGER));
acpi_os_printf ("String %3d\n", sizeof (ACPI_OBJECT_STRING));
acpi_os_printf ("Buffer %3d\n", sizeof (ACPI_OBJECT_BUFFER));
acpi_os_printf ("Package %3d\n", sizeof (ACPI_OBJECT_PACKAGE));
acpi_os_printf ("Buffer_field %3d\n", sizeof (ACPI_OBJECT_BUFFER_FIELD));
acpi_os_printf ("Device %3d\n", sizeof (ACPI_OBJECT_DEVICE));
acpi_os_printf ("Event %3d\n", sizeof (ACPI_OBJECT_EVENT));
acpi_os_printf ("Method %3d\n", sizeof (ACPI_OBJECT_METHOD));
acpi_os_printf ("Mutex %3d\n", sizeof (ACPI_OBJECT_MUTEX));
acpi_os_printf ("Region %3d\n", sizeof (ACPI_OBJECT_REGION));
acpi_os_printf ("Power_resource %3d\n", sizeof (ACPI_OBJECT_POWER_RESOURCE));
acpi_os_printf ("Processor %3d\n", sizeof (ACPI_OBJECT_PROCESSOR));
acpi_os_printf ("Thermal_zone %3d\n", sizeof (ACPI_OBJECT_THERMAL_ZONE));
acpi_os_printf ("Region_field %3d\n", sizeof (ACPI_OBJECT_REGION_FIELD));
acpi_os_printf ("Bank_field %3d\n", sizeof (ACPI_OBJECT_BANK_FIELD));
acpi_os_printf ("Index_field %3d\n", sizeof (ACPI_OBJECT_INDEX_FIELD));
acpi_os_printf ("Reference %3d\n", sizeof (ACPI_OBJECT_REFERENCE));
acpi_os_printf ("Notify_handler %3d\n", sizeof (ACPI_OBJECT_NOTIFY_HANDLER));
acpi_os_printf ("Addr_handler %3d\n", sizeof (ACPI_OBJECT_ADDR_HANDLER));
acpi_os_printf ("Extra %3d\n", sizeof (ACPI_OBJECT_EXTRA));
acpi_os_printf ("Data %3d\n", sizeof (ACPI_OBJECT_DATA));
acpi_os_printf ("\n");
acpi_os_printf ("Parse_object %3d\n", sizeof (ACPI_PARSE_OBJ_COMMON));
acpi_os_printf ("Parse_object_named %3d\n", sizeof (ACPI_PARSE_OBJ_NAMED));
acpi_os_printf ("Parse_object_asl %3d\n", sizeof (ACPI_PARSE_OBJ_ASL));
acpi_os_printf ("Operand_object %3d\n", sizeof (acpi_operand_object));
acpi_os_printf ("Namespace_node %3d\n", sizeof (acpi_namespace_node));
break;
case CMD_STAT_STACK:
#if defined(ACPI_DEBUG_OUTPUT)
size = (u32) (acpi_gbl_entry_stack_pointer - acpi_gbl_lowest_stack_pointer);
acpi_os_printf ("\nSubsystem Stack Usage:\n\n");
acpi_os_printf ("Entry Stack Pointer %X\n", acpi_gbl_entry_stack_pointer);
acpi_os_printf ("Lowest Stack Pointer %X\n", acpi_gbl_lowest_stack_pointer);
acpi_os_printf ("Stack Use %X (%d)\n", size, size);
acpi_os_printf ("Deepest Procedure Nesting %d\n", acpi_gbl_deepest_nesting);
#endif
break;
default:
break;
}
acpi_os_printf ("\n");
return (AE_OK);
}
#endif /* ACPI_DEBUGGER */
/*******************************************************************************
*
* Module Name: dbutils - AML debugger utilities
* $Revision: 56 $
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2002, 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 "amlcode.h"
#include "acnamesp.h"
#include "acdebug.h"
#include "acdispat.h"
#ifdef ACPI_DEBUGGER
#define _COMPONENT ACPI_CA_DEBUGGER
ACPI_MODULE_NAME ("dbutils")
/*******************************************************************************
*
* FUNCTION: Acpi_db_set_output_destination
*
* PARAMETERS: Output_flags - Current flags word
*
* RETURN: None
*
* DESCRIPTION: Set the current destination for debugger output. Alos sets
* the debug output level accordingly.
*
******************************************************************************/
void
acpi_db_set_output_destination (
u32 output_flags)
{
acpi_gbl_db_output_flags = (u8) output_flags;
if ((output_flags & ACPI_DB_REDIRECTABLE_OUTPUT) && acpi_gbl_db_output_to_file) {
acpi_dbg_level = acpi_gbl_db_debug_level;
}
else {
acpi_dbg_level = acpi_gbl_db_console_debug_level;
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_dump_buffer
*
* PARAMETERS: Address - Pointer to the buffer
*
* RETURN: None
*
* DESCRIPTION: Print a portion of a buffer
*
******************************************************************************/
void
acpi_db_dump_buffer (
u32 address)
{
acpi_os_printf ("\nLocation %X:\n", address);
acpi_dbg_level |= ACPI_LV_TABLES;
acpi_ut_dump_buffer (ACPI_TO_POINTER (address), 64, DB_BYTE_DISPLAY, ACPI_UINT32_MAX);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_dump_object
*
* PARAMETERS: Obj_desc - External ACPI object to dump
* Level - Nesting level.
*
* RETURN: None
*
* DESCRIPTION: Dump the contents of an ACPI external object
*
******************************************************************************/
void
acpi_db_dump_object (
acpi_object *obj_desc,
u32 level)
{
u32 i;
if (!obj_desc) {
acpi_os_printf ("[Null Object]\n");
return;
}
for (i = 0; i < level; i++) {
acpi_os_printf (" ");
}
switch (obj_desc->type) {
case ACPI_TYPE_ANY:
acpi_os_printf ("[Object Reference] = %p\n", obj_desc->reference.handle);
break;
case ACPI_TYPE_INTEGER:
acpi_os_printf ("[Integer] = %8.8X%8.8X\n",
ACPI_HIDWORD (obj_desc->integer.value),
ACPI_LODWORD (obj_desc->integer.value));
break;
case ACPI_TYPE_STRING:
acpi_os_printf ("[String] Value: ");
for (i = 0; i < obj_desc->string.length; i++) {
acpi_os_printf ("%c", obj_desc->string.pointer[i]);
}
acpi_os_printf ("\n");
break;
case ACPI_TYPE_BUFFER:
acpi_os_printf ("[Buffer] Length %.2X = ", obj_desc->buffer.length);
acpi_ut_dump_buffer ((u8 *) obj_desc->buffer.pointer, obj_desc->buffer.length, DB_DWORD_DISPLAY, _COMPONENT);
break;
case ACPI_TYPE_PACKAGE:
acpi_os_printf ("[Package] Contains %d Elements: \n", obj_desc->package.count);
for (i = 0; i < obj_desc->package.count; i++) {
acpi_db_dump_object (&obj_desc->package.elements[i], level+1);
}
break;
case INTERNAL_TYPE_REFERENCE:
acpi_os_printf ("[Object Reference] = %p\n", obj_desc->reference.handle);
break;
case ACPI_TYPE_PROCESSOR:
acpi_os_printf ("[Processor]\n");
break;
case ACPI_TYPE_POWER:
acpi_os_printf ("[Power Resource]\n");
break;
default:
acpi_os_printf ("[Unknown Type] %X \n", obj_desc->type);
break;
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_prep_namestring
*
* PARAMETERS: Name - String to prepare
*
* RETURN: None
*
* DESCRIPTION: Translate all forward slashes and dots to backslashes.
*
******************************************************************************/
void
acpi_db_prep_namestring (
NATIVE_CHAR *name)
{
if (!name) {
return;
}
ACPI_STRUPR (name);
/* Convert a leading forward slash to a backslash */
if (*name == '/') {
*name = '\\';
}
/* Ignore a leading backslash, this is the root prefix */
if (*name == '\\') {
name++;
}
/* Convert all slash path separators to dots */
while (*name) {
if ((*name == '/') ||
(*name == '\\')) {
*name = '.';
}
name++;
}
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_second_pass_parse
*
* PARAMETERS: Root - Root of the parse tree
*
* RETURN: Status
*
* DESCRIPTION: Second pass parse of the ACPI tables. We need to wait until
* second pass to parse the control methods
*
******************************************************************************/
acpi_status
acpi_db_second_pass_parse (
acpi_parse_object *root)
{
acpi_parse_object *op = root;
acpi_parse_object *method;
acpi_parse_object *search_op;
acpi_parse_object *start_op;
acpi_status status = AE_OK;
u32 base_aml_offset;
acpi_walk_state *walk_state;
ACPI_FUNCTION_ENTRY ();
acpi_os_printf ("Pass two parse ....\n");
while (op) {
if (op->common.aml_opcode == AML_METHOD_OP) {
method = op;
/* Create a new walk state for the parse */
walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT,
NULL, NULL, NULL);
if (!walk_state) {
return (AE_NO_MEMORY);
}
/* Init the Walk State */
walk_state->parser_state.aml =
walk_state->parser_state.aml_start = method->named.data;
walk_state->parser_state.aml_end =
walk_state->parser_state.pkg_end = method->named.data + method->named.length;
walk_state->parser_state.start_scope = op;
walk_state->descending_callback = acpi_ds_load1_begin_op;
walk_state->ascending_callback = acpi_ds_load1_end_op;
/* Perform the AML parse */
status = acpi_ps_parse_aml (walk_state);
base_aml_offset = (method->common.value.arg)->common.aml_offset + 1;
start_op = (method->common.value.arg)->common.next;
search_op = start_op;
while (search_op) {
search_op->common.aml_offset += base_aml_offset;
search_op = acpi_ps_get_depth_next (start_op, search_op);
}
}
if (op->common.aml_opcode == AML_REGION_OP) {
/* TBD: [Investigate] this isn't quite the right thing to do! */
/*
*
* Method = (ACPI_DEFERRED_OP *) Op;
* Status = Acpi_ps_parse_aml (Op, Method->Body, Method->Body_length);
*/
}
if (ACPI_FAILURE (status)) {
break;
}
op = acpi_ps_get_depth_next (root, op);
}
return (status);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_local_ns_lookup
*
* PARAMETERS: Name - Name to lookup
*
* RETURN: Pointer to a namespace node
*
* DESCRIPTION: Lookup a name in the ACPI namespace
*
* Note: Currently begins search from the root. Could be enhanced to use
* the current prefix (scope) node as the search beginning point.
*
******************************************************************************/
acpi_namespace_node *
acpi_db_local_ns_lookup (
NATIVE_CHAR *name)
{
NATIVE_CHAR *internal_path;
acpi_status status;
acpi_namespace_node *node = NULL;
acpi_db_prep_namestring (name);
/* Build an internal namestring */
status = acpi_ns_internalize_name (name, &internal_path);
if (ACPI_FAILURE (status)) {
acpi_os_printf ("Invalid namestring: %s\n", name);
return (NULL);
}
/*
* Lookup the name.
* (Uses root node as the search starting point)
*/
status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE, NULL, &node);
if (ACPI_FAILURE (status)) {
acpi_os_printf ("Could not locate name: %s %s\n", name, acpi_format_exception (status));
}
ACPI_MEM_FREE (internal_path);
return (node);
}
#endif /* ACPI_DEBUGGER */
/*******************************************************************************
*
* Module Name: dbxface - AML Debugger external interfaces
* $Revision: 64 $
*
******************************************************************************/
/*
* Copyright (C) 2000 - 2002, 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 "amlcode.h"
#include "acdebug.h"
#include "acdisasm.h"
#ifdef ACPI_DEBUGGER
#define _COMPONENT ACPI_CA_DEBUGGER
ACPI_MODULE_NAME ("dbxface")
/*******************************************************************************
*
* FUNCTION: Acpi_db_single_step
*
* PARAMETERS: Walk_state - Current walk
* Op - Current executing op
* Opcode_class - Class of the current AML Opcode
*
* RETURN: Status
*
* DESCRIPTION: Called just before execution of an AML opcode.
*
******************************************************************************/
acpi_status
acpi_db_single_step (
acpi_walk_state *walk_state,
acpi_parse_object *op,
u32 opcode_class)
{
acpi_parse_object *next;
acpi_status status = AE_OK;
u32 original_debug_level;
acpi_parse_object *display_op;
acpi_parse_object *parent_op;
ACPI_FUNCTION_ENTRY ();
/* Check for single-step breakpoint */
if (walk_state->method_breakpoint &&
(walk_state->method_breakpoint <= op->common.aml_offset)) {
/* Check if the breakpoint has been reached or passed */
/* Hit the breakpoint, resume single step, reset breakpoint */
acpi_os_printf ("***Break*** at AML offset %X\n", op->common.aml_offset);
acpi_gbl_cm_single_step = TRUE;
acpi_gbl_step_to_next_call = FALSE;
walk_state->method_breakpoint = 0;
}
/* Check for user breakpoint (Must be on exact Aml offset) */
else if (walk_state->user_breakpoint &&
(walk_state->user_breakpoint == op->common.aml_offset)) {
acpi_os_printf ("***User_breakpoint*** at AML offset %X\n", op->common.aml_offset);
acpi_gbl_cm_single_step = TRUE;
acpi_gbl_step_to_next_call = FALSE;
walk_state->method_breakpoint = 0;
}
/*
* Check if this is an opcode that we are interested in --
* namely, opcodes that have arguments
*/
if (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
return (AE_OK);
}
switch (opcode_class) {
case AML_CLASS_UNKNOWN:
case AML_CLASS_ARGUMENT: /* constants, literals, etc. do nothing */
return (AE_OK);
default:
/* All other opcodes -- continue */
break;
}
/*
* Under certain debug conditions, display this opcode and its operands
*/
if ((acpi_gbl_db_output_to_file) ||
(acpi_gbl_cm_single_step) ||
(acpi_dbg_level & ACPI_LV_PARSE)) {
if ((acpi_gbl_db_output_to_file) ||
(acpi_dbg_level & ACPI_LV_PARSE)) {
acpi_os_printf ("\n[Aml_debug] Next AML Opcode to execute:\n");
}
/*
* Display this op (and only this op - zero out the NEXT field temporarily,
* and disable parser trace output for the duration of the display because
* we don't want the extraneous debug output)
*/
original_debug_level = acpi_dbg_level;
acpi_dbg_level &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS);
next = op->common.next;
op->common.next = NULL;
display_op = op;
parent_op = op->common.parent;
if (parent_op) {
if ((walk_state->control_state) &&
(walk_state->control_state->common.state == ACPI_CONTROL_PREDICATE_EXECUTING)) {
/*
* We are executing the predicate of an IF or WHILE statement
* Search upwards for the containing IF or WHILE so that the
* entire predicate can be displayed.
*/
while (parent_op) {
if ((parent_op->common.aml_opcode == AML_IF_OP) ||
(parent_op->common.aml_opcode == AML_WHILE_OP)) {
display_op = parent_op;
break;
}
parent_op = parent_op->common.parent;
}
}
else {
while (parent_op) {
if ((parent_op->common.aml_opcode == AML_IF_OP) ||
(parent_op->common.aml_opcode == AML_ELSE_OP) ||
(parent_op->common.aml_opcode == AML_SCOPE_OP) ||
(parent_op->common.aml_opcode == AML_METHOD_OP) ||
(parent_op->common.aml_opcode == AML_WHILE_OP)) {
break;
}
display_op = parent_op;
parent_op = parent_op->common.parent;
}
}
}
/* Now we can display it */
acpi_dm_disassemble (walk_state, display_op, ACPI_UINT32_MAX);
if ((op->common.aml_opcode == AML_IF_OP) ||
(op->common.aml_opcode == AML_WHILE_OP)) {
if (walk_state->control_state->common.value) {
acpi_os_printf ("Predicate = [True], IF block was executed\n");
}
else {
acpi_os_printf ("Predicate = [False], Skipping IF block\n");
}
}
else if (op->common.aml_opcode == AML_ELSE_OP) {
acpi_os_printf ("Predicate = [False], ELSE block was executed\n");
}
/* Restore everything */
op->common.next = next;
acpi_os_printf ("\n\n");
acpi_dbg_level = original_debug_level;
}
/* If we are not single stepping, just continue executing the method */
if (!acpi_gbl_cm_single_step) {
return (AE_OK);
}
/*
* If we are executing a step-to-call command,
* Check if this is a method call.
*/
if (acpi_gbl_step_to_next_call) {
if (op->common.aml_opcode != AML_INT_METHODCALL_OP) {
/* Not a method call, just keep executing */
return (AE_OK);
}
/* Found a method call, stop executing */
acpi_gbl_step_to_next_call = FALSE;
}
/*
* If the next opcode is a method call, we will "step over" it
* by default.
*/
if (op->common.aml_opcode == AML_INT_METHODCALL_OP) {
acpi_gbl_cm_single_step = FALSE; /* No more single step while executing called method */
/* Set the breakpoint on/before the call, it will stop execution as soon as we return */
walk_state->method_breakpoint = 1; /* Must be non-zero! */
}
/* TBD: [Investigate] what are the namespace locking issues here */
/* Acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */
/* Go into the command loop and await next user command */
acpi_gbl_method_executing = TRUE;
status = AE_CTRL_TRUE;
while (status == AE_CTRL_TRUE) {
if (acpi_gbl_debugger_configuration == DEBUGGER_MULTI_THREADED) {
/* Handshake with the front-end that gets user command lines */
status = acpi_ut_release_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE);
if (ACPI_FAILURE (status)) {
return (status);
}
status = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_READY);
if (ACPI_FAILURE (status)) {
return (status);
}
}
else {
/* Single threaded, we must get a command line ourselves */
/* Force output to console until a command is entered */
acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
/* Different prompt if method is executing */
if (!acpi_gbl_method_executing) {
acpi_os_printf ("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
}
else {
acpi_os_printf ("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
}
/* Get the user input line */
(void) acpi_os_get_line (acpi_gbl_db_line_buf);
}
status = acpi_db_command_dispatch (acpi_gbl_db_line_buf, walk_state, op);
}
/* Acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */
/* User commands complete, continue execution of the interrupted method */
return (status);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_initialize
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: Init and start debugger
*
******************************************************************************/
acpi_status
acpi_db_initialize (void)
{
acpi_status status;
/* Init globals */
acpi_gbl_db_buffer = NULL;
acpi_gbl_db_filename = NULL;
acpi_gbl_db_output_to_file = FALSE;
acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2;
acpi_gbl_db_console_debug_level = NORMAL_DEFAULT | ACPI_LV_TABLES;
acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
acpi_gbl_db_opt_tables = FALSE;
acpi_gbl_db_opt_disasm = FALSE;
acpi_gbl_db_opt_stats = FALSE;
acpi_gbl_db_opt_verbose = TRUE;
acpi_gbl_db_opt_ini_methods = TRUE;
acpi_gbl_db_buffer = acpi_os_allocate (ACPI_DEBUG_BUFFER_SIZE);
if (!acpi_gbl_db_buffer) {
return (AE_NO_MEMORY);
}
ACPI_MEMSET (acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE);
/* Initial scope is the root */
acpi_gbl_db_scope_buf [0] = '\\';
acpi_gbl_db_scope_buf [1] = 0;
acpi_gbl_db_scope_node = acpi_gbl_root_node;
/*
* If configured for multi-thread support, the debug executor runs in
* a separate thread so that the front end can be in another address
* space, environment, or even another machine.
*/
if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
/* These were created with one unit, grab it */
status = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE);
if (ACPI_FAILURE (status)) {
acpi_os_printf ("Could not get debugger mutex\n");
return (status);
}
status = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_READY);
if (ACPI_FAILURE (status)) {
acpi_os_printf ("Could not get debugger mutex\n");
return (status);
}
/* Create the debug execution thread to execute commands */
status = acpi_os_queue_for_execution (0, acpi_db_execute_thread, NULL);
if (ACPI_FAILURE (status)) {
acpi_os_printf ("Could not start debugger thread\n");
return (status);
}
}
if (!acpi_gbl_db_opt_verbose) {
acpi_gbl_db_opt_disasm = TRUE;
acpi_gbl_db_opt_stats = FALSE;
}
return (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: Acpi_db_terminate
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: Stop debugger
*
******************************************************************************/
void
acpi_db_terminate (void)
{
if (acpi_gbl_db_table_ptr) {
acpi_os_free (acpi_gbl_db_table_ptr);
}
if (acpi_gbl_db_buffer) {
acpi_os_free (acpi_gbl_db_buffer);
}
}
#endif /* ACPI_DEBUGGER */
Using the ACPI debugger with kdb
--------------------------------
ACPI CA includes a full-featured debugger, which allows the examination of
a running system's ACPI tables, as well as running and stepping through
control methods.
Configuration
-------------
1) Edit the main acpi Makefile. On the ACPI_CFLAGS line, remove the '#', thus
enabling the debugger.
2) Download the latest kdb patch from:
ftp://oss.sgi.com/www/projects/kdb/download/ix86/
Follow the instructions at http://oss.sgi.com/projects/kdb/ on how to
install the patch and configure KDB.
3) This would probably be a good time to recompile the kernel, and make sure
kdb works (Hitting the Pause key should drop you into it. Type "go" to exit
it.
4) The kdb <--> ACPI debugger interface is a module. Type "make modules", and
it will be built and placed in drivers/acpi/kdb.
5) Change to that directory and type "insmod kdbm_acpi.o". This loads the
module we just built.
6) Break back into kdb. If you type help, you should now see "acpi" listed as
a command, at the bottom.
7) Type "acpi". You are now in the ACPI debugger. While hosted by kdb, it is
wholly separate, and has many ACPI-specific commands. Type "?" or "help"
to get a listing of the command categories, and then "help <category>" for
a list of commands and their descriptions
/*
* kdbm_acpi.c - kdb debugger module interface for ACPI debugger
*
* Copyright (C) 2000 Andrew Grover
*
* 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 <linux/types.h>
#include <linux/kdb.h>
#include <linux/module.h>
#include "acpi.h"
#include "acdebug.h"
extern int acpi_in_debugger;
static int
kdbm_acpi(int argc, const char **argv, const char **envp, struct pt_regs *regs)
{
acpi_in_debugger = 1;
acpi_db_user_commands(DB_COMMAND_PROMPT, NULL);
acpi_in_debugger = 0;
return 0;
}
int
init_module(void)
{
kdb_register("acpi", kdbm_acpi, "", "Enter ACPI debugger", 0);
return 0;
}
void
cleanup_module(void)
{
kdb_unregister("acpi");
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment