// SPDX-License-Identifier: GPL-2.0+ #pragma GCC push_options #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wsign-compare" #include #include #include #include #pragma GCC pop_options #include #include #include #include "debug.h" /* #define CHECK_ALLOC */ #if defined(CHECK_ALLOC) #define MALLOC_KENNUNG_START 0x56785AA5 #define MALLOC_KENNUNG_END 0x1234A55A #endif /*--- #if defined(CHECK_ALLOC) ---*/ #if defined(CHECK_ALLOC) static atomic_t alloc_value; static atomic_t alloc_open; static atomic_t alloc_open_max; #define N_ALLOC_REFS 1024 static void *alloc_refs[N_ALLOC_REFS]; /** */ void alloc_ref_add(void *ref) { unsigned int n = 0; static unsigned int i; if (ref == NULL) { DEB_ERR("{%s} error: invalid pointer\n", __func__); return; } atomic_inc(&alloc_open); if (atomic_read(&alloc_open) > atomic_read(&alloc_open_max)) atomic_inc(&alloc_open_max); while (n < N_ALLOC_REFS) { EnterCritical(); if (alloc_refs[i] == NULL) { /* DEB_TRACE("{%s} 0x%p (%u)\n", __func__, ref, i); */ alloc_refs[i] = ref; LeaveCritical(); i++; return; } LeaveCritical(); n++; if (++i >= N_ALLOC_REFS) i = 0; } DEB_ERR("{%s} error: no resource ...\n", __func__); } /** */ void alloc_ref_del(void *ref) { int i = 0; if (ref == NULL) { DEB_ERR("{%s} error: invalid pointer\n", __func__); return; } if (atomic_read(&alloc_open) == 0) { DEB_ERR("{%s} error: invalid action\n", __func__); return; } atomic_dec(&alloc_open); i = 0; while (i < N_ALLOC_REFS) { EnterCritical(); if (alloc_refs[i] == ref) { alloc_refs[i] = NULL; /* DEB_TRACE( "{%s} 0x%p (%u)\n", __func__, ref, i ); */ LeaveCritical(); return; } LeaveCritical(); i++; } DEB_ERR("{%s} error: not in list 0x%p (%s:%d)\n", __func__, ref, (char *)((unsigned int *)ref)[2], (unsigned int)((unsigned int *)ref)[3]); } /** */ void alloc_ref_print(void) { int i = 0; while (i < N_ALLOC_REFS) { if (alloc_refs[i] != NULL) { DEB_ERR("{%s} still allocated 0x%p (%s:%d)\n", __func__, alloc_refs[i], (char *)((unsigned int *)alloc_refs[i])[2], (unsigned int)((unsigned int *)alloc_refs[i])[3]); } i++; } } #endif /* defined( CHECK_ALLOC ) */ /** */ void *_CA_MALLOC(unsigned int size, char *File __attribute__((unused)), unsigned int Line __attribute__((unused))) { void *rtn; #if defined(CHECK_ALLOC) rtn = kmalloc(size + 5 * sizeof(unsigned int), GFP_ATOMIC); if (rtn) { size += 3; size &= ~0x03; ((unsigned int *)rtn)[0] = size; ((unsigned int *)rtn)[1] = MALLOC_KENNUNG_START; ((unsigned int *)rtn)[2] = (unsigned int)File; ((unsigned int *)rtn)[3] = Line; ((unsigned int *)rtn)[(size >> 2) + 4] = MALLOC_KENNUNG_END; alloc_ref_add(rtn); rtn = (void *)((unsigned int *)rtn + 4); } /*--- DEB_TRACE("%s: %u bytes ptr=%x (%s, %d)\n", __func__, size, (unsigned int)rtn, File, Line); ---*/ if (rtn) memset(rtn, 0, size); atomic_add((signed int)size, &alloc_value); #else /* defined(CHECK_ALLOC) */ rtn = kmalloc(size, GFP_ATOMIC); if (rtn != NULL) { memset(rtn, 0, size); } else { DEB_WARN("[%s] calloc %u bytes failed\n", __func__, size); } #endif /* defined(CHECK_ALLOC) */ return rtn; } EXPORT_SYMBOL(_CA_MALLOC); /** */ void _CA_FREE(void *p, char *File __attribute__((unused)), unsigned int Line __attribute__((unused))) { #if defined(CHECK_ALLOC) unsigned int size = 0; if (p) { unsigned int Start; unsigned int Ende; char *a_File; unsigned int a_Line; p = (void *)((unsigned int *)p - 4); size = ((unsigned int *)p)[0]; Start = ((unsigned int *)p)[1]; a_File = (char *)(((unsigned int *)p)[2]); a_Line = ((unsigned int *)p)[3]; Ende = ((unsigned int *)p)[(size >> 2) + 4]; ((unsigned int *)p)[1] = 0; /*--- kennzeichen zurücksetzen ---*/ ((unsigned int *)p)[(size >> 2) + 4] = 0; /*--- kennzeichen zurücksetzen ---*/ atomic_sub((signed int)size, &alloc_value); alloc_ref_del(p); if (Start != MALLOC_KENNUNG_START || Ende != MALLOC_KENNUNG_END) { DEB_ERR("%s: StartKennung=%s EndeKennung=%s Size=%u (%s, %u) (alloc: %s, %u)\n", __func__, Start == MALLOC_KENNUNG_START ? "ok" : "error", Ende == MALLOC_KENNUNG_END ? "ok" : "error", size, File, Line, a_File, a_Line); return; } } #endif /* defined(CHECK_ALLOC) */ /*--- DEB_TRACE("CA_FREE: %u bytes %x (%s, %d)\n", size, (unsigned int)p, File, Line); ---*/ kfree(p); } EXPORT_SYMBOL(_CA_FREE); /** */ void *CA_MALLOC(unsigned int size) { void *rtn; rtn = kmalloc(size, GFP_ATOMIC); if (rtn != NULL) { memset(rtn, 0, size); } else { DEB_WARN("[%s] calloc %u bytes failed\n", __func__, size); } return rtn; } EXPORT_SYMBOL(CA_MALLOC); /** */ void CA_FREE(void *p) { kfree(p); } EXPORT_SYMBOL(CA_FREE); /** */ void CA_MEM_SHOW(void) { #if defined(CHECK_ALLOC) DEB_WARN("{%s} memory in use: %u bytes (%u allocations, %u max. allocations)\n", __func__, atomic_read(&alloc_value), atomic_read(&alloc_open), atomic_read(&alloc_open_max)); #endif } EXPORT_SYMBOL(CA_MEM_SHOW); /** */ void CA_MEM_EXIT(void) { #if defined(CHECK_ALLOC) DEB_WARN("{%s} %u bytes still allocated (%u allocations, %u max allocations)\n", __func__, atomic_read(&alloc_value), atomic_read(&alloc_open), atomic_read(&alloc_open_max)); alloc_ref_print(); #endif } EXPORT_SYMBOL(CA_MEM_EXIT);