xref: /openbmc/linux/drivers/acpi/acpica/nsconvert.c (revision 612c2932)
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
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