2018-03-15 02:13:07 +03:00
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2016-03-24 04:39:51 +03:00
/******************************************************************************
*
* Module Name : exconcat - Concatenate - type AML operators
*
2020-01-10 22:31:49 +03:00
* Copyright ( C ) 2000 - 2020 , Intel Corp .
2016-03-24 04:39:51 +03:00
*
2018-03-15 02:13:07 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-03-24 04:39:51 +03:00
# include <acpi/acpi.h>
# include "accommon.h"
# include "acinterp.h"
# include "amlresrc.h"
# define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ( " exconcat " )
/* Local Prototypes */
static acpi_status
acpi_ex_convert_to_object_type_string ( union acpi_operand_object * obj_desc ,
union acpi_operand_object * * result_desc ) ;
/*******************************************************************************
*
* FUNCTION : acpi_ex_do_concatenate
*
* PARAMETERS : operand0 - First source object
* operand1 - Second source object
* actual_return_desc - Where to place the return object
* walk_state - Current walk state
*
* RETURN : Status
*
* DESCRIPTION : Concatenate two objects with the ACPI - defined conversion
* rules as necessary .
* NOTE :
* Per the ACPI spec ( up to 6.1 ) , Concatenate only supports Integer ,
* String , and Buffer objects . However , we support all objects here
* as an extension . This improves the usefulness of both Concatenate
* and the Printf / Fprintf macros . The extension returns a string
* describing the object type for the other objects .
* 02 / 2016.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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 )
{
union acpi_operand_object * local_operand0 = operand0 ;
union acpi_operand_object * local_operand1 = operand1 ;
union acpi_operand_object * temp_operand1 = NULL ;
union acpi_operand_object * return_desc ;
char * buffer ;
acpi_object_type operand0_type ;
acpi_object_type operand1_type ;
acpi_status status ;
ACPI_FUNCTION_TRACE ( ex_do_concatenate ) ;
/* Operand 0 preprocessing */
switch ( operand0 - > common . type ) {
case ACPI_TYPE_INTEGER :
case ACPI_TYPE_STRING :
case ACPI_TYPE_BUFFER :
operand0_type = operand0 - > common . type ;
break ;
default :
/* For all other types, get the "object type" string */
status =
acpi_ex_convert_to_object_type_string ( operand0 ,
& local_operand0 ) ;
if ( ACPI_FAILURE ( status ) ) {
goto cleanup ;
}
operand0_type = ACPI_TYPE_STRING ;
break ;
}
/* Operand 1 preprocessing */
switch ( operand1 - > common . type ) {
case ACPI_TYPE_INTEGER :
case ACPI_TYPE_STRING :
case ACPI_TYPE_BUFFER :
operand1_type = operand1 - > common . type ;
break ;
default :
/* For all other types, get the "object type" string */
status =
acpi_ex_convert_to_object_type_string ( operand1 ,
& local_operand1 ) ;
if ( ACPI_FAILURE ( status ) ) {
goto cleanup ;
}
operand1_type = ACPI_TYPE_STRING ;
break ;
}
/*
* Convert the second operand if necessary . The first operand ( 0 )
* determines the type of the second operand ( 1 ) ( See the Data Types
* section of the ACPI specification ) . Both object types are
* guaranteed to be either Integer / String / Buffer by the operand
* resolution mechanism .
*/
switch ( operand0_type ) {
case ACPI_TYPE_INTEGER :
status =
acpi_ex_convert_to_integer ( local_operand1 , & temp_operand1 ,
2017-09-20 05:00:36 +03:00
ACPI_IMPLICIT_CONVERSION ) ;
2016-03-24 04:39:51 +03:00
break ;
case ACPI_TYPE_BUFFER :
status =
acpi_ex_convert_to_buffer ( local_operand1 , & temp_operand1 ) ;
break ;
case ACPI_TYPE_STRING :
switch ( operand1_type ) {
case ACPI_TYPE_INTEGER :
case ACPI_TYPE_STRING :
case ACPI_TYPE_BUFFER :
/* Other types have already been converted to string */
status =
acpi_ex_convert_to_string ( local_operand1 ,
& temp_operand1 ,
ACPI_IMPLICIT_CONVERT_HEX ) ;
break ;
default :
status = AE_OK ;
break ;
}
break ;
default :
ACPI_ERROR ( ( AE_INFO , " Invalid object type: 0x%X " ,
operand0 - > common . type ) ) ;
status = AE_AML_INTERNAL ;
}
if ( ACPI_FAILURE ( status ) ) {
goto cleanup ;
}
/* Take care with any newly created operand objects */
if ( ( local_operand1 ! = operand1 ) & & ( local_operand1 ! = temp_operand1 ) ) {
acpi_ut_remove_reference ( local_operand1 ) ;
}
local_operand1 = temp_operand1 ;
/*
* Both operands are now known to be the same object type
* ( Both are Integer , String , or Buffer ) , and we can now perform
* the concatenation .
*
* There are three cases to handle , as per the ACPI spec :
*
* 1 ) Two Integers concatenated to produce a new Buffer
* 2 ) Two Strings concatenated to produce a new String
* 3 ) Two Buffers concatenated to produce a new Buffer
*/
switch ( operand0_type ) {
case ACPI_TYPE_INTEGER :
/* Result of two Integers is a Buffer */
/* Need enough buffer space for two integers */
return_desc = acpi_ut_create_buffer_object ( ( acpi_size )
ACPI_MUL_2
( acpi_gbl_integer_byte_width ) ) ;
if ( ! return_desc ) {
status = AE_NO_MEMORY ;
goto cleanup ;
}
buffer = ( char * ) return_desc - > buffer . pointer ;
/* Copy the first integer, LSB first */
memcpy ( buffer , & operand0 - > integer . value ,
acpi_gbl_integer_byte_width ) ;
/* Copy the second integer (LSB first) after the first */
memcpy ( buffer + acpi_gbl_integer_byte_width ,
& local_operand1 - > integer . value ,
acpi_gbl_integer_byte_width ) ;
break ;
case ACPI_TYPE_STRING :
/* Result of two Strings is a String */
return_desc = acpi_ut_create_string_object ( ( ( acpi_size )
local_operand0 - >
string . length +
local_operand1 - >
string . length ) ) ;
if ( ! return_desc ) {
status = AE_NO_MEMORY ;
goto cleanup ;
}
buffer = return_desc - > string . pointer ;
/* Concatenate the strings */
strcpy ( buffer , local_operand0 - > string . pointer ) ;
strcat ( buffer , local_operand1 - > string . pointer ) ;
break ;
case ACPI_TYPE_BUFFER :
/* Result of two Buffers is a Buffer */
return_desc = acpi_ut_create_buffer_object ( ( ( acpi_size )
operand0 - > buffer .
length +
local_operand1 - >
buffer . length ) ) ;
if ( ! return_desc ) {
status = AE_NO_MEMORY ;
goto cleanup ;
}
buffer = ( char * ) return_desc - > buffer . pointer ;
/* Concatenate the buffers */
memcpy ( buffer , operand0 - > buffer . pointer ,
operand0 - > buffer . length ) ;
memcpy ( buffer + operand0 - > buffer . length ,
local_operand1 - > buffer . pointer ,
local_operand1 - > buffer . length ) ;
break ;
default :
/* Invalid object type, should not happen here */
ACPI_ERROR ( ( AE_INFO , " Invalid object type: 0x%X " ,
operand0 - > common . type ) ) ;
status = AE_AML_INTERNAL ;
goto cleanup ;
}
* actual_return_desc = return_desc ;
cleanup :
if ( local_operand0 ! = operand0 ) {
acpi_ut_remove_reference ( local_operand0 ) ;
}
if ( local_operand1 ! = operand1 ) {
acpi_ut_remove_reference ( local_operand1 ) ;
}
return_ACPI_STATUS ( status ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_ex_convert_to_object_type_string
*
* PARAMETERS : obj_desc - Object to be converted
* return_desc - Where to place the return object
*
* RETURN : Status
*
* DESCRIPTION : Convert an object of arbitrary type to a string object that
* contains the namestring for the object . Used for the
* concatenate operator .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static acpi_status
acpi_ex_convert_to_object_type_string ( union acpi_operand_object * obj_desc ,
union acpi_operand_object * * result_desc )
{
union acpi_operand_object * return_desc ;
const char * type_string ;
type_string = acpi_ut_get_type_name ( obj_desc - > common . type ) ;
2016-05-05 07:57:53 +03:00
return_desc = acpi_ut_create_string_object ( ( ( acpi_size ) strlen ( type_string ) + 9 ) ) ; /* 9 For "[ Object]" */
2016-03-24 04:39:51 +03:00
if ( ! return_desc ) {
return ( AE_NO_MEMORY ) ;
}
strcpy ( return_desc - > string . pointer , " [ " ) ;
strcat ( return_desc - > string . pointer , type_string ) ;
strcat ( return_desc - > string . pointer , " Object] " ) ;
* result_desc = return_desc ;
return ( AE_OK ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_ex_concat_template
*
* PARAMETERS : operand0 - First source object
* operand1 - Second source object
* actual_return_desc - Where to place the return object
* walk_state - Current walk state
*
* RETURN : Status
*
* DESCRIPTION : Concatenate two resource templates
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
acpi_ex_concat_template ( union acpi_operand_object * operand0 ,
union acpi_operand_object * operand1 ,
union acpi_operand_object * * actual_return_desc ,
2016-05-05 07:57:53 +03:00
struct acpi_walk_state * walk_state )
2016-03-24 04:39:51 +03:00
{
acpi_status status ;
union acpi_operand_object * return_desc ;
u8 * new_buf ;
u8 * end_tag ;
acpi_size length0 ;
acpi_size length1 ;
acpi_size new_length ;
ACPI_FUNCTION_TRACE ( ex_concat_template ) ;
/*
* Find the end_tag descriptor in each resource template .
* Note1 : returned pointers point TO the end_tag , not past it .
* Note2 : zero - length buffers are allowed ; treated like one end_tag
*/
/* Get the length of the first resource template */
status = acpi_ut_get_resource_end_tag ( operand0 , & end_tag ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
}
length0 = ACPI_PTR_DIFF ( end_tag , operand0 - > buffer . pointer ) ;
/* Get the length of the second resource template */
status = acpi_ut_get_resource_end_tag ( operand1 , & end_tag ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
}
length1 = ACPI_PTR_DIFF ( end_tag , operand1 - > buffer . pointer ) ;
/* Combine both lengths, minimum size will be 2 for end_tag */
new_length = length0 + length1 + sizeof ( struct aml_resource_end_tag ) ;
/* Create a new buffer object for the result (with one end_tag) */
return_desc = acpi_ut_create_buffer_object ( new_length ) ;
if ( ! return_desc ) {
return_ACPI_STATUS ( AE_NO_MEMORY ) ;
}
/*
* Copy the templates to the new buffer , 0 first , then 1 follows . One
* end_tag descriptor is copied from Operand1 .
*/
new_buf = return_desc - > buffer . pointer ;
memcpy ( new_buf , operand0 - > buffer . pointer , length0 ) ;
memcpy ( new_buf + length0 , operand1 - > buffer . pointer , length1 ) ;
/* Insert end_tag and set the checksum to zero, means "ignore checksum" */
new_buf [ new_length - 1 ] = 0 ;
new_buf [ new_length - 2 ] = ACPI_RESOURCE_NAME_END_TAG | 1 ;
/* Return the completed resource template */
* actual_return_desc = return_desc ;
return_ACPI_STATUS ( AE_OK ) ;
}