1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: dsobject - Dispatcher object management routines |
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 "acnamesp.h" |
16 | #include "acinterp.h" |
17 | |
18 | #define _COMPONENT ACPI_DISPATCHER |
19 | ACPI_MODULE_NAME("dsobject" ) |
20 | |
21 | /******************************************************************************* |
22 | * |
23 | * FUNCTION: acpi_ds_build_internal_object |
24 | * |
25 | * PARAMETERS: walk_state - Current walk state |
26 | * op - Parser object to be translated |
27 | * obj_desc_ptr - Where the ACPI internal object is returned |
28 | * |
29 | * RETURN: Status |
30 | * |
31 | * DESCRIPTION: Translate a parser Op object to the equivalent namespace object |
32 | * Simple objects are any objects other than a package object! |
33 | * |
34 | ******************************************************************************/ |
35 | acpi_status |
36 | acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, |
37 | union acpi_parse_object *op, |
38 | union acpi_operand_object **obj_desc_ptr) |
39 | { |
40 | union acpi_operand_object *obj_desc; |
41 | acpi_status status; |
42 | |
43 | ACPI_FUNCTION_TRACE(ds_build_internal_object); |
44 | |
45 | *obj_desc_ptr = NULL; |
46 | if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { |
47 | /* |
48 | * This is a named object reference. If this name was |
49 | * previously looked up in the namespace, it was stored in |
50 | * this op. Otherwise, go ahead and look it up now |
51 | */ |
52 | if (!op->common.node) { |
53 | |
54 | /* Check if we are resolving a named reference within a package */ |
55 | |
56 | if ((op->common.parent->common.aml_opcode == |
57 | AML_PACKAGE_OP) |
58 | || (op->common.parent->common.aml_opcode == |
59 | AML_VARIABLE_PACKAGE_OP)) { |
60 | /* |
61 | * We won't resolve package elements here, we will do this |
62 | * after all ACPI tables are loaded into the namespace. This |
63 | * behavior supports both forward references to named objects |
64 | * and external references to objects in other tables. |
65 | */ |
66 | goto create_new_object; |
67 | } else { |
68 | status = acpi_ns_lookup(scope_info: walk_state->scope_info, |
69 | name: op->common.value.string, |
70 | ACPI_TYPE_ANY, |
71 | interpreter_mode: ACPI_IMODE_EXECUTE, |
72 | ACPI_NS_SEARCH_PARENT | |
73 | ACPI_NS_DONT_OPEN_SCOPE, |
74 | NULL, |
75 | ACPI_CAST_INDIRECT_PTR |
76 | (struct |
77 | acpi_namespace_node, |
78 | &(op->common.node))); |
79 | if (ACPI_FAILURE(status)) { |
80 | ACPI_ERROR_NAMESPACE(walk_state-> |
81 | scope_info, |
82 | op->common.value. |
83 | string, status); |
84 | return_ACPI_STATUS(status); |
85 | } |
86 | } |
87 | } |
88 | } |
89 | |
90 | create_new_object: |
91 | |
92 | /* Create and init a new internal ACPI object */ |
93 | |
94 | obj_desc = acpi_ut_create_internal_object((acpi_ps_get_opcode_info |
95 | (op->common.aml_opcode))-> |
96 | object_type); |
97 | if (!obj_desc) { |
98 | return_ACPI_STATUS(AE_NO_MEMORY); |
99 | } |
100 | |
101 | status = |
102 | acpi_ds_init_object_from_op(walk_state, op, opcode: op->common.aml_opcode, |
103 | obj_desc: &obj_desc); |
104 | if (ACPI_FAILURE(status)) { |
105 | acpi_ut_remove_reference(object: obj_desc); |
106 | return_ACPI_STATUS(status); |
107 | } |
108 | |
109 | /* |
110 | * Handling for unresolved package reference elements. |
111 | * These are elements that are namepaths. |
112 | */ |
113 | if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || |
114 | (op->common.parent->common.aml_opcode == AML_VARIABLE_PACKAGE_OP)) { |
115 | obj_desc->reference.resolved = TRUE; |
116 | |
117 | if ((op->common.aml_opcode == AML_INT_NAMEPATH_OP) && |
118 | !obj_desc->reference.node) { |
119 | /* |
120 | * Name was unresolved above. |
121 | * Get the prefix node for later lookup |
122 | */ |
123 | obj_desc->reference.node = |
124 | walk_state->scope_info->scope.node; |
125 | obj_desc->reference.aml = op->common.aml; |
126 | obj_desc->reference.resolved = FALSE; |
127 | } |
128 | } |
129 | |
130 | *obj_desc_ptr = obj_desc; |
131 | return_ACPI_STATUS(status); |
132 | } |
133 | |
134 | /******************************************************************************* |
135 | * |
136 | * FUNCTION: acpi_ds_build_internal_buffer_obj |
137 | * |
138 | * PARAMETERS: walk_state - Current walk state |
139 | * op - Parser object to be translated |
140 | * buffer_length - Length of the buffer |
141 | * obj_desc_ptr - Where the ACPI internal object is returned |
142 | * |
143 | * RETURN: Status |
144 | * |
145 | * DESCRIPTION: Translate a parser Op package object to the equivalent |
146 | * namespace object |
147 | * |
148 | ******************************************************************************/ |
149 | |
150 | acpi_status |
151 | acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, |
152 | union acpi_parse_object *op, |
153 | u32 buffer_length, |
154 | union acpi_operand_object **obj_desc_ptr) |
155 | { |
156 | union acpi_parse_object *arg; |
157 | union acpi_operand_object *obj_desc; |
158 | union acpi_parse_object *byte_list; |
159 | u32 byte_list_length = 0; |
160 | |
161 | ACPI_FUNCTION_TRACE(ds_build_internal_buffer_obj); |
162 | |
163 | /* |
164 | * If we are evaluating a Named buffer object "Name (xxxx, Buffer)". |
165 | * The buffer object already exists (from the NS node), otherwise it must |
166 | * be created. |
167 | */ |
168 | obj_desc = *obj_desc_ptr; |
169 | if (!obj_desc) { |
170 | |
171 | /* Create a new buffer object */ |
172 | |
173 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER); |
174 | *obj_desc_ptr = obj_desc; |
175 | if (!obj_desc) { |
176 | return_ACPI_STATUS(AE_NO_MEMORY); |
177 | } |
178 | } |
179 | |
180 | /* |
181 | * Second arg is the buffer data (optional) byte_list can be either |
182 | * individual bytes or a string initializer. In either case, a |
183 | * byte_list appears in the AML. |
184 | */ |
185 | arg = op->common.value.arg; /* skip first arg */ |
186 | |
187 | byte_list = arg->named.next; |
188 | if (byte_list) { |
189 | if (byte_list->common.aml_opcode != AML_INT_BYTELIST_OP) { |
190 | ACPI_ERROR((AE_INFO, |
191 | "Expecting bytelist, found AML opcode 0x%X in op %p" , |
192 | byte_list->common.aml_opcode, byte_list)); |
193 | |
194 | acpi_ut_remove_reference(object: obj_desc); |
195 | return (AE_TYPE); |
196 | } |
197 | |
198 | byte_list_length = (u32) byte_list->common.value.integer; |
199 | } |
200 | |
201 | /* |
202 | * The buffer length (number of bytes) will be the larger of: |
203 | * 1) The specified buffer length and |
204 | * 2) The length of the initializer byte list |
205 | */ |
206 | obj_desc->buffer.length = buffer_length; |
207 | if (byte_list_length > buffer_length) { |
208 | obj_desc->buffer.length = byte_list_length; |
209 | } |
210 | |
211 | /* Allocate the buffer */ |
212 | |
213 | if (obj_desc->buffer.length == 0) { |
214 | obj_desc->buffer.pointer = NULL; |
215 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
216 | "Buffer defined with zero length in AML, creating\n" )); |
217 | } else { |
218 | obj_desc->buffer.pointer = |
219 | ACPI_ALLOCATE_ZEROED(obj_desc->buffer.length); |
220 | if (!obj_desc->buffer.pointer) { |
221 | acpi_ut_delete_object_desc(object: obj_desc); |
222 | return_ACPI_STATUS(AE_NO_MEMORY); |
223 | } |
224 | |
225 | /* Initialize buffer from the byte_list (if present) */ |
226 | |
227 | if (byte_list) { |
228 | memcpy(obj_desc->buffer.pointer, byte_list->named.data, |
229 | byte_list_length); |
230 | } |
231 | } |
232 | |
233 | obj_desc->buffer.flags |= AOPOBJ_DATA_VALID; |
234 | op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc); |
235 | return_ACPI_STATUS(AE_OK); |
236 | } |
237 | |
238 | /******************************************************************************* |
239 | * |
240 | * FUNCTION: acpi_ds_create_node |
241 | * |
242 | * PARAMETERS: walk_state - Current walk state |
243 | * node - NS Node to be initialized |
244 | * op - Parser object to be translated |
245 | * |
246 | * RETURN: Status |
247 | * |
248 | * DESCRIPTION: Create the object to be associated with a namespace node |
249 | * |
250 | ******************************************************************************/ |
251 | |
252 | acpi_status |
253 | acpi_ds_create_node(struct acpi_walk_state *walk_state, |
254 | struct acpi_namespace_node *node, |
255 | union acpi_parse_object *op) |
256 | { |
257 | acpi_status status; |
258 | union acpi_operand_object *obj_desc; |
259 | |
260 | ACPI_FUNCTION_TRACE_PTR(ds_create_node, op); |
261 | |
262 | /* |
263 | * Because of the execution pass through the non-control-method |
264 | * parts of the table, we can arrive here twice. Only init |
265 | * the named object node the first time through |
266 | */ |
267 | if (acpi_ns_get_attached_object(node)) { |
268 | return_ACPI_STATUS(AE_OK); |
269 | } |
270 | |
271 | if (!op->common.value.arg) { |
272 | |
273 | /* No arguments, there is nothing to do */ |
274 | |
275 | return_ACPI_STATUS(AE_OK); |
276 | } |
277 | |
278 | /* Build an internal object for the argument(s) */ |
279 | |
280 | status = |
281 | acpi_ds_build_internal_object(walk_state, op: op->common.value.arg, |
282 | obj_desc_ptr: &obj_desc); |
283 | if (ACPI_FAILURE(status)) { |
284 | return_ACPI_STATUS(status); |
285 | } |
286 | |
287 | /* Re-type the object according to its argument */ |
288 | |
289 | node->type = obj_desc->common.type; |
290 | |
291 | /* Attach obj to node */ |
292 | |
293 | status = acpi_ns_attach_object(node, object: obj_desc, type: node->type); |
294 | |
295 | /* Remove local reference to the object */ |
296 | |
297 | acpi_ut_remove_reference(object: obj_desc); |
298 | return_ACPI_STATUS(status); |
299 | } |
300 | |
301 | /******************************************************************************* |
302 | * |
303 | * FUNCTION: acpi_ds_init_object_from_op |
304 | * |
305 | * PARAMETERS: walk_state - Current walk state |
306 | * op - Parser op used to init the internal object |
307 | * opcode - AML opcode associated with the object |
308 | * ret_obj_desc - Namespace object to be initialized |
309 | * |
310 | * RETURN: Status |
311 | * |
312 | * DESCRIPTION: Initialize a namespace object from a parser Op and its |
313 | * associated arguments. The namespace object is a more compact |
314 | * representation of the Op and its arguments. |
315 | * |
316 | ******************************************************************************/ |
317 | |
318 | acpi_status |
319 | acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, |
320 | union acpi_parse_object *op, |
321 | u16 opcode, |
322 | union acpi_operand_object **ret_obj_desc) |
323 | { |
324 | const struct acpi_opcode_info *op_info; |
325 | union acpi_operand_object *obj_desc; |
326 | acpi_status status = AE_OK; |
327 | |
328 | ACPI_FUNCTION_TRACE(ds_init_object_from_op); |
329 | |
330 | obj_desc = *ret_obj_desc; |
331 | op_info = acpi_ps_get_opcode_info(opcode); |
332 | if (op_info->class == AML_CLASS_UNKNOWN) { |
333 | |
334 | /* Unknown opcode */ |
335 | |
336 | return_ACPI_STATUS(AE_TYPE); |
337 | } |
338 | |
339 | /* Perform per-object initialization */ |
340 | |
341 | switch (obj_desc->common.type) { |
342 | case ACPI_TYPE_BUFFER: |
343 | /* |
344 | * Defer evaluation of Buffer term_arg operand |
345 | */ |
346 | obj_desc->buffer.node = |
347 | ACPI_CAST_PTR(struct acpi_namespace_node, |
348 | walk_state->operands[0]); |
349 | obj_desc->buffer.aml_start = op->named.data; |
350 | obj_desc->buffer.aml_length = op->named.length; |
351 | break; |
352 | |
353 | case ACPI_TYPE_PACKAGE: |
354 | /* |
355 | * Defer evaluation of Package term_arg operand and all |
356 | * package elements. (01/2017): We defer the element |
357 | * resolution to allow forward references from the package |
358 | * in order to provide compatibility with other ACPI |
359 | * implementations. |
360 | */ |
361 | obj_desc->package.node = |
362 | ACPI_CAST_PTR(struct acpi_namespace_node, |
363 | walk_state->operands[0]); |
364 | |
365 | if (!op->named.data) { |
366 | return_ACPI_STATUS(AE_OK); |
367 | } |
368 | |
369 | obj_desc->package.aml_start = op->named.data; |
370 | obj_desc->package.aml_length = op->named.length; |
371 | break; |
372 | |
373 | case ACPI_TYPE_INTEGER: |
374 | |
375 | switch (op_info->type) { |
376 | case AML_TYPE_CONSTANT: |
377 | /* |
378 | * Resolve AML Constants here - AND ONLY HERE! |
379 | * All constants are integers. |
380 | * We mark the integer with a flag that indicates that it started |
381 | * life as a constant -- so that stores to constants will perform |
382 | * as expected (noop). zero_op is used as a placeholder for optional |
383 | * target operands. |
384 | */ |
385 | obj_desc->common.flags = AOPOBJ_AML_CONSTANT; |
386 | |
387 | switch (opcode) { |
388 | case AML_ZERO_OP: |
389 | |
390 | obj_desc->integer.value = 0; |
391 | break; |
392 | |
393 | case AML_ONE_OP: |
394 | |
395 | obj_desc->integer.value = 1; |
396 | break; |
397 | |
398 | case AML_ONES_OP: |
399 | |
400 | obj_desc->integer.value = ACPI_UINT64_MAX; |
401 | |
402 | /* Truncate value if we are executing from a 32-bit ACPI table */ |
403 | |
404 | (void)acpi_ex_truncate_for32bit_table(obj_desc); |
405 | break; |
406 | |
407 | case AML_REVISION_OP: |
408 | |
409 | obj_desc->integer.value = ACPI_CA_VERSION; |
410 | break; |
411 | |
412 | default: |
413 | |
414 | ACPI_ERROR((AE_INFO, |
415 | "Unknown constant opcode 0x%X" , |
416 | opcode)); |
417 | status = AE_AML_OPERAND_TYPE; |
418 | break; |
419 | } |
420 | break; |
421 | |
422 | case AML_TYPE_LITERAL: |
423 | |
424 | obj_desc->integer.value = op->common.value.integer; |
425 | |
426 | if (acpi_ex_truncate_for32bit_table(obj_desc)) { |
427 | |
428 | /* Warn if we found a 64-bit constant in a 32-bit table */ |
429 | |
430 | ACPI_WARNING((AE_INFO, |
431 | "Truncated 64-bit constant found in 32-bit table: %8.8X%8.8X => %8.8X" , |
432 | ACPI_FORMAT_UINT64(op->common. |
433 | value.integer), |
434 | (u32)obj_desc->integer.value)); |
435 | } |
436 | break; |
437 | |
438 | default: |
439 | |
440 | ACPI_ERROR((AE_INFO, "Unknown Integer type 0x%X" , |
441 | op_info->type)); |
442 | status = AE_AML_OPERAND_TYPE; |
443 | break; |
444 | } |
445 | break; |
446 | |
447 | case ACPI_TYPE_STRING: |
448 | |
449 | obj_desc->string.pointer = op->common.value.string; |
450 | obj_desc->string.length = (u32)strlen(op->common.value.string); |
451 | |
452 | /* |
453 | * The string is contained in the ACPI table, don't ever try |
454 | * to delete it |
455 | */ |
456 | obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; |
457 | break; |
458 | |
459 | case ACPI_TYPE_METHOD: |
460 | break; |
461 | |
462 | case ACPI_TYPE_LOCAL_REFERENCE: |
463 | |
464 | switch (op_info->type) { |
465 | case AML_TYPE_LOCAL_VARIABLE: |
466 | |
467 | /* Local ID (0-7) is (AML opcode - base AML_FIRST_LOCAL_OP) */ |
468 | |
469 | obj_desc->reference.value = |
470 | ((u32)opcode) - AML_FIRST_LOCAL_OP; |
471 | obj_desc->reference.class = ACPI_REFCLASS_LOCAL; |
472 | |
473 | status = |
474 | acpi_ds_method_data_get_node(type: ACPI_REFCLASS_LOCAL, |
475 | index: obj_desc->reference. |
476 | value, walk_state, |
477 | ACPI_CAST_INDIRECT_PTR |
478 | (struct |
479 | acpi_namespace_node, |
480 | &obj_desc->reference. |
481 | object)); |
482 | break; |
483 | |
484 | case AML_TYPE_METHOD_ARGUMENT: |
485 | |
486 | /* Arg ID (0-6) is (AML opcode - base AML_FIRST_ARG_OP) */ |
487 | |
488 | obj_desc->reference.value = |
489 | ((u32)opcode) - AML_FIRST_ARG_OP; |
490 | obj_desc->reference.class = ACPI_REFCLASS_ARG; |
491 | |
492 | status = acpi_ds_method_data_get_node(type: ACPI_REFCLASS_ARG, |
493 | index: obj_desc-> |
494 | reference.value, |
495 | walk_state, |
496 | ACPI_CAST_INDIRECT_PTR |
497 | (struct |
498 | acpi_namespace_node, |
499 | &obj_desc-> |
500 | reference. |
501 | object)); |
502 | break; |
503 | |
504 | default: /* Object name or Debug object */ |
505 | |
506 | switch (op->common.aml_opcode) { |
507 | case AML_INT_NAMEPATH_OP: |
508 | |
509 | /* Node was saved in Op */ |
510 | |
511 | obj_desc->reference.node = op->common.node; |
512 | obj_desc->reference.class = ACPI_REFCLASS_NAME; |
513 | if (op->common.node) { |
514 | obj_desc->reference.object = |
515 | op->common.node->object; |
516 | } |
517 | break; |
518 | |
519 | case AML_DEBUG_OP: |
520 | |
521 | obj_desc->reference.class = ACPI_REFCLASS_DEBUG; |
522 | break; |
523 | |
524 | default: |
525 | |
526 | ACPI_ERROR((AE_INFO, |
527 | "Unimplemented reference type for AML opcode: 0x%4.4X" , |
528 | opcode)); |
529 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
530 | } |
531 | break; |
532 | } |
533 | break; |
534 | |
535 | default: |
536 | |
537 | ACPI_ERROR((AE_INFO, "Unimplemented data type: 0x%X" , |
538 | obj_desc->common.type)); |
539 | |
540 | status = AE_AML_OPERAND_TYPE; |
541 | break; |
542 | } |
543 | |
544 | return_ACPI_STATUS(status); |
545 | } |
546 | |