| /******************************************************************************* |
| * |
| * Module Name: dbexec - debugger control method execution |
| * $Revision: 34 $ |
| * |
| ******************************************************************************/ |
| |
| /* |
| * Copyright (C) 2000, 2001 R. Byron Moore |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| |
| #include "acpi.h" |
| #include "acparser.h" |
| #include "acdispat.h" |
| #include "amlcode.h" |
| #include "acnamesp.h" |
| #include "acparser.h" |
| #include "acevents.h" |
| #include "acinterp.h" |
| #include "acdebug.h" |
| #include "actables.h" |
| |
| #ifdef ENABLE_DEBUGGER |
| |
| #define _COMPONENT ACPI_DEBUGGER |
| MODULE_NAME ("dbexec") |
| |
| |
| 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 ( |
| 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 = 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, ¶m_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 ( |
| db_method_info *info) |
| { |
| |
| /* Catenate the current scope to the supplied name */ |
| |
| info->pathname[0] = 0; |
| if ((info->name[0] != '\\') && |
| (info->name[0] != '/')) { |
| STRCAT (info->pathname, acpi_gbl_db_scope_buf); |
| } |
| |
| STRCAT (info->pathname, info->name); |
| acpi_db_prep_namestring (info->pathname); |
| |
| acpi_db_set_output_destination (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 (DB_CONSOLE_OUTPUT); |
| } |
| |
| else { |
| /* No single step, allow redirection to a file */ |
| |
| acpi_db_set_output_destination (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 i; |
| u32 outstanding = 0; |
| |
| |
| #ifdef ACPI_DBG_TRACK_ALLOCATIONS |
| |
| 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 |
| 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; |
| |
| 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 |
| |
| /* Memory allocation tracking */ |
| |
| allocations = acpi_db_get_outstanding_allocations () - previous_allocations; |
| |
| acpi_db_set_output_destination (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); |
| } |
| } |
| |
| acpi_db_set_output_destination (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_db_method_thread ( |
| void *context) |
| { |
| acpi_status status; |
| 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 */ |
| |
| acpi_os_signal_semaphore (info->thread_gate, 1); |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * 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 = STRTOUL (num_threads_arg, NULL, 0); |
| num_loops = 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++) { |
| acpi_os_queue_for_execution (OSD_PRIORITY_MED, acpi_db_method_thread, &acpi_gbl_db_method_info); |
| } |
| |
| |
| /* 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 */ |
| |
| acpi_os_delete_semaphore (thread_gate); |
| |
| acpi_db_set_output_destination (DB_DUPLICATE_OUTPUT); |
| acpi_os_printf ("All threads (%X) have completed\n", num_threads); |
| acpi_db_set_output_destination (DB_CONSOLE_OUTPUT); |
| } |
| |
| |
| #endif /* ENABLE_DEBUGGER */ |
| |
| |