195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2890b090eSBob Moore /******************************************************************************
3890b090eSBob Moore *
4890b090eSBob Moore * Module Name: exconcat - Concatenate-type AML operators
5890b090eSBob Moore *
6*612c2932SBob Moore * Copyright (C) 2000 - 2023, Intel Corp.
7890b090eSBob Moore *
895857638SErik Schmauss *****************************************************************************/
9890b090eSBob Moore
10890b090eSBob Moore #include <acpi/acpi.h>
11890b090eSBob Moore #include "accommon.h"
12890b090eSBob Moore #include "acinterp.h"
13890b090eSBob Moore #include "amlresrc.h"
14890b090eSBob Moore
15890b090eSBob Moore #define _COMPONENT ACPI_EXECUTER
16890b090eSBob Moore ACPI_MODULE_NAME("exconcat")
17890b090eSBob Moore
18890b090eSBob Moore /* Local Prototypes */
19890b090eSBob Moore static acpi_status
20890b090eSBob Moore acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc,
21890b090eSBob Moore union acpi_operand_object **result_desc);
22890b090eSBob Moore
23890b090eSBob Moore /*******************************************************************************
24890b090eSBob Moore *
25890b090eSBob Moore * FUNCTION: acpi_ex_do_concatenate
26890b090eSBob Moore *
27890b090eSBob Moore * PARAMETERS: operand0 - First source object
28890b090eSBob Moore * operand1 - Second source object
29890b090eSBob Moore * actual_return_desc - Where to place the return object
30890b090eSBob Moore * walk_state - Current walk state
31890b090eSBob Moore *
32890b090eSBob Moore * RETURN: Status
33890b090eSBob Moore *
34890b090eSBob Moore * DESCRIPTION: Concatenate two objects with the ACPI-defined conversion
35890b090eSBob Moore * rules as necessary.
36890b090eSBob Moore * NOTE:
37890b090eSBob Moore * Per the ACPI spec (up to 6.1), Concatenate only supports Integer,
38890b090eSBob Moore * String, and Buffer objects. However, we support all objects here
39890b090eSBob Moore * as an extension. This improves the usefulness of both Concatenate
40890b090eSBob Moore * and the Printf/Fprintf macros. The extension returns a string
41890b090eSBob Moore * describing the object type for the other objects.
42890b090eSBob Moore * 02/2016.
43890b090eSBob Moore *
44890b090eSBob Moore ******************************************************************************/
45890b090eSBob Moore
46890b090eSBob Moore acpi_status
acpi_ex_do_concatenate(union acpi_operand_object * operand0,union acpi_operand_object * operand1,union acpi_operand_object ** actual_return_desc,struct acpi_walk_state * walk_state)47890b090eSBob Moore acpi_ex_do_concatenate(union acpi_operand_object *operand0,
48890b090eSBob Moore union acpi_operand_object *operand1,
49890b090eSBob Moore union acpi_operand_object **actual_return_desc,
50890b090eSBob Moore struct acpi_walk_state *walk_state)
51890b090eSBob Moore {
52890b090eSBob Moore union acpi_operand_object *local_operand0 = operand0;
53890b090eSBob Moore union acpi_operand_object *local_operand1 = operand1;
54890b090eSBob Moore union acpi_operand_object *temp_operand1 = NULL;
55890b090eSBob Moore union acpi_operand_object *return_desc;
56890b090eSBob Moore char *buffer;
57890b090eSBob Moore acpi_object_type operand0_type;
58890b090eSBob Moore acpi_object_type operand1_type;
59890b090eSBob Moore acpi_status status;
60890b090eSBob Moore
61890b090eSBob Moore ACPI_FUNCTION_TRACE(ex_do_concatenate);
62890b090eSBob Moore
63890b090eSBob Moore /* Operand 0 preprocessing */
64890b090eSBob Moore
65890b090eSBob Moore switch (operand0->common.type) {
66890b090eSBob Moore case ACPI_TYPE_INTEGER:
67890b090eSBob Moore case ACPI_TYPE_STRING:
68890b090eSBob Moore case ACPI_TYPE_BUFFER:
69890b090eSBob Moore
70890b090eSBob Moore operand0_type = operand0->common.type;
71890b090eSBob Moore break;
72890b090eSBob Moore
73890b090eSBob Moore default:
74890b090eSBob Moore
75890b090eSBob Moore /* For all other types, get the "object type" string */
76890b090eSBob Moore
77890b090eSBob Moore status =
78890b090eSBob Moore acpi_ex_convert_to_object_type_string(operand0,
79890b090eSBob Moore &local_operand0);
80890b090eSBob Moore if (ACPI_FAILURE(status)) {
81890b090eSBob Moore goto cleanup;
82890b090eSBob Moore }
83890b090eSBob Moore
84890b090eSBob Moore operand0_type = ACPI_TYPE_STRING;
85890b090eSBob Moore break;
86890b090eSBob Moore }
87890b090eSBob Moore
88890b090eSBob Moore /* Operand 1 preprocessing */
89890b090eSBob Moore
90890b090eSBob Moore switch (operand1->common.type) {
91890b090eSBob Moore case ACPI_TYPE_INTEGER:
92890b090eSBob Moore case ACPI_TYPE_STRING:
93890b090eSBob Moore case ACPI_TYPE_BUFFER:
94890b090eSBob Moore
95890b090eSBob Moore operand1_type = operand1->common.type;
96890b090eSBob Moore break;
97890b090eSBob Moore
98890b090eSBob Moore default:
99890b090eSBob Moore
100890b090eSBob Moore /* For all other types, get the "object type" string */
101890b090eSBob Moore
102890b090eSBob Moore status =
103890b090eSBob Moore acpi_ex_convert_to_object_type_string(operand1,
104890b090eSBob Moore &local_operand1);
105890b090eSBob Moore if (ACPI_FAILURE(status)) {
106890b090eSBob Moore goto cleanup;
107890b090eSBob Moore }
108890b090eSBob Moore
109890b090eSBob Moore operand1_type = ACPI_TYPE_STRING;
110890b090eSBob Moore break;
111890b090eSBob Moore }
112890b090eSBob Moore
113890b090eSBob Moore /*
114890b090eSBob Moore * Convert the second operand if necessary. The first operand (0)
115890b090eSBob Moore * determines the type of the second operand (1) (See the Data Types
116890b090eSBob Moore * section of the ACPI specification). Both object types are
117890b090eSBob Moore * guaranteed to be either Integer/String/Buffer by the operand
118890b090eSBob Moore * resolution mechanism.
119890b090eSBob Moore */
120890b090eSBob Moore switch (operand0_type) {
121890b090eSBob Moore case ACPI_TYPE_INTEGER:
122890b090eSBob Moore
123890b090eSBob Moore status =
124890b090eSBob Moore acpi_ex_convert_to_integer(local_operand1, &temp_operand1,
125fe97d287SBob Moore ACPI_IMPLICIT_CONVERSION);
126890b090eSBob Moore break;
127890b090eSBob Moore
128890b090eSBob Moore case ACPI_TYPE_BUFFER:
129890b090eSBob Moore
130890b090eSBob Moore status =
131890b090eSBob Moore acpi_ex_convert_to_buffer(local_operand1, &temp_operand1);
132890b090eSBob Moore break;
133890b090eSBob Moore
134890b090eSBob Moore case ACPI_TYPE_STRING:
135890b090eSBob Moore
136890b090eSBob Moore switch (operand1_type) {
137890b090eSBob Moore case ACPI_TYPE_INTEGER:
138890b090eSBob Moore case ACPI_TYPE_STRING:
139890b090eSBob Moore case ACPI_TYPE_BUFFER:
140890b090eSBob Moore
141890b090eSBob Moore /* Other types have already been converted to string */
142890b090eSBob Moore
143890b090eSBob Moore status =
144890b090eSBob Moore acpi_ex_convert_to_string(local_operand1,
145890b090eSBob Moore &temp_operand1,
146890b090eSBob Moore ACPI_IMPLICIT_CONVERT_HEX);
147890b090eSBob Moore break;
148890b090eSBob Moore
149890b090eSBob Moore default:
150890b090eSBob Moore
151890b090eSBob Moore status = AE_OK;
152890b090eSBob Moore break;
153890b090eSBob Moore }
154890b090eSBob Moore break;
155890b090eSBob Moore
156890b090eSBob Moore default:
157890b090eSBob Moore
158890b090eSBob Moore ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",
159890b090eSBob Moore operand0->common.type));
160890b090eSBob Moore status = AE_AML_INTERNAL;
161890b090eSBob Moore }
162890b090eSBob Moore
163890b090eSBob Moore if (ACPI_FAILURE(status)) {
164890b090eSBob Moore goto cleanup;
165890b090eSBob Moore }
166890b090eSBob Moore
167890b090eSBob Moore /* Take care with any newly created operand objects */
168890b090eSBob Moore
169890b090eSBob Moore if ((local_operand1 != operand1) && (local_operand1 != temp_operand1)) {
170890b090eSBob Moore acpi_ut_remove_reference(local_operand1);
171890b090eSBob Moore }
172890b090eSBob Moore
173890b090eSBob Moore local_operand1 = temp_operand1;
174890b090eSBob Moore
175890b090eSBob Moore /*
176890b090eSBob Moore * Both operands are now known to be the same object type
177890b090eSBob Moore * (Both are Integer, String, or Buffer), and we can now perform
178890b090eSBob Moore * the concatenation.
179890b090eSBob Moore *
180890b090eSBob Moore * There are three cases to handle, as per the ACPI spec:
181890b090eSBob Moore *
182890b090eSBob Moore * 1) Two Integers concatenated to produce a new Buffer
183890b090eSBob Moore * 2) Two Strings concatenated to produce a new String
184890b090eSBob Moore * 3) Two Buffers concatenated to produce a new Buffer
185890b090eSBob Moore */
186890b090eSBob Moore switch (operand0_type) {
187890b090eSBob Moore case ACPI_TYPE_INTEGER:
188890b090eSBob Moore
189890b090eSBob Moore /* Result of two Integers is a Buffer */
190890b090eSBob Moore /* Need enough buffer space for two integers */
191890b090eSBob Moore
192890b090eSBob Moore return_desc = acpi_ut_create_buffer_object((acpi_size)
193890b090eSBob Moore ACPI_MUL_2
194890b090eSBob Moore (acpi_gbl_integer_byte_width));
195890b090eSBob Moore if (!return_desc) {
196890b090eSBob Moore status = AE_NO_MEMORY;
197890b090eSBob Moore goto cleanup;
198890b090eSBob Moore }
199890b090eSBob Moore
200890b090eSBob Moore buffer = (char *)return_desc->buffer.pointer;
201890b090eSBob Moore
202890b090eSBob Moore /* Copy the first integer, LSB first */
203890b090eSBob Moore
204890b090eSBob Moore memcpy(buffer, &operand0->integer.value,
205890b090eSBob Moore acpi_gbl_integer_byte_width);
206890b090eSBob Moore
207890b090eSBob Moore /* Copy the second integer (LSB first) after the first */
208890b090eSBob Moore
209890b090eSBob Moore memcpy(buffer + acpi_gbl_integer_byte_width,
210890b090eSBob Moore &local_operand1->integer.value,
211890b090eSBob Moore acpi_gbl_integer_byte_width);
212890b090eSBob Moore break;
213890b090eSBob Moore
214890b090eSBob Moore case ACPI_TYPE_STRING:
215890b090eSBob Moore
216890b090eSBob Moore /* Result of two Strings is a String */
217890b090eSBob Moore
218890b090eSBob Moore return_desc = acpi_ut_create_string_object(((acpi_size)
219890b090eSBob Moore local_operand0->
220890b090eSBob Moore string.length +
221890b090eSBob Moore local_operand1->
222890b090eSBob Moore string.length));
223890b090eSBob Moore if (!return_desc) {
224890b090eSBob Moore status = AE_NO_MEMORY;
225890b090eSBob Moore goto cleanup;
226890b090eSBob Moore }
227890b090eSBob Moore
228890b090eSBob Moore buffer = return_desc->string.pointer;
229890b090eSBob Moore
230890b090eSBob Moore /* Concatenate the strings */
231890b090eSBob Moore
232890b090eSBob Moore strcpy(buffer, local_operand0->string.pointer);
233890b090eSBob Moore strcat(buffer, local_operand1->string.pointer);
234890b090eSBob Moore break;
235890b090eSBob Moore
236890b090eSBob Moore case ACPI_TYPE_BUFFER:
237890b090eSBob Moore
238890b090eSBob Moore /* Result of two Buffers is a Buffer */
239890b090eSBob Moore
240890b090eSBob Moore return_desc = acpi_ut_create_buffer_object(((acpi_size)
241890b090eSBob Moore operand0->buffer.
242890b090eSBob Moore length +
243890b090eSBob Moore local_operand1->
244890b090eSBob Moore buffer.length));
245890b090eSBob Moore if (!return_desc) {
246890b090eSBob Moore status = AE_NO_MEMORY;
247890b090eSBob Moore goto cleanup;
248890b090eSBob Moore }
249890b090eSBob Moore
250890b090eSBob Moore buffer = (char *)return_desc->buffer.pointer;
251890b090eSBob Moore
252890b090eSBob Moore /* Concatenate the buffers */
253890b090eSBob Moore
254890b090eSBob Moore memcpy(buffer, operand0->buffer.pointer,
255890b090eSBob Moore operand0->buffer.length);
256890b090eSBob Moore memcpy(buffer + operand0->buffer.length,
257890b090eSBob Moore local_operand1->buffer.pointer,
258890b090eSBob Moore local_operand1->buffer.length);
259890b090eSBob Moore break;
260890b090eSBob Moore
261890b090eSBob Moore default:
262890b090eSBob Moore
263890b090eSBob Moore /* Invalid object type, should not happen here */
264890b090eSBob Moore
265890b090eSBob Moore ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",
266890b090eSBob Moore operand0->common.type));
267890b090eSBob Moore status = AE_AML_INTERNAL;
268890b090eSBob Moore goto cleanup;
269890b090eSBob Moore }
270890b090eSBob Moore
271890b090eSBob Moore *actual_return_desc = return_desc;
272890b090eSBob Moore
273890b090eSBob Moore cleanup:
274890b090eSBob Moore if (local_operand0 != operand0) {
275890b090eSBob Moore acpi_ut_remove_reference(local_operand0);
276890b090eSBob Moore }
277890b090eSBob Moore
278890b090eSBob Moore if (local_operand1 != operand1) {
279890b090eSBob Moore acpi_ut_remove_reference(local_operand1);
280890b090eSBob Moore }
281890b090eSBob Moore
282890b090eSBob Moore return_ACPI_STATUS(status);
283890b090eSBob Moore }
284890b090eSBob Moore
285890b090eSBob Moore /*******************************************************************************
286890b090eSBob Moore *
287890b090eSBob Moore * FUNCTION: acpi_ex_convert_to_object_type_string
288890b090eSBob Moore *
289890b090eSBob Moore * PARAMETERS: obj_desc - Object to be converted
290890b090eSBob Moore * return_desc - Where to place the return object
291890b090eSBob Moore *
292890b090eSBob Moore * RETURN: Status
293890b090eSBob Moore *
294890b090eSBob Moore * DESCRIPTION: Convert an object of arbitrary type to a string object that
295890b090eSBob Moore * contains the namestring for the object. Used for the
296890b090eSBob Moore * concatenate operator.
297890b090eSBob Moore *
298890b090eSBob Moore ******************************************************************************/
299890b090eSBob Moore
300890b090eSBob Moore static acpi_status
acpi_ex_convert_to_object_type_string(union acpi_operand_object * obj_desc,union acpi_operand_object ** result_desc)301890b090eSBob Moore acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc,
302890b090eSBob Moore union acpi_operand_object **result_desc)
303890b090eSBob Moore {
304890b090eSBob Moore union acpi_operand_object *return_desc;
305890b090eSBob Moore const char *type_string;
306890b090eSBob Moore
307890b090eSBob Moore type_string = acpi_ut_get_type_name(obj_desc->common.type);
308890b090eSBob Moore
309890b090eSBob Moore return_desc = acpi_ut_create_string_object(((acpi_size)strlen(type_string) + 9)); /* 9 For "[ Object]" */
310890b090eSBob Moore if (!return_desc) {
311890b090eSBob Moore return (AE_NO_MEMORY);
312890b090eSBob Moore }
313890b090eSBob Moore
314890b090eSBob Moore strcpy(return_desc->string.pointer, "[");
315890b090eSBob Moore strcat(return_desc->string.pointer, type_string);
316890b090eSBob Moore strcat(return_desc->string.pointer, " Object]");
317890b090eSBob Moore
318890b090eSBob Moore *result_desc = return_desc;
319890b090eSBob Moore return (AE_OK);
320890b090eSBob Moore }
321890b090eSBob Moore
322890b090eSBob Moore /*******************************************************************************
323890b090eSBob Moore *
324890b090eSBob Moore * FUNCTION: acpi_ex_concat_template
325890b090eSBob Moore *
326890b090eSBob Moore * PARAMETERS: operand0 - First source object
327890b090eSBob Moore * operand1 - Second source object
328890b090eSBob Moore * actual_return_desc - Where to place the return object
329890b090eSBob Moore * walk_state - Current walk state
330890b090eSBob Moore *
331890b090eSBob Moore * RETURN: Status
332890b090eSBob Moore *
333890b090eSBob Moore * DESCRIPTION: Concatenate two resource templates
334890b090eSBob Moore *
335890b090eSBob Moore ******************************************************************************/
336890b090eSBob Moore
337890b090eSBob Moore acpi_status
acpi_ex_concat_template(union acpi_operand_object * operand0,union acpi_operand_object * operand1,union acpi_operand_object ** actual_return_desc,struct acpi_walk_state * walk_state)338890b090eSBob Moore acpi_ex_concat_template(union acpi_operand_object *operand0,
339890b090eSBob Moore union acpi_operand_object *operand1,
340890b090eSBob Moore union acpi_operand_object **actual_return_desc,
341890b090eSBob Moore struct acpi_walk_state *walk_state)
342890b090eSBob Moore {
343890b090eSBob Moore acpi_status status;
344890b090eSBob Moore union acpi_operand_object *return_desc;
345890b090eSBob Moore u8 *new_buf;
346890b090eSBob Moore u8 *end_tag;
347890b090eSBob Moore acpi_size length0;
348890b090eSBob Moore acpi_size length1;
349890b090eSBob Moore acpi_size new_length;
350890b090eSBob Moore
351890b090eSBob Moore ACPI_FUNCTION_TRACE(ex_concat_template);
352890b090eSBob Moore
353890b090eSBob Moore /*
354890b090eSBob Moore * Find the end_tag descriptor in each resource template.
355890b090eSBob Moore * Note1: returned pointers point TO the end_tag, not past it.
356890b090eSBob Moore * Note2: zero-length buffers are allowed; treated like one end_tag
357890b090eSBob Moore */
358890b090eSBob Moore
359890b090eSBob Moore /* Get the length of the first resource template */
360890b090eSBob Moore
361890b090eSBob Moore status = acpi_ut_get_resource_end_tag(operand0, &end_tag);
362890b090eSBob Moore if (ACPI_FAILURE(status)) {
363890b090eSBob Moore return_ACPI_STATUS(status);
364890b090eSBob Moore }
365890b090eSBob Moore
366890b090eSBob Moore length0 = ACPI_PTR_DIFF(end_tag, operand0->buffer.pointer);
367890b090eSBob Moore
368890b090eSBob Moore /* Get the length of the second resource template */
369890b090eSBob Moore
370890b090eSBob Moore status = acpi_ut_get_resource_end_tag(operand1, &end_tag);
371890b090eSBob Moore if (ACPI_FAILURE(status)) {
372890b090eSBob Moore return_ACPI_STATUS(status);
373890b090eSBob Moore }
374890b090eSBob Moore
375890b090eSBob Moore length1 = ACPI_PTR_DIFF(end_tag, operand1->buffer.pointer);
376890b090eSBob Moore
377890b090eSBob Moore /* Combine both lengths, minimum size will be 2 for end_tag */
378890b090eSBob Moore
379890b090eSBob Moore new_length = length0 + length1 + sizeof(struct aml_resource_end_tag);
380890b090eSBob Moore
381890b090eSBob Moore /* Create a new buffer object for the result (with one end_tag) */
382890b090eSBob Moore
383890b090eSBob Moore return_desc = acpi_ut_create_buffer_object(new_length);
384890b090eSBob Moore if (!return_desc) {
385890b090eSBob Moore return_ACPI_STATUS(AE_NO_MEMORY);
386890b090eSBob Moore }
387890b090eSBob Moore
388890b090eSBob Moore /*
389890b090eSBob Moore * Copy the templates to the new buffer, 0 first, then 1 follows. One
390890b090eSBob Moore * end_tag descriptor is copied from Operand1.
391890b090eSBob Moore */
392890b090eSBob Moore new_buf = return_desc->buffer.pointer;
393890b090eSBob Moore memcpy(new_buf, operand0->buffer.pointer, length0);
394890b090eSBob Moore memcpy(new_buf + length0, operand1->buffer.pointer, length1);
395890b090eSBob Moore
396890b090eSBob Moore /* Insert end_tag and set the checksum to zero, means "ignore checksum" */
397890b090eSBob Moore
398890b090eSBob Moore new_buf[new_length - 1] = 0;
399890b090eSBob Moore new_buf[new_length - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;
400890b090eSBob Moore
401890b090eSBob Moore /* Return the completed resource template */
402890b090eSBob Moore
403890b090eSBob Moore *actual_return_desc = return_desc;
404890b090eSBob Moore return_ACPI_STATUS(AE_OK);
405890b090eSBob Moore }
406