0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "acdispat.h"
0013 #include "acinterp.h"
0014 #include "acnamesp.h"
0015 #include "acparser.h"
0016 #include "amlcode.h"
0017 #include "acdebug.h"
0018
0019 #define _COMPONENT ACPI_DISPATCHER
0020 ACPI_MODULE_NAME("dsmethod")
0021
0022
0023 static acpi_status
0024 acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state,
0025 union acpi_parse_object **out_op);
0026
0027 static acpi_status
0028 acpi_ds_create_method_mutex(union acpi_operand_object *method_desc);
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054 acpi_status
0055 acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
0056 union acpi_operand_object *obj_desc)
0057 {
0058 acpi_status status;
0059 union acpi_parse_object *op = NULL;
0060 struct acpi_walk_state *walk_state;
0061
0062 ACPI_FUNCTION_TRACE_PTR(ds_auto_serialize_method, node);
0063
0064 ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
0065 "Method auto-serialization parse [%4.4s] %p\n",
0066 acpi_ut_get_node_name(node), node));
0067
0068
0069
0070 op = acpi_ps_alloc_op(AML_METHOD_OP, obj_desc->method.aml_start);
0071 if (!op) {
0072 return_ACPI_STATUS(AE_NO_MEMORY);
0073 }
0074
0075 acpi_ps_set_name(op, node->name.integer);
0076 op->common.node = node;
0077
0078
0079
0080 walk_state =
0081 acpi_ds_create_walk_state(node->owner_id, NULL, NULL, NULL);
0082 if (!walk_state) {
0083 acpi_ps_free_op(op);
0084 return_ACPI_STATUS(AE_NO_MEMORY);
0085 }
0086
0087 status = acpi_ds_init_aml_walk(walk_state, op, node,
0088 obj_desc->method.aml_start,
0089 obj_desc->method.aml_length, NULL, 0);
0090 if (ACPI_FAILURE(status)) {
0091 acpi_ds_delete_walk_state(walk_state);
0092 acpi_ps_free_op(op);
0093 return_ACPI_STATUS(status);
0094 }
0095
0096 walk_state->descending_callback = acpi_ds_detect_named_opcodes;
0097
0098
0099
0100 status = acpi_ps_parse_aml(walk_state);
0101
0102 acpi_ps_delete_parse_tree(op);
0103 return_ACPI_STATUS(status);
0104 }
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121 static acpi_status
0122 acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state,
0123 union acpi_parse_object **out_op)
0124 {
0125
0126 ACPI_FUNCTION_NAME(acpi_ds_detect_named_opcodes);
0127
0128
0129
0130 if (!
0131 (walk_state->op_info->
0132 flags & (AML_NAMED | AML_CREATE | AML_FIELD))) {
0133 return (AE_OK);
0134 }
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146 walk_state->method_desc->method.sync_level = 0;
0147 walk_state->method_desc->method.info_flags |=
0148 (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
0149
0150 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
0151 "Method serialized [%4.4s] %p - [%s] (%4.4X)\n",
0152 walk_state->method_node->name.ascii,
0153 walk_state->method_node, walk_state->op_info->name,
0154 walk_state->opcode));
0155
0156
0157
0158 return (AE_CTRL_TERMINATE);
0159 }
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177 acpi_status
0178 acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
0179 {
0180 u32 aml_offset;
0181 acpi_name name = 0;
0182
0183 ACPI_FUNCTION_ENTRY();
0184
0185
0186
0187 if (ACPI_SUCCESS(status) || (status & AE_CODE_CONTROL)) {
0188 return (status);
0189 }
0190
0191
0192
0193 if (acpi_gbl_exception_handler) {
0194
0195
0196
0197 acpi_ex_exit_interpreter();
0198
0199
0200
0201
0202
0203 aml_offset = (u32)ACPI_PTR_DIFF(walk_state->aml,
0204 walk_state->parser_state.
0205 aml_start);
0206
0207 if (walk_state->method_node) {
0208 name = walk_state->method_node->name.integer;
0209 } else if (walk_state->deferred_node) {
0210 name = walk_state->deferred_node->name.integer;
0211 }
0212
0213 status = acpi_gbl_exception_handler(status, name,
0214 walk_state->opcode,
0215 aml_offset, NULL);
0216 acpi_ex_enter_interpreter();
0217 }
0218
0219 acpi_ds_clear_implicit_return(walk_state);
0220
0221 if (ACPI_FAILURE(status)) {
0222 acpi_ds_dump_method_stack(status, walk_state, walk_state->op);
0223
0224
0225
0226 #ifdef ACPI_DEBUGGER
0227 acpi_db_dump_method_info(status, walk_state);
0228 #endif
0229 }
0230
0231 return (status);
0232 }
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246 static acpi_status
0247 acpi_ds_create_method_mutex(union acpi_operand_object *method_desc)
0248 {
0249 union acpi_operand_object *mutex_desc;
0250 acpi_status status;
0251
0252 ACPI_FUNCTION_TRACE(ds_create_method_mutex);
0253
0254
0255
0256 mutex_desc = acpi_ut_create_internal_object(ACPI_TYPE_MUTEX);
0257 if (!mutex_desc) {
0258 return_ACPI_STATUS(AE_NO_MEMORY);
0259 }
0260
0261
0262
0263 status = acpi_os_create_mutex(&mutex_desc->mutex.os_mutex);
0264 if (ACPI_FAILURE(status)) {
0265 acpi_ut_delete_object_desc(mutex_desc);
0266 return_ACPI_STATUS(status);
0267 }
0268
0269 mutex_desc->mutex.sync_level = method_desc->method.sync_level;
0270 method_desc->method.mutex = mutex_desc;
0271 return_ACPI_STATUS(AE_OK);
0272 }
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291 acpi_status
0292 acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
0293 union acpi_operand_object *obj_desc,
0294 struct acpi_walk_state *walk_state)
0295 {
0296 acpi_status status = AE_OK;
0297
0298 ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node);
0299
0300 if (!method_node) {
0301 return_ACPI_STATUS(AE_NULL_ENTRY);
0302 }
0303
0304 acpi_ex_start_trace_method(method_node, obj_desc, walk_state);
0305
0306
0307
0308 if (obj_desc->method.thread_count == ACPI_UINT8_MAX) {
0309 ACPI_ERROR((AE_INFO,
0310 "Method reached maximum reentrancy limit (255)"));
0311 return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
0312 }
0313
0314
0315
0316
0317 if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) {
0318
0319
0320
0321
0322
0323 if (!obj_desc->method.mutex) {
0324 status = acpi_ds_create_method_mutex(obj_desc);
0325 if (ACPI_FAILURE(status)) {
0326 return_ACPI_STATUS(status);
0327 }
0328 }
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341 if (walk_state &&
0342 (!(obj_desc->method.
0343 info_flags & ACPI_METHOD_IGNORE_SYNC_LEVEL))
0344 && (walk_state->thread->current_sync_level >
0345 obj_desc->method.mutex->mutex.sync_level)) {
0346 ACPI_ERROR((AE_INFO,
0347 "Cannot acquire Mutex for method [%4.4s]"
0348 ", current SyncLevel is too large (%u)",
0349 acpi_ut_get_node_name(method_node),
0350 walk_state->thread->current_sync_level));
0351
0352 return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
0353 }
0354
0355
0356
0357
0358
0359 if (!walk_state ||
0360 !obj_desc->method.mutex->mutex.thread_id ||
0361 (walk_state->thread->thread_id !=
0362 obj_desc->method.mutex->mutex.thread_id)) {
0363
0364
0365
0366
0367 status =
0368 acpi_ex_system_wait_mutex(obj_desc->method.mutex->
0369 mutex.os_mutex,
0370 ACPI_WAIT_FOREVER);
0371 if (ACPI_FAILURE(status)) {
0372 return_ACPI_STATUS(status);
0373 }
0374
0375
0376
0377 if (walk_state) {
0378 obj_desc->method.mutex->mutex.
0379 original_sync_level =
0380 walk_state->thread->current_sync_level;
0381
0382 obj_desc->method.mutex->mutex.thread_id =
0383 walk_state->thread->thread_id;
0384
0385
0386
0387
0388
0389
0390
0391
0392 if (!(obj_desc->method.info_flags &
0393 ACPI_METHOD_IGNORE_SYNC_LEVEL)) {
0394 walk_state->thread->current_sync_level =
0395 obj_desc->method.sync_level;
0396 }
0397 } else {
0398 obj_desc->method.mutex->mutex.
0399 original_sync_level =
0400 obj_desc->method.mutex->mutex.sync_level;
0401
0402 obj_desc->method.mutex->mutex.thread_id =
0403 acpi_os_get_thread_id();
0404 }
0405 }
0406
0407
0408
0409 obj_desc->method.mutex->mutex.acquisition_depth++;
0410 }
0411
0412
0413
0414
0415
0416
0417 if (!obj_desc->method.owner_id) {
0418 status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
0419 if (ACPI_FAILURE(status)) {
0420 goto cleanup;
0421 }
0422 }
0423
0424
0425
0426
0427
0428 obj_desc->method.thread_count++;
0429 acpi_method_count++;
0430 return_ACPI_STATUS(status);
0431
0432 cleanup:
0433
0434
0435 if (obj_desc->method.mutex) {
0436 acpi_os_release_mutex(obj_desc->method.mutex->mutex.os_mutex);
0437 }
0438 return_ACPI_STATUS(status);
0439 }
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455 acpi_status
0456 acpi_ds_call_control_method(struct acpi_thread_state *thread,
0457 struct acpi_walk_state *this_walk_state,
0458 union acpi_parse_object *op)
0459 {
0460 acpi_status status;
0461 struct acpi_namespace_node *method_node;
0462 struct acpi_walk_state *next_walk_state = NULL;
0463 union acpi_operand_object *obj_desc;
0464 struct acpi_evaluate_info *info;
0465 u32 i;
0466
0467 ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state);
0468
0469 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
0470 "Calling method %p, currentstate=%p\n",
0471 this_walk_state->prev_op, this_walk_state));
0472
0473
0474
0475
0476 method_node = this_walk_state->method_call_node;
0477 if (!method_node) {
0478 return_ACPI_STATUS(AE_NULL_ENTRY);
0479 }
0480
0481 obj_desc = acpi_ns_get_attached_object(method_node);
0482 if (!obj_desc) {
0483 return_ACPI_STATUS(AE_NULL_OBJECT);
0484 }
0485
0486
0487
0488 status =
0489 acpi_ds_begin_method_execution(method_node, obj_desc,
0490 this_walk_state);
0491 if (ACPI_FAILURE(status)) {
0492 return_ACPI_STATUS(status);
0493 }
0494
0495
0496
0497 next_walk_state =
0498 acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, obj_desc,
0499 thread);
0500 if (!next_walk_state) {
0501 status = AE_NO_MEMORY;
0502 goto cleanup;
0503 }
0504
0505
0506
0507
0508
0509
0510 this_walk_state->operands[this_walk_state->num_operands] = NULL;
0511
0512
0513
0514
0515
0516
0517 info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
0518 if (!info) {
0519 status = AE_NO_MEMORY;
0520 goto cleanup;
0521 }
0522
0523 info->parameters = &this_walk_state->operands[0];
0524
0525 status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
0526 obj_desc->method.aml_start,
0527 obj_desc->method.aml_length, info,
0528 ACPI_IMODE_EXECUTE);
0529
0530 ACPI_FREE(info);
0531 if (ACPI_FAILURE(status)) {
0532 goto cleanup;
0533 }
0534
0535 next_walk_state->method_nesting_depth =
0536 this_walk_state->method_nesting_depth + 1;
0537
0538
0539
0540
0541
0542 for (i = 0; i < obj_desc->method.param_count; i++) {
0543 acpi_ut_remove_reference(this_walk_state->operands[i]);
0544 this_walk_state->operands[i] = NULL;
0545 }
0546
0547
0548
0549 this_walk_state->num_operands = 0;
0550
0551 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
0552 "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
0553 method_node->name.ascii, next_walk_state));
0554
0555 this_walk_state->method_pathname =
0556 acpi_ns_get_normalized_pathname(method_node, TRUE);
0557 this_walk_state->method_is_nested = TRUE;
0558
0559
0560
0561 ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
0562 "%-26s: %*s%s\n", " Nested method call",
0563 next_walk_state->method_nesting_depth * 3, " ",
0564 &this_walk_state->method_pathname[1]));
0565
0566
0567
0568 if (obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) {
0569 status =
0570 obj_desc->method.dispatch.implementation(next_walk_state);
0571 if (status == AE_OK) {
0572 status = AE_CTRL_TERMINATE;
0573 }
0574 }
0575
0576 return_ACPI_STATUS(status);
0577
0578 cleanup:
0579
0580
0581
0582 acpi_ds_terminate_control_method(obj_desc, next_walk_state);
0583 acpi_ds_delete_walk_state(next_walk_state);
0584
0585 return_ACPI_STATUS(status);
0586 }
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596
0597
0598
0599
0600
0601
0602 acpi_status
0603 acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
0604 union acpi_operand_object *return_desc)
0605 {
0606 acpi_status status;
0607 int same_as_implicit_return;
0608
0609 ACPI_FUNCTION_TRACE_PTR(ds_restart_control_method, walk_state);
0610
0611 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
0612 "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
0613 acpi_ut_get_node_name(walk_state->method_node),
0614 walk_state->method_call_op, return_desc));
0615
0616 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
0617 " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
0618 walk_state->return_used,
0619 walk_state->results, walk_state));
0620
0621
0622
0623 if (return_desc) {
0624
0625
0626
0627 same_as_implicit_return =
0628 (walk_state->implicit_return_obj == return_desc);
0629
0630
0631
0632 if (walk_state->return_used) {
0633
0634
0635
0636 status = acpi_ds_result_push(return_desc, walk_state);
0637 if (ACPI_FAILURE(status)) {
0638 acpi_ut_remove_reference(return_desc);
0639 return_ACPI_STATUS(status);
0640 }
0641
0642
0643
0644
0645
0646 walk_state->return_desc = return_desc;
0647 }
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659
0660 else if (!acpi_ds_do_implicit_return
0661 (return_desc, walk_state, FALSE)
0662 || same_as_implicit_return) {
0663
0664
0665
0666
0667
0668 acpi_ut_remove_reference(return_desc);
0669 }
0670 }
0671
0672 return_ACPI_STATUS(AE_OK);
0673 }
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688
0689
0690
0691
0692 void
0693 acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
0694 struct acpi_walk_state *walk_state)
0695 {
0696
0697 ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state);
0698
0699
0700
0701 if (!method_desc) {
0702 return_VOID;
0703 }
0704
0705 if (walk_state) {
0706
0707
0708
0709 acpi_ds_method_data_delete_all(walk_state);
0710
0711
0712
0713
0714
0715
0716
0717
0718
0719 if (!(method_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL)
0720 && (method_desc->method.thread_count == 1)) {
0721
0722
0723
0724 (void)acpi_ex_exit_interpreter();
0725 acpi_ns_delete_namespace_subtree(walk_state->
0726 method_node);
0727 (void)acpi_ex_enter_interpreter();
0728
0729
0730
0731
0732
0733
0734
0735
0736 if (method_desc->method.
0737 info_flags & ACPI_METHOD_MODIFIED_NAMESPACE) {
0738 (void)acpi_ex_exit_interpreter();
0739 acpi_ns_delete_namespace_by_owner(method_desc->
0740 method.
0741 owner_id);
0742 (void)acpi_ex_enter_interpreter();
0743 method_desc->method.info_flags &=
0744 ~ACPI_METHOD_MODIFIED_NAMESPACE;
0745 }
0746 }
0747
0748
0749
0750
0751
0752 if (method_desc->method.mutex) {
0753
0754
0755
0756 method_desc->method.mutex->mutex.acquisition_depth--;
0757 if (!method_desc->method.mutex->mutex.acquisition_depth) {
0758 walk_state->thread->current_sync_level =
0759 method_desc->method.mutex->mutex.
0760 original_sync_level;
0761
0762 acpi_os_release_mutex(method_desc->method.
0763 mutex->mutex.os_mutex);
0764 method_desc->method.mutex->mutex.thread_id = 0;
0765 }
0766 }
0767 }
0768
0769
0770
0771 if (method_desc->method.thread_count) {
0772 method_desc->method.thread_count--;
0773 } else {
0774 ACPI_ERROR((AE_INFO, "Invalid zero thread count in method"));
0775 }
0776
0777
0778
0779 if (method_desc->method.thread_count) {
0780
0781
0782
0783
0784 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
0785 "*** Completed execution of one thread, %u threads remaining\n",
0786 method_desc->method.thread_count));
0787 } else {
0788
0789
0790
0791
0792
0793
0794
0795
0796
0797
0798
0799
0800 if (method_desc->method.
0801 info_flags & ACPI_METHOD_SERIALIZED_PENDING) {
0802 if (walk_state) {
0803 ACPI_INFO(("Marking method %4.4s as Serialized "
0804 "because of AE_ALREADY_EXISTS error",
0805 walk_state->method_node->name.
0806 ascii));
0807 }
0808
0809
0810
0811
0812
0813
0814
0815
0816
0817
0818
0819
0820 method_desc->method.info_flags &=
0821 ~ACPI_METHOD_SERIALIZED_PENDING;
0822
0823 method_desc->method.info_flags |=
0824 (ACPI_METHOD_SERIALIZED |
0825 ACPI_METHOD_IGNORE_SYNC_LEVEL);
0826 method_desc->method.sync_level = 0;
0827 }
0828
0829
0830
0831 if (!
0832 (method_desc->method.
0833 info_flags & ACPI_METHOD_MODULE_LEVEL)) {
0834 acpi_ut_release_owner_id(&method_desc->method.owner_id);
0835 }
0836 }
0837
0838 acpi_ex_stop_trace_method((struct acpi_namespace_node *)method_desc->
0839 method.node, method_desc, walk_state);
0840
0841 return_VOID;
0842 }