diff options
author | Bob Moore <robert.moore@intel.com> | 2008-04-10 11:06:44 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-04-22 23:01:51 -0400 |
commit | cca97b81564c5edbc8700ebb64fc2b4e13dfa51f (patch) | |
tree | cf997613fe23d04d05be41d727602016e0a1e350 /drivers/acpi/dispatcher/dsfield.c | |
parent | 66e2c0bcc5f6b8454d9091f6ba9ef4090abca4fd (diff) |
ACPICA: Fix for some local named nodes not marked temporary and to disallow duplicates
Fixed a problem with the CreateField, CreateXXXField (Bit, Byte,
Word, Dword, Qword), Field, BankField, and IndexField operators
when invoked from inside an executing control method. In this case,
these operators created namespace nodes that were incorrectly
left marked as permanent nodes instead of temporary nodes. This
could cause a problem if there is race condition between an
exiting control method and a running namespace walk. (Reported
by Linn Crosetto). Fixed a problem where the CreateField and
CreateXXXField operators would incorrectly allow duplicate names
(the name of the field) with no exception generated.
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/dispatcher/dsfield.c')
-rw-r--r-- | drivers/acpi/dispatcher/dsfield.c | 121 |
1 files changed, 73 insertions, 48 deletions
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c index e87f6bfbfa5c..0befcff19f5a 100644 --- a/drivers/acpi/dispatcher/dsfield.c +++ b/drivers/acpi/dispatcher/dsfield.c | |||
@@ -89,12 +89,16 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, | |||
89 | 89 | ||
90 | ACPI_FUNCTION_TRACE(ds_create_buffer_field); | 90 | ACPI_FUNCTION_TRACE(ds_create_buffer_field); |
91 | 91 | ||
92 | /* Get the name_string argument */ | 92 | /* |
93 | 93 | * Get the name_string argument (name of the new buffer_field) | |
94 | */ | ||
94 | if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { | 95 | if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { |
96 | |||
97 | /* For create_field, name is the 4th argument */ | ||
98 | |||
95 | arg = acpi_ps_get_arg(op, 3); | 99 | arg = acpi_ps_get_arg(op, 3); |
96 | } else { | 100 | } else { |
97 | /* Create Bit/Byte/Word/Dword field */ | 101 | /* For all other create_xXXField operators, name is the 3rd argument */ |
98 | 102 | ||
99 | arg = acpi_ps_get_arg(op, 2); | 103 | arg = acpi_ps_get_arg(op, 2); |
100 | } | 104 | } |
@@ -107,26 +111,30 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, | |||
107 | node = walk_state->deferred_node; | 111 | node = walk_state->deferred_node; |
108 | status = AE_OK; | 112 | status = AE_OK; |
109 | } else { | 113 | } else { |
110 | /* | 114 | /* Execute flag should always be set when this function is entered */ |
111 | * During the load phase, we want to enter the name of the field into | 115 | |
112 | * the namespace. During the execute phase (when we evaluate the size | 116 | if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) { |
113 | * operand), we want to lookup the name | 117 | return_ACPI_STATUS(AE_AML_INTERNAL); |
114 | */ | ||
115 | if (walk_state->parse_flags & ACPI_PARSE_EXECUTE) { | ||
116 | flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE; | ||
117 | } else { | ||
118 | flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | | ||
119 | ACPI_NS_ERROR_IF_FOUND; | ||
120 | } | 118 | } |
121 | 119 | ||
122 | /* | 120 | /* Creating new namespace node, should not already exist */ |
123 | * Enter the name_string into the namespace | 121 | |
124 | */ | 122 | flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | |
123 | ACPI_NS_ERROR_IF_FOUND; | ||
124 | |||
125 | /* Mark node temporary if we are executing a method */ | ||
126 | |||
127 | if (walk_state->method_node) { | ||
128 | flags |= ACPI_NS_TEMPORARY; | ||
129 | } | ||
130 | |||
131 | /* Enter the name_string into the namespace */ | ||
132 | |||
125 | status = | 133 | status = |
126 | acpi_ns_lookup(walk_state->scope_info, | 134 | acpi_ns_lookup(walk_state->scope_info, |
127 | arg->common.value.string, ACPI_TYPE_ANY, | 135 | arg->common.value.string, ACPI_TYPE_ANY, |
128 | ACPI_IMODE_LOAD_PASS1, flags, walk_state, | 136 | ACPI_IMODE_LOAD_PASS1, flags, walk_state, |
129 | &(node)); | 137 | &node); |
130 | if (ACPI_FAILURE(status)) { | 138 | if (ACPI_FAILURE(status)) { |
131 | ACPI_ERROR_NAMESPACE(arg->common.value.string, status); | 139 | ACPI_ERROR_NAMESPACE(arg->common.value.string, status); |
132 | return_ACPI_STATUS(status); | 140 | return_ACPI_STATUS(status); |
@@ -136,13 +144,13 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, | |||
136 | /* | 144 | /* |
137 | * We could put the returned object (Node) on the object stack for later, | 145 | * We could put the returned object (Node) on the object stack for later, |
138 | * but for now, we will put it in the "op" object that the parser uses, | 146 | * but for now, we will put it in the "op" object that the parser uses, |
139 | * so we can get it again at the end of this scope | 147 | * so we can get it again at the end of this scope. |
140 | */ | 148 | */ |
141 | op->common.node = node; | 149 | op->common.node = node; |
142 | 150 | ||
143 | /* | 151 | /* |
144 | * If there is no object attached to the node, this node was just created | 152 | * If there is no object attached to the node, this node was just created |
145 | * and we need to create the field object. Otherwise, this was a lookup | 153 | * and we need to create the field object. Otherwise, this was a lookup |
146 | * of an existing node and we don't want to create the field object again. | 154 | * of an existing node and we don't want to create the field object again. |
147 | */ | 155 | */ |
148 | obj_desc = acpi_ns_get_attached_object(node); | 156 | obj_desc = acpi_ns_get_attached_object(node); |
@@ -164,9 +172,8 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, | |||
164 | } | 172 | } |
165 | 173 | ||
166 | /* | 174 | /* |
167 | * Remember location in AML stream of the field unit | 175 | * Remember location in AML stream of the field unit opcode and operands -- |
168 | * opcode and operands -- since the buffer and index | 176 | * since the buffer and index operands must be evaluated. |
169 | * operands must be evaluated. | ||
170 | */ | 177 | */ |
171 | second_desc = obj_desc->common.next_object; | 178 | second_desc = obj_desc->common.next_object; |
172 | second_desc->extra.aml_start = op->named.data; | 179 | second_desc->extra.aml_start = op->named.data; |
@@ -261,7 +268,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, | |||
261 | 268 | ||
262 | case AML_INT_NAMEDFIELD_OP: | 269 | case AML_INT_NAMEDFIELD_OP: |
263 | 270 | ||
264 | /* Lookup the name */ | 271 | /* Lookup the name, it should already exist */ |
265 | 272 | ||
266 | status = acpi_ns_lookup(walk_state->scope_info, | 273 | status = acpi_ns_lookup(walk_state->scope_info, |
267 | (char *)&arg->named.name, | 274 | (char *)&arg->named.name, |
@@ -272,19 +279,16 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, | |||
272 | if (ACPI_FAILURE(status)) { | 279 | if (ACPI_FAILURE(status)) { |
273 | ACPI_ERROR_NAMESPACE((char *)&arg->named.name, | 280 | ACPI_ERROR_NAMESPACE((char *)&arg->named.name, |
274 | status); | 281 | status); |
275 | if (status != AE_ALREADY_EXISTS) { | 282 | return_ACPI_STATUS(status); |
276 | return_ACPI_STATUS(status); | ||
277 | } | ||
278 | |||
279 | /* Already exists, ignore error */ | ||
280 | } else { | 283 | } else { |
281 | arg->common.node = info->field_node; | 284 | arg->common.node = info->field_node; |
282 | info->field_bit_length = arg->common.value.size; | 285 | info->field_bit_length = arg->common.value.size; |
283 | 286 | ||
284 | /* | 287 | /* |
285 | * If there is no object attached to the node, this node was just created | 288 | * If there is no object attached to the node, this node was |
286 | * and we need to create the field object. Otherwise, this was a lookup | 289 | * just created and we need to create the field object. |
287 | * of an existing node and we don't want to create the field object again. | 290 | * Otherwise, this was a lookup of an existing node and we |
291 | * don't want to create the field object again. | ||
288 | */ | 292 | */ |
289 | if (!acpi_ns_get_attached_object | 293 | if (!acpi_ns_get_attached_object |
290 | (info->field_node)) { | 294 | (info->field_node)) { |
@@ -409,18 +413,23 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, | |||
409 | 413 | ||
410 | ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op); | 414 | ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op); |
411 | 415 | ||
412 | /* | 416 | /* Execute flag should always be set when this function is entered */ |
413 | * During the load phase, we want to enter the name of the field into | 417 | |
414 | * the namespace. During the execute phase (when we evaluate the bank_value | 418 | if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) { |
415 | * operand), we want to lookup the name. | 419 | if (walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP) { |
416 | */ | 420 | |
417 | if (walk_state->deferred_node) { | 421 | /* bank_field Op is deferred, just return OK */ |
418 | flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE; | 422 | |
419 | } else { | 423 | return_ACPI_STATUS(AE_OK); |
420 | flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | | 424 | } |
421 | ACPI_NS_ERROR_IF_FOUND; | 425 | |
426 | return_ACPI_STATUS(AE_AML_INTERNAL); | ||
422 | } | 427 | } |
423 | 428 | ||
429 | /* | ||
430 | * Get the field_list argument for this opcode. This is the start of the | ||
431 | * list of field elements. | ||
432 | */ | ||
424 | switch (walk_state->opcode) { | 433 | switch (walk_state->opcode) { |
425 | case AML_FIELD_OP: | 434 | case AML_FIELD_OP: |
426 | arg = acpi_ps_get_arg(op, 2); | 435 | arg = acpi_ps_get_arg(op, 2); |
@@ -441,18 +450,34 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, | |||
441 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 450 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
442 | } | 451 | } |
443 | 452 | ||
453 | if (!arg) { | ||
454 | return_ACPI_STATUS(AE_AML_NO_OPERAND); | ||
455 | } | ||
456 | |||
457 | /* Creating new namespace node(s), should not already exist */ | ||
458 | |||
459 | flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | | ||
460 | ACPI_NS_ERROR_IF_FOUND; | ||
461 | |||
462 | /* Mark node(s) temporary if we are executing a method */ | ||
463 | |||
464 | if (walk_state->method_node) { | ||
465 | flags |= ACPI_NS_TEMPORARY; | ||
466 | } | ||
467 | |||
444 | /* | 468 | /* |
445 | * Walk the list of entries in the field_list | 469 | * Walk the list of entries in the field_list |
446 | */ | 470 | */ |
447 | while (arg) { | 471 | while (arg) { |
448 | 472 | /* | |
449 | /* Ignore OFFSET and ACCESSAS terms here */ | 473 | * Ignore OFFSET and ACCESSAS terms here; we are only interested in the |
450 | 474 | * field names in order to enter them into the namespace. | |
475 | */ | ||
451 | if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { | 476 | if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { |
452 | status = acpi_ns_lookup(walk_state->scope_info, | 477 | status = acpi_ns_lookup(walk_state->scope_info, |
453 | (char *)&arg->named.name, | 478 | (char *)&arg->named.name, type, |
454 | type, ACPI_IMODE_LOAD_PASS1, | 479 | ACPI_IMODE_LOAD_PASS1, flags, |
455 | flags, walk_state, &node); | 480 | walk_state, &node); |
456 | if (ACPI_FAILURE(status)) { | 481 | if (ACPI_FAILURE(status)) { |
457 | ACPI_ERROR_NAMESPACE((char *)&arg->named.name, | 482 | ACPI_ERROR_NAMESPACE((char *)&arg->named.name, |
458 | status); | 483 | status); |
@@ -468,7 +493,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, | |||
468 | arg->common.node = node; | 493 | arg->common.node = node; |
469 | } | 494 | } |
470 | 495 | ||
471 | /* Move to next field in the list */ | 496 | /* Get the next field element in the list */ |
472 | 497 | ||
473 | arg = arg->common.next; | 498 | arg = arg->common.next; |
474 | } | 499 | } |