1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: nsconvert - Object conversions for objects returned by |
5 | * predefined methods |
6 | * |
7 | * Copyright (C) 2000 - 2023, Intel Corp. |
8 | * |
9 | *****************************************************************************/ |
10 | |
11 | #include <acpi/acpi.h> |
12 | #include "accommon.h" |
13 | #include "acnamesp.h" |
14 | #include "acinterp.h" |
15 | #include "acpredef.h" |
16 | #include "amlresrc.h" |
17 | |
18 | #define _COMPONENT ACPI_NAMESPACE |
19 | ACPI_MODULE_NAME("nsconvert" ) |
20 | |
21 | /******************************************************************************* |
22 | * |
23 | * FUNCTION: acpi_ns_convert_to_integer |
24 | * |
25 | * PARAMETERS: original_object - Object to be converted |
26 | * return_object - Where the new converted object is returned |
27 | * |
28 | * RETURN: Status. AE_OK if conversion was successful. |
29 | * |
30 | * DESCRIPTION: Attempt to convert a String/Buffer object to an Integer. |
31 | * |
32 | ******************************************************************************/ |
33 | acpi_status |
34 | acpi_ns_convert_to_integer(union acpi_operand_object *original_object, |
35 | union acpi_operand_object **return_object) |
36 | { |
37 | union acpi_operand_object *new_object; |
38 | acpi_status status; |
39 | u64 value = 0; |
40 | u32 i; |
41 | |
42 | switch (original_object->common.type) { |
43 | case ACPI_TYPE_STRING: |
44 | |
45 | /* String-to-Integer conversion */ |
46 | |
47 | status = |
48 | acpi_ut_strtoul64(string: original_object->string.pointer, ret_integer: &value); |
49 | if (ACPI_FAILURE(status)) { |
50 | return (status); |
51 | } |
52 | break; |
53 | |
54 | case ACPI_TYPE_BUFFER: |
55 | |
56 | /* Buffer-to-Integer conversion. Max buffer size is 64 bits. */ |
57 | |
58 | if (original_object->buffer.length > 8) { |
59 | return (AE_AML_OPERAND_TYPE); |
60 | } |
61 | |
62 | /* Extract each buffer byte to create the integer */ |
63 | |
64 | for (i = 0; i < original_object->buffer.length; i++) { |
65 | value |= ((u64) |
66 | original_object->buffer.pointer[i] << (i * |
67 | 8)); |
68 | } |
69 | break; |
70 | |
71 | default: |
72 | |
73 | return (AE_AML_OPERAND_TYPE); |
74 | } |
75 | |
76 | new_object = acpi_ut_create_integer_object(value); |
77 | if (!new_object) { |
78 | return (AE_NO_MEMORY); |
79 | } |
80 | |
81 | *return_object = new_object; |
82 | return (AE_OK); |
83 | } |
84 | |
85 | /******************************************************************************* |
86 | * |
87 | * FUNCTION: acpi_ns_convert_to_string |
88 | * |
89 | * PARAMETERS: original_object - Object to be converted |
90 | * return_object - Where the new converted object is returned |
91 | * |
92 | * RETURN: Status. AE_OK if conversion was successful. |
93 | * |
94 | * DESCRIPTION: Attempt to convert a Integer/Buffer object to a String. |
95 | * |
96 | ******************************************************************************/ |
97 | |
98 | acpi_status |
99 | acpi_ns_convert_to_string(union acpi_operand_object *original_object, |
100 | union acpi_operand_object **return_object) |
101 | { |
102 | union acpi_operand_object *new_object; |
103 | acpi_size length; |
104 | acpi_status status; |
105 | |
106 | switch (original_object->common.type) { |
107 | case ACPI_TYPE_INTEGER: |
108 | /* |
109 | * Integer-to-String conversion. Commonly, convert |
110 | * an integer of value 0 to a NULL string. The last element of |
111 | * _BIF and _BIX packages occasionally need this fix. |
112 | */ |
113 | if (original_object->integer.value == 0) { |
114 | |
115 | /* Allocate a new NULL string object */ |
116 | |
117 | new_object = acpi_ut_create_string_object(string_size: 0); |
118 | if (!new_object) { |
119 | return (AE_NO_MEMORY); |
120 | } |
121 | } else { |
122 | status = acpi_ex_convert_to_string(obj_desc: original_object, |
123 | result_desc: &new_object, |
124 | ACPI_IMPLICIT_CONVERT_HEX); |
125 | if (ACPI_FAILURE(status)) { |
126 | return (status); |
127 | } |
128 | } |
129 | break; |
130 | |
131 | case ACPI_TYPE_BUFFER: |
132 | /* |
133 | * Buffer-to-String conversion. Use a to_string |
134 | * conversion, no transform performed on the buffer data. The best |
135 | * example of this is the _BIF method, where the string data from |
136 | * the battery is often (incorrectly) returned as buffer object(s). |
137 | */ |
138 | length = 0; |
139 | while ((length < original_object->buffer.length) && |
140 | (original_object->buffer.pointer[length])) { |
141 | length++; |
142 | } |
143 | |
144 | /* Allocate a new string object */ |
145 | |
146 | new_object = acpi_ut_create_string_object(string_size: length); |
147 | if (!new_object) { |
148 | return (AE_NO_MEMORY); |
149 | } |
150 | |
151 | /* |
152 | * Copy the raw buffer data with no transform. String is already NULL |
153 | * terminated at Length+1. |
154 | */ |
155 | memcpy(new_object->string.pointer, |
156 | original_object->buffer.pointer, length); |
157 | break; |
158 | |
159 | default: |
160 | |
161 | return (AE_AML_OPERAND_TYPE); |
162 | } |
163 | |
164 | *return_object = new_object; |
165 | return (AE_OK); |
166 | } |
167 | |
168 | /******************************************************************************* |
169 | * |
170 | * FUNCTION: acpi_ns_convert_to_buffer |
171 | * |
172 | * PARAMETERS: original_object - Object to be converted |
173 | * return_object - Where the new converted object is returned |
174 | * |
175 | * RETURN: Status. AE_OK if conversion was successful. |
176 | * |
177 | * DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer. |
178 | * |
179 | ******************************************************************************/ |
180 | |
181 | acpi_status |
182 | acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, |
183 | union acpi_operand_object **return_object) |
184 | { |
185 | union acpi_operand_object *new_object; |
186 | acpi_status status; |
187 | union acpi_operand_object **elements; |
188 | u32 *dword_buffer; |
189 | u32 count; |
190 | u32 i; |
191 | |
192 | switch (original_object->common.type) { |
193 | case ACPI_TYPE_INTEGER: |
194 | /* |
195 | * Integer-to-Buffer conversion. |
196 | * Convert the Integer to a packed-byte buffer. _MAT and other |
197 | * objects need this sometimes, if a read has been performed on a |
198 | * Field object that is less than or equal to the global integer |
199 | * size (32 or 64 bits). |
200 | */ |
201 | status = |
202 | acpi_ex_convert_to_buffer(obj_desc: original_object, result_desc: &new_object); |
203 | if (ACPI_FAILURE(status)) { |
204 | return (status); |
205 | } |
206 | break; |
207 | |
208 | case ACPI_TYPE_STRING: |
209 | |
210 | /* String-to-Buffer conversion. Simple data copy */ |
211 | |
212 | new_object = acpi_ut_create_buffer_object |
213 | (buffer_size: original_object->string.length); |
214 | if (!new_object) { |
215 | return (AE_NO_MEMORY); |
216 | } |
217 | |
218 | memcpy(new_object->buffer.pointer, |
219 | original_object->string.pointer, |
220 | original_object->string.length); |
221 | break; |
222 | |
223 | case ACPI_TYPE_PACKAGE: |
224 | /* |
225 | * This case is often seen for predefined names that must return a |
226 | * Buffer object with multiple DWORD integers within. For example, |
227 | * _FDE and _GTM. The Package can be converted to a Buffer. |
228 | */ |
229 | |
230 | /* All elements of the Package must be integers */ |
231 | |
232 | elements = original_object->package.elements; |
233 | count = original_object->package.count; |
234 | |
235 | for (i = 0; i < count; i++) { |
236 | if ((!*elements) || |
237 | ((*elements)->common.type != ACPI_TYPE_INTEGER)) { |
238 | return (AE_AML_OPERAND_TYPE); |
239 | } |
240 | elements++; |
241 | } |
242 | |
243 | /* Create the new buffer object to replace the Package */ |
244 | |
245 | new_object = acpi_ut_create_buffer_object(ACPI_MUL_4(count)); |
246 | if (!new_object) { |
247 | return (AE_NO_MEMORY); |
248 | } |
249 | |
250 | /* Copy the package elements (integers) to the buffer as DWORDs */ |
251 | |
252 | elements = original_object->package.elements; |
253 | dword_buffer = ACPI_CAST_PTR(u32, new_object->buffer.pointer); |
254 | |
255 | for (i = 0; i < count; i++) { |
256 | *dword_buffer = (u32)(*elements)->integer.value; |
257 | dword_buffer++; |
258 | elements++; |
259 | } |
260 | break; |
261 | |
262 | default: |
263 | |
264 | return (AE_AML_OPERAND_TYPE); |
265 | } |
266 | |
267 | *return_object = new_object; |
268 | return (AE_OK); |
269 | } |
270 | |
271 | /******************************************************************************* |
272 | * |
273 | * FUNCTION: acpi_ns_convert_to_unicode |
274 | * |
275 | * PARAMETERS: scope - Namespace node for the method/object |
276 | * original_object - ASCII String Object to be converted |
277 | * return_object - Where the new converted object is returned |
278 | * |
279 | * RETURN: Status. AE_OK if conversion was successful. |
280 | * |
281 | * DESCRIPTION: Attempt to convert a String object to a Unicode string Buffer. |
282 | * |
283 | ******************************************************************************/ |
284 | |
285 | acpi_status |
286 | acpi_ns_convert_to_unicode(struct acpi_namespace_node *scope, |
287 | union acpi_operand_object *original_object, |
288 | union acpi_operand_object **return_object) |
289 | { |
290 | union acpi_operand_object *new_object; |
291 | char *ascii_string; |
292 | u16 *unicode_buffer; |
293 | u32 unicode_length; |
294 | u32 i; |
295 | |
296 | if (!original_object) { |
297 | return (AE_OK); |
298 | } |
299 | |
300 | /* If a Buffer was returned, it must be at least two bytes long */ |
301 | |
302 | if (original_object->common.type == ACPI_TYPE_BUFFER) { |
303 | if (original_object->buffer.length < 2) { |
304 | return (AE_AML_OPERAND_VALUE); |
305 | } |
306 | |
307 | *return_object = NULL; |
308 | return (AE_OK); |
309 | } |
310 | |
311 | /* |
312 | * The original object is an ASCII string. Convert this string to |
313 | * a unicode buffer. |
314 | */ |
315 | ascii_string = original_object->string.pointer; |
316 | unicode_length = (original_object->string.length * 2) + 2; |
317 | |
318 | /* Create a new buffer object for the Unicode data */ |
319 | |
320 | new_object = acpi_ut_create_buffer_object(buffer_size: unicode_length); |
321 | if (!new_object) { |
322 | return (AE_NO_MEMORY); |
323 | } |
324 | |
325 | unicode_buffer = ACPI_CAST_PTR(u16, new_object->buffer.pointer); |
326 | |
327 | /* Convert ASCII to Unicode */ |
328 | |
329 | for (i = 0; i < original_object->string.length; i++) { |
330 | unicode_buffer[i] = (u16)ascii_string[i]; |
331 | } |
332 | |
333 | *return_object = new_object; |
334 | return (AE_OK); |
335 | } |
336 | |
337 | /******************************************************************************* |
338 | * |
339 | * FUNCTION: acpi_ns_convert_to_resource |
340 | * |
341 | * PARAMETERS: scope - Namespace node for the method/object |
342 | * original_object - Object to be converted |
343 | * return_object - Where the new converted object is returned |
344 | * |
345 | * RETURN: Status. AE_OK if conversion was successful |
346 | * |
347 | * DESCRIPTION: Attempt to convert a Integer object to a resource_template |
348 | * Buffer. |
349 | * |
350 | ******************************************************************************/ |
351 | |
352 | acpi_status |
353 | acpi_ns_convert_to_resource(struct acpi_namespace_node *scope, |
354 | union acpi_operand_object *original_object, |
355 | union acpi_operand_object **return_object) |
356 | { |
357 | union acpi_operand_object *new_object; |
358 | u8 *buffer; |
359 | |
360 | /* |
361 | * We can fix the following cases for an expected resource template: |
362 | * 1. No return value (interpreter slack mode is disabled) |
363 | * 2. A "Return (Zero)" statement |
364 | * 3. A "Return empty buffer" statement |
365 | * |
366 | * We will return a buffer containing a single end_tag |
367 | * resource descriptor. |
368 | */ |
369 | if (original_object) { |
370 | switch (original_object->common.type) { |
371 | case ACPI_TYPE_INTEGER: |
372 | |
373 | /* We can only repair an Integer==0 */ |
374 | |
375 | if (original_object->integer.value) { |
376 | return (AE_AML_OPERAND_TYPE); |
377 | } |
378 | break; |
379 | |
380 | case ACPI_TYPE_BUFFER: |
381 | |
382 | if (original_object->buffer.length) { |
383 | |
384 | /* Additional checks can be added in the future */ |
385 | |
386 | *return_object = NULL; |
387 | return (AE_OK); |
388 | } |
389 | break; |
390 | |
391 | case ACPI_TYPE_STRING: |
392 | default: |
393 | |
394 | return (AE_AML_OPERAND_TYPE); |
395 | } |
396 | } |
397 | |
398 | /* Create the new buffer object for the resource descriptor */ |
399 | |
400 | new_object = acpi_ut_create_buffer_object(buffer_size: 2); |
401 | if (!new_object) { |
402 | return (AE_NO_MEMORY); |
403 | } |
404 | |
405 | buffer = ACPI_CAST_PTR(u8, new_object->buffer.pointer); |
406 | |
407 | /* Initialize the Buffer with a single end_tag descriptor */ |
408 | |
409 | buffer[0] = (ACPI_RESOURCE_NAME_END_TAG | ASL_RDESC_END_TAG_SIZE); |
410 | buffer[1] = 0x00; |
411 | |
412 | *return_object = new_object; |
413 | return (AE_OK); |
414 | } |
415 | |
416 | /******************************************************************************* |
417 | * |
418 | * FUNCTION: acpi_ns_convert_to_reference |
419 | * |
420 | * PARAMETERS: scope - Namespace node for the method/object |
421 | * original_object - Object to be converted |
422 | * return_object - Where the new converted object is returned |
423 | * |
424 | * RETURN: Status. AE_OK if conversion was successful |
425 | * |
426 | * DESCRIPTION: Attempt to convert a Integer object to a object_reference. |
427 | * Buffer. |
428 | * |
429 | ******************************************************************************/ |
430 | |
431 | acpi_status |
432 | acpi_ns_convert_to_reference(struct acpi_namespace_node *scope, |
433 | union acpi_operand_object *original_object, |
434 | union acpi_operand_object **return_object) |
435 | { |
436 | union acpi_operand_object *new_object = NULL; |
437 | acpi_status status; |
438 | struct acpi_namespace_node *node; |
439 | union acpi_generic_state scope_info; |
440 | char *name; |
441 | |
442 | ACPI_FUNCTION_NAME(ns_convert_to_reference); |
443 | |
444 | /* Convert path into internal presentation */ |
445 | |
446 | status = |
447 | acpi_ns_internalize_name(dotted_name: original_object->string.pointer, converted_name: &name); |
448 | if (ACPI_FAILURE(status)) { |
449 | return_ACPI_STATUS(status); |
450 | } |
451 | |
452 | /* Find the namespace node */ |
453 | |
454 | scope_info.scope.node = |
455 | ACPI_CAST_PTR(struct acpi_namespace_node, scope); |
456 | status = |
457 | acpi_ns_lookup(scope_info: &scope_info, name, ACPI_TYPE_ANY, interpreter_mode: ACPI_IMODE_EXECUTE, |
458 | ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, |
459 | NULL, ret_node: &node); |
460 | if (ACPI_FAILURE(status)) { |
461 | |
462 | /* Check if we are resolving a named reference within a package */ |
463 | |
464 | ACPI_ERROR_NAMESPACE(&scope_info, |
465 | original_object->string.pointer, status); |
466 | goto error_exit; |
467 | } |
468 | |
469 | /* Create and init a new internal ACPI object */ |
470 | |
471 | new_object = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE); |
472 | if (!new_object) { |
473 | status = AE_NO_MEMORY; |
474 | goto error_exit; |
475 | } |
476 | new_object->reference.node = node; |
477 | new_object->reference.object = node->object; |
478 | new_object->reference.class = ACPI_REFCLASS_NAME; |
479 | |
480 | /* |
481 | * Increase reference of the object if needed (the object is likely a |
482 | * null for device nodes). |
483 | */ |
484 | acpi_ut_add_reference(object: node->object); |
485 | |
486 | error_exit: |
487 | ACPI_FREE(name); |
488 | *return_object = new_object; |
489 | return (status); |
490 | } |
491 | |