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