162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: utalloc - local memory allocation routines 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 "acdebug.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define _COMPONENT ACPI_UTILITIES 1562306a36Sopenharmony_ciACPI_MODULE_NAME("utalloc") 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#if !defined (USE_NATIVE_ALLOCATE_ZEROED) 1862306a36Sopenharmony_ci/******************************************************************************* 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * FUNCTION: acpi_os_allocate_zeroed 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * PARAMETERS: size - Size of the allocation 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * RETURN: Address of the allocated memory on success, NULL on failure. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * DESCRIPTION: Subsystem equivalent of calloc. Allocate and zero memory. 2762306a36Sopenharmony_ci * This is the default implementation. Can be overridden via the 2862306a36Sopenharmony_ci * USE_NATIVE_ALLOCATE_ZEROED flag. 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci ******************************************************************************/ 3162306a36Sopenharmony_civoid *acpi_os_allocate_zeroed(acpi_size size) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci void *allocation; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci ACPI_FUNCTION_ENTRY(); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci allocation = acpi_os_allocate(size); 3862306a36Sopenharmony_ci if (allocation) { 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* Clear the memory block */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci memset(allocation, 0, size); 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci return (allocation); 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#endif /* !USE_NATIVE_ALLOCATE_ZEROED */ 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/******************************************************************************* 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * FUNCTION: acpi_ut_create_caches 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * PARAMETERS: None 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * RETURN: Status 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * DESCRIPTION: Create all local caches 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci ******************************************************************************/ 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciacpi_status acpi_ut_create_caches(void) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci acpi_status status; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* Object Caches, for frequently used objects */ 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci status = 6962306a36Sopenharmony_ci acpi_os_create_cache("Acpi-Namespace", 7062306a36Sopenharmony_ci sizeof(struct acpi_namespace_node), 7162306a36Sopenharmony_ci ACPI_MAX_NAMESPACE_CACHE_DEPTH, 7262306a36Sopenharmony_ci &acpi_gbl_namespace_cache); 7362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 7462306a36Sopenharmony_ci return (status); 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci status = 7862306a36Sopenharmony_ci acpi_os_create_cache("Acpi-State", sizeof(union acpi_generic_state), 7962306a36Sopenharmony_ci ACPI_MAX_STATE_CACHE_DEPTH, 8062306a36Sopenharmony_ci &acpi_gbl_state_cache); 8162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 8262306a36Sopenharmony_ci return (status); 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci status = 8662306a36Sopenharmony_ci acpi_os_create_cache("Acpi-Parse", 8762306a36Sopenharmony_ci sizeof(struct acpi_parse_obj_common), 8862306a36Sopenharmony_ci ACPI_MAX_PARSE_CACHE_DEPTH, 8962306a36Sopenharmony_ci &acpi_gbl_ps_node_cache); 9062306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 9162306a36Sopenharmony_ci return (status); 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci status = 9562306a36Sopenharmony_ci acpi_os_create_cache("Acpi-ParseExt", 9662306a36Sopenharmony_ci sizeof(struct acpi_parse_obj_named), 9762306a36Sopenharmony_ci ACPI_MAX_EXTPARSE_CACHE_DEPTH, 9862306a36Sopenharmony_ci &acpi_gbl_ps_node_ext_cache); 9962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 10062306a36Sopenharmony_ci return (status); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci status = 10462306a36Sopenharmony_ci acpi_os_create_cache("Acpi-Operand", 10562306a36Sopenharmony_ci sizeof(union acpi_operand_object), 10662306a36Sopenharmony_ci ACPI_MAX_OBJECT_CACHE_DEPTH, 10762306a36Sopenharmony_ci &acpi_gbl_operand_cache); 10862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 10962306a36Sopenharmony_ci return (status); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci#ifdef ACPI_ASL_COMPILER 11262306a36Sopenharmony_ci /* 11362306a36Sopenharmony_ci * For use with the ASL-/ASL+ option. This cache keeps track of regular 11462306a36Sopenharmony_ci * 0xA9 0x01 comments. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci status = 11762306a36Sopenharmony_ci acpi_os_create_cache("Acpi-Comment", 11862306a36Sopenharmony_ci sizeof(struct acpi_comment_node), 11962306a36Sopenharmony_ci ACPI_MAX_COMMENT_CACHE_DEPTH, 12062306a36Sopenharmony_ci &acpi_gbl_reg_comment_cache); 12162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 12262306a36Sopenharmony_ci return (status); 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* 12662306a36Sopenharmony_ci * This cache keeps track of the starting addresses of where the comments 12762306a36Sopenharmony_ci * lie. This helps prevent duplication of comments. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ci status = 13062306a36Sopenharmony_ci acpi_os_create_cache("Acpi-Comment-Addr", 13162306a36Sopenharmony_ci sizeof(struct acpi_comment_addr_node), 13262306a36Sopenharmony_ci ACPI_MAX_COMMENT_CACHE_DEPTH, 13362306a36Sopenharmony_ci &acpi_gbl_comment_addr_cache); 13462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 13562306a36Sopenharmony_ci return (status); 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* 13962306a36Sopenharmony_ci * This cache will be used for nodes that represent files. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci status = 14262306a36Sopenharmony_ci acpi_os_create_cache("Acpi-File", sizeof(struct acpi_file_node), 14362306a36Sopenharmony_ci ACPI_MAX_COMMENT_CACHE_DEPTH, 14462306a36Sopenharmony_ci &acpi_gbl_file_cache); 14562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 14662306a36Sopenharmony_ci return (status); 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci#endif 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci#ifdef ACPI_DBG_TRACK_ALLOCATIONS 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* Memory allocation lists */ 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci status = acpi_ut_create_list("Acpi-Global", 0, &acpi_gbl_global_list); 15562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 15662306a36Sopenharmony_ci return (status); 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci status = 16062306a36Sopenharmony_ci acpi_ut_create_list("Acpi-Namespace", 16162306a36Sopenharmony_ci sizeof(struct acpi_namespace_node), 16262306a36Sopenharmony_ci &acpi_gbl_ns_node_list); 16362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 16462306a36Sopenharmony_ci return (status); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci#endif 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return (AE_OK); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/******************************************************************************* 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * FUNCTION: acpi_ut_delete_caches 17462306a36Sopenharmony_ci * 17562306a36Sopenharmony_ci * PARAMETERS: None 17662306a36Sopenharmony_ci * 17762306a36Sopenharmony_ci * RETURN: Status 17862306a36Sopenharmony_ci * 17962306a36Sopenharmony_ci * DESCRIPTION: Purge and delete all local caches 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci ******************************************************************************/ 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ciacpi_status acpi_ut_delete_caches(void) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci#ifdef ACPI_DBG_TRACK_ALLOCATIONS 18662306a36Sopenharmony_ci char buffer[7]; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (acpi_gbl_display_final_mem_stats) { 18962306a36Sopenharmony_ci strcpy(buffer, "MEMORY"); 19062306a36Sopenharmony_ci (void)acpi_db_display_statistics(buffer); 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci#endif 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci (void)acpi_os_delete_cache(acpi_gbl_namespace_cache); 19562306a36Sopenharmony_ci acpi_gbl_namespace_cache = NULL; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci (void)acpi_os_delete_cache(acpi_gbl_state_cache); 19862306a36Sopenharmony_ci acpi_gbl_state_cache = NULL; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci (void)acpi_os_delete_cache(acpi_gbl_operand_cache); 20162306a36Sopenharmony_ci acpi_gbl_operand_cache = NULL; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci (void)acpi_os_delete_cache(acpi_gbl_ps_node_cache); 20462306a36Sopenharmony_ci acpi_gbl_ps_node_cache = NULL; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci (void)acpi_os_delete_cache(acpi_gbl_ps_node_ext_cache); 20762306a36Sopenharmony_ci acpi_gbl_ps_node_ext_cache = NULL; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci#ifdef ACPI_ASL_COMPILER 21062306a36Sopenharmony_ci (void)acpi_os_delete_cache(acpi_gbl_reg_comment_cache); 21162306a36Sopenharmony_ci acpi_gbl_reg_comment_cache = NULL; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci (void)acpi_os_delete_cache(acpi_gbl_comment_addr_cache); 21462306a36Sopenharmony_ci acpi_gbl_comment_addr_cache = NULL; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci (void)acpi_os_delete_cache(acpi_gbl_file_cache); 21762306a36Sopenharmony_ci acpi_gbl_file_cache = NULL; 21862306a36Sopenharmony_ci#endif 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci#ifdef ACPI_DBG_TRACK_ALLOCATIONS 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* Debug only - display leftover memory allocation, if any */ 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci acpi_ut_dump_allocations(ACPI_UINT32_MAX, NULL); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* Free memory lists */ 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci acpi_os_free(acpi_gbl_global_list); 22962306a36Sopenharmony_ci acpi_gbl_global_list = NULL; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci acpi_os_free(acpi_gbl_ns_node_list); 23262306a36Sopenharmony_ci acpi_gbl_ns_node_list = NULL; 23362306a36Sopenharmony_ci#endif 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci return (AE_OK); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci/******************************************************************************* 23962306a36Sopenharmony_ci * 24062306a36Sopenharmony_ci * FUNCTION: acpi_ut_validate_buffer 24162306a36Sopenharmony_ci * 24262306a36Sopenharmony_ci * PARAMETERS: buffer - Buffer descriptor to be validated 24362306a36Sopenharmony_ci * 24462306a36Sopenharmony_ci * RETURN: Status 24562306a36Sopenharmony_ci * 24662306a36Sopenharmony_ci * DESCRIPTION: Perform parameter validation checks on an struct acpi_buffer 24762306a36Sopenharmony_ci * 24862306a36Sopenharmony_ci ******************************************************************************/ 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ciacpi_status acpi_ut_validate_buffer(struct acpi_buffer *buffer) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* Obviously, the structure pointer must be valid */ 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (!buffer) { 25662306a36Sopenharmony_ci return (AE_BAD_PARAMETER); 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* Special semantics for the length */ 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if ((buffer->length == ACPI_NO_BUFFER) || 26262306a36Sopenharmony_ci (buffer->length == ACPI_ALLOCATE_BUFFER) || 26362306a36Sopenharmony_ci (buffer->length == ACPI_ALLOCATE_LOCAL_BUFFER)) { 26462306a36Sopenharmony_ci return (AE_OK); 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* Length is valid, the buffer pointer must be also */ 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (!buffer->pointer) { 27062306a36Sopenharmony_ci return (AE_BAD_PARAMETER); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return (AE_OK); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci/******************************************************************************* 27762306a36Sopenharmony_ci * 27862306a36Sopenharmony_ci * FUNCTION: acpi_ut_initialize_buffer 27962306a36Sopenharmony_ci * 28062306a36Sopenharmony_ci * PARAMETERS: buffer - Buffer to be validated 28162306a36Sopenharmony_ci * required_length - Length needed 28262306a36Sopenharmony_ci * 28362306a36Sopenharmony_ci * RETURN: Status 28462306a36Sopenharmony_ci * 28562306a36Sopenharmony_ci * DESCRIPTION: Validate that the buffer is of the required length or 28662306a36Sopenharmony_ci * allocate a new buffer. Returned buffer is always zeroed. 28762306a36Sopenharmony_ci * 28862306a36Sopenharmony_ci ******************************************************************************/ 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ciacpi_status 29162306a36Sopenharmony_ciacpi_ut_initialize_buffer(struct acpi_buffer *buffer, acpi_size required_length) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci acpi_size input_buffer_length; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Parameter validation */ 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (!buffer || !required_length) { 29862306a36Sopenharmony_ci return (AE_BAD_PARAMETER); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* 30262306a36Sopenharmony_ci * Buffer->Length is used as both an input and output parameter. Get the 30362306a36Sopenharmony_ci * input actual length and set the output required buffer length. 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_ci input_buffer_length = buffer->length; 30662306a36Sopenharmony_ci buffer->length = required_length; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* 30962306a36Sopenharmony_ci * The input buffer length contains the actual buffer length, or the type 31062306a36Sopenharmony_ci * of buffer to be allocated by this routine. 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_ci switch (input_buffer_length) { 31362306a36Sopenharmony_ci case ACPI_NO_BUFFER: 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* Return the exception (and the required buffer length) */ 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return (AE_BUFFER_OVERFLOW); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci case ACPI_ALLOCATE_BUFFER: 32062306a36Sopenharmony_ci /* 32162306a36Sopenharmony_ci * Allocate a new buffer. We directectly call acpi_os_allocate here to 32262306a36Sopenharmony_ci * purposefully bypass the (optionally enabled) internal allocation 32362306a36Sopenharmony_ci * tracking mechanism since we only want to track internal 32462306a36Sopenharmony_ci * allocations. Note: The caller should use acpi_os_free to free this 32562306a36Sopenharmony_ci * buffer created via ACPI_ALLOCATE_BUFFER. 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_ci buffer->pointer = acpi_os_allocate(required_length); 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci case ACPI_ALLOCATE_LOCAL_BUFFER: 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* Allocate a new buffer with local interface to allow tracking */ 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci buffer->pointer = ACPI_ALLOCATE(required_length); 33562306a36Sopenharmony_ci break; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci default: 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* Existing buffer: Validate the size of the buffer */ 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (input_buffer_length < required_length) { 34262306a36Sopenharmony_ci return (AE_BUFFER_OVERFLOW); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci break; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* Validate allocation from above or input buffer pointer */ 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (!buffer->pointer) { 35062306a36Sopenharmony_ci return (AE_NO_MEMORY); 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* Have a valid buffer, clear it */ 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci memset(buffer->pointer, 0, required_length); 35662306a36Sopenharmony_ci return (AE_OK); 35762306a36Sopenharmony_ci} 358