1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: exoparg3 - AML execution - opcodes with 3 arguments |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acinterp.h" |
13 | #include "acparser.h" |
14 | #include "amlcode.h" |
15 | |
16 | #define _COMPONENT ACPI_EXECUTER |
17 | ACPI_MODULE_NAME("exoparg3" ) |
18 | |
19 | /*! |
20 | * Naming convention for AML interpreter execution routines. |
21 | * |
22 | * The routines that begin execution of AML opcodes are named with a common |
23 | * convention based upon the number of arguments, the number of target operands, |
24 | * and whether or not a value is returned: |
25 | * |
26 | * AcpiExOpcode_xA_yT_zR |
27 | * |
28 | * Where: |
29 | * |
30 | * xA - ARGUMENTS: The number of arguments (input operands) that are |
31 | * required for this opcode type (1 through 6 args). |
32 | * yT - TARGETS: The number of targets (output operands) that are required |
33 | * for this opcode type (0, 1, or 2 targets). |
34 | * zR - RETURN VALUE: Indicates whether this opcode type returns a value |
35 | * as the function return (0 or 1). |
36 | * |
37 | * The AcpiExOpcode* functions are called via the Dispatcher component with |
38 | * fully resolved operands. |
39 | !*/ |
40 | /******************************************************************************* |
41 | * |
42 | * FUNCTION: acpi_ex_opcode_3A_0T_0R |
43 | * |
44 | * PARAMETERS: walk_state - Current walk state |
45 | * |
46 | * RETURN: Status |
47 | * |
48 | * DESCRIPTION: Execute Triadic operator (3 operands) |
49 | * |
50 | ******************************************************************************/ |
51 | acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state) |
52 | { |
53 | union acpi_operand_object **operand = &walk_state->operands[0]; |
54 | struct acpi_signal_fatal_info *fatal; |
55 | acpi_status status = AE_OK; |
56 | |
57 | ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_0T_0R, |
58 | acpi_ps_get_opcode_name(walk_state->opcode)); |
59 | |
60 | switch (walk_state->opcode) { |
61 | case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */ |
62 | |
63 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
64 | "FatalOp: Type %X Code %X Arg %X " |
65 | "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n" , |
66 | (u32)operand[0]->integer.value, |
67 | (u32)operand[1]->integer.value, |
68 | (u32)operand[2]->integer.value)); |
69 | |
70 | fatal = ACPI_ALLOCATE(sizeof(struct acpi_signal_fatal_info)); |
71 | if (fatal) { |
72 | fatal->type = (u32) operand[0]->integer.value; |
73 | fatal->code = (u32) operand[1]->integer.value; |
74 | fatal->argument = (u32) operand[2]->integer.value; |
75 | } |
76 | |
77 | /* Always signal the OS! */ |
78 | |
79 | status = acpi_os_signal(ACPI_SIGNAL_FATAL, info: fatal); |
80 | |
81 | /* Might return while OS is shutting down, just continue */ |
82 | |
83 | ACPI_FREE(fatal); |
84 | goto cleanup; |
85 | |
86 | case AML_EXTERNAL_OP: |
87 | /* |
88 | * If the interpreter sees this opcode, just ignore it. The External |
89 | * op is intended for use by disassemblers in order to properly |
90 | * disassemble control method invocations. The opcode or group of |
91 | * opcodes should be surrounded by an "if (0)" clause to ensure that |
92 | * AML interpreters never see the opcode. Thus, something is |
93 | * wrong if an external opcode ever gets here. |
94 | */ |
95 | ACPI_ERROR((AE_INFO, "Executed External Op" )); |
96 | status = AE_OK; |
97 | goto cleanup; |
98 | |
99 | default: |
100 | |
101 | ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X" , |
102 | walk_state->opcode)); |
103 | |
104 | status = AE_AML_BAD_OPCODE; |
105 | goto cleanup; |
106 | } |
107 | |
108 | cleanup: |
109 | |
110 | return_ACPI_STATUS(status); |
111 | } |
112 | |
113 | /******************************************************************************* |
114 | * |
115 | * FUNCTION: acpi_ex_opcode_3A_1T_1R |
116 | * |
117 | * PARAMETERS: walk_state - Current walk state |
118 | * |
119 | * RETURN: Status |
120 | * |
121 | * DESCRIPTION: Execute Triadic operator (3 operands) |
122 | * |
123 | ******************************************************************************/ |
124 | |
125 | acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) |
126 | { |
127 | union acpi_operand_object **operand = &walk_state->operands[0]; |
128 | union acpi_operand_object *return_desc = NULL; |
129 | char *buffer = NULL; |
130 | acpi_status status = AE_OK; |
131 | u64 index; |
132 | acpi_size length; |
133 | |
134 | ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_1T_1R, |
135 | acpi_ps_get_opcode_name(walk_state->opcode)); |
136 | |
137 | switch (walk_state->opcode) { |
138 | case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */ |
139 | /* |
140 | * Create the return object. The Source operand is guaranteed to be |
141 | * either a String or a Buffer, so just use its type. |
142 | */ |
143 | return_desc = acpi_ut_create_internal_object((operand[0])-> |
144 | common.type); |
145 | if (!return_desc) { |
146 | status = AE_NO_MEMORY; |
147 | goto cleanup; |
148 | } |
149 | |
150 | /* Get the Integer values from the objects */ |
151 | |
152 | index = operand[1]->integer.value; |
153 | length = (acpi_size)operand[2]->integer.value; |
154 | |
155 | /* |
156 | * If the index is beyond the length of the String/Buffer, or if the |
157 | * requested length is zero, return a zero-length String/Buffer |
158 | */ |
159 | if (index >= operand[0]->string.length) { |
160 | length = 0; |
161 | } |
162 | |
163 | /* Truncate request if larger than the actual String/Buffer */ |
164 | |
165 | else if ((index + length) > operand[0]->string.length) { |
166 | length = |
167 | (acpi_size)operand[0]->string.length - |
168 | (acpi_size)index; |
169 | } |
170 | |
171 | /* Strings always have a sub-pointer, not so for buffers */ |
172 | |
173 | switch ((operand[0])->common.type) { |
174 | case ACPI_TYPE_STRING: |
175 | |
176 | /* Always allocate a new buffer for the String */ |
177 | |
178 | buffer = ACPI_ALLOCATE_ZEROED((acpi_size)length + 1); |
179 | if (!buffer) { |
180 | status = AE_NO_MEMORY; |
181 | goto cleanup; |
182 | } |
183 | break; |
184 | |
185 | case ACPI_TYPE_BUFFER: |
186 | |
187 | /* If the requested length is zero, don't allocate a buffer */ |
188 | |
189 | if (length > 0) { |
190 | |
191 | /* Allocate a new buffer for the Buffer */ |
192 | |
193 | buffer = ACPI_ALLOCATE_ZEROED(length); |
194 | if (!buffer) { |
195 | status = AE_NO_MEMORY; |
196 | goto cleanup; |
197 | } |
198 | } |
199 | break; |
200 | |
201 | default: /* Should not happen */ |
202 | |
203 | status = AE_AML_OPERAND_TYPE; |
204 | goto cleanup; |
205 | } |
206 | |
207 | if (buffer) { |
208 | |
209 | /* We have a buffer, copy the portion requested */ |
210 | |
211 | memcpy(buffer, |
212 | operand[0]->string.pointer + index, length); |
213 | } |
214 | |
215 | /* Set the length of the new String/Buffer */ |
216 | |
217 | return_desc->string.pointer = buffer; |
218 | return_desc->string.length = (u32) length; |
219 | |
220 | /* Mark buffer initialized */ |
221 | |
222 | return_desc->buffer.flags |= AOPOBJ_DATA_VALID; |
223 | break; |
224 | |
225 | default: |
226 | |
227 | ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X" , |
228 | walk_state->opcode)); |
229 | |
230 | status = AE_AML_BAD_OPCODE; |
231 | goto cleanup; |
232 | } |
233 | |
234 | /* Store the result in the target */ |
235 | |
236 | status = acpi_ex_store(val_desc: return_desc, dest_desc: operand[3], walk_state); |
237 | |
238 | cleanup: |
239 | |
240 | /* Delete return object on error */ |
241 | |
242 | if (ACPI_FAILURE(status) || walk_state->result_obj) { |
243 | acpi_ut_remove_reference(object: return_desc); |
244 | walk_state->result_obj = NULL; |
245 | } else { |
246 | /* Set the return object and exit */ |
247 | |
248 | walk_state->result_obj = return_desc; |
249 | } |
250 | |
251 | return_ACPI_STATUS(status); |
252 | } |
253 | |