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
19ACPI_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 ******************************************************************************/
33acpi_status
34acpi_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
98acpi_status
99acpi_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
181acpi_status
182acpi_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
285acpi_status
286acpi_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
352acpi_status
353acpi_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
431acpi_status
432acpi_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
486error_exit:
487	ACPI_FREE(name);
488	*return_object = new_object;
489	return (status);
490}
491