Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: exconcat - Concatenate-type AML operators
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
0007  *
0008  *****************************************************************************/
0009 
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "acinterp.h"
0013 #include "amlresrc.h"
0014 
0015 #define _COMPONENT          ACPI_EXECUTER
0016 ACPI_MODULE_NAME("exconcat")
0017 
0018 /* Local Prototypes */
0019 static acpi_status
0020 acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc,
0021                       union acpi_operand_object **result_desc);
0022 
0023 /*******************************************************************************
0024  *
0025  * FUNCTION:    acpi_ex_do_concatenate
0026  *
0027  * PARAMETERS:  operand0            - First source object
0028  *              operand1            - Second source object
0029  *              actual_return_desc  - Where to place the return object
0030  *              walk_state          - Current walk state
0031  *
0032  * RETURN:      Status
0033  *
0034  * DESCRIPTION: Concatenate two objects with the ACPI-defined conversion
0035  *              rules as necessary.
0036  * NOTE:
0037  * Per the ACPI spec (up to 6.1), Concatenate only supports Integer,
0038  * String, and Buffer objects. However, we support all objects here
0039  * as an extension. This improves the usefulness of both Concatenate
0040  * and the Printf/Fprintf macros. The extension returns a string
0041  * describing the object type for the other objects.
0042  * 02/2016.
0043  *
0044  ******************************************************************************/
0045 
0046 acpi_status
0047 acpi_ex_do_concatenate(union acpi_operand_object *operand0,
0048                union acpi_operand_object *operand1,
0049                union acpi_operand_object **actual_return_desc,
0050                struct acpi_walk_state *walk_state)
0051 {
0052     union acpi_operand_object *local_operand0 = operand0;
0053     union acpi_operand_object *local_operand1 = operand1;
0054     union acpi_operand_object *temp_operand1 = NULL;
0055     union acpi_operand_object *return_desc;
0056     char *buffer;
0057     acpi_object_type operand0_type;
0058     acpi_object_type operand1_type;
0059     acpi_status status;
0060 
0061     ACPI_FUNCTION_TRACE(ex_do_concatenate);
0062 
0063     /* Operand 0 preprocessing */
0064 
0065     switch (operand0->common.type) {
0066     case ACPI_TYPE_INTEGER:
0067     case ACPI_TYPE_STRING:
0068     case ACPI_TYPE_BUFFER:
0069 
0070         operand0_type = operand0->common.type;
0071         break;
0072 
0073     default:
0074 
0075         /* For all other types, get the "object type" string */
0076 
0077         status =
0078             acpi_ex_convert_to_object_type_string(operand0,
0079                               &local_operand0);
0080         if (ACPI_FAILURE(status)) {
0081             goto cleanup;
0082         }
0083 
0084         operand0_type = ACPI_TYPE_STRING;
0085         break;
0086     }
0087 
0088     /* Operand 1 preprocessing */
0089 
0090     switch (operand1->common.type) {
0091     case ACPI_TYPE_INTEGER:
0092     case ACPI_TYPE_STRING:
0093     case ACPI_TYPE_BUFFER:
0094 
0095         operand1_type = operand1->common.type;
0096         break;
0097 
0098     default:
0099 
0100         /* For all other types, get the "object type" string */
0101 
0102         status =
0103             acpi_ex_convert_to_object_type_string(operand1,
0104                               &local_operand1);
0105         if (ACPI_FAILURE(status)) {
0106             goto cleanup;
0107         }
0108 
0109         operand1_type = ACPI_TYPE_STRING;
0110         break;
0111     }
0112 
0113     /*
0114      * Convert the second operand if necessary. The first operand (0)
0115      * determines the type of the second operand (1) (See the Data Types
0116      * section of the ACPI specification). Both object types are
0117      * guaranteed to be either Integer/String/Buffer by the operand
0118      * resolution mechanism.
0119      */
0120     switch (operand0_type) {
0121     case ACPI_TYPE_INTEGER:
0122 
0123         status =
0124             acpi_ex_convert_to_integer(local_operand1, &temp_operand1,
0125                            ACPI_IMPLICIT_CONVERSION);
0126         break;
0127 
0128     case ACPI_TYPE_BUFFER:
0129 
0130         status =
0131             acpi_ex_convert_to_buffer(local_operand1, &temp_operand1);
0132         break;
0133 
0134     case ACPI_TYPE_STRING:
0135 
0136         switch (operand1_type) {
0137         case ACPI_TYPE_INTEGER:
0138         case ACPI_TYPE_STRING:
0139         case ACPI_TYPE_BUFFER:
0140 
0141             /* Other types have already been converted to string */
0142 
0143             status =
0144                 acpi_ex_convert_to_string(local_operand1,
0145                               &temp_operand1,
0146                               ACPI_IMPLICIT_CONVERT_HEX);
0147             break;
0148 
0149         default:
0150 
0151             status = AE_OK;
0152             break;
0153         }
0154         break;
0155 
0156     default:
0157 
0158         ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",
0159                 operand0->common.type));
0160         status = AE_AML_INTERNAL;
0161     }
0162 
0163     if (ACPI_FAILURE(status)) {
0164         goto cleanup;
0165     }
0166 
0167     /* Take care with any newly created operand objects */
0168 
0169     if ((local_operand1 != operand1) && (local_operand1 != temp_operand1)) {
0170         acpi_ut_remove_reference(local_operand1);
0171     }
0172 
0173     local_operand1 = temp_operand1;
0174 
0175     /*
0176      * Both operands are now known to be the same object type
0177      * (Both are Integer, String, or Buffer), and we can now perform
0178      * the concatenation.
0179      *
0180      * There are three cases to handle, as per the ACPI spec:
0181      *
0182      * 1) Two Integers concatenated to produce a new Buffer
0183      * 2) Two Strings concatenated to produce a new String
0184      * 3) Two Buffers concatenated to produce a new Buffer
0185      */
0186     switch (operand0_type) {
0187     case ACPI_TYPE_INTEGER:
0188 
0189         /* Result of two Integers is a Buffer */
0190         /* Need enough buffer space for two integers */
0191 
0192         return_desc = acpi_ut_create_buffer_object((acpi_size)
0193                                ACPI_MUL_2
0194                                (acpi_gbl_integer_byte_width));
0195         if (!return_desc) {
0196             status = AE_NO_MEMORY;
0197             goto cleanup;
0198         }
0199 
0200         buffer = (char *)return_desc->buffer.pointer;
0201 
0202         /* Copy the first integer, LSB first */
0203 
0204         memcpy(buffer, &operand0->integer.value,
0205                acpi_gbl_integer_byte_width);
0206 
0207         /* Copy the second integer (LSB first) after the first */
0208 
0209         memcpy(buffer + acpi_gbl_integer_byte_width,
0210                &local_operand1->integer.value,
0211                acpi_gbl_integer_byte_width);
0212         break;
0213 
0214     case ACPI_TYPE_STRING:
0215 
0216         /* Result of two Strings is a String */
0217 
0218         return_desc = acpi_ut_create_string_object(((acpi_size)
0219                                 local_operand0->
0220                                 string.length +
0221                                 local_operand1->
0222                                 string.length));
0223         if (!return_desc) {
0224             status = AE_NO_MEMORY;
0225             goto cleanup;
0226         }
0227 
0228         buffer = return_desc->string.pointer;
0229 
0230         /* Concatenate the strings */
0231 
0232         strcpy(buffer, local_operand0->string.pointer);
0233         strcat(buffer, local_operand1->string.pointer);
0234         break;
0235 
0236     case ACPI_TYPE_BUFFER:
0237 
0238         /* Result of two Buffers is a Buffer */
0239 
0240         return_desc = acpi_ut_create_buffer_object(((acpi_size)
0241                                 operand0->buffer.
0242                                 length +
0243                                 local_operand1->
0244                                 buffer.length));
0245         if (!return_desc) {
0246             status = AE_NO_MEMORY;
0247             goto cleanup;
0248         }
0249 
0250         buffer = (char *)return_desc->buffer.pointer;
0251 
0252         /* Concatenate the buffers */
0253 
0254         memcpy(buffer, operand0->buffer.pointer,
0255                operand0->buffer.length);
0256         memcpy(buffer + operand0->buffer.length,
0257                local_operand1->buffer.pointer,
0258                local_operand1->buffer.length);
0259         break;
0260 
0261     default:
0262 
0263         /* Invalid object type, should not happen here */
0264 
0265         ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",
0266                 operand0->common.type));
0267         status = AE_AML_INTERNAL;
0268         goto cleanup;
0269     }
0270 
0271     *actual_return_desc = return_desc;
0272 
0273 cleanup:
0274     if (local_operand0 != operand0) {
0275         acpi_ut_remove_reference(local_operand0);
0276     }
0277 
0278     if (local_operand1 != operand1) {
0279         acpi_ut_remove_reference(local_operand1);
0280     }
0281 
0282     return_ACPI_STATUS(status);
0283 }
0284 
0285 /*******************************************************************************
0286  *
0287  * FUNCTION:    acpi_ex_convert_to_object_type_string
0288  *
0289  * PARAMETERS:  obj_desc            - Object to be converted
0290  *              return_desc         - Where to place the return object
0291  *
0292  * RETURN:      Status
0293  *
0294  * DESCRIPTION: Convert an object of arbitrary type to a string object that
0295  *              contains the namestring for the object. Used for the
0296  *              concatenate operator.
0297  *
0298  ******************************************************************************/
0299 
0300 static acpi_status
0301 acpi_ex_convert_to_object_type_string(union acpi_operand_object *obj_desc,
0302                       union acpi_operand_object **result_desc)
0303 {
0304     union acpi_operand_object *return_desc;
0305     const char *type_string;
0306 
0307     type_string = acpi_ut_get_type_name(obj_desc->common.type);
0308 
0309     return_desc = acpi_ut_create_string_object(((acpi_size)strlen(type_string) + 9));   /* 9 For "[ Object]" */
0310     if (!return_desc) {
0311         return (AE_NO_MEMORY);
0312     }
0313 
0314     strcpy(return_desc->string.pointer, "[");
0315     strcat(return_desc->string.pointer, type_string);
0316     strcat(return_desc->string.pointer, " Object]");
0317 
0318     *result_desc = return_desc;
0319     return (AE_OK);
0320 }
0321 
0322 /*******************************************************************************
0323  *
0324  * FUNCTION:    acpi_ex_concat_template
0325  *
0326  * PARAMETERS:  operand0            - First source object
0327  *              operand1            - Second source object
0328  *              actual_return_desc  - Where to place the return object
0329  *              walk_state          - Current walk state
0330  *
0331  * RETURN:      Status
0332  *
0333  * DESCRIPTION: Concatenate two resource templates
0334  *
0335  ******************************************************************************/
0336 
0337 acpi_status
0338 acpi_ex_concat_template(union acpi_operand_object *operand0,
0339             union acpi_operand_object *operand1,
0340             union acpi_operand_object **actual_return_desc,
0341             struct acpi_walk_state *walk_state)
0342 {
0343     acpi_status status;
0344     union acpi_operand_object *return_desc;
0345     u8 *new_buf;
0346     u8 *end_tag;
0347     acpi_size length0;
0348     acpi_size length1;
0349     acpi_size new_length;
0350 
0351     ACPI_FUNCTION_TRACE(ex_concat_template);
0352 
0353     /*
0354      * Find the end_tag descriptor in each resource template.
0355      * Note1: returned pointers point TO the end_tag, not past it.
0356      * Note2: zero-length buffers are allowed; treated like one end_tag
0357      */
0358 
0359     /* Get the length of the first resource template */
0360 
0361     status = acpi_ut_get_resource_end_tag(operand0, &end_tag);
0362     if (ACPI_FAILURE(status)) {
0363         return_ACPI_STATUS(status);
0364     }
0365 
0366     length0 = ACPI_PTR_DIFF(end_tag, operand0->buffer.pointer);
0367 
0368     /* Get the length of the second resource template */
0369 
0370     status = acpi_ut_get_resource_end_tag(operand1, &end_tag);
0371     if (ACPI_FAILURE(status)) {
0372         return_ACPI_STATUS(status);
0373     }
0374 
0375     length1 = ACPI_PTR_DIFF(end_tag, operand1->buffer.pointer);
0376 
0377     /* Combine both lengths, minimum size will be 2 for end_tag */
0378 
0379     new_length = length0 + length1 + sizeof(struct aml_resource_end_tag);
0380 
0381     /* Create a new buffer object for the result (with one end_tag) */
0382 
0383     return_desc = acpi_ut_create_buffer_object(new_length);
0384     if (!return_desc) {
0385         return_ACPI_STATUS(AE_NO_MEMORY);
0386     }
0387 
0388     /*
0389      * Copy the templates to the new buffer, 0 first, then 1 follows. One
0390      * end_tag descriptor is copied from Operand1.
0391      */
0392     new_buf = return_desc->buffer.pointer;
0393     memcpy(new_buf, operand0->buffer.pointer, length0);
0394     memcpy(new_buf + length0, operand1->buffer.pointer, length1);
0395 
0396     /* Insert end_tag and set the checksum to zero, means "ignore checksum" */
0397 
0398     new_buf[new_length - 1] = 0;
0399     new_buf[new_length - 2] = ACPI_RESOURCE_NAME_END_TAG | 1;
0400 
0401     /* Return the completed resource template */
0402 
0403     *actual_return_desc = return_desc;
0404     return_ACPI_STATUS(AE_OK);
0405 }