• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Winner Microelectronics Co., Ltd. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 /*****************************************************************************
17 *
18 * File Name : wm_mem.c
19 *
20 * Description: memory manager Module
21 *
22 * Copyright (c) 2014 Winner Micro Electronic Design Co., Ltd.
23 * All rights reserved.
24 *
25 * Author : dave
26 *
27 * Date : 2014-6-12
28 *****************************************************************************/
29 
30 #include <string.h>
31 #include "wm_osal.h"
32 #include "list.h"
33 #include "wm_mem.h"
34 #if TLS_OS_LITEOS
35 #include "los_memory.h"
36 #endif
37 extern u8 tls_get_isr_count(void);
38 /**
39  * This variable is set if the memory mananger has been initialized.
40  * This is available only for debug version of the driver
41  */
42 bool         memory_manager_initialized = false;
43 /**
44  * This mutex is used to synchronize the list of allocated
45  * memory blocks. This is a debug version only feature
46  */
47 tls_os_sem_t    *mem_sem;
48 #if WM_MEM_DEBUG
49 
50 struct dl_list memory_used_list;
51 struct dl_list memory_free_list;
52 #define MEM_BLOCK_SIZE           800
53 MEMORY_BLOCK mem_blocks[MEM_BLOCK_SIZE];
54 
55 u32 alloc_heap_mem_bytes = 0;
56 u32 alloc_heap_mem_blk_cnt = 0;
57 u32 alloc_heap_mem_max_size = 0;
58 
59 #define PRE_OVERSIZE        0
60 #define OVERSIZE        0
61 
62 /**
63  * This is a debug only function that performs memory management operations for us.
64  * Memory allocated using this function is tracked, flagged when leaked, and caught for
65  * overflows and underflows.
66  *
67  * \param size            The size in bytes of memory to
68  *        allocate
69  *
70  * \param file            The full path of file where this
71  *        function is invoked from
72  * \param line            The line number in the file where this
73  *        method was called from
74  * \return Pointer to the allocated memory or NULL in case of a failure
75  */
mem_alloc_debug(u32 size,char * file,int line)76 void *mem_alloc_debug(u32 size, char* file, int line)
77 {
78     void *buf = NULL;
79     u32 pad_len;
80     u32  cpu_sr;
81     //
82     // If the memory manager has not been initialized, do so now
83     //
84     cpu_sr = tls_os_set_critical();
85     if (!memory_manager_initialized) {
86         tls_os_status_t os_status;
87         memory_manager_initialized = true;
88         //
89         // NOTE: If two thread allocate the very first allocation simultaneously
90         // it could cause double initialization of the memory manager. This is a
91         // highly unlikely scenario and will occur in debug versions only.
92         //
93         os_status = tls_os_sem_create(&mem_sem, 1);
94         if (os_status != TLS_OS_SUCCESS)
95             printf("mem_alloc_debug: tls_os_sem_create mem_sem error\r\n");
96         dl_list_init(&memory_used_list);
97         dl_list_init(&memory_free_list);
98         for (int i = 0; i < MEM_BLOCK_SIZE; i++) {
99             dl_list_add_tail(&memory_free_list, &mem_blocks[i].list);
100         }
101     }
102     tls_os_release_critical(cpu_sr);
103 
104     tls_os_sem_acquire(mem_sem, 0);
105     cpu_sr = tls_os_set_critical();
106     //
107     // Allocate the required memory chunk plus header and trailer bytes
108     //
109     pad_len = sizeof(u32) - (size & 0x3);
110     buf = malloc(sizeof(MEMORY_PATTERN) + PRE_OVERSIZE + size + pad_len + OVERSIZE + sizeof(MEMORY_PATTERN));
111     if (buf) {
112         //
113         // Memory allocation succeeded. Add information about the allocated
114         // block in the list that tracks all allocations.
115         //
116         PMEMORY_PATTERN  mem_ptn_hd;
117         PMEMORY_PATTERN  mem_ptn_tl;
118         PMEMORY_BLOCK  mem_blk_hd1;
119 
120         if (dl_list_empty(&memory_free_list)) {
121             printf("Memory blocks empty!\r\n");
122                 free(buf);
123                 tls_os_release_critical(cpu_sr);
124                 tls_os_sem_release(mem_sem);
125             tls_mem_alloc_info();
126                 return NULL;
127         }
128         mem_blk_hd1 = dl_list_first(&memory_free_list, MEMORY_BLOCK, list);
129         dl_list_del(&mem_blk_hd1->list);
130         dl_list_add_tail(&memory_used_list, &mem_blk_hd1->list);
131             alloc_heap_mem_bytes += size+sizeof(MEMORY_PATTERN) + sizeof(MEMORY_PATTERN) + pad_len +\
132                 PRE_OVERSIZE + OVERSIZE;
133             alloc_heap_mem_blk_cnt++;
134             if (alloc_heap_mem_bytes > alloc_heap_mem_max_size) {
135                 alloc_heap_mem_max_size = alloc_heap_mem_bytes;
136             }
137 
138             mem_blk_hd1->pad = pad_len;
139             mem_blk_hd1->file = file;
140             mem_blk_hd1->line = line;
141             mem_blk_hd1->length = size;
142             mem_blk_hd1->header_pattern = (u32)buf;
143 
144             // Fill in the memory header and trailer
145             mem_ptn_hd = (PMEMORY_PATTERN)buf;
146             mem_ptn_hd->pattern0= MEM_HEADER_PATTERN;
147 
148             mem_ptn_tl = (PMEMORY_PATTERN)(((u8 *)(buf))+size + sizeof(MEMORY_PATTERN)+pad_len + \
149                 PRE_OVERSIZE + OVERSIZE);
150             mem_ptn_tl->pattern0= MEM_TAILER_PATTERN;
151 
152             // Jump ahead by memory header so pointer returned to caller points at the right place
153             buf = ((u8 *)buf) + sizeof (MEMORY_PATTERN) + PRE_OVERSIZE;
154     } else {
155         printf("==>Memory was allocated from %s at line %d with length %d, allocated size %d, count %d\r\n",
156                file,
157                line,
158                size, alloc_heap_mem_bytes, alloc_heap_mem_blk_cnt);
159         tls_os_release_critical(cpu_sr);
160     tls_os_sem_release(mem_sem);
161     tls_mem_alloc_info();
162     return buf;
163     }
164     tls_os_release_critical(cpu_sr);
165     tls_os_sem_release(mem_sem);
166     return buf;
167 }
168 
mem_calloc_debug(u32 n,u32 size,char * file,int line)169 void *mem_calloc_debug(u32 n, u32 size, char* file, int line)
170 {
171     void *buf = NULL;
172     u32 pad_len;
173     u32  cpu_sr;
174     //
175     // If the memory manager has not been initialized, do so now
176     //
177     cpu_sr = tls_os_set_critical();
178     if (!memory_manager_initialized) {
179         tls_os_status_t os_status;
180         memory_manager_initialized = true;
181         //
182         // NOTE: If two thread allocate the very first allocation simultaneously
183         // it could cause double initialization of the memory manager. This is a
184         // highly unlikely scenario and will occur in debug versions only.
185         //
186         os_status = tls_os_sem_create(&mem_sem, 1);
187         if (os_status != TLS_OS_SUCCESS)
188             printf("mem_alloc_debug: tls_os_sem_create mem_sem error\r\n");
189         dl_list_init(&memory_used_list);
190         dl_list_init(&memory_free_list);
191         for (int i = 0; i < MEM_BLOCK_SIZE; i++) {
192             dl_list_add_tail(&memory_free_list, &mem_blocks[i].list);
193         }
194     }
195     tls_os_release_critical(cpu_sr);
196 
197     tls_os_sem_acquire(mem_sem, 0);
198     cpu_sr = tls_os_set_critical();
199     //
200     // Allocate the required memory chunk plus header and trailer bytes
201     //
202     pad_len = sizeof(u32) - ((n*size) & 0x3);
203     buf = malloc(sizeof(MEMORY_PATTERN) + PRE_OVERSIZE + n*size + pad_len + OVERSIZE + sizeof(MEMORY_PATTERN));
204     if (buf) {
205         //
206         // Memory allocation succeeded. Add information about the allocated
207         // block in the list that tracks all allocations.
208         //
209         PMEMORY_PATTERN  mem_ptn_hd;
210         PMEMORY_PATTERN  mem_ptn_tl;
211         PMEMORY_BLOCK  mem_blk_hd1;
212 
213     if (dl_list_empty(&memory_free_list)) {
214     printf("Memory blocks empty!\r\n");
215     free(buf);
216     tls_os_release_critical(cpu_sr);
217     tls_os_sem_release(mem_sem);
218     tls_mem_alloc_info();
219     return NULL;
220     }
221         mem_blk_hd1 = dl_list_first(&memory_free_list, MEMORY_BLOCK, list);
222         dl_list_del(&mem_blk_hd1->list);
223         dl_list_add_tail(&memory_used_list, &mem_blk_hd1->list);
224         alloc_heap_mem_bytes += n*size+sizeof(MEMORY_PATTERN)+sizeof(MEMORY_PATTERN)+pad_len + PRE_OVERSIZE + OVERSIZE;
225         alloc_heap_mem_blk_cnt++;
226         if (alloc_heap_mem_bytes > alloc_heap_mem_max_size) {
227             alloc_heap_mem_max_size = alloc_heap_mem_bytes;
228         }
229 
230         mem_blk_hd1->pad = pad_len;
231         mem_blk_hd1->file = file;
232         mem_blk_hd1->line = line;
233         mem_blk_hd1->length = n*size;
234         mem_blk_hd1->header_pattern = (u32)buf;
235 
236         // Fill in the memory header and trailer
237         mem_ptn_hd = (PMEMORY_PATTERN)buf;
238         mem_ptn_hd->pattern0= MEM_HEADER_PATTERN;
239 
240         mem_ptn_tl = (PMEMORY_PATTERN)(((u8 *)(buf))+n*size + sizeof(MEMORY_PATTERN)+pad_len + PRE_OVERSIZE + OVERSIZE);
241         mem_ptn_tl->pattern0= MEM_TAILER_PATTERN;
242 
243         // Jump ahead by memory header so pointer returned to caller points at the right place
244         buf = ((u8 *)buf) + sizeof (MEMORY_PATTERN) + PRE_OVERSIZE;
245     } else {
246         printf("==>Memory was allocated from %s at line %d with length %d, allocated size %d, count %d\r\n",
247                file,
248                line,
249                n*size, alloc_heap_mem_bytes, alloc_heap_mem_blk_cnt);
250 
251     tls_os_release_critical(cpu_sr);
252     tls_os_sem_release(mem_sem);
253     tls_mem_alloc_info();
254     return buf;
255     }
256     tls_os_release_critical(cpu_sr);
257     tls_os_sem_release(mem_sem);
258     return buf;
259 }
260 /**
261  * This routine is called to free memory which was previously allocated using MpAllocateMemory function.
262  * Before freeing the memory, this function checks and makes sure that no overflow or underflows have
263  * happened and will also try to detect multiple frees of the same memory chunk.
264  *
265  * \param p    Pointer to allocated memory
266  */
mem_free_debug(void * p,char * file,int line)267 void mem_free_debug(void *p,  char* file, int line)
268 {
269     PMEMORY_PATTERN  mem_ptn_hd;
270     PMEMORY_PATTERN  mem_ptn_tl;
271     PMEMORY_BLOCK  mem_blk_hd1;
272     u8              needfree = 0;
273     u8  haserr = 0;
274     u32  cpu_sr;
275 
276     // Jump back by memory header size so we can get to the header
277     mem_ptn_hd = (PMEMORY_PATTERN) (((u8 *)p) - sizeof(MEMORY_PATTERN)  - PRE_OVERSIZE);
278     tls_os_sem_acquire(mem_sem, 0);
279     cpu_sr = tls_os_set_critical();
280     dl_list_for_each(mem_blk_hd1, &memory_used_list, MEMORY_BLOCK, list) {
281         if (mem_blk_hd1->header_pattern == (u32)mem_ptn_hd) {
282             needfree = 1;
283             break;
284         }
285     }
286     if (needfree) {
287         dl_list_del(&mem_blk_hd1->list);
288         dl_list_add_tail(&memory_free_list, &mem_blk_hd1->list);
289         alloc_heap_mem_bytes -= mem_blk_hd1->length + sizeof(MEMORY_PATTERN) + sizeof(MEMORY_PATTERN) +
290             PRE_OVERSIZE + OVERSIZE + mem_blk_hd1->pad;
291         alloc_heap_mem_blk_cnt--;
292     }
293     if (needfree == 0) {
294     printf("Memory Block %p was deallocated from %s at line %d \r\n", mem_ptn_hd, file, line);
295     printf("Memory %p has been deallocated!\r\n", p);
296     dl_list_for_each_reverse(mem_blk_hd1, &memory_free_list, MEMORY_BLOCK, list) {
297         if (mem_blk_hd1->header_pattern == (u32)mem_ptn_hd) {
298             printf("Memory Block %p has been put free list!\r\n", mem_ptn_hd);
299             break;
300         }
301     }
302     tls_os_release_critical(cpu_sr);
303     tls_os_sem_release(mem_sem);
304     tls_mem_alloc_info();
305     return;
306     }
307     mem_ptn_tl = (PMEMORY_PATTERN) ((u8 *)p + mem_blk_hd1->length + mem_blk_hd1->pad + OVERSIZE);
308     //
309     // Check that header was not corrupted
310     //
311     if (mem_ptn_hd->pattern0 != MEM_HEADER_PATTERN) {
312         printf("Memory %p was deallocated from %s at line %d \r\n", p, file, line);
313         printf("Memory header corruption due to underflow detected at memory block %p\r\n",
314             mem_ptn_hd);
315         printf("Header pattern 0(0x%x)\r\n", mem_ptn_hd->pattern0);
316         printf("Memory was allocated from %s at line %d with length %d\r\n",
317                mem_blk_hd1->file,
318                mem_blk_hd1->line,
319                mem_blk_hd1->length);
320         haserr = 1;
321     }
322 
323     //
324     // Check that trailer was not corrupted
325     //
326     if (mem_ptn_tl->pattern0 != MEM_TAILER_PATTERN) {
327         printf("Memory %p was deallocated from %s at line %d \r\n", p, file, line);
328         printf("Memory tailer corruption due to overflow detected at %p\r\n", mem_ptn_hd);
329         printf("Tailer pattern 0(0x%x)\r\n", mem_ptn_tl->pattern0);
330         printf("Memory was allocated from %s at line %d with length %d\r\n",
331             mem_blk_hd1->file, mem_blk_hd1->line, mem_blk_hd1->length);
332         haserr = 1;
333     }
334     if (needfree) {
335         free(mem_ptn_hd);
336     }
337 
338     tls_os_release_critical(cpu_sr);
339     tls_os_sem_release(mem_sem);
340 
341     if (haserr)
342         tls_mem_alloc_info();
343 }
344 
mem_realloc_debug(void * mem_address,u32 size,char * file,int line)345 void *mem_realloc_debug(void *mem_address, u32 size, char* file, int line)
346 {
347     void *mem_re_addr;
348     u32 cpu_sr;
349 
350     if ((mem_re_addr = mem_alloc_debug(size,  file, line)) == NULL) {
351         printf("mem_realloc_debug failed(size=%d).\r\n", size);
352         return NULL;
353     }
354     if (mem_address != NULL) {
355         cpu_sr = tls_os_set_critical();
356         memcpy_s(mem_re_addr, sizeof(mem_re_addr), mem_address, size);
357         tls_os_release_critical(cpu_sr);
358         mem_free_debug(mem_address, file, line);
359     }
360     return mem_re_addr;
361 }
362 
tls_mem_alloc_info(void)363 void tls_mem_alloc_info(void)
364 {
365     int i;
366     MEMORY_BLOCK *pos;
367     u32 cpu_sr;
368 
369     tls_os_sem_acquire(mem_sem, 0);
370     cpu_sr = tls_os_set_critical();
371     printf("==>Memory was allocated size %d, count %d\r\n",
372         alloc_heap_mem_bytes, alloc_heap_mem_blk_cnt);
373     i = 1;
374     dl_list_for_each(pos, &memory_used_list, MEMORY_BLOCK, list) {
375         printf("Block(%2d): addr<%p>, file<%s>, line<%d>, length<%d>\r\n",
376                i, pos->header_pattern, pos->file, pos->line, pos->length);
377         i++;
378     }
379     tls_os_release_critical(cpu_sr);
380     tls_os_sem_release(mem_sem);
381 }
382 
is_safe_addr_debug(void * p,u32 len,char * file,int line)383 int is_safe_addr_debug(void* p, u32 len, char* file, int line)
384 {
385     int i;
386     MEMORY_BLOCK *pos;
387     u32 cpu_sr;
388 
389     if (((u32)p) >= (u32)0x64ae8 || ((u32)p) < (u32)0x54ae8) {
390         return 1;
391     }
392     tls_os_sem_acquire(mem_sem, 0);
393     cpu_sr = tls_os_set_critical();
394     i = 1;
395     dl_list_for_each(pos, &memory_used_list, MEMORY_BLOCK, list) {
396         if ((pos->header_pattern + sizeof (MEMORY_PATTERN)  + PRE_OVERSIZE) <= ((u32)p) && ((u32)p) <= \
397             ((u32)(pos->header_pattern + sizeof(MEMORY_PATTERN) + PRE_OVERSIZE + pos->length))) {
398             if (((u32)p) + len > ((u32)(pos->header_pattern + sizeof(MEMORY_PATTERN) + PRE_OVERSIZE + pos->length))) {
399                 printf("==>Memory oversize. Block(%2d): addr<%p>, file<%s>, line<%d>, length<%d>\r\n",
400                     i, pos->header_pattern, pos->file, pos->line, pos->length);
401                 break;
402             } else {
403                 tls_os_release_critical(cpu_sr);
404                 tls_os_sem_release(mem_sem);
405                 return 1;
406             }
407         }
408         i++;
409     }
410     tls_os_release_critical(cpu_sr);
411     tls_os_sem_release(mem_sem);
412     printf("==>Memory is not safe addr<%p>, file<%s>, line<%d>.\r\n", p, file, line);
413     return 0;
414 }
415 
416 #else /* WM_MEM_DEBUG */
mem_alloc_debug(u32 size)417 void *mem_alloc_debug(u32 size)
418 {
419     u32 *buffer = (u32 *)LOS_MemAlloc(OS_SYS_MEM_ADDR, size);
420 
421     if (buffer == NULL)
422         printf("malloc error \n");
423 
424     return buffer;
425 }
426 
mem_free_debug(void * p)427 void mem_free_debug(void *p)
428 {
429     int ret = LOS_MemFree(OS_SYS_MEM_ADDR, p);
430     if (ret) {
431         printf("mem free error\n");
432     }
433 }
434 
mem_realloc_debug(void * mem_address,u32 size)435 void *mem_realloc_debug(void *mem_address, u32 size)
436 {
437     u32 *mem_re_addr = (u32 *)LOS_MemRealloc(OS_SYS_MEM_ADDR, mem_address, size);
438 
439     return mem_re_addr;
440 }
441 
mem_calloc_debug(u32 n,u32 size)442 void *mem_calloc_debug(u32 n, u32 size)
443 {
444     u32 *buffer = (u32 *)LOS_MemAlloc(OS_SYS_MEM_ADDR, n*size);
445     if (buffer) {
446         memset_s(buffer, sizeof(buffer), 0, n*size);
447     }
448 
449     return buffer;
450 }
451 #endif /* WM_MEM_DEBUG */
452 
tls_mem_get_avail_heapsize(void)453 u32 tls_mem_get_avail_heapsize(void)
454 {
455     LOS_MEM_POOL_STATUS status = {0};
456     if (LOS_MemInfoGet(OS_SYS_MEM_ADDR, &status) == LOS_NOK) {
457         return 0;
458     }
459     return status.totalFreeSize;
460 }