dbexec.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
  2. /*******************************************************************************
  3. *
  4. * Module Name: dbexec - debugger control method execution
  5. *
  6. ******************************************************************************/
  7. #include <acpi/acpi.h>
  8. #include "accommon.h"
  9. #include "acdebug.h"
  10. #include "acnamesp.h"
  11. #define _COMPONENT ACPI_CA_DEBUGGER
  12. ACPI_MODULE_NAME("dbexec")
  13. static struct acpi_db_method_info acpi_gbl_db_method_info;
  14. /* Local prototypes */
  15. static acpi_status
  16. acpi_db_execute_method(struct acpi_db_method_info *info,
  17. struct acpi_buffer *return_obj);
  18. static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info);
  19. static u32 acpi_db_get_outstanding_allocations(void);
  20. static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context);
  21. static acpi_status
  22. acpi_db_execution_walk(acpi_handle obj_handle,
  23. u32 nesting_level, void *context, void **return_value);
  24. static void ACPI_SYSTEM_XFACE acpi_db_single_execution_thread(void *context);
  25. /*******************************************************************************
  26. *
  27. * FUNCTION: acpi_db_delete_objects
  28. *
  29. * PARAMETERS: count - Count of objects in the list
  30. * objects - Array of ACPI_OBJECTs to be deleted
  31. *
  32. * RETURN: None
  33. *
  34. * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested
  35. * packages via recursion.
  36. *
  37. ******************************************************************************/
  38. void acpi_db_delete_objects(u32 count, union acpi_object *objects)
  39. {
  40. u32 i;
  41. for (i = 0; i < count; i++) {
  42. switch (objects[i].type) {
  43. case ACPI_TYPE_BUFFER:
  44. ACPI_FREE(objects[i].buffer.pointer);
  45. break;
  46. case ACPI_TYPE_PACKAGE:
  47. /* Recursive call to delete package elements */
  48. acpi_db_delete_objects(objects[i].package.count,
  49. objects[i].package.elements);
  50. /* Free the elements array */
  51. ACPI_FREE(objects[i].package.elements);
  52. break;
  53. default:
  54. break;
  55. }
  56. }
  57. }
  58. /*******************************************************************************
  59. *
  60. * FUNCTION: acpi_db_execute_method
  61. *
  62. * PARAMETERS: info - Valid info segment
  63. * return_obj - Where to put return object
  64. *
  65. * RETURN: Status
  66. *
  67. * DESCRIPTION: Execute a control method. Used to evaluate objects via the
  68. * "EXECUTE" or "EVALUATE" commands.
  69. *
  70. ******************************************************************************/
  71. static acpi_status
  72. acpi_db_execute_method(struct acpi_db_method_info *info,
  73. struct acpi_buffer *return_obj)
  74. {
  75. acpi_status status;
  76. struct acpi_object_list param_objects;
  77. union acpi_object params[ACPI_DEBUGGER_MAX_ARGS + 1];
  78. u32 i;
  79. ACPI_FUNCTION_TRACE(db_execute_method);
  80. if (acpi_gbl_db_output_to_file && !acpi_dbg_level) {
  81. acpi_os_printf("Warning: debug output is not enabled!\n");
  82. }
  83. param_objects.count = 0;
  84. param_objects.pointer = NULL;
  85. /* Pass through any command-line arguments */
  86. if (info->args && info->args[0]) {
  87. /* Get arguments passed on the command line */
  88. for (i = 0; (info->args[i] && *(info->args[i])); i++) {
  89. /* Convert input string (token) to an actual union acpi_object */
  90. status = acpi_db_convert_to_object(info->types[i],
  91. info->args[i],
  92. &params[i]);
  93. if (ACPI_FAILURE(status)) {
  94. ACPI_EXCEPTION((AE_INFO, status,
  95. "While parsing method arguments"));
  96. goto cleanup;
  97. }
  98. }
  99. param_objects.count = i;
  100. param_objects.pointer = params;
  101. }
  102. /* Prepare for a return object of arbitrary size */
  103. return_obj->pointer = acpi_gbl_db_buffer;
  104. return_obj->length = ACPI_DEBUG_BUFFER_SIZE;
  105. /* Do the actual method execution */
  106. acpi_gbl_method_executing = TRUE;
  107. status = acpi_evaluate_object(NULL, info->pathname,
  108. &param_objects, return_obj);
  109. acpi_gbl_cm_single_step = FALSE;
  110. acpi_gbl_method_executing = FALSE;
  111. if (ACPI_FAILURE(status)) {
  112. if ((status == AE_ABORT_METHOD) || acpi_gbl_abort_method) {
  113. /* Clear the abort and fall back to the debugger prompt */
  114. ACPI_EXCEPTION((AE_INFO, status,
  115. "Aborting top-level method"));
  116. acpi_gbl_abort_method = FALSE;
  117. status = AE_OK;
  118. goto cleanup;
  119. }
  120. ACPI_EXCEPTION((AE_INFO, status,
  121. "while executing %s from AML Debugger",
  122. info->pathname));
  123. if (status == AE_BUFFER_OVERFLOW) {
  124. ACPI_ERROR((AE_INFO,
  125. "Possible buffer overflow within AML Debugger "
  126. "buffer (size 0x%X needed 0x%X)",
  127. ACPI_DEBUG_BUFFER_SIZE,
  128. (u32)return_obj->length));
  129. }
  130. }
  131. cleanup:
  132. acpi_db_delete_objects(param_objects.count, params);
  133. return_ACPI_STATUS(status);
  134. }
  135. /*******************************************************************************
  136. *
  137. * FUNCTION: acpi_db_execute_setup
  138. *
  139. * PARAMETERS: info - Valid method info
  140. *
  141. * RETURN: None
  142. *
  143. * DESCRIPTION: Setup info segment prior to method execution
  144. *
  145. ******************************************************************************/
  146. static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info)
  147. {
  148. acpi_status status;
  149. ACPI_FUNCTION_NAME(db_execute_setup);
  150. /* Concatenate the current scope to the supplied name */
  151. info->pathname[0] = 0;
  152. if ((info->name[0] != '\\') && (info->name[0] != '/')) {
  153. if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
  154. acpi_gbl_db_scope_buf)) {
  155. status = AE_BUFFER_OVERFLOW;
  156. goto error_exit;
  157. }
  158. }
  159. if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
  160. info->name)) {
  161. status = AE_BUFFER_OVERFLOW;
  162. goto error_exit;
  163. }
  164. acpi_db_prep_namestring(info->pathname);
  165. acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
  166. acpi_os_printf("Evaluating %s\n", info->pathname);
  167. if (info->flags & EX_SINGLE_STEP) {
  168. acpi_gbl_cm_single_step = TRUE;
  169. acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
  170. }
  171. else {
  172. /* No single step, allow redirection to a file */
  173. acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
  174. }
  175. return (AE_OK);
  176. error_exit:
  177. ACPI_EXCEPTION((AE_INFO, status, "During setup for method execution"));
  178. return (status);
  179. }
  180. #ifdef ACPI_DBG_TRACK_ALLOCATIONS
  181. u32 acpi_db_get_cache_info(struct acpi_memory_list *cache)
  182. {
  183. return (cache->total_allocated - cache->total_freed -
  184. cache->current_depth);
  185. }
  186. #endif
  187. /*******************************************************************************
  188. *
  189. * FUNCTION: acpi_db_get_outstanding_allocations
  190. *
  191. * PARAMETERS: None
  192. *
  193. * RETURN: Current global allocation count minus cache entries
  194. *
  195. * DESCRIPTION: Determine the current number of "outstanding" allocations --
  196. * those allocations that have not been freed and also are not
  197. * in one of the various object caches.
  198. *
  199. ******************************************************************************/
  200. static u32 acpi_db_get_outstanding_allocations(void)
  201. {
  202. u32 outstanding = 0;
  203. #ifdef ACPI_DBG_TRACK_ALLOCATIONS
  204. outstanding += acpi_db_get_cache_info(acpi_gbl_state_cache);
  205. outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_cache);
  206. outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_ext_cache);
  207. outstanding += acpi_db_get_cache_info(acpi_gbl_operand_cache);
  208. #endif
  209. return (outstanding);
  210. }
  211. /*******************************************************************************
  212. *
  213. * FUNCTION: acpi_db_execution_walk
  214. *
  215. * PARAMETERS: WALK_CALLBACK
  216. *
  217. * RETURN: Status
  218. *
  219. * DESCRIPTION: Execute a control method. Name is relative to the current
  220. * scope.
  221. *
  222. ******************************************************************************/
  223. static acpi_status
  224. acpi_db_execution_walk(acpi_handle obj_handle,
  225. u32 nesting_level, void *context, void **return_value)
  226. {
  227. union acpi_operand_object *obj_desc;
  228. struct acpi_namespace_node *node =
  229. (struct acpi_namespace_node *)obj_handle;
  230. struct acpi_buffer return_obj;
  231. acpi_status status;
  232. obj_desc = acpi_ns_get_attached_object(node);
  233. if (obj_desc->method.param_count) {
  234. return (AE_OK);
  235. }
  236. return_obj.pointer = NULL;
  237. return_obj.length = ACPI_ALLOCATE_BUFFER;
  238. acpi_ns_print_node_pathname(node, "Evaluating");
  239. /* Do the actual method execution */
  240. acpi_os_printf("\n");
  241. acpi_gbl_method_executing = TRUE;
  242. status = acpi_evaluate_object(node, NULL, NULL, &return_obj);
  243. acpi_gbl_method_executing = FALSE;
  244. acpi_os_printf("Evaluation of [%4.4s] returned %s\n",
  245. acpi_ut_get_node_name(node),
  246. acpi_format_exception(status));
  247. return (AE_OK);
  248. }
  249. /*******************************************************************************
  250. *
  251. * FUNCTION: acpi_db_execute
  252. *
  253. * PARAMETERS: name - Name of method to execute
  254. * args - Parameters to the method
  255. * Types -
  256. * flags - single step/no single step
  257. *
  258. * RETURN: None
  259. *
  260. * DESCRIPTION: Execute a control method. Name is relative to the current
  261. * scope. Function used for the "EXECUTE", "EVALUATE", and
  262. * "ALL" commands
  263. *
  264. ******************************************************************************/
  265. void
  266. acpi_db_execute(char *name, char **args, acpi_object_type *types, u32 flags)
  267. {
  268. acpi_status status;
  269. struct acpi_buffer return_obj;
  270. char *name_string;
  271. #ifdef ACPI_DEBUG_OUTPUT
  272. u32 previous_allocations;
  273. u32 allocations;
  274. #endif
  275. /*
  276. * Allow one execution to be performed by debugger or single step
  277. * execution will be dead locked by the interpreter mutexes.
  278. */
  279. if (acpi_gbl_method_executing) {
  280. acpi_os_printf("Only one debugger execution is allowed.\n");
  281. return;
  282. }
  283. #ifdef ACPI_DEBUG_OUTPUT
  284. /* Memory allocation tracking */
  285. previous_allocations = acpi_db_get_outstanding_allocations();
  286. #endif
  287. if (*name == '*') {
  288. (void)acpi_walk_namespace(ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
  289. ACPI_UINT32_MAX,
  290. acpi_db_execution_walk, NULL, NULL,
  291. NULL);
  292. return;
  293. }
  294. if ((flags & EX_ALL) && (strlen(name) > 4)) {
  295. acpi_os_printf("Input name (%s) must be a 4-char NameSeg\n",
  296. name);
  297. return;
  298. }
  299. name_string = ACPI_ALLOCATE(strlen(name) + 1);
  300. if (!name_string) {
  301. return;
  302. }
  303. memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
  304. strcpy(name_string, name);
  305. acpi_ut_strupr(name_string);
  306. /* Subcommand to Execute all predefined names in the namespace */
  307. if (!strncmp(name_string, "PREDEF", 6)) {
  308. acpi_db_evaluate_predefined_names();
  309. ACPI_FREE(name_string);
  310. return;
  311. }
  312. /* Command (ALL <nameseg>) to execute all methods of a particular name */
  313. else if (flags & EX_ALL) {
  314. acpi_gbl_db_method_info.name = name_string;
  315. return_obj.pointer = NULL;
  316. return_obj.length = ACPI_ALLOCATE_BUFFER;
  317. acpi_db_evaluate_all(name_string);
  318. ACPI_FREE(name_string);
  319. return;
  320. } else {
  321. acpi_gbl_db_method_info.name = name_string;
  322. acpi_gbl_db_method_info.args = args;
  323. acpi_gbl_db_method_info.types = types;
  324. acpi_gbl_db_method_info.flags = flags;
  325. return_obj.pointer = NULL;
  326. return_obj.length = ACPI_ALLOCATE_BUFFER;
  327. }
  328. status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
  329. if (ACPI_FAILURE(status)) {
  330. ACPI_FREE(name_string);
  331. return;
  332. }
  333. /* Get the NS node, determines existence also */
  334. status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
  335. &acpi_gbl_db_method_info.method);
  336. if (ACPI_SUCCESS(status)) {
  337. status = acpi_db_execute_method(&acpi_gbl_db_method_info,
  338. &return_obj);
  339. }
  340. ACPI_FREE(name_string);
  341. /*
  342. * Allow any handlers in separate threads to complete.
  343. * (Such as Notify handlers invoked from AML executed above).
  344. */
  345. acpi_os_sleep((u64)10);
  346. #ifdef ACPI_DEBUG_OUTPUT
  347. /* Memory allocation tracking */
  348. allocations =
  349. acpi_db_get_outstanding_allocations() - previous_allocations;
  350. acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
  351. if (allocations > 0) {
  352. acpi_os_printf
  353. ("0x%X Outstanding allocations after evaluation of %s\n",
  354. allocations, acpi_gbl_db_method_info.pathname);
  355. }
  356. #endif
  357. if (ACPI_FAILURE(status)) {
  358. acpi_os_printf("Evaluation of %s failed with status %s\n",
  359. acpi_gbl_db_method_info.pathname,
  360. acpi_format_exception(status));
  361. } else {
  362. /* Display a return object, if any */
  363. if (return_obj.length) {
  364. acpi_os_printf("Evaluation of %s returned object %p, "
  365. "external buffer length %X\n",
  366. acpi_gbl_db_method_info.pathname,
  367. return_obj.pointer,
  368. (u32)return_obj.length);
  369. acpi_db_dump_external_object(return_obj.pointer, 1);
  370. acpi_os_printf("\n");
  371. /* Dump a _PLD buffer if present */
  372. if (ACPI_COMPARE_NAMESEG
  373. ((ACPI_CAST_PTR
  374. (struct acpi_namespace_node,
  375. acpi_gbl_db_method_info.method)->name.ascii),
  376. METHOD_NAME__PLD)) {
  377. acpi_db_dump_pld_buffer(return_obj.pointer);
  378. }
  379. } else {
  380. acpi_os_printf
  381. ("No object was returned from evaluation of %s\n",
  382. acpi_gbl_db_method_info.pathname);
  383. }
  384. }
  385. acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
  386. }
  387. /*******************************************************************************
  388. *
  389. * FUNCTION: acpi_db_method_thread
  390. *
  391. * PARAMETERS: context - Execution info segment
  392. *
  393. * RETURN: None
  394. *
  395. * DESCRIPTION: Debugger execute thread. Waits for a command line, then
  396. * simply dispatches it.
  397. *
  398. ******************************************************************************/
  399. static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context)
  400. {
  401. acpi_status status;
  402. struct acpi_db_method_info *info = context;
  403. struct acpi_db_method_info local_info;
  404. u32 i;
  405. u8 allow;
  406. struct acpi_buffer return_obj;
  407. /*
  408. * acpi_gbl_db_method_info.Arguments will be passed as method arguments.
  409. * Prevent acpi_gbl_db_method_info from being modified by multiple threads
  410. * concurrently.
  411. *
  412. * Note: The arguments we are passing are used by the ASL test suite
  413. * (aslts). Do not change them without updating the tests.
  414. */
  415. (void)acpi_os_wait_semaphore(info->info_gate, 1, ACPI_WAIT_FOREVER);
  416. if (info->init_args) {
  417. acpi_db_uint32_to_hex_string(info->num_created,
  418. info->index_of_thread_str);
  419. acpi_db_uint32_to_hex_string((u32)acpi_os_get_thread_id(),
  420. info->id_of_thread_str);
  421. }
  422. if (info->threads && (info->num_created < info->num_threads)) {
  423. info->threads[info->num_created++] = acpi_os_get_thread_id();
  424. }
  425. local_info = *info;
  426. local_info.args = local_info.arguments;
  427. local_info.arguments[0] = local_info.num_threads_str;
  428. local_info.arguments[1] = local_info.id_of_thread_str;
  429. local_info.arguments[2] = local_info.index_of_thread_str;
  430. local_info.arguments[3] = NULL;
  431. local_info.types = local_info.arg_types;
  432. (void)acpi_os_signal_semaphore(info->info_gate, 1);
  433. for (i = 0; i < info->num_loops; i++) {
  434. status = acpi_db_execute_method(&local_info, &return_obj);
  435. if (ACPI_FAILURE(status)) {
  436. acpi_os_printf
  437. ("%s During evaluation of %s at iteration %X\n",
  438. acpi_format_exception(status), info->pathname, i);
  439. if (status == AE_ABORT_METHOD) {
  440. break;
  441. }
  442. }
  443. #if 0
  444. if ((i % 100) == 0) {
  445. acpi_os_printf("%u loops, Thread 0x%x\n",
  446. i, acpi_os_get_thread_id());
  447. }
  448. if (return_obj.length) {
  449. acpi_os_printf
  450. ("Evaluation of %s returned object %p Buflen %X\n",
  451. info->pathname, return_obj.pointer,
  452. (u32)return_obj.length);
  453. acpi_db_dump_external_object(return_obj.pointer, 1);
  454. }
  455. #endif
  456. }
  457. /* Signal our completion */
  458. allow = 0;
  459. (void)acpi_os_wait_semaphore(info->thread_complete_gate,
  460. 1, ACPI_WAIT_FOREVER);
  461. info->num_completed++;
  462. if (info->num_completed == info->num_threads) {
  463. /* Do signal for main thread once only */
  464. allow = 1;
  465. }
  466. (void)acpi_os_signal_semaphore(info->thread_complete_gate, 1);
  467. if (allow) {
  468. status = acpi_os_signal_semaphore(info->main_thread_gate, 1);
  469. if (ACPI_FAILURE(status)) {
  470. acpi_os_printf
  471. ("Could not signal debugger thread sync semaphore, %s\n",
  472. acpi_format_exception(status));
  473. }
  474. }
  475. }
  476. /*******************************************************************************
  477. *
  478. * FUNCTION: acpi_db_single_execution_thread
  479. *
  480. * PARAMETERS: context - Method info struct
  481. *
  482. * RETURN: None
  483. *
  484. * DESCRIPTION: Create one thread and execute a method
  485. *
  486. ******************************************************************************/
  487. static void ACPI_SYSTEM_XFACE acpi_db_single_execution_thread(void *context)
  488. {
  489. struct acpi_db_method_info *info = context;
  490. acpi_status status;
  491. struct acpi_buffer return_obj;
  492. acpi_os_printf("\n");
  493. status = acpi_db_execute_method(info, &return_obj);
  494. if (ACPI_FAILURE(status)) {
  495. acpi_os_printf("%s During evaluation of %s\n",
  496. acpi_format_exception(status), info->pathname);
  497. return;
  498. }
  499. /* Display a return object, if any */
  500. if (return_obj.length) {
  501. acpi_os_printf("Evaluation of %s returned object %p, "
  502. "external buffer length %X\n",
  503. acpi_gbl_db_method_info.pathname,
  504. return_obj.pointer, (u32)return_obj.length);
  505. acpi_db_dump_external_object(return_obj.pointer, 1);
  506. }
  507. acpi_os_printf("\nBackground thread completed\n%c ",
  508. ACPI_DEBUGGER_COMMAND_PROMPT);
  509. }
  510. /*******************************************************************************
  511. *
  512. * FUNCTION: acpi_db_create_execution_thread
  513. *
  514. * PARAMETERS: method_name_arg - Control method to execute
  515. * arguments - Array of arguments to the method
  516. * types - Corresponding array of object types
  517. *
  518. * RETURN: None
  519. *
  520. * DESCRIPTION: Create a single thread to evaluate a namespace object. Handles
  521. * arguments passed on command line for control methods.
  522. *
  523. ******************************************************************************/
  524. void
  525. acpi_db_create_execution_thread(char *method_name_arg,
  526. char **arguments, acpi_object_type *types)
  527. {
  528. acpi_status status;
  529. u32 i;
  530. memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
  531. acpi_gbl_db_method_info.name = method_name_arg;
  532. acpi_gbl_db_method_info.init_args = 1;
  533. acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments;
  534. acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types;
  535. /* Setup method arguments, up to 7 (0-6) */
  536. for (i = 0; (i < ACPI_METHOD_NUM_ARGS) && *arguments; i++) {
  537. acpi_gbl_db_method_info.arguments[i] = *arguments;
  538. arguments++;
  539. acpi_gbl_db_method_info.arg_types[i] = *types;
  540. types++;
  541. }
  542. status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
  543. if (ACPI_FAILURE(status)) {
  544. return;
  545. }
  546. /* Get the NS node, determines existence also */
  547. status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
  548. &acpi_gbl_db_method_info.method);
  549. if (ACPI_FAILURE(status)) {
  550. acpi_os_printf("%s Could not get handle for %s\n",
  551. acpi_format_exception(status),
  552. acpi_gbl_db_method_info.pathname);
  553. return;
  554. }
  555. status = acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD,
  556. acpi_db_single_execution_thread,
  557. &acpi_gbl_db_method_info);
  558. if (ACPI_FAILURE(status)) {
  559. return;
  560. }
  561. acpi_os_printf("\nBackground thread started\n");
  562. }
  563. /*******************************************************************************
  564. *
  565. * FUNCTION: acpi_db_create_execution_threads
  566. *
  567. * PARAMETERS: num_threads_arg - Number of threads to create
  568. * num_loops_arg - Loop count for the thread(s)
  569. * method_name_arg - Control method to execute
  570. *
  571. * RETURN: None
  572. *
  573. * DESCRIPTION: Create threads to execute method(s)
  574. *
  575. ******************************************************************************/
  576. void
  577. acpi_db_create_execution_threads(char *num_threads_arg,
  578. char *num_loops_arg, char *method_name_arg)
  579. {
  580. acpi_status status;
  581. u32 num_threads;
  582. u32 num_loops;
  583. u32 i;
  584. u32 size;
  585. acpi_mutex main_thread_gate;
  586. acpi_mutex thread_complete_gate;
  587. acpi_mutex info_gate;
  588. /* Get the arguments */
  589. num_threads = strtoul(num_threads_arg, NULL, 0);
  590. num_loops = strtoul(num_loops_arg, NULL, 0);
  591. if (!num_threads || !num_loops) {
  592. acpi_os_printf("Bad argument: Threads %X, Loops %X\n",
  593. num_threads, num_loops);
  594. return;
  595. }
  596. /*
  597. * Create the semaphore for synchronization of
  598. * the created threads with the main thread.
  599. */
  600. status = acpi_os_create_semaphore(1, 0, &main_thread_gate);
  601. if (ACPI_FAILURE(status)) {
  602. acpi_os_printf("Could not create semaphore for "
  603. "synchronization with the main thread, %s\n",
  604. acpi_format_exception(status));
  605. return;
  606. }
  607. /*
  608. * Create the semaphore for synchronization
  609. * between the created threads.
  610. */
  611. status = acpi_os_create_semaphore(1, 1, &thread_complete_gate);
  612. if (ACPI_FAILURE(status)) {
  613. acpi_os_printf("Could not create semaphore for "
  614. "synchronization between the created threads, %s\n",
  615. acpi_format_exception(status));
  616. (void)acpi_os_delete_semaphore(main_thread_gate);
  617. return;
  618. }
  619. status = acpi_os_create_semaphore(1, 1, &info_gate);
  620. if (ACPI_FAILURE(status)) {
  621. acpi_os_printf("Could not create semaphore for "
  622. "synchronization of AcpiGbl_DbMethodInfo, %s\n",
  623. acpi_format_exception(status));
  624. (void)acpi_os_delete_semaphore(thread_complete_gate);
  625. (void)acpi_os_delete_semaphore(main_thread_gate);
  626. return;
  627. }
  628. memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
  629. /* Array to store IDs of threads */
  630. acpi_gbl_db_method_info.num_threads = num_threads;
  631. size = sizeof(acpi_thread_id) * acpi_gbl_db_method_info.num_threads;
  632. acpi_gbl_db_method_info.threads = acpi_os_allocate(size);
  633. if (acpi_gbl_db_method_info.threads == NULL) {
  634. acpi_os_printf("No memory for thread IDs array\n");
  635. (void)acpi_os_delete_semaphore(main_thread_gate);
  636. (void)acpi_os_delete_semaphore(thread_complete_gate);
  637. (void)acpi_os_delete_semaphore(info_gate);
  638. return;
  639. }
  640. memset(acpi_gbl_db_method_info.threads, 0, size);
  641. /* Setup the context to be passed to each thread */
  642. acpi_gbl_db_method_info.name = method_name_arg;
  643. acpi_gbl_db_method_info.flags = 0;
  644. acpi_gbl_db_method_info.num_loops = num_loops;
  645. acpi_gbl_db_method_info.main_thread_gate = main_thread_gate;
  646. acpi_gbl_db_method_info.thread_complete_gate = thread_complete_gate;
  647. acpi_gbl_db_method_info.info_gate = info_gate;
  648. /* Init arguments to be passed to method */
  649. acpi_gbl_db_method_info.init_args = 1;
  650. acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments;
  651. acpi_gbl_db_method_info.arguments[0] =
  652. acpi_gbl_db_method_info.num_threads_str;
  653. acpi_gbl_db_method_info.arguments[1] =
  654. acpi_gbl_db_method_info.id_of_thread_str;
  655. acpi_gbl_db_method_info.arguments[2] =
  656. acpi_gbl_db_method_info.index_of_thread_str;
  657. acpi_gbl_db_method_info.arguments[3] = NULL;
  658. acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types;
  659. acpi_gbl_db_method_info.arg_types[0] = ACPI_TYPE_INTEGER;
  660. acpi_gbl_db_method_info.arg_types[1] = ACPI_TYPE_INTEGER;
  661. acpi_gbl_db_method_info.arg_types[2] = ACPI_TYPE_INTEGER;
  662. acpi_db_uint32_to_hex_string(num_threads,
  663. acpi_gbl_db_method_info.num_threads_str);
  664. status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
  665. if (ACPI_FAILURE(status)) {
  666. goto cleanup_and_exit;
  667. }
  668. /* Get the NS node, determines existence also */
  669. status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
  670. &acpi_gbl_db_method_info.method);
  671. if (ACPI_FAILURE(status)) {
  672. acpi_os_printf("%s Could not get handle for %s\n",
  673. acpi_format_exception(status),
  674. acpi_gbl_db_method_info.pathname);
  675. goto cleanup_and_exit;
  676. }
  677. /* Create the threads */
  678. acpi_os_printf("Creating %X threads to execute %X times each\n",
  679. num_threads, num_loops);
  680. for (i = 0; i < (num_threads); i++) {
  681. status =
  682. acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD,
  683. acpi_db_method_thread,
  684. &acpi_gbl_db_method_info);
  685. if (ACPI_FAILURE(status)) {
  686. break;
  687. }
  688. }
  689. /* Wait for all threads to complete */
  690. (void)acpi_os_wait_semaphore(main_thread_gate, 1, ACPI_WAIT_FOREVER);
  691. acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
  692. acpi_os_printf("All threads (%X) have completed\n", num_threads);
  693. acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
  694. cleanup_and_exit:
  695. /* Cleanup and exit */
  696. (void)acpi_os_delete_semaphore(main_thread_gate);
  697. (void)acpi_os_delete_semaphore(thread_complete_gate);
  698. (void)acpi_os_delete_semaphore(info_gate);
  699. acpi_os_free(acpi_gbl_db_method_info.threads);
  700. acpi_gbl_db_method_info.threads = NULL;
  701. }