162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *****************************************************************************/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <acpi/acpi.h>
1162306a36Sopenharmony_ci#include "accommon.h"
1262306a36Sopenharmony_ci#include "acinterp.h"
1362306a36Sopenharmony_ci#include "amlcode.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define _COMPONENT          ACPI_EXECUTER
1662306a36Sopenharmony_ciACPI_MODULE_NAME("exmisc")
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/*******************************************************************************
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * FUNCTION:    acpi_ex_get_object_reference
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * PARAMETERS:  obj_desc            - Create a reference to this object
2362306a36Sopenharmony_ci *              return_desc         - Where to store the reference
2462306a36Sopenharmony_ci *              walk_state          - Current state
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * RETURN:      Status
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * DESCRIPTION: Obtain and return a "reference" to the target object
2962306a36Sopenharmony_ci *              Common code for the ref_of_op and the cond_ref_of_op.
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci ******************************************************************************/
3262306a36Sopenharmony_ciacpi_status
3362306a36Sopenharmony_ciacpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
3462306a36Sopenharmony_ci			     union acpi_operand_object **return_desc,
3562306a36Sopenharmony_ci			     struct acpi_walk_state *walk_state)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	union acpi_operand_object *reference_obj;
3862306a36Sopenharmony_ci	union acpi_operand_object *referenced_obj;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_PTR(ex_get_object_reference, obj_desc);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	*return_desc = NULL;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {
4562306a36Sopenharmony_ci	case ACPI_DESC_TYPE_OPERAND:
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci		if (obj_desc->common.type != ACPI_TYPE_LOCAL_REFERENCE) {
4862306a36Sopenharmony_ci			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
4962306a36Sopenharmony_ci		}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci		/*
5262306a36Sopenharmony_ci		 * Must be a reference to a Local or Arg
5362306a36Sopenharmony_ci		 */
5462306a36Sopenharmony_ci		switch (obj_desc->reference.class) {
5562306a36Sopenharmony_ci		case ACPI_REFCLASS_LOCAL:
5662306a36Sopenharmony_ci		case ACPI_REFCLASS_ARG:
5762306a36Sopenharmony_ci		case ACPI_REFCLASS_DEBUG:
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci			/* The referenced object is the pseudo-node for the local/arg */
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci			referenced_obj = obj_desc->reference.object;
6262306a36Sopenharmony_ci			break;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci		default:
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci			ACPI_ERROR((AE_INFO, "Invalid Reference Class 0x%2.2X",
6762306a36Sopenharmony_ci				    obj_desc->reference.class));
6862306a36Sopenharmony_ci			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
6962306a36Sopenharmony_ci		}
7062306a36Sopenharmony_ci		break;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	case ACPI_DESC_TYPE_NAMED:
7362306a36Sopenharmony_ci		/*
7462306a36Sopenharmony_ci		 * A named reference that has already been resolved to a Node
7562306a36Sopenharmony_ci		 */
7662306a36Sopenharmony_ci		referenced_obj = obj_desc;
7762306a36Sopenharmony_ci		break;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	default:
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "Invalid descriptor type 0x%X",
8262306a36Sopenharmony_ci			    ACPI_GET_DESCRIPTOR_TYPE(obj_desc)));
8362306a36Sopenharmony_ci		return_ACPI_STATUS(AE_TYPE);
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* Create a new reference object */
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	reference_obj =
8962306a36Sopenharmony_ci	    acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE);
9062306a36Sopenharmony_ci	if (!reference_obj) {
9162306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NO_MEMORY);
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	reference_obj->reference.class = ACPI_REFCLASS_REFOF;
9562306a36Sopenharmony_ci	reference_obj->reference.object = referenced_obj;
9662306a36Sopenharmony_ci	*return_desc = reference_obj;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
9962306a36Sopenharmony_ci			  "Object %p Type [%s], returning Reference %p\n",
10062306a36Sopenharmony_ci			  obj_desc, acpi_ut_get_object_type_name(obj_desc),
10162306a36Sopenharmony_ci			  *return_desc));
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/*******************************************************************************
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * FUNCTION:    acpi_ex_do_math_op
10962306a36Sopenharmony_ci *
11062306a36Sopenharmony_ci * PARAMETERS:  opcode              - AML opcode
11162306a36Sopenharmony_ci *              integer0            - Integer operand #0
11262306a36Sopenharmony_ci *              integer1            - Integer operand #1
11362306a36Sopenharmony_ci *
11462306a36Sopenharmony_ci * RETURN:      Integer result of the operation
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
11762306a36Sopenharmony_ci *              math functions here is to prevent a lot of pointer dereferencing
11862306a36Sopenharmony_ci *              to obtain the operands.
11962306a36Sopenharmony_ci *
12062306a36Sopenharmony_ci ******************************************************************************/
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ciu64 acpi_ex_do_math_op(u16 opcode, u64 integer0, u64 integer1)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	ACPI_FUNCTION_ENTRY();
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	switch (opcode) {
12862306a36Sopenharmony_ci	case AML_ADD_OP:	/* Add (Integer0, Integer1, Result) */
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		return (integer0 + integer1);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	case AML_BIT_AND_OP:	/* And (Integer0, Integer1, Result) */
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci		return (integer0 & integer1);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	case AML_BIT_NAND_OP:	/* NAnd (Integer0, Integer1, Result) */
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci		return (~(integer0 & integer1));
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	case AML_BIT_OR_OP:	/* Or (Integer0, Integer1, Result) */
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		return (integer0 | integer1);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	case AML_BIT_NOR_OP:	/* NOr (Integer0, Integer1, Result) */
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci		return (~(integer0 | integer1));
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	case AML_BIT_XOR_OP:	/* XOr (Integer0, Integer1, Result) */
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci		return (integer0 ^ integer1);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	case AML_MULTIPLY_OP:	/* Multiply (Integer0, Integer1, Result) */
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci		return (integer0 * integer1);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	case AML_SHIFT_LEFT_OP:	/* shift_left (Operand, shift_count, Result) */
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci		/*
15962306a36Sopenharmony_ci		 * We need to check if the shiftcount is larger than the integer bit
16062306a36Sopenharmony_ci		 * width since the behavior of this is not well-defined in the C language.
16162306a36Sopenharmony_ci		 */
16262306a36Sopenharmony_ci		if (integer1 >= acpi_gbl_integer_bit_width) {
16362306a36Sopenharmony_ci			return (0);
16462306a36Sopenharmony_ci		}
16562306a36Sopenharmony_ci		return (integer0 << integer1);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	case AML_SHIFT_RIGHT_OP:	/* shift_right (Operand, shift_count, Result) */
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci		/*
17062306a36Sopenharmony_ci		 * We need to check if the shiftcount is larger than the integer bit
17162306a36Sopenharmony_ci		 * width since the behavior of this is not well-defined in the C language.
17262306a36Sopenharmony_ci		 */
17362306a36Sopenharmony_ci		if (integer1 >= acpi_gbl_integer_bit_width) {
17462306a36Sopenharmony_ci			return (0);
17562306a36Sopenharmony_ci		}
17662306a36Sopenharmony_ci		return (integer0 >> integer1);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	case AML_SUBTRACT_OP:	/* Subtract (Integer0, Integer1, Result) */
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		return (integer0 - integer1);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	default:
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci		return (0);
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/*******************************************************************************
18962306a36Sopenharmony_ci *
19062306a36Sopenharmony_ci * FUNCTION:    acpi_ex_do_logical_numeric_op
19162306a36Sopenharmony_ci *
19262306a36Sopenharmony_ci * PARAMETERS:  opcode              - AML opcode
19362306a36Sopenharmony_ci *              integer0            - Integer operand #0
19462306a36Sopenharmony_ci *              integer1            - Integer operand #1
19562306a36Sopenharmony_ci *              logical_result      - TRUE/FALSE result of the operation
19662306a36Sopenharmony_ci *
19762306a36Sopenharmony_ci * RETURN:      Status
19862306a36Sopenharmony_ci *
19962306a36Sopenharmony_ci * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric
20062306a36Sopenharmony_ci *              operators (LAnd and LOr), both operands must be integers.
20162306a36Sopenharmony_ci *
20262306a36Sopenharmony_ci *              Note: cleanest machine code seems to be produced by the code
20362306a36Sopenharmony_ci *              below, rather than using statements of the form:
20462306a36Sopenharmony_ci *                  Result = (Integer0 && Integer1);
20562306a36Sopenharmony_ci *
20662306a36Sopenharmony_ci ******************************************************************************/
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ciacpi_status
20962306a36Sopenharmony_ciacpi_ex_do_logical_numeric_op(u16 opcode,
21062306a36Sopenharmony_ci			      u64 integer0, u64 integer1, u8 *logical_result)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	acpi_status status = AE_OK;
21362306a36Sopenharmony_ci	u8 local_result = FALSE;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ex_do_logical_numeric_op);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	switch (opcode) {
21862306a36Sopenharmony_ci	case AML_LOGICAL_AND_OP:	/* LAnd (Integer0, Integer1) */
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		if (integer0 && integer1) {
22162306a36Sopenharmony_ci			local_result = TRUE;
22262306a36Sopenharmony_ci		}
22362306a36Sopenharmony_ci		break;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	case AML_LOGICAL_OR_OP:	/* LOr (Integer0, Integer1) */
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci		if (integer0 || integer1) {
22862306a36Sopenharmony_ci			local_result = TRUE;
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci		break;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	default:
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO,
23562306a36Sopenharmony_ci			    "Invalid numeric logical opcode: %X", opcode));
23662306a36Sopenharmony_ci		status = AE_AML_INTERNAL;
23762306a36Sopenharmony_ci		break;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	/* Return the logical result and status */
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	*logical_result = local_result;
24362306a36Sopenharmony_ci	return_ACPI_STATUS(status);
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci/*******************************************************************************
24762306a36Sopenharmony_ci *
24862306a36Sopenharmony_ci * FUNCTION:    acpi_ex_do_logical_op
24962306a36Sopenharmony_ci *
25062306a36Sopenharmony_ci * PARAMETERS:  opcode              - AML opcode
25162306a36Sopenharmony_ci *              operand0            - operand #0
25262306a36Sopenharmony_ci *              operand1            - operand #1
25362306a36Sopenharmony_ci *              logical_result      - TRUE/FALSE result of the operation
25462306a36Sopenharmony_ci *
25562306a36Sopenharmony_ci * RETURN:      Status
25662306a36Sopenharmony_ci *
25762306a36Sopenharmony_ci * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
25862306a36Sopenharmony_ci *              functions here is to prevent a lot of pointer dereferencing
25962306a36Sopenharmony_ci *              to obtain the operands and to simplify the generation of the
26062306a36Sopenharmony_ci *              logical value. For the Numeric operators (LAnd and LOr), both
26162306a36Sopenharmony_ci *              operands must be integers. For the other logical operators,
26262306a36Sopenharmony_ci *              operands can be any combination of Integer/String/Buffer. The
26362306a36Sopenharmony_ci *              first operand determines the type to which the second operand
26462306a36Sopenharmony_ci *              will be converted.
26562306a36Sopenharmony_ci *
26662306a36Sopenharmony_ci *              Note: cleanest machine code seems to be produced by the code
26762306a36Sopenharmony_ci *              below, rather than using statements of the form:
26862306a36Sopenharmony_ci *                  Result = (Operand0 == Operand1);
26962306a36Sopenharmony_ci *
27062306a36Sopenharmony_ci ******************************************************************************/
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ciacpi_status
27362306a36Sopenharmony_ciacpi_ex_do_logical_op(u16 opcode,
27462306a36Sopenharmony_ci		      union acpi_operand_object *operand0,
27562306a36Sopenharmony_ci		      union acpi_operand_object *operand1, u8 * logical_result)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	union acpi_operand_object *local_operand1 = operand1;
27862306a36Sopenharmony_ci	u64 integer0;
27962306a36Sopenharmony_ci	u64 integer1;
28062306a36Sopenharmony_ci	u32 length0;
28162306a36Sopenharmony_ci	u32 length1;
28262306a36Sopenharmony_ci	acpi_status status = AE_OK;
28362306a36Sopenharmony_ci	u8 local_result = FALSE;
28462306a36Sopenharmony_ci	int compare;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ex_do_logical_op);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/*
28962306a36Sopenharmony_ci	 * Convert the second operand if necessary. The first operand
29062306a36Sopenharmony_ci	 * determines the type of the second operand, (See the Data Types
29162306a36Sopenharmony_ci	 * section of the ACPI 3.0+ specification.)  Both object types are
29262306a36Sopenharmony_ci	 * guaranteed to be either Integer/String/Buffer by the operand
29362306a36Sopenharmony_ci	 * resolution mechanism.
29462306a36Sopenharmony_ci	 */
29562306a36Sopenharmony_ci	switch (operand0->common.type) {
29662306a36Sopenharmony_ci	case ACPI_TYPE_INTEGER:
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci		status = acpi_ex_convert_to_integer(operand1, &local_operand1,
29962306a36Sopenharmony_ci						    ACPI_IMPLICIT_CONVERSION);
30062306a36Sopenharmony_ci		break;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	case ACPI_TYPE_STRING:
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		status =
30562306a36Sopenharmony_ci		    acpi_ex_convert_to_string(operand1, &local_operand1,
30662306a36Sopenharmony_ci					      ACPI_IMPLICIT_CONVERT_HEX);
30762306a36Sopenharmony_ci		break;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	case ACPI_TYPE_BUFFER:
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci		status = acpi_ex_convert_to_buffer(operand1, &local_operand1);
31262306a36Sopenharmony_ci		break;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	default:
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO,
31762306a36Sopenharmony_ci			    "Invalid object type for logical operator: %X",
31862306a36Sopenharmony_ci			    operand0->common.type));
31962306a36Sopenharmony_ci		status = AE_AML_INTERNAL;
32062306a36Sopenharmony_ci		break;
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
32462306a36Sopenharmony_ci		goto cleanup;
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/*
32862306a36Sopenharmony_ci	 * Two cases: 1) Both Integers, 2) Both Strings or Buffers
32962306a36Sopenharmony_ci	 */
33062306a36Sopenharmony_ci	if (operand0->common.type == ACPI_TYPE_INTEGER) {
33162306a36Sopenharmony_ci		/*
33262306a36Sopenharmony_ci		 * 1) Both operands are of type integer
33362306a36Sopenharmony_ci		 *    Note: local_operand1 may have changed above
33462306a36Sopenharmony_ci		 */
33562306a36Sopenharmony_ci		integer0 = operand0->integer.value;
33662306a36Sopenharmony_ci		integer1 = local_operand1->integer.value;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci		switch (opcode) {
33962306a36Sopenharmony_ci		case AML_LOGICAL_EQUAL_OP:	/* LEqual (Operand0, Operand1) */
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci			if (integer0 == integer1) {
34262306a36Sopenharmony_ci				local_result = TRUE;
34362306a36Sopenharmony_ci			}
34462306a36Sopenharmony_ci			break;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		case AML_LOGICAL_GREATER_OP:	/* LGreater (Operand0, Operand1) */
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci			if (integer0 > integer1) {
34962306a36Sopenharmony_ci				local_result = TRUE;
35062306a36Sopenharmony_ci			}
35162306a36Sopenharmony_ci			break;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci		case AML_LOGICAL_LESS_OP:	/* LLess (Operand0, Operand1) */
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci			if (integer0 < integer1) {
35662306a36Sopenharmony_ci				local_result = TRUE;
35762306a36Sopenharmony_ci			}
35862306a36Sopenharmony_ci			break;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci		default:
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci			ACPI_ERROR((AE_INFO,
36362306a36Sopenharmony_ci				    "Invalid comparison opcode: %X", opcode));
36462306a36Sopenharmony_ci			status = AE_AML_INTERNAL;
36562306a36Sopenharmony_ci			break;
36662306a36Sopenharmony_ci		}
36762306a36Sopenharmony_ci	} else {
36862306a36Sopenharmony_ci		/*
36962306a36Sopenharmony_ci		 * 2) Both operands are Strings or both are Buffers
37062306a36Sopenharmony_ci		 *    Note: Code below takes advantage of common Buffer/String
37162306a36Sopenharmony_ci		 *          object fields. local_operand1 may have changed above. Use
37262306a36Sopenharmony_ci		 *          memcmp to handle nulls in buffers.
37362306a36Sopenharmony_ci		 */
37462306a36Sopenharmony_ci		length0 = operand0->buffer.length;
37562306a36Sopenharmony_ci		length1 = local_operand1->buffer.length;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		/* Lexicographic compare: compare the data bytes */
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		compare = memcmp(operand0->buffer.pointer,
38062306a36Sopenharmony_ci				 local_operand1->buffer.pointer,
38162306a36Sopenharmony_ci				 (length0 > length1) ? length1 : length0);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci		switch (opcode) {
38462306a36Sopenharmony_ci		case AML_LOGICAL_EQUAL_OP:	/* LEqual (Operand0, Operand1) */
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci			/* Length and all bytes must be equal */
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci			if ((length0 == length1) && (compare == 0)) {
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci				/* Length and all bytes match ==> TRUE */
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci				local_result = TRUE;
39362306a36Sopenharmony_ci			}
39462306a36Sopenharmony_ci			break;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci		case AML_LOGICAL_GREATER_OP:	/* LGreater (Operand0, Operand1) */
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci			if (compare > 0) {
39962306a36Sopenharmony_ci				local_result = TRUE;
40062306a36Sopenharmony_ci				goto cleanup;	/* TRUE */
40162306a36Sopenharmony_ci			}
40262306a36Sopenharmony_ci			if (compare < 0) {
40362306a36Sopenharmony_ci				goto cleanup;	/* FALSE */
40462306a36Sopenharmony_ci			}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci			/* Bytes match (to shortest length), compare lengths */
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci			if (length0 > length1) {
40962306a36Sopenharmony_ci				local_result = TRUE;
41062306a36Sopenharmony_ci			}
41162306a36Sopenharmony_ci			break;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		case AML_LOGICAL_LESS_OP:	/* LLess (Operand0, Operand1) */
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci			if (compare > 0) {
41662306a36Sopenharmony_ci				goto cleanup;	/* FALSE */
41762306a36Sopenharmony_ci			}
41862306a36Sopenharmony_ci			if (compare < 0) {
41962306a36Sopenharmony_ci				local_result = TRUE;
42062306a36Sopenharmony_ci				goto cleanup;	/* TRUE */
42162306a36Sopenharmony_ci			}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci			/* Bytes match (to shortest length), compare lengths */
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci			if (length0 < length1) {
42662306a36Sopenharmony_ci				local_result = TRUE;
42762306a36Sopenharmony_ci			}
42862306a36Sopenharmony_ci			break;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci		default:
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci			ACPI_ERROR((AE_INFO,
43362306a36Sopenharmony_ci				    "Invalid comparison opcode: %X", opcode));
43462306a36Sopenharmony_ci			status = AE_AML_INTERNAL;
43562306a36Sopenharmony_ci			break;
43662306a36Sopenharmony_ci		}
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cicleanup:
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	/* New object was created if implicit conversion performed - delete */
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	if (local_operand1 != operand1) {
44462306a36Sopenharmony_ci		acpi_ut_remove_reference(local_operand1);
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	/* Return the logical result and status */
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	*logical_result = local_result;
45062306a36Sopenharmony_ci	return_ACPI_STATUS(status);
45162306a36Sopenharmony_ci}
452