162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: exstorob - AML object store support, store to object
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
1462306a36Sopenharmony_ci#define _COMPONENT          ACPI_EXECUTER
1562306a36Sopenharmony_ciACPI_MODULE_NAME("exstorob")
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*******************************************************************************
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * FUNCTION:    acpi_ex_store_buffer_to_buffer
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * PARAMETERS:  source_desc         - Source object to copy
2262306a36Sopenharmony_ci *              target_desc         - Destination object of the copy
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * RETURN:      Status
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * DESCRIPTION: Copy a buffer object to another buffer object.
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci ******************************************************************************/
2962306a36Sopenharmony_ciacpi_status
3062306a36Sopenharmony_ciacpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc,
3162306a36Sopenharmony_ci			       union acpi_operand_object *target_desc)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	u32 length;
3462306a36Sopenharmony_ci	u8 *buffer;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_PTR(ex_store_buffer_to_buffer, source_desc);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	/* If Source and Target are the same, just return */
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	if (source_desc == target_desc) {
4162306a36Sopenharmony_ci		return_ACPI_STATUS(AE_OK);
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	/* We know that source_desc is a buffer by now */
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	buffer = ACPI_CAST_PTR(u8, source_desc->buffer.pointer);
4762306a36Sopenharmony_ci	length = source_desc->buffer.length;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/*
5062306a36Sopenharmony_ci	 * If target is a buffer of length zero or is a static buffer,
5162306a36Sopenharmony_ci	 * allocate a new buffer of the proper length
5262306a36Sopenharmony_ci	 */
5362306a36Sopenharmony_ci	if ((target_desc->buffer.length == 0) ||
5462306a36Sopenharmony_ci	    (target_desc->common.flags & AOPOBJ_STATIC_POINTER)) {
5562306a36Sopenharmony_ci		target_desc->buffer.pointer = ACPI_ALLOCATE(length);
5662306a36Sopenharmony_ci		if (!target_desc->buffer.pointer) {
5762306a36Sopenharmony_ci			return_ACPI_STATUS(AE_NO_MEMORY);
5862306a36Sopenharmony_ci		}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci		target_desc->buffer.length = length;
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/* Copy source buffer to target buffer */
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (length <= target_desc->buffer.length) {
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci		/* Clear existing buffer and copy in the new one */
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci		memset(target_desc->buffer.pointer, 0,
7062306a36Sopenharmony_ci		       target_desc->buffer.length);
7162306a36Sopenharmony_ci		memcpy(target_desc->buffer.pointer, buffer, length);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#ifdef ACPI_OBSOLETE_BEHAVIOR
7462306a36Sopenharmony_ci		/*
7562306a36Sopenharmony_ci		 * NOTE: ACPI versions up to 3.0 specified that the buffer must be
7662306a36Sopenharmony_ci		 * truncated if the string is smaller than the buffer. However, "other"
7762306a36Sopenharmony_ci		 * implementations of ACPI never did this and thus became the defacto
7862306a36Sopenharmony_ci		 * standard. ACPI 3.0A changes this behavior such that the buffer
7962306a36Sopenharmony_ci		 * is no longer truncated.
8062306a36Sopenharmony_ci		 */
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci		/*
8362306a36Sopenharmony_ci		 * OBSOLETE BEHAVIOR:
8462306a36Sopenharmony_ci		 * If the original source was a string, we must truncate the buffer,
8562306a36Sopenharmony_ci		 * according to the ACPI spec. Integer-to-Buffer and Buffer-to-Buffer
8662306a36Sopenharmony_ci		 * copy must not truncate the original buffer.
8762306a36Sopenharmony_ci		 */
8862306a36Sopenharmony_ci		if (original_src_type == ACPI_TYPE_STRING) {
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci			/* Set the new length of the target */
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci			target_desc->buffer.length = length;
9362306a36Sopenharmony_ci		}
9462306a36Sopenharmony_ci#endif
9562306a36Sopenharmony_ci	} else {
9662306a36Sopenharmony_ci		/* Truncate the source, copy only what will fit */
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci		memcpy(target_desc->buffer.pointer, buffer,
9962306a36Sopenharmony_ci		       target_desc->buffer.length);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
10262306a36Sopenharmony_ci				  "Truncating source buffer from %X to %X\n",
10362306a36Sopenharmony_ci				  length, target_desc->buffer.length));
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	/* Copy flags */
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	target_desc->buffer.flags = source_desc->buffer.flags;
10962306a36Sopenharmony_ci	target_desc->common.flags &= ~AOPOBJ_STATIC_POINTER;
11062306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/*******************************************************************************
11462306a36Sopenharmony_ci *
11562306a36Sopenharmony_ci * FUNCTION:    acpi_ex_store_string_to_string
11662306a36Sopenharmony_ci *
11762306a36Sopenharmony_ci * PARAMETERS:  source_desc         - Source object to copy
11862306a36Sopenharmony_ci *              target_desc         - Destination object of the copy
11962306a36Sopenharmony_ci *
12062306a36Sopenharmony_ci * RETURN:      Status
12162306a36Sopenharmony_ci *
12262306a36Sopenharmony_ci * DESCRIPTION: Copy a String object to another String object
12362306a36Sopenharmony_ci *
12462306a36Sopenharmony_ci ******************************************************************************/
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciacpi_status
12762306a36Sopenharmony_ciacpi_ex_store_string_to_string(union acpi_operand_object *source_desc,
12862306a36Sopenharmony_ci			       union acpi_operand_object *target_desc)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	u32 length;
13162306a36Sopenharmony_ci	u8 *buffer;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_PTR(ex_store_string_to_string, source_desc);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/* If Source and Target are the same, just return */
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	if (source_desc == target_desc) {
13862306a36Sopenharmony_ci		return_ACPI_STATUS(AE_OK);
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* We know that source_desc is a string by now */
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	buffer = ACPI_CAST_PTR(u8, source_desc->string.pointer);
14462306a36Sopenharmony_ci	length = source_desc->string.length;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/*
14762306a36Sopenharmony_ci	 * Replace existing string value if it will fit and the string
14862306a36Sopenharmony_ci	 * pointer is not a static pointer (part of an ACPI table)
14962306a36Sopenharmony_ci	 */
15062306a36Sopenharmony_ci	if ((length < target_desc->string.length) &&
15162306a36Sopenharmony_ci	    (!(target_desc->common.flags & AOPOBJ_STATIC_POINTER))) {
15262306a36Sopenharmony_ci		/*
15362306a36Sopenharmony_ci		 * String will fit in existing non-static buffer.
15462306a36Sopenharmony_ci		 * Clear old string and copy in the new one
15562306a36Sopenharmony_ci		 */
15662306a36Sopenharmony_ci		memset(target_desc->string.pointer, 0,
15762306a36Sopenharmony_ci		       (acpi_size)target_desc->string.length + 1);
15862306a36Sopenharmony_ci		memcpy(target_desc->string.pointer, buffer, length);
15962306a36Sopenharmony_ci	} else {
16062306a36Sopenharmony_ci		/*
16162306a36Sopenharmony_ci		 * Free the current buffer, then allocate a new buffer
16262306a36Sopenharmony_ci		 * large enough to hold the value
16362306a36Sopenharmony_ci		 */
16462306a36Sopenharmony_ci		if (target_desc->string.pointer &&
16562306a36Sopenharmony_ci		    (!(target_desc->common.flags & AOPOBJ_STATIC_POINTER))) {
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci			/* Only free if not a pointer into the DSDT */
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci			ACPI_FREE(target_desc->string.pointer);
17062306a36Sopenharmony_ci		}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci		target_desc->string.pointer =
17362306a36Sopenharmony_ci		    ACPI_ALLOCATE_ZEROED((acpi_size)length + 1);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci		if (!target_desc->string.pointer) {
17662306a36Sopenharmony_ci			return_ACPI_STATUS(AE_NO_MEMORY);
17762306a36Sopenharmony_ci		}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci		target_desc->common.flags &= ~AOPOBJ_STATIC_POINTER;
18062306a36Sopenharmony_ci		memcpy(target_desc->string.pointer, buffer, length);
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* Set the new target length */
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	target_desc->string.length = length;
18662306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
18762306a36Sopenharmony_ci}
188