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 - 2021, 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
acpi_ns_convert_to_integer(union acpi_operand_object * original_object,union acpi_operand_object ** return_object)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(original_object->string.pointer, &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
acpi_ns_convert_to_string(union acpi_operand_object * original_object,union acpi_operand_object ** return_object)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(0);
118 if (!new_object) {
119 return (AE_NO_MEMORY);
120 }
121 } else {
122 status = acpi_ex_convert_to_string(original_object,
123 &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(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
acpi_ns_convert_to_buffer(union acpi_operand_object * original_object,union acpi_operand_object ** return_object)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(original_object, &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 (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
acpi_ns_convert_to_unicode(struct acpi_namespace_node * scope,union acpi_operand_object * original_object,union acpi_operand_object ** return_object)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(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
acpi_ns_convert_to_resource(struct acpi_namespace_node * scope,union acpi_operand_object * original_object,union acpi_operand_object ** return_object)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(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
acpi_ns_convert_to_reference(struct acpi_namespace_node * scope,union acpi_operand_object * original_object,union acpi_operand_object ** return_object)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(original_object->string.pointer, &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, name, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
458 ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
459 NULL, &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(node->object);
485
486 error_exit:
487 ACPI_FREE(name);
488 *return_object = new_object;
489 return (status);
490 }
491