cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

exmisc.c (11917B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/******************************************************************************
      3 *
      4 * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
      5 *
      6 * Copyright (C) 2000 - 2022, Intel Corp.
      7 *
      8 *****************************************************************************/
      9
     10#include <acpi/acpi.h>
     11#include "accommon.h"
     12#include "acinterp.h"
     13#include "amlcode.h"
     14
     15#define _COMPONENT          ACPI_EXECUTER
     16ACPI_MODULE_NAME("exmisc")
     17
     18/*******************************************************************************
     19 *
     20 * FUNCTION:    acpi_ex_get_object_reference
     21 *
     22 * PARAMETERS:  obj_desc            - Create a reference to this object
     23 *              return_desc         - Where to store the reference
     24 *              walk_state          - Current state
     25 *
     26 * RETURN:      Status
     27 *
     28 * DESCRIPTION: Obtain and return a "reference" to the target object
     29 *              Common code for the ref_of_op and the cond_ref_of_op.
     30 *
     31 ******************************************************************************/
     32acpi_status
     33acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
     34			     union acpi_operand_object **return_desc,
     35			     struct acpi_walk_state *walk_state)
     36{
     37	union acpi_operand_object *reference_obj;
     38	union acpi_operand_object *referenced_obj;
     39
     40	ACPI_FUNCTION_TRACE_PTR(ex_get_object_reference, obj_desc);
     41
     42	*return_desc = NULL;
     43
     44	switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {
     45	case ACPI_DESC_TYPE_OPERAND:
     46
     47		if (obj_desc->common.type != ACPI_TYPE_LOCAL_REFERENCE) {
     48			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
     49		}
     50
     51		/*
     52		 * Must be a reference to a Local or Arg
     53		 */
     54		switch (obj_desc->reference.class) {
     55		case ACPI_REFCLASS_LOCAL:
     56		case ACPI_REFCLASS_ARG:
     57		case ACPI_REFCLASS_DEBUG:
     58
     59			/* The referenced object is the pseudo-node for the local/arg */
     60
     61			referenced_obj = obj_desc->reference.object;
     62			break;
     63
     64		default:
     65
     66			ACPI_ERROR((AE_INFO, "Invalid Reference Class 0x%2.2X",
     67				    obj_desc->reference.class));
     68			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
     69		}
     70		break;
     71
     72	case ACPI_DESC_TYPE_NAMED:
     73		/*
     74		 * A named reference that has already been resolved to a Node
     75		 */
     76		referenced_obj = obj_desc;
     77		break;
     78
     79	default:
     80
     81		ACPI_ERROR((AE_INFO, "Invalid descriptor type 0x%X",
     82			    ACPI_GET_DESCRIPTOR_TYPE(obj_desc)));
     83		return_ACPI_STATUS(AE_TYPE);
     84	}
     85
     86	/* Create a new reference object */
     87
     88	reference_obj =
     89	    acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE);
     90	if (!reference_obj) {
     91		return_ACPI_STATUS(AE_NO_MEMORY);
     92	}
     93
     94	reference_obj->reference.class = ACPI_REFCLASS_REFOF;
     95	reference_obj->reference.object = referenced_obj;
     96	*return_desc = reference_obj;
     97
     98	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
     99			  "Object %p Type [%s], returning Reference %p\n",
    100			  obj_desc, acpi_ut_get_object_type_name(obj_desc),
    101			  *return_desc));
    102
    103	return_ACPI_STATUS(AE_OK);
    104}
    105
    106/*******************************************************************************
    107 *
    108 * FUNCTION:    acpi_ex_do_math_op
    109 *
    110 * PARAMETERS:  opcode              - AML opcode
    111 *              integer0            - Integer operand #0
    112 *              integer1            - Integer operand #1
    113 *
    114 * RETURN:      Integer result of the operation
    115 *
    116 * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
    117 *              math functions here is to prevent a lot of pointer dereferencing
    118 *              to obtain the operands.
    119 *
    120 ******************************************************************************/
    121
    122u64 acpi_ex_do_math_op(u16 opcode, u64 integer0, u64 integer1)
    123{
    124
    125	ACPI_FUNCTION_ENTRY();
    126
    127	switch (opcode) {
    128	case AML_ADD_OP:	/* Add (Integer0, Integer1, Result) */
    129
    130		return (integer0 + integer1);
    131
    132	case AML_BIT_AND_OP:	/* And (Integer0, Integer1, Result) */
    133
    134		return (integer0 & integer1);
    135
    136	case AML_BIT_NAND_OP:	/* NAnd (Integer0, Integer1, Result) */
    137
    138		return (~(integer0 & integer1));
    139
    140	case AML_BIT_OR_OP:	/* Or (Integer0, Integer1, Result) */
    141
    142		return (integer0 | integer1);
    143
    144	case AML_BIT_NOR_OP:	/* NOr (Integer0, Integer1, Result) */
    145
    146		return (~(integer0 | integer1));
    147
    148	case AML_BIT_XOR_OP:	/* XOr (Integer0, Integer1, Result) */
    149
    150		return (integer0 ^ integer1);
    151
    152	case AML_MULTIPLY_OP:	/* Multiply (Integer0, Integer1, Result) */
    153
    154		return (integer0 * integer1);
    155
    156	case AML_SHIFT_LEFT_OP:	/* shift_left (Operand, shift_count, Result) */
    157
    158		/*
    159		 * We need to check if the shiftcount is larger than the integer bit
    160		 * width since the behavior of this is not well-defined in the C language.
    161		 */
    162		if (integer1 >= acpi_gbl_integer_bit_width) {
    163			return (0);
    164		}
    165		return (integer0 << integer1);
    166
    167	case AML_SHIFT_RIGHT_OP:	/* shift_right (Operand, shift_count, Result) */
    168
    169		/*
    170		 * We need to check if the shiftcount is larger than the integer bit
    171		 * width since the behavior of this is not well-defined in the C language.
    172		 */
    173		if (integer1 >= acpi_gbl_integer_bit_width) {
    174			return (0);
    175		}
    176		return (integer0 >> integer1);
    177
    178	case AML_SUBTRACT_OP:	/* Subtract (Integer0, Integer1, Result) */
    179
    180		return (integer0 - integer1);
    181
    182	default:
    183
    184		return (0);
    185	}
    186}
    187
    188/*******************************************************************************
    189 *
    190 * FUNCTION:    acpi_ex_do_logical_numeric_op
    191 *
    192 * PARAMETERS:  opcode              - AML opcode
    193 *              integer0            - Integer operand #0
    194 *              integer1            - Integer operand #1
    195 *              logical_result      - TRUE/FALSE result of the operation
    196 *
    197 * RETURN:      Status
    198 *
    199 * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric
    200 *              operators (LAnd and LOr), both operands must be integers.
    201 *
    202 *              Note: cleanest machine code seems to be produced by the code
    203 *              below, rather than using statements of the form:
    204 *                  Result = (Integer0 && Integer1);
    205 *
    206 ******************************************************************************/
    207
    208acpi_status
    209acpi_ex_do_logical_numeric_op(u16 opcode,
    210			      u64 integer0, u64 integer1, u8 *logical_result)
    211{
    212	acpi_status status = AE_OK;
    213	u8 local_result = FALSE;
    214
    215	ACPI_FUNCTION_TRACE(ex_do_logical_numeric_op);
    216
    217	switch (opcode) {
    218	case AML_LOGICAL_AND_OP:	/* LAnd (Integer0, Integer1) */
    219
    220		if (integer0 && integer1) {
    221			local_result = TRUE;
    222		}
    223		break;
    224
    225	case AML_LOGICAL_OR_OP:	/* LOr (Integer0, Integer1) */
    226
    227		if (integer0 || integer1) {
    228			local_result = TRUE;
    229		}
    230		break;
    231
    232	default:
    233
    234		ACPI_ERROR((AE_INFO,
    235			    "Invalid numeric logical opcode: %X", opcode));
    236		status = AE_AML_INTERNAL;
    237		break;
    238	}
    239
    240	/* Return the logical result and status */
    241
    242	*logical_result = local_result;
    243	return_ACPI_STATUS(status);
    244}
    245
    246/*******************************************************************************
    247 *
    248 * FUNCTION:    acpi_ex_do_logical_op
    249 *
    250 * PARAMETERS:  opcode              - AML opcode
    251 *              operand0            - operand #0
    252 *              operand1            - operand #1
    253 *              logical_result      - TRUE/FALSE result of the operation
    254 *
    255 * RETURN:      Status
    256 *
    257 * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
    258 *              functions here is to prevent a lot of pointer dereferencing
    259 *              to obtain the operands and to simplify the generation of the
    260 *              logical value. For the Numeric operators (LAnd and LOr), both
    261 *              operands must be integers. For the other logical operators,
    262 *              operands can be any combination of Integer/String/Buffer. The
    263 *              first operand determines the type to which the second operand
    264 *              will be converted.
    265 *
    266 *              Note: cleanest machine code seems to be produced by the code
    267 *              below, rather than using statements of the form:
    268 *                  Result = (Operand0 == Operand1);
    269 *
    270 ******************************************************************************/
    271
    272acpi_status
    273acpi_ex_do_logical_op(u16 opcode,
    274		      union acpi_operand_object *operand0,
    275		      union acpi_operand_object *operand1, u8 * logical_result)
    276{
    277	union acpi_operand_object *local_operand1 = operand1;
    278	u64 integer0;
    279	u64 integer1;
    280	u32 length0;
    281	u32 length1;
    282	acpi_status status = AE_OK;
    283	u8 local_result = FALSE;
    284	int compare;
    285
    286	ACPI_FUNCTION_TRACE(ex_do_logical_op);
    287
    288	/*
    289	 * Convert the second operand if necessary. The first operand
    290	 * determines the type of the second operand, (See the Data Types
    291	 * section of the ACPI 3.0+ specification.)  Both object types are
    292	 * guaranteed to be either Integer/String/Buffer by the operand
    293	 * resolution mechanism.
    294	 */
    295	switch (operand0->common.type) {
    296	case ACPI_TYPE_INTEGER:
    297
    298		status = acpi_ex_convert_to_integer(operand1, &local_operand1,
    299						    ACPI_IMPLICIT_CONVERSION);
    300		break;
    301
    302	case ACPI_TYPE_STRING:
    303
    304		status =
    305		    acpi_ex_convert_to_string(operand1, &local_operand1,
    306					      ACPI_IMPLICIT_CONVERT_HEX);
    307		break;
    308
    309	case ACPI_TYPE_BUFFER:
    310
    311		status = acpi_ex_convert_to_buffer(operand1, &local_operand1);
    312		break;
    313
    314	default:
    315
    316		ACPI_ERROR((AE_INFO,
    317			    "Invalid object type for logical operator: %X",
    318			    operand0->common.type));
    319		status = AE_AML_INTERNAL;
    320		break;
    321	}
    322
    323	if (ACPI_FAILURE(status)) {
    324		goto cleanup;
    325	}
    326
    327	/*
    328	 * Two cases: 1) Both Integers, 2) Both Strings or Buffers
    329	 */
    330	if (operand0->common.type == ACPI_TYPE_INTEGER) {
    331		/*
    332		 * 1) Both operands are of type integer
    333		 *    Note: local_operand1 may have changed above
    334		 */
    335		integer0 = operand0->integer.value;
    336		integer1 = local_operand1->integer.value;
    337
    338		switch (opcode) {
    339		case AML_LOGICAL_EQUAL_OP:	/* LEqual (Operand0, Operand1) */
    340
    341			if (integer0 == integer1) {
    342				local_result = TRUE;
    343			}
    344			break;
    345
    346		case AML_LOGICAL_GREATER_OP:	/* LGreater (Operand0, Operand1) */
    347
    348			if (integer0 > integer1) {
    349				local_result = TRUE;
    350			}
    351			break;
    352
    353		case AML_LOGICAL_LESS_OP:	/* LLess (Operand0, Operand1) */
    354
    355			if (integer0 < integer1) {
    356				local_result = TRUE;
    357			}
    358			break;
    359
    360		default:
    361
    362			ACPI_ERROR((AE_INFO,
    363				    "Invalid comparison opcode: %X", opcode));
    364			status = AE_AML_INTERNAL;
    365			break;
    366		}
    367	} else {
    368		/*
    369		 * 2) Both operands are Strings or both are Buffers
    370		 *    Note: Code below takes advantage of common Buffer/String
    371		 *          object fields. local_operand1 may have changed above. Use
    372		 *          memcmp to handle nulls in buffers.
    373		 */
    374		length0 = operand0->buffer.length;
    375		length1 = local_operand1->buffer.length;
    376
    377		/* Lexicographic compare: compare the data bytes */
    378
    379		compare = memcmp(operand0->buffer.pointer,
    380				 local_operand1->buffer.pointer,
    381				 (length0 > length1) ? length1 : length0);
    382
    383		switch (opcode) {
    384		case AML_LOGICAL_EQUAL_OP:	/* LEqual (Operand0, Operand1) */
    385
    386			/* Length and all bytes must be equal */
    387
    388			if ((length0 == length1) && (compare == 0)) {
    389
    390				/* Length and all bytes match ==> TRUE */
    391
    392				local_result = TRUE;
    393			}
    394			break;
    395
    396		case AML_LOGICAL_GREATER_OP:	/* LGreater (Operand0, Operand1) */
    397
    398			if (compare > 0) {
    399				local_result = TRUE;
    400				goto cleanup;	/* TRUE */
    401			}
    402			if (compare < 0) {
    403				goto cleanup;	/* FALSE */
    404			}
    405
    406			/* Bytes match (to shortest length), compare lengths */
    407
    408			if (length0 > length1) {
    409				local_result = TRUE;
    410			}
    411			break;
    412
    413		case AML_LOGICAL_LESS_OP:	/* LLess (Operand0, Operand1) */
    414
    415			if (compare > 0) {
    416				goto cleanup;	/* FALSE */
    417			}
    418			if (compare < 0) {
    419				local_result = TRUE;
    420				goto cleanup;	/* TRUE */
    421			}
    422
    423			/* Bytes match (to shortest length), compare lengths */
    424
    425			if (length0 < length1) {
    426				local_result = TRUE;
    427			}
    428			break;
    429
    430		default:
    431
    432			ACPI_ERROR((AE_INFO,
    433				    "Invalid comparison opcode: %X", opcode));
    434			status = AE_AML_INTERNAL;
    435			break;
    436		}
    437	}
    438
    439cleanup:
    440
    441	/* New object was created if implicit conversion performed - delete */
    442
    443	if (local_operand1 != operand1) {
    444		acpi_ut_remove_reference(local_operand1);
    445	}
    446
    447	/* Return the logical result and status */
    448
    449	*logical_result = local_result;
    450	return_ACPI_STATUS(status);
    451}