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