1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: dsopcode - Dispatcher support for regions and fields |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acparser.h" |
13 | #include "amlcode.h" |
14 | #include "acdispat.h" |
15 | #include "acinterp.h" |
16 | #include "acnamesp.h" |
17 | #include "acevents.h" |
18 | #include "actables.h" |
19 | |
20 | #define _COMPONENT ACPI_DISPATCHER |
21 | ACPI_MODULE_NAME("dsopcode" ) |
22 | |
23 | /* Local prototypes */ |
24 | static acpi_status |
25 | acpi_ds_init_buffer_field(u16 aml_opcode, |
26 | union acpi_operand_object *obj_desc, |
27 | union acpi_operand_object *buffer_desc, |
28 | union acpi_operand_object *offset_desc, |
29 | union acpi_operand_object *length_desc, |
30 | union acpi_operand_object *result_desc); |
31 | |
32 | /******************************************************************************* |
33 | * |
34 | * FUNCTION: acpi_ds_initialize_region |
35 | * |
36 | * PARAMETERS: obj_handle - Region namespace node |
37 | * |
38 | * RETURN: Status |
39 | * |
40 | * DESCRIPTION: Front end to ev_initialize_region |
41 | * |
42 | ******************************************************************************/ |
43 | |
44 | acpi_status acpi_ds_initialize_region(acpi_handle obj_handle) |
45 | { |
46 | union acpi_operand_object *obj_desc; |
47 | acpi_status status; |
48 | |
49 | obj_desc = acpi_ns_get_attached_object(node: obj_handle); |
50 | |
51 | /* Namespace is NOT locked */ |
52 | |
53 | status = acpi_ev_initialize_region(region_obj: obj_desc); |
54 | return (status); |
55 | } |
56 | |
57 | /******************************************************************************* |
58 | * |
59 | * FUNCTION: acpi_ds_init_buffer_field |
60 | * |
61 | * PARAMETERS: aml_opcode - create_xxx_field |
62 | * obj_desc - buffer_field object |
63 | * buffer_desc - Host Buffer |
64 | * offset_desc - Offset into buffer |
65 | * length_desc - Length of field (CREATE_FIELD_OP only) |
66 | * result_desc - Where to store the result |
67 | * |
68 | * RETURN: Status |
69 | * |
70 | * DESCRIPTION: Perform actual initialization of a buffer field |
71 | * |
72 | ******************************************************************************/ |
73 | |
74 | static acpi_status |
75 | acpi_ds_init_buffer_field(u16 aml_opcode, |
76 | union acpi_operand_object *obj_desc, |
77 | union acpi_operand_object *buffer_desc, |
78 | union acpi_operand_object *offset_desc, |
79 | union acpi_operand_object *length_desc, |
80 | union acpi_operand_object *result_desc) |
81 | { |
82 | u32 offset; |
83 | u32 bit_offset; |
84 | u32 bit_count; |
85 | u8 field_flags; |
86 | acpi_status status; |
87 | |
88 | ACPI_FUNCTION_TRACE_PTR(ds_init_buffer_field, obj_desc); |
89 | |
90 | /* Host object must be a Buffer */ |
91 | |
92 | if (buffer_desc->common.type != ACPI_TYPE_BUFFER) { |
93 | ACPI_ERROR((AE_INFO, |
94 | "Target of Create Field is not a Buffer object - %s" , |
95 | acpi_ut_get_object_type_name(buffer_desc))); |
96 | |
97 | status = AE_AML_OPERAND_TYPE; |
98 | goto cleanup; |
99 | } |
100 | |
101 | /* |
102 | * The last parameter to all of these opcodes (result_desc) started |
103 | * out as a name_string, and should therefore now be a NS node |
104 | * after resolution in acpi_ex_resolve_operands(). |
105 | */ |
106 | if (ACPI_GET_DESCRIPTOR_TYPE(result_desc) != ACPI_DESC_TYPE_NAMED) { |
107 | ACPI_ERROR((AE_INFO, |
108 | "(%s) destination not a NS Node [%s]" , |
109 | acpi_ps_get_opcode_name(aml_opcode), |
110 | acpi_ut_get_descriptor_name(result_desc))); |
111 | |
112 | status = AE_AML_OPERAND_TYPE; |
113 | goto cleanup; |
114 | } |
115 | |
116 | offset = (u32) offset_desc->integer.value; |
117 | |
118 | /* |
119 | * Setup the Bit offsets and counts, according to the opcode |
120 | */ |
121 | switch (aml_opcode) { |
122 | case AML_CREATE_FIELD_OP: |
123 | |
124 | /* Offset is in bits, count is in bits */ |
125 | |
126 | field_flags = AML_FIELD_ACCESS_BYTE; |
127 | bit_offset = offset; |
128 | bit_count = (u32) length_desc->integer.value; |
129 | |
130 | /* Must have a valid (>0) bit count */ |
131 | |
132 | if (bit_count == 0) { |
133 | ACPI_BIOS_ERROR((AE_INFO, |
134 | "Attempt to CreateField of length zero" )); |
135 | status = AE_AML_OPERAND_VALUE; |
136 | goto cleanup; |
137 | } |
138 | break; |
139 | |
140 | case AML_CREATE_BIT_FIELD_OP: |
141 | |
142 | /* Offset is in bits, Field is one bit */ |
143 | |
144 | bit_offset = offset; |
145 | bit_count = 1; |
146 | field_flags = AML_FIELD_ACCESS_BYTE; |
147 | break; |
148 | |
149 | case AML_CREATE_BYTE_FIELD_OP: |
150 | |
151 | /* Offset is in bytes, field is one byte */ |
152 | |
153 | bit_offset = 8 * offset; |
154 | bit_count = 8; |
155 | field_flags = AML_FIELD_ACCESS_BYTE; |
156 | break; |
157 | |
158 | case AML_CREATE_WORD_FIELD_OP: |
159 | |
160 | /* Offset is in bytes, field is one word */ |
161 | |
162 | bit_offset = 8 * offset; |
163 | bit_count = 16; |
164 | field_flags = AML_FIELD_ACCESS_WORD; |
165 | break; |
166 | |
167 | case AML_CREATE_DWORD_FIELD_OP: |
168 | |
169 | /* Offset is in bytes, field is one dword */ |
170 | |
171 | bit_offset = 8 * offset; |
172 | bit_count = 32; |
173 | field_flags = AML_FIELD_ACCESS_DWORD; |
174 | break; |
175 | |
176 | case AML_CREATE_QWORD_FIELD_OP: |
177 | |
178 | /* Offset is in bytes, field is one qword */ |
179 | |
180 | bit_offset = 8 * offset; |
181 | bit_count = 64; |
182 | field_flags = AML_FIELD_ACCESS_QWORD; |
183 | break; |
184 | |
185 | default: |
186 | |
187 | ACPI_ERROR((AE_INFO, |
188 | "Unknown field creation opcode 0x%02X" , |
189 | aml_opcode)); |
190 | status = AE_AML_BAD_OPCODE; |
191 | goto cleanup; |
192 | } |
193 | |
194 | /* Entire field must fit within the current length of the buffer */ |
195 | |
196 | if ((bit_offset + bit_count) > (8 * (u32)buffer_desc->buffer.length)) { |
197 | status = AE_AML_BUFFER_LIMIT; |
198 | ACPI_BIOS_EXCEPTION((AE_INFO, status, |
199 | "Field [%4.4s] at bit offset/length %u/%u " |
200 | "exceeds size of target Buffer (%u bits)" , |
201 | acpi_ut_get_node_name(result_desc), |
202 | bit_offset, bit_count, |
203 | 8 * (u32)buffer_desc->buffer.length)); |
204 | goto cleanup; |
205 | } |
206 | |
207 | /* |
208 | * Initialize areas of the field object that are common to all fields |
209 | * For field_flags, use LOCK_RULE = 0 (NO_LOCK), |
210 | * UPDATE_RULE = 0 (UPDATE_PRESERVE) |
211 | */ |
212 | status = |
213 | acpi_ex_prep_common_field_object(obj_desc, field_flags, field_attribute: 0, |
214 | field_bit_position: bit_offset, field_bit_length: bit_count); |
215 | if (ACPI_FAILURE(status)) { |
216 | goto cleanup; |
217 | } |
218 | |
219 | obj_desc->buffer_field.buffer_obj = buffer_desc; |
220 | obj_desc->buffer_field.is_create_field = |
221 | aml_opcode == AML_CREATE_FIELD_OP; |
222 | |
223 | /* Reference count for buffer_desc inherits obj_desc count */ |
224 | |
225 | buffer_desc->common.reference_count = (u16) |
226 | (buffer_desc->common.reference_count + |
227 | obj_desc->common.reference_count); |
228 | |
229 | cleanup: |
230 | |
231 | /* Always delete the operands */ |
232 | |
233 | acpi_ut_remove_reference(object: offset_desc); |
234 | acpi_ut_remove_reference(object: buffer_desc); |
235 | |
236 | if (aml_opcode == AML_CREATE_FIELD_OP) { |
237 | acpi_ut_remove_reference(object: length_desc); |
238 | } |
239 | |
240 | /* On failure, delete the result descriptor */ |
241 | |
242 | if (ACPI_FAILURE(status)) { |
243 | acpi_ut_remove_reference(object: result_desc); /* Result descriptor */ |
244 | } else { |
245 | /* Now the address and length are valid for this buffer_field */ |
246 | |
247 | obj_desc->buffer_field.flags |= AOPOBJ_DATA_VALID; |
248 | } |
249 | |
250 | return_ACPI_STATUS(status); |
251 | } |
252 | |
253 | /******************************************************************************* |
254 | * |
255 | * FUNCTION: acpi_ds_eval_buffer_field_operands |
256 | * |
257 | * PARAMETERS: walk_state - Current walk |
258 | * op - A valid buffer_field Op object |
259 | * |
260 | * RETURN: Status |
261 | * |
262 | * DESCRIPTION: Get buffer_field Buffer and Index |
263 | * Called from acpi_ds_exec_end_op during buffer_field parse tree walk |
264 | * |
265 | ******************************************************************************/ |
266 | |
267 | acpi_status |
268 | acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state, |
269 | union acpi_parse_object *op) |
270 | { |
271 | acpi_status status; |
272 | union acpi_operand_object *obj_desc; |
273 | struct acpi_namespace_node *node; |
274 | union acpi_parse_object *next_op; |
275 | |
276 | ACPI_FUNCTION_TRACE_PTR(ds_eval_buffer_field_operands, op); |
277 | |
278 | /* |
279 | * This is where we evaluate the address and length fields of the |
280 | * create_xxx_field declaration |
281 | */ |
282 | node = op->common.node; |
283 | |
284 | /* next_op points to the op that holds the Buffer */ |
285 | |
286 | next_op = op->common.value.arg; |
287 | |
288 | /* Evaluate/create the address and length operands */ |
289 | |
290 | status = acpi_ds_create_operands(walk_state, first_arg: next_op); |
291 | if (ACPI_FAILURE(status)) { |
292 | return_ACPI_STATUS(status); |
293 | } |
294 | |
295 | obj_desc = acpi_ns_get_attached_object(node); |
296 | if (!obj_desc) { |
297 | return_ACPI_STATUS(AE_NOT_EXIST); |
298 | } |
299 | |
300 | /* Resolve the operands */ |
301 | |
302 | status = |
303 | acpi_ex_resolve_operands(opcode: op->common.aml_opcode, ACPI_WALK_OPERANDS, |
304 | walk_state); |
305 | if (ACPI_FAILURE(status)) { |
306 | ACPI_ERROR((AE_INFO, "(%s) bad operand(s), status 0x%X" , |
307 | acpi_ps_get_opcode_name(op->common.aml_opcode), |
308 | status)); |
309 | |
310 | return_ACPI_STATUS(status); |
311 | } |
312 | |
313 | /* Initialize the Buffer Field */ |
314 | |
315 | if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { |
316 | |
317 | /* NOTE: Slightly different operands for this opcode */ |
318 | |
319 | status = |
320 | acpi_ds_init_buffer_field(aml_opcode: op->common.aml_opcode, obj_desc, |
321 | buffer_desc: walk_state->operands[0], |
322 | offset_desc: walk_state->operands[1], |
323 | length_desc: walk_state->operands[2], |
324 | result_desc: walk_state->operands[3]); |
325 | } else { |
326 | /* All other, create_xxx_field opcodes */ |
327 | |
328 | status = |
329 | acpi_ds_init_buffer_field(aml_opcode: op->common.aml_opcode, obj_desc, |
330 | buffer_desc: walk_state->operands[0], |
331 | offset_desc: walk_state->operands[1], NULL, |
332 | result_desc: walk_state->operands[2]); |
333 | } |
334 | |
335 | return_ACPI_STATUS(status); |
336 | } |
337 | |
338 | /******************************************************************************* |
339 | * |
340 | * FUNCTION: acpi_ds_eval_region_operands |
341 | * |
342 | * PARAMETERS: walk_state - Current walk |
343 | * op - A valid region Op object |
344 | * |
345 | * RETURN: Status |
346 | * |
347 | * DESCRIPTION: Get region address and length |
348 | * Called from acpi_ds_exec_end_op during op_region parse tree walk |
349 | * |
350 | ******************************************************************************/ |
351 | |
352 | acpi_status |
353 | acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, |
354 | union acpi_parse_object *op) |
355 | { |
356 | acpi_status status; |
357 | union acpi_operand_object *obj_desc; |
358 | union acpi_operand_object *operand_desc; |
359 | struct acpi_namespace_node *node; |
360 | union acpi_parse_object *next_op; |
361 | acpi_adr_space_type space_id; |
362 | |
363 | ACPI_FUNCTION_TRACE_PTR(ds_eval_region_operands, op); |
364 | |
365 | /* |
366 | * This is where we evaluate the address and length fields of the |
367 | * op_region declaration |
368 | */ |
369 | node = op->common.node; |
370 | |
371 | /* next_op points to the op that holds the space_ID */ |
372 | |
373 | next_op = op->common.value.arg; |
374 | space_id = (acpi_adr_space_type)next_op->common.value.integer; |
375 | |
376 | /* next_op points to address op */ |
377 | |
378 | next_op = next_op->common.next; |
379 | |
380 | /* Evaluate/create the address and length operands */ |
381 | |
382 | status = acpi_ds_create_operands(walk_state, first_arg: next_op); |
383 | if (ACPI_FAILURE(status)) { |
384 | return_ACPI_STATUS(status); |
385 | } |
386 | |
387 | /* Resolve the length and address operands to numbers */ |
388 | |
389 | status = |
390 | acpi_ex_resolve_operands(opcode: op->common.aml_opcode, ACPI_WALK_OPERANDS, |
391 | walk_state); |
392 | if (ACPI_FAILURE(status)) { |
393 | return_ACPI_STATUS(status); |
394 | } |
395 | |
396 | obj_desc = acpi_ns_get_attached_object(node); |
397 | if (!obj_desc) { |
398 | return_ACPI_STATUS(AE_NOT_EXIST); |
399 | } |
400 | |
401 | /* |
402 | * Get the length operand and save it |
403 | * (at Top of stack) |
404 | */ |
405 | operand_desc = walk_state->operands[walk_state->num_operands - 1]; |
406 | |
407 | obj_desc->region.length = (u32) operand_desc->integer.value; |
408 | acpi_ut_remove_reference(object: operand_desc); |
409 | |
410 | /* A zero-length operation region is unusable. Just warn */ |
411 | |
412 | if (!obj_desc->region.length |
413 | && (space_id < ACPI_NUM_PREDEFINED_REGIONS)) { |
414 | ACPI_WARNING((AE_INFO, |
415 | "Operation Region [%4.4s] has zero length (SpaceId %X)" , |
416 | node->name.ascii, space_id)); |
417 | } |
418 | |
419 | /* |
420 | * Get the address and save it |
421 | * (at top of stack - 1) |
422 | */ |
423 | operand_desc = walk_state->operands[walk_state->num_operands - 2]; |
424 | |
425 | obj_desc->region.address = (acpi_physical_address) |
426 | operand_desc->integer.value; |
427 | acpi_ut_remove_reference(object: operand_desc); |
428 | |
429 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n" , |
430 | obj_desc, |
431 | ACPI_FORMAT_UINT64(obj_desc->region.address), |
432 | obj_desc->region.length)); |
433 | |
434 | status = acpi_ut_add_address_range(space_id: obj_desc->region.space_id, |
435 | address: obj_desc->region.address, |
436 | length: obj_desc->region.length, region_node: node); |
437 | |
438 | /* Now the address and length are valid for this opregion */ |
439 | |
440 | obj_desc->region.flags |= AOPOBJ_DATA_VALID; |
441 | return_ACPI_STATUS(status); |
442 | } |
443 | |
444 | /******************************************************************************* |
445 | * |
446 | * FUNCTION: acpi_ds_eval_table_region_operands |
447 | * |
448 | * PARAMETERS: walk_state - Current walk |
449 | * op - A valid region Op object |
450 | * |
451 | * RETURN: Status |
452 | * |
453 | * DESCRIPTION: Get region address and length. |
454 | * Called from acpi_ds_exec_end_op during data_table_region parse |
455 | * tree walk. |
456 | * |
457 | ******************************************************************************/ |
458 | |
459 | acpi_status |
460 | acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state, |
461 | union acpi_parse_object *op) |
462 | { |
463 | acpi_status status; |
464 | union acpi_operand_object *obj_desc; |
465 | union acpi_operand_object **operand; |
466 | struct acpi_namespace_node *node; |
467 | union acpi_parse_object *next_op; |
468 | struct acpi_table_header *table; |
469 | u32 table_index; |
470 | |
471 | ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op); |
472 | |
473 | /* |
474 | * This is where we evaluate the Signature string, oem_id string, |
475 | * and oem_table_id string of the Data Table Region declaration |
476 | */ |
477 | node = op->common.node; |
478 | |
479 | /* next_op points to Signature string op */ |
480 | |
481 | next_op = op->common.value.arg; |
482 | |
483 | /* |
484 | * Evaluate/create the Signature string, oem_id string, |
485 | * and oem_table_id string operands |
486 | */ |
487 | status = acpi_ds_create_operands(walk_state, first_arg: next_op); |
488 | if (ACPI_FAILURE(status)) { |
489 | return_ACPI_STATUS(status); |
490 | } |
491 | |
492 | operand = &walk_state->operands[0]; |
493 | |
494 | /* |
495 | * Resolve the Signature string, oem_id string, |
496 | * and oem_table_id string operands |
497 | */ |
498 | status = |
499 | acpi_ex_resolve_operands(opcode: op->common.aml_opcode, ACPI_WALK_OPERANDS, |
500 | walk_state); |
501 | if (ACPI_FAILURE(status)) { |
502 | goto cleanup; |
503 | } |
504 | |
505 | /* Find the ACPI table */ |
506 | |
507 | status = acpi_tb_find_table(signature: operand[0]->string.pointer, |
508 | oem_id: operand[1]->string.pointer, |
509 | oem_table_id: operand[2]->string.pointer, table_index: &table_index); |
510 | if (ACPI_FAILURE(status)) { |
511 | if (status == AE_NOT_FOUND) { |
512 | ACPI_ERROR((AE_INFO, |
513 | "ACPI Table [%4.4s] OEM:(%s, %s) not found in RSDT/XSDT" , |
514 | operand[0]->string.pointer, |
515 | operand[1]->string.pointer, |
516 | operand[2]->string.pointer)); |
517 | } |
518 | goto cleanup; |
519 | } |
520 | |
521 | status = acpi_get_table_by_index(table_index, out_table: &table); |
522 | if (ACPI_FAILURE(status)) { |
523 | goto cleanup; |
524 | } |
525 | |
526 | obj_desc = acpi_ns_get_attached_object(node); |
527 | if (!obj_desc) { |
528 | status = AE_NOT_EXIST; |
529 | goto cleanup; |
530 | } |
531 | |
532 | obj_desc->region.address = ACPI_PTR_TO_PHYSADDR(table); |
533 | obj_desc->region.length = table->length; |
534 | obj_desc->region.pointer = table; |
535 | |
536 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n" , |
537 | obj_desc, |
538 | ACPI_FORMAT_UINT64(obj_desc->region.address), |
539 | obj_desc->region.length)); |
540 | |
541 | /* Now the address and length are valid for this opregion */ |
542 | |
543 | obj_desc->region.flags |= AOPOBJ_DATA_VALID; |
544 | |
545 | cleanup: |
546 | acpi_ut_remove_reference(object: operand[0]); |
547 | acpi_ut_remove_reference(object: operand[1]); |
548 | acpi_ut_remove_reference(object: operand[2]); |
549 | |
550 | return_ACPI_STATUS(status); |
551 | } |
552 | |
553 | /******************************************************************************* |
554 | * |
555 | * FUNCTION: acpi_ds_eval_data_object_operands |
556 | * |
557 | * PARAMETERS: walk_state - Current walk |
558 | * op - A valid data_object Op object |
559 | * obj_desc - data_object |
560 | * |
561 | * RETURN: Status |
562 | * |
563 | * DESCRIPTION: Get the operands and complete the following data object types: |
564 | * Buffer, Package. |
565 | * |
566 | ******************************************************************************/ |
567 | |
568 | acpi_status |
569 | acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state, |
570 | union acpi_parse_object *op, |
571 | union acpi_operand_object *obj_desc) |
572 | { |
573 | acpi_status status; |
574 | union acpi_operand_object *arg_desc; |
575 | u32 length; |
576 | |
577 | ACPI_FUNCTION_TRACE(ds_eval_data_object_operands); |
578 | |
579 | /* The first operand (for all of these data objects) is the length */ |
580 | |
581 | /* |
582 | * Set proper index into operand stack for acpi_ds_obj_stack_push |
583 | * invoked inside acpi_ds_create_operand. |
584 | */ |
585 | walk_state->operand_index = walk_state->num_operands; |
586 | |
587 | /* Ignore if child is not valid */ |
588 | |
589 | if (!op->common.value.arg) { |
590 | ACPI_ERROR((AE_INFO, |
591 | "Missing child while evaluating opcode %4.4X, Op %p" , |
592 | op->common.aml_opcode, op)); |
593 | return_ACPI_STATUS(AE_OK); |
594 | } |
595 | |
596 | status = acpi_ds_create_operand(walk_state, arg: op->common.value.arg, args_remaining: 1); |
597 | if (ACPI_FAILURE(status)) { |
598 | return_ACPI_STATUS(status); |
599 | } |
600 | |
601 | status = acpi_ex_resolve_operands(opcode: walk_state->opcode, |
602 | stack_ptr: &(walk_state-> |
603 | operands[walk_state->num_operands - |
604 | 1]), walk_state); |
605 | if (ACPI_FAILURE(status)) { |
606 | return_ACPI_STATUS(status); |
607 | } |
608 | |
609 | /* Extract length operand */ |
610 | |
611 | arg_desc = walk_state->operands[walk_state->num_operands - 1]; |
612 | length = (u32) arg_desc->integer.value; |
613 | |
614 | /* Cleanup for length operand */ |
615 | |
616 | status = acpi_ds_obj_stack_pop(pop_count: 1, walk_state); |
617 | if (ACPI_FAILURE(status)) { |
618 | return_ACPI_STATUS(status); |
619 | } |
620 | |
621 | acpi_ut_remove_reference(object: arg_desc); |
622 | |
623 | /* |
624 | * Create the actual data object |
625 | */ |
626 | switch (op->common.aml_opcode) { |
627 | case AML_BUFFER_OP: |
628 | |
629 | status = |
630 | acpi_ds_build_internal_buffer_obj(walk_state, op, buffer_length: length, |
631 | obj_desc_ptr: &obj_desc); |
632 | break; |
633 | |
634 | case AML_PACKAGE_OP: |
635 | case AML_VARIABLE_PACKAGE_OP: |
636 | |
637 | status = |
638 | acpi_ds_build_internal_package_obj(walk_state, op, package_length: length, |
639 | obj_desc: &obj_desc); |
640 | break; |
641 | |
642 | default: |
643 | |
644 | return_ACPI_STATUS(AE_AML_BAD_OPCODE); |
645 | } |
646 | |
647 | if (ACPI_SUCCESS(status)) { |
648 | /* |
649 | * Return the object in the walk_state, unless the parent is a package - |
650 | * in this case, the return object will be stored in the parse tree |
651 | * for the package. |
652 | */ |
653 | if ((!op->common.parent) || |
654 | ((op->common.parent->common.aml_opcode != AML_PACKAGE_OP) && |
655 | (op->common.parent->common.aml_opcode != |
656 | AML_VARIABLE_PACKAGE_OP) |
657 | && (op->common.parent->common.aml_opcode != |
658 | AML_NAME_OP))) { |
659 | walk_state->result_obj = obj_desc; |
660 | } |
661 | } |
662 | |
663 | return_ACPI_STATUS(status); |
664 | } |
665 | |
666 | /******************************************************************************* |
667 | * |
668 | * FUNCTION: acpi_ds_eval_bank_field_operands |
669 | * |
670 | * PARAMETERS: walk_state - Current walk |
671 | * op - A valid bank_field Op object |
672 | * |
673 | * RETURN: Status |
674 | * |
675 | * DESCRIPTION: Get bank_field bank_value |
676 | * Called from acpi_ds_exec_end_op during bank_field parse tree walk |
677 | * |
678 | ******************************************************************************/ |
679 | |
680 | acpi_status |
681 | acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state, |
682 | union acpi_parse_object *op) |
683 | { |
684 | acpi_status status; |
685 | union acpi_operand_object *obj_desc; |
686 | union acpi_operand_object *operand_desc; |
687 | struct acpi_namespace_node *node; |
688 | union acpi_parse_object *next_op; |
689 | union acpi_parse_object *arg; |
690 | |
691 | ACPI_FUNCTION_TRACE_PTR(ds_eval_bank_field_operands, op); |
692 | |
693 | /* |
694 | * This is where we evaluate the bank_value field of the |
695 | * bank_field declaration |
696 | */ |
697 | |
698 | /* next_op points to the op that holds the Region */ |
699 | |
700 | next_op = op->common.value.arg; |
701 | |
702 | /* next_op points to the op that holds the Bank Register */ |
703 | |
704 | next_op = next_op->common.next; |
705 | |
706 | /* next_op points to the op that holds the Bank Value */ |
707 | |
708 | next_op = next_op->common.next; |
709 | |
710 | /* |
711 | * Set proper index into operand stack for acpi_ds_obj_stack_push |
712 | * invoked inside acpi_ds_create_operand. |
713 | * |
714 | * We use walk_state->Operands[0] to store the evaluated bank_value |
715 | */ |
716 | walk_state->operand_index = 0; |
717 | |
718 | status = acpi_ds_create_operand(walk_state, arg: next_op, args_remaining: 0); |
719 | if (ACPI_FAILURE(status)) { |
720 | return_ACPI_STATUS(status); |
721 | } |
722 | |
723 | status = acpi_ex_resolve_to_value(stack_ptr: &walk_state->operands[0], walk_state); |
724 | if (ACPI_FAILURE(status)) { |
725 | return_ACPI_STATUS(status); |
726 | } |
727 | |
728 | ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, |
729 | acpi_ps_get_opcode_name(op->common.aml_opcode), 1); |
730 | /* |
731 | * Get the bank_value operand and save it |
732 | * (at Top of stack) |
733 | */ |
734 | operand_desc = walk_state->operands[0]; |
735 | |
736 | /* Arg points to the start Bank Field */ |
737 | |
738 | arg = acpi_ps_get_arg(op, argn: 4); |
739 | while (arg) { |
740 | |
741 | /* Ignore OFFSET and ACCESSAS terms here */ |
742 | |
743 | if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { |
744 | node = arg->common.node; |
745 | |
746 | obj_desc = acpi_ns_get_attached_object(node); |
747 | if (!obj_desc) { |
748 | return_ACPI_STATUS(AE_NOT_EXIST); |
749 | } |
750 | |
751 | obj_desc->bank_field.value = |
752 | (u32) operand_desc->integer.value; |
753 | } |
754 | |
755 | /* Move to next field in the list */ |
756 | |
757 | arg = arg->common.next; |
758 | } |
759 | |
760 | acpi_ut_remove_reference(object: operand_desc); |
761 | return_ACPI_STATUS(status); |
762 | } |
763 | |