cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

uttrack.c (19017B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/******************************************************************************
      3 *
      4 * Module Name: uttrack - Memory allocation tracking routines (debug only)
      5 *
      6 * Copyright (C) 2000 - 2022, Intel Corp.
      7 *
      8 *****************************************************************************/
      9
     10/*
     11 * These procedures are used for tracking memory leaks in the subsystem, and
     12 * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set.
     13 *
     14 * Each memory allocation is tracked via a doubly linked list. Each
     15 * element contains the caller's component, module name, function name, and
     16 * line number. acpi_ut_allocate and acpi_ut_allocate_zeroed call
     17 * acpi_ut_track_allocation to add an element to the list; deletion
     18 * occurs in the body of acpi_ut_free.
     19 */
     20
     21#include <acpi/acpi.h>
     22#include "accommon.h"
     23
     24#ifdef ACPI_DBG_TRACK_ALLOCATIONS
     25
     26#define _COMPONENT          ACPI_UTILITIES
     27ACPI_MODULE_NAME("uttrack")
     28
     29/* Local prototypes */
     30static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct
     31							    acpi_debug_mem_block
     32							    *allocation);
     33
     34static acpi_status
     35acpi_ut_track_allocation(struct acpi_debug_mem_block *address,
     36			 acpi_size size,
     37			 u8 alloc_type,
     38			 u32 component, const char *module, u32 line);
     39
     40static acpi_status
     41acpi_ut_remove_allocation(struct acpi_debug_mem_block *address,
     42			  u32 component, const char *module, u32 line);
     43
     44/*******************************************************************************
     45 *
     46 * FUNCTION:    acpi_ut_create_list
     47 *
     48 * PARAMETERS:  cache_name      - Ascii name for the cache
     49 *              object_size     - Size of each cached object
     50 *              return_cache    - Where the new cache object is returned
     51 *
     52 * RETURN:      Status
     53 *
     54 * DESCRIPTION: Create a local memory list for tracking purposed
     55 *
     56 ******************************************************************************/
     57
     58acpi_status
     59acpi_ut_create_list(const char *list_name,
     60		    u16 object_size, struct acpi_memory_list **return_cache)
     61{
     62	struct acpi_memory_list *cache;
     63
     64	cache = acpi_os_allocate_zeroed(sizeof(struct acpi_memory_list));
     65	if (!cache) {
     66		return (AE_NO_MEMORY);
     67	}
     68
     69	cache->list_name = list_name;
     70	cache->object_size = object_size;
     71
     72	*return_cache = cache;
     73	return (AE_OK);
     74}
     75
     76/*******************************************************************************
     77 *
     78 * FUNCTION:    acpi_ut_allocate_and_track
     79 *
     80 * PARAMETERS:  size                - Size of the allocation
     81 *              component           - Component type of caller
     82 *              module              - Source file name of caller
     83 *              line                - Line number of caller
     84 *
     85 * RETURN:      Address of the allocated memory on success, NULL on failure.
     86 *
     87 * DESCRIPTION: The subsystem's equivalent of malloc.
     88 *
     89 ******************************************************************************/
     90
     91void *acpi_ut_allocate_and_track(acpi_size size,
     92				 u32 component, const char *module, u32 line)
     93{
     94	struct acpi_debug_mem_block *allocation;
     95	acpi_status status;
     96
     97	/* Check for an inadvertent size of zero bytes */
     98
     99	if (!size) {
    100		ACPI_WARNING((module, line,
    101			      "Attempt to allocate zero bytes, allocating 1 byte"));
    102		size = 1;
    103	}
    104
    105	allocation =
    106	    acpi_os_allocate(size + sizeof(struct acpi_debug_mem_header));
    107	if (!allocation) {
    108
    109		/* Report allocation error */
    110
    111		ACPI_WARNING((module, line,
    112			      "Could not allocate size %u", (u32)size));
    113
    114		return (NULL);
    115	}
    116
    117	status =
    118	    acpi_ut_track_allocation(allocation, size, ACPI_MEM_MALLOC,
    119				     component, module, line);
    120	if (ACPI_FAILURE(status)) {
    121		acpi_os_free(allocation);
    122		return (NULL);
    123	}
    124
    125	acpi_gbl_global_list->total_allocated++;
    126	acpi_gbl_global_list->total_size += (u32)size;
    127	acpi_gbl_global_list->current_total_size += (u32)size;
    128
    129	if (acpi_gbl_global_list->current_total_size >
    130	    acpi_gbl_global_list->max_occupied) {
    131		acpi_gbl_global_list->max_occupied =
    132		    acpi_gbl_global_list->current_total_size;
    133	}
    134
    135	return ((void *)&allocation->user_space);
    136}
    137
    138/*******************************************************************************
    139 *
    140 * FUNCTION:    acpi_ut_allocate_zeroed_and_track
    141 *
    142 * PARAMETERS:  size                - Size of the allocation
    143 *              component           - Component type of caller
    144 *              module              - Source file name of caller
    145 *              line                - Line number of caller
    146 *
    147 * RETURN:      Address of the allocated memory on success, NULL on failure.
    148 *
    149 * DESCRIPTION: Subsystem equivalent of calloc.
    150 *
    151 ******************************************************************************/
    152
    153void *acpi_ut_allocate_zeroed_and_track(acpi_size size,
    154					u32 component,
    155					const char *module, u32 line)
    156{
    157	struct acpi_debug_mem_block *allocation;
    158	acpi_status status;
    159
    160	/* Check for an inadvertent size of zero bytes */
    161
    162	if (!size) {
    163		ACPI_WARNING((module, line,
    164			      "Attempt to allocate zero bytes, allocating 1 byte"));
    165		size = 1;
    166	}
    167
    168	allocation =
    169	    acpi_os_allocate_zeroed(size +
    170				    sizeof(struct acpi_debug_mem_header));
    171	if (!allocation) {
    172
    173		/* Report allocation error */
    174
    175		ACPI_ERROR((module, line,
    176			    "Could not allocate size %u", (u32)size));
    177		return (NULL);
    178	}
    179
    180	status = acpi_ut_track_allocation(allocation, size,
    181					  ACPI_MEM_CALLOC, component, module,
    182					  line);
    183	if (ACPI_FAILURE(status)) {
    184		acpi_os_free(allocation);
    185		return (NULL);
    186	}
    187
    188	acpi_gbl_global_list->total_allocated++;
    189	acpi_gbl_global_list->total_size += (u32)size;
    190	acpi_gbl_global_list->current_total_size += (u32)size;
    191
    192	if (acpi_gbl_global_list->current_total_size >
    193	    acpi_gbl_global_list->max_occupied) {
    194		acpi_gbl_global_list->max_occupied =
    195		    acpi_gbl_global_list->current_total_size;
    196	}
    197
    198	return ((void *)&allocation->user_space);
    199}
    200
    201/*******************************************************************************
    202 *
    203 * FUNCTION:    acpi_ut_free_and_track
    204 *
    205 * PARAMETERS:  allocation          - Address of the memory to deallocate
    206 *              component           - Component type of caller
    207 *              module              - Source file name of caller
    208 *              line                - Line number of caller
    209 *
    210 * RETURN:      None
    211 *
    212 * DESCRIPTION: Frees the memory at Allocation
    213 *
    214 ******************************************************************************/
    215
    216void
    217acpi_ut_free_and_track(void *allocation,
    218		       u32 component, const char *module, u32 line)
    219{
    220	struct acpi_debug_mem_block *debug_block;
    221	acpi_status status;
    222
    223	ACPI_FUNCTION_TRACE_PTR(ut_free, allocation);
    224
    225	if (NULL == allocation) {
    226		ACPI_ERROR((module, line, "Attempt to delete a NULL address"));
    227
    228		return_VOID;
    229	}
    230
    231	debug_block = ACPI_CAST_PTR(struct acpi_debug_mem_block,
    232				    (((char *)allocation) -
    233				     sizeof(struct acpi_debug_mem_header)));
    234
    235	acpi_gbl_global_list->total_freed++;
    236	acpi_gbl_global_list->current_total_size -= debug_block->size;
    237
    238	status =
    239	    acpi_ut_remove_allocation(debug_block, component, module, line);
    240	if (ACPI_FAILURE(status)) {
    241		ACPI_EXCEPTION((AE_INFO, status, "Could not free memory"));
    242	}
    243
    244	acpi_os_free(debug_block);
    245	ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed (block %p)\n",
    246			  allocation, debug_block));
    247	return_VOID;
    248}
    249
    250/*******************************************************************************
    251 *
    252 * FUNCTION:    acpi_ut_find_allocation
    253 *
    254 * PARAMETERS:  allocation              - Address of allocated memory
    255 *
    256 * RETURN:      Three cases:
    257 *              1) List is empty, NULL is returned.
    258 *              2) Element was found. Returns Allocation parameter.
    259 *              3) Element was not found. Returns position where it should be
    260 *                  inserted into the list.
    261 *
    262 * DESCRIPTION: Searches for an element in the global allocation tracking list.
    263 *              If the element is not found, returns the location within the
    264 *              list where the element should be inserted.
    265 *
    266 *              Note: The list is ordered by larger-to-smaller addresses.
    267 *
    268 *              This global list is used to detect memory leaks in ACPICA as
    269 *              well as other issues such as an attempt to release the same
    270 *              internal object more than once. Although expensive as far
    271 *              as cpu time, this list is much more helpful for finding these
    272 *              types of issues than using memory leak detectors outside of
    273 *              the ACPICA code.
    274 *
    275 ******************************************************************************/
    276
    277static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct
    278							    acpi_debug_mem_block
    279							    *allocation)
    280{
    281	struct acpi_debug_mem_block *element;
    282
    283	element = acpi_gbl_global_list->list_head;
    284	if (!element) {
    285		return (NULL);
    286	}
    287
    288	/*
    289	 * Search for the address.
    290	 *
    291	 * Note: List is ordered by larger-to-smaller addresses, on the
    292	 * assumption that a new allocation usually has a larger address
    293	 * than previous allocations.
    294	 */
    295	while (element > allocation) {
    296
    297		/* Check for end-of-list */
    298
    299		if (!element->next) {
    300			return (element);
    301		}
    302
    303		element = element->next;
    304	}
    305
    306	if (element == allocation) {
    307		return (element);
    308	}
    309
    310	return (element->previous);
    311}
    312
    313/*******************************************************************************
    314 *
    315 * FUNCTION:    acpi_ut_track_allocation
    316 *
    317 * PARAMETERS:  allocation          - Address of allocated memory
    318 *              size                - Size of the allocation
    319 *              alloc_type          - MEM_MALLOC or MEM_CALLOC
    320 *              component           - Component type of caller
    321 *              module              - Source file name of caller
    322 *              line                - Line number of caller
    323 *
    324 * RETURN:      Status
    325 *
    326 * DESCRIPTION: Inserts an element into the global allocation tracking list.
    327 *
    328 ******************************************************************************/
    329
    330static acpi_status
    331acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation,
    332			 acpi_size size,
    333			 u8 alloc_type,
    334			 u32 component, const char *module, u32 line)
    335{
    336	struct acpi_memory_list *mem_list;
    337	struct acpi_debug_mem_block *element;
    338	acpi_status status = AE_OK;
    339
    340	ACPI_FUNCTION_TRACE_PTR(ut_track_allocation, allocation);
    341
    342	if (acpi_gbl_disable_mem_tracking) {
    343		return_ACPI_STATUS(AE_OK);
    344	}
    345
    346	mem_list = acpi_gbl_global_list;
    347	status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY);
    348	if (ACPI_FAILURE(status)) {
    349		return_ACPI_STATUS(status);
    350	}
    351
    352	/*
    353	 * Search the global list for this address to make sure it is not
    354	 * already present. This will catch several kinds of problems.
    355	 */
    356	element = acpi_ut_find_allocation(allocation);
    357	if (element == allocation) {
    358		ACPI_ERROR((AE_INFO,
    359			    "UtTrackAllocation: Allocation (%p) already present in global list!",
    360			    allocation));
    361		goto unlock_and_exit;
    362	}
    363
    364	/* Fill in the instance data */
    365
    366	allocation->size = (u32)size;
    367	allocation->alloc_type = alloc_type;
    368	allocation->component = component;
    369	allocation->line = line;
    370
    371	acpi_ut_safe_strncpy(allocation->module, (char *)module,
    372			     ACPI_MAX_MODULE_NAME);
    373
    374	if (!element) {
    375
    376		/* Insert at list head */
    377
    378		if (mem_list->list_head) {
    379			((struct acpi_debug_mem_block *)(mem_list->list_head))->
    380			    previous = allocation;
    381		}
    382
    383		allocation->next = mem_list->list_head;
    384		allocation->previous = NULL;
    385
    386		mem_list->list_head = allocation;
    387	} else {
    388		/* Insert after element */
    389
    390		allocation->next = element->next;
    391		allocation->previous = element;
    392
    393		if (element->next) {
    394			(element->next)->previous = allocation;
    395		}
    396
    397		element->next = allocation;
    398	}
    399
    400unlock_and_exit:
    401	status = acpi_ut_release_mutex(ACPI_MTX_MEMORY);
    402	return_ACPI_STATUS(status);
    403}
    404
    405/*******************************************************************************
    406 *
    407 * FUNCTION:    acpi_ut_remove_allocation
    408 *
    409 * PARAMETERS:  allocation          - Address of allocated memory
    410 *              component           - Component type of caller
    411 *              module              - Source file name of caller
    412 *              line                - Line number of caller
    413 *
    414 * RETURN:      Status
    415 *
    416 * DESCRIPTION: Deletes an element from the global allocation tracking list.
    417 *
    418 ******************************************************************************/
    419
    420static acpi_status
    421acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation,
    422			  u32 component, const char *module, u32 line)
    423{
    424	struct acpi_memory_list *mem_list;
    425	acpi_status status;
    426
    427	ACPI_FUNCTION_NAME(ut_remove_allocation);
    428
    429	if (acpi_gbl_disable_mem_tracking) {
    430		return (AE_OK);
    431	}
    432
    433	mem_list = acpi_gbl_global_list;
    434	if (NULL == mem_list->list_head) {
    435
    436		/* No allocations! */
    437
    438		ACPI_ERROR((module, line,
    439			    "Empty allocation list, nothing to free!"));
    440
    441		return (AE_OK);
    442	}
    443
    444	status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY);
    445	if (ACPI_FAILURE(status)) {
    446		return (status);
    447	}
    448
    449	/* Unlink */
    450
    451	if (allocation->previous) {
    452		(allocation->previous)->next = allocation->next;
    453	} else {
    454		mem_list->list_head = allocation->next;
    455	}
    456
    457	if (allocation->next) {
    458		(allocation->next)->previous = allocation->previous;
    459	}
    460
    461	ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Freeing %p, size 0%X\n",
    462			  &allocation->user_space, allocation->size));
    463
    464	/* Mark the segment as deleted */
    465
    466	memset(&allocation->user_space, 0xEA, allocation->size);
    467
    468	status = acpi_ut_release_mutex(ACPI_MTX_MEMORY);
    469	return (status);
    470}
    471
    472/*******************************************************************************
    473 *
    474 * FUNCTION:    acpi_ut_dump_allocation_info
    475 *
    476 * PARAMETERS:  None
    477 *
    478 * RETURN:      None
    479 *
    480 * DESCRIPTION: Print some info about the outstanding allocations.
    481 *
    482 ******************************************************************************/
    483
    484void acpi_ut_dump_allocation_info(void)
    485{
    486/*
    487	struct acpi_memory_list         *mem_list;
    488*/
    489
    490	ACPI_FUNCTION_TRACE(ut_dump_allocation_info);
    491
    492/*
    493	ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
    494		("%30s: %4d (%3d Kb)\n", "Current allocations",
    495		mem_list->current_count,
    496		ROUND_UP_TO_1K (mem_list->current_size)));
    497
    498	ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
    499		("%30s: %4d (%3d Kb)\n", "Max concurrent allocations",
    500		mem_list->max_concurrent_count,
    501		ROUND_UP_TO_1K (mem_list->max_concurrent_size)));
    502
    503	ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
    504		("%30s: %4d (%3d Kb)\n", "Total (all) internal objects",
    505		running_object_count,
    506		ROUND_UP_TO_1K (running_object_size)));
    507
    508	ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
    509		("%30s: %4d (%3d Kb)\n", "Total (all) allocations",
    510		running_alloc_count,
    511		ROUND_UP_TO_1K (running_alloc_size)));
    512
    513	ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
    514		("%30s: %4d (%3d Kb)\n", "Current Nodes",
    515		acpi_gbl_current_node_count,
    516		ROUND_UP_TO_1K (acpi_gbl_current_node_size)));
    517
    518	ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
    519		("%30s: %4d (%3d Kb)\n", "Max Nodes",
    520		acpi_gbl_max_concurrent_node_count,
    521		ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count *
    522			sizeof (struct acpi_namespace_node)))));
    523*/
    524	return_VOID;
    525}
    526
    527/*******************************************************************************
    528 *
    529 * FUNCTION:    acpi_ut_dump_allocations
    530 *
    531 * PARAMETERS:  component           - Component(s) to dump info for.
    532 *              module              - Module to dump info for. NULL means all.
    533 *
    534 * RETURN:      None
    535 *
    536 * DESCRIPTION: Print a list of all outstanding allocations.
    537 *
    538 ******************************************************************************/
    539
    540void acpi_ut_dump_allocations(u32 component, const char *module)
    541{
    542	struct acpi_debug_mem_block *element;
    543	union acpi_descriptor *descriptor;
    544	u32 num_outstanding = 0;
    545	u8 descriptor_type;
    546
    547	ACPI_FUNCTION_TRACE(ut_dump_allocations);
    548
    549	if (acpi_gbl_disable_mem_tracking) {
    550		return_VOID;
    551	}
    552
    553	/*
    554	 * Walk the allocation list.
    555	 */
    556	if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_MEMORY))) {
    557		return_VOID;
    558	}
    559
    560	if (!acpi_gbl_global_list) {
    561		goto exit;
    562	}
    563
    564	element = acpi_gbl_global_list->list_head;
    565	while (element) {
    566		if ((element->component & component) &&
    567		    ((module == NULL)
    568		     || (0 == strcmp(module, element->module)))) {
    569			descriptor =
    570			    ACPI_CAST_PTR(union acpi_descriptor,
    571					  &element->user_space);
    572
    573			if (element->size <
    574			    sizeof(struct acpi_common_descriptor)) {
    575				acpi_os_printf("%p Length 0x%04X %9.9s-%4.4u "
    576					       "[Not a Descriptor - too small]\n",
    577					       descriptor, element->size,
    578					       element->module, element->line);
    579			} else {
    580				/* Ignore allocated objects that are in a cache */
    581
    582				if (ACPI_GET_DESCRIPTOR_TYPE(descriptor) !=
    583				    ACPI_DESC_TYPE_CACHED) {
    584					acpi_os_printf
    585					    ("%p Length 0x%04X %9.9s-%4.4u [%s] ",
    586					     descriptor, element->size,
    587					     element->module, element->line,
    588					     acpi_ut_get_descriptor_name
    589					     (descriptor));
    590
    591					/* Optional object hex dump */
    592
    593					if (acpi_gbl_verbose_leak_dump) {
    594						acpi_os_printf("\n");
    595						acpi_ut_dump_buffer((u8 *)
    596								    descriptor,
    597								    element->
    598								    size,
    599								    DB_BYTE_DISPLAY,
    600								    0);
    601					}
    602
    603					/* Validate the descriptor type using Type field and length */
    604
    605					descriptor_type = 0;	/* Not a valid descriptor type */
    606
    607					switch (ACPI_GET_DESCRIPTOR_TYPE
    608						(descriptor)) {
    609					case ACPI_DESC_TYPE_OPERAND:
    610
    611						if (element->size ==
    612						    sizeof(union
    613							   acpi_operand_object))
    614						{
    615							descriptor_type =
    616							    ACPI_DESC_TYPE_OPERAND;
    617						}
    618						break;
    619
    620					case ACPI_DESC_TYPE_PARSER:
    621
    622						if (element->size ==
    623						    sizeof(union
    624							   acpi_parse_object)) {
    625							descriptor_type =
    626							    ACPI_DESC_TYPE_PARSER;
    627						}
    628						break;
    629
    630					case ACPI_DESC_TYPE_NAMED:
    631
    632						if (element->size ==
    633						    sizeof(struct
    634							   acpi_namespace_node))
    635						{
    636							descriptor_type =
    637							    ACPI_DESC_TYPE_NAMED;
    638						}
    639						break;
    640
    641					default:
    642
    643						break;
    644					}
    645
    646					/* Display additional info for the major descriptor types */
    647
    648					switch (descriptor_type) {
    649					case ACPI_DESC_TYPE_OPERAND:
    650
    651						acpi_os_printf
    652						    ("%12.12s RefCount 0x%04X\n",
    653						     acpi_ut_get_type_name
    654						     (descriptor->object.common.
    655						      type),
    656						     descriptor->object.common.
    657						     reference_count);
    658						break;
    659
    660					case ACPI_DESC_TYPE_PARSER:
    661
    662						acpi_os_printf
    663						    ("AmlOpcode 0x%04X\n",
    664						     descriptor->op.asl.
    665						     aml_opcode);
    666						break;
    667
    668					case ACPI_DESC_TYPE_NAMED:
    669
    670						acpi_os_printf("%4.4s\n",
    671							       acpi_ut_get_node_name
    672							       (&descriptor->
    673								node));
    674						break;
    675
    676					default:
    677
    678						acpi_os_printf("\n");
    679						break;
    680					}
    681				}
    682			}
    683
    684			num_outstanding++;
    685		}
    686
    687		element = element->next;
    688	}
    689
    690exit:
    691	(void)acpi_ut_release_mutex(ACPI_MTX_MEMORY);
    692
    693	/* Print summary */
    694
    695	if (!num_outstanding) {
    696		ACPI_INFO(("No outstanding allocations"));
    697	} else {
    698		ACPI_ERROR((AE_INFO, "%u (0x%X) Outstanding cache allocations",
    699			    num_outstanding, num_outstanding));
    700	}
    701
    702	return_VOID;
    703}
    704
    705#endif				/* ACPI_DBG_TRACK_ALLOCATIONS */