1 /**
2  * @file lv_mem.c
3  * General and portable implementation of malloc and free.
4  * The dynamic memory monitoring is also supported.
5  */
6 
7 /*********************
8  *      INCLUDES
9  *********************/
10 #include "lv_mem.h"
11 #include "lv_math.h"
12 #include "lv_gc.h"
13 #include <string.h>
14 
15 #if LV_MEM_CUSTOM != 0
16     #include LV_MEM_CUSTOM_INCLUDE
17 #endif
18 
19 #if defined(LV_GC_INCLUDE)
20     #include LV_GC_INCLUDE
21 #endif /* LV_ENABLE_GC */
22 
23 /*********************
24  *      DEFINES
25  *********************/
26 /*Add memory junk on alloc (0xaa) and free(0xbb) (just for testing purposes)*/
27 #ifndef LV_MEM_ADD_JUNK
28     #define LV_MEM_ADD_JUNK 0
29 #endif
30 
31 #ifndef LV_MEM_FULL_DEFRAG_CNT
32     #define LV_MEM_FULL_DEFRAG_CNT 16
33 #endif
34 
35 #ifdef LV_ARCH_64
36     #define MEM_UNIT uint64_t
37 #else
38     #define MEM_UNIT uint32_t
39 #endif
40 
41 /**********************
42  *      TYPEDEFS
43  **********************/
44 
45 #if LV_ENABLE_GC == 0 /*gc custom allocations must not include header*/
46 
47 /*The size of this union must be 4 bytes (uint32_t)*/
48 typedef union {
49     struct {
50         MEM_UNIT used : 1;    /* 1: if the entry is used*/
51         MEM_UNIT d_size : 31; /* Size off the data (1 means 4 bytes)*/
52     } s;
53     MEM_UNIT header; /* The header (used + d_size)*/
54 } lv_mem_header_t;
55 
56 typedef struct {
57     lv_mem_header_t header;
58     uint8_t first_data; /*First data byte in the allocated data (Just for easily create a pointer)*/
59 } lv_mem_ent_t;
60 
61 #endif /* LV_ENABLE_GC */
62 
63 #ifdef LV_ARCH_64
64     #define ALIGN_MASK  0x7
65 #else
66     #define ALIGN_MASK  0x3
67 #endif
68 
69 #define MEM_BUF_SMALL_SIZE 16
70 
71 /**********************
72  *  STATIC PROTOTYPES
73  **********************/
74 #if LV_MEM_CUSTOM == 0
75     static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e);
76     static void * ent_alloc(lv_mem_ent_t * e, size_t size);
77     static void ent_trunc(lv_mem_ent_t * e, size_t size);
78 #endif
79 
80 /**********************
81  *  STATIC VARIABLES
82  **********************/
83 #if LV_MEM_CUSTOM == 0
84     static uint8_t * work_mem;
85 #endif
86 
87 static uint32_t zero_mem; /*Give the address of this variable if 0 byte should be allocated*/
88 
89 #if LV_MEM_CUSTOM == 0
90     static uint32_t mem_max_size; /*Tracks the maximum total size of memory ever used from the internal heap*/
91 #endif
92 
93 static uint8_t mem_buf1_32[MEM_BUF_SMALL_SIZE];
94 static uint8_t mem_buf2_32[MEM_BUF_SMALL_SIZE];
95 
96 static lv_mem_buf_t mem_buf_small[] = {{.p = mem_buf1_32, .size = MEM_BUF_SMALL_SIZE, .used = 0},
97     {.p = mem_buf2_32, .size = MEM_BUF_SMALL_SIZE, .used = 0}
98 };
99 
100 /**********************
101  *      MACROS
102  **********************/
103 
104 #define COPY32 *d32 = *s32; d32++; s32++;
105 #define COPY8 *d8 = *s8; d8++; s8++;
106 #define SET32(x) *d32 = x; d32++;
107 #define REPEAT8(expr) expr expr expr expr expr expr expr expr
108 
109 /**********************
110  *   GLOBAL FUNCTIONS
111  **********************/
112 
113 /**
114  * Initialize the dyn_mem module (work memory and other variables)
115  */
_lv_mem_init(void)116 void _lv_mem_init(void)
117 {
118 #if LV_MEM_CUSTOM == 0
119 
120 #if LV_MEM_ADR == 0
121     /*Allocate a large array to store the dynamically allocated data*/
122     static LV_MEM_ATTR MEM_UNIT work_mem_int[LV_MEM_SIZE / sizeof(MEM_UNIT)];
123     work_mem = (uint8_t *)work_mem_int;
124     mem_max_size = 0;
125 #else
126     work_mem = (uint8_t *)LV_MEM_ADR;
127 #endif
128 
129     lv_mem_ent_t * full = (lv_mem_ent_t *)work_mem;
130     full->header.s.used = 0;
131     /*The total mem size id reduced by the first header and the close patterns */
132     full->header.s.d_size = LV_MEM_SIZE - sizeof(lv_mem_header_t);
133 #endif
134 }
135 
136 /**
137  * Clean up the memory buffer which frees all the allocated memories.
138  * @note It work only if `LV_MEM_CUSTOM == 0`
139  */
_lv_mem_deinit(void)140 void _lv_mem_deinit(void)
141 {
142 #if LV_MEM_CUSTOM == 0
143     _lv_memset_00(work_mem, (LV_MEM_SIZE / sizeof(MEM_UNIT)) * sizeof(MEM_UNIT));
144     lv_mem_ent_t * full = (lv_mem_ent_t *)work_mem;
145     full->header.s.used = 0;
146     /*The total mem size id reduced by the first header and the close patterns */
147     full->header.s.d_size = LV_MEM_SIZE - sizeof(lv_mem_header_t);
148 #endif
149 }
150 
151 /**
152  * Allocate a memory dynamically
153  * @param size size of the memory to allocate in bytes
154  * @return pointer to the allocated memory
155  */
lv_mem_alloc(size_t size)156 void * lv_mem_alloc(size_t size)
157 {
158     if(size == 0) {
159         return &zero_mem;
160     }
161 
162 #ifdef LV_ARCH_64
163     /*Round the size up to 8*/
164     size = (size + 7) & (~0x7);
165 #else
166     /*Round the size up to 4*/
167     size = (size + 3) & (~0x3);
168 #endif
169     void * alloc = NULL;
170 
171 #if LV_MEM_CUSTOM == 0
172     /*Use the built-in allocators*/
173     lv_mem_ent_t * e = NULL;
174 
175     /* Search for a appropriate entry*/
176     do {
177         /* Get the next entry*/
178         e = ent_get_next(e);
179 
180         /*If there is next entry then try to allocate there*/
181         if(e != NULL) {
182             alloc = ent_alloc(e, size);
183         }
184         /* End if there is not next entry OR the alloc. is successful*/
185     } while(e != NULL && alloc == NULL);
186 
187 #else
188     /*Use custom, user defined malloc function*/
189 #if LV_ENABLE_GC == 1 /*gc must not include header*/
190     alloc = LV_MEM_CUSTOM_ALLOC(size);
191 #else                 /* LV_ENABLE_GC */
192     /*Allocate a header too to store the size*/
193     alloc = LV_MEM_CUSTOM_ALLOC(size + sizeof(lv_mem_header_t));
194     if(alloc != NULL) {
195         ((lv_mem_ent_t *)alloc)->header.s.d_size = size;
196         ((lv_mem_ent_t *)alloc)->header.s.used   = 1;
197 
198         alloc = &((lv_mem_ent_t *)alloc)->first_data;
199     }
200 #endif                /* LV_ENABLE_GC */
201 #endif                /* LV_MEM_CUSTOM */
202 
203 #if LV_MEM_ADD_JUNK
204     if(alloc != NULL) _lv_memset(alloc, 0xaa, size);
205 #endif
206 
207     if(alloc == NULL) {
208         LV_LOG_WARN("Couldn't allocate memory");
209     }
210     else {
211 #if LV_MEM_CUSTOM == 0
212         /* just a safety check, should always be true */
213         if((uintptr_t) alloc > (uintptr_t) work_mem) {
214             if((((uintptr_t) alloc - (uintptr_t) work_mem) + size) > mem_max_size) {
215                 mem_max_size = ((uintptr_t) alloc - (uintptr_t) work_mem) + size;
216             }
217         }
218 #endif
219     }
220 
221     return alloc;
222 }
223 
224 /**
225  * Free an allocated data
226  * @param data pointer to an allocated memory
227  */
lv_mem_free(const void * data)228 void lv_mem_free(const void * data)
229 {
230     if(data == &zero_mem) return;
231     if(data == NULL) return;
232 
233 #if LV_MEM_ADD_JUNK
234     _lv_memset((void *)data, 0xbb, _lv_mem_get_size(data));
235 #endif
236 
237 #if LV_ENABLE_GC == 0
238     /*e points to the header*/
239     lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *)data - sizeof(lv_mem_header_t));
240     e->header.s.used = 0;
241 #endif
242 
243 #if LV_MEM_CUSTOM == 0
244 #if LV_MEM_AUTO_DEFRAG
245     static uint16_t full_defrag_cnt = 0;
246     full_defrag_cnt++;
247     if(full_defrag_cnt < LV_MEM_FULL_DEFRAG_CNT) {
248         /* Make a simple defrag.
249          * Join the following free entries after this*/
250         lv_mem_ent_t * e_next;
251         e_next = ent_get_next(e);
252         while(e_next != NULL) {
253             if(e_next->header.s.used == 0) {
254                 e->header.s.d_size += e_next->header.s.d_size + sizeof(e->header);
255             }
256             else {
257                 break;
258             }
259             e_next = ent_get_next(e_next);
260         }
261     }
262     else {
263         full_defrag_cnt = 0;
264         lv_mem_defrag();
265 
266     }
267 
268 
269 #endif /*LV_MEM_AUTO_DEFRAG*/
270 #else /*Use custom, user defined free function*/
271 #if LV_ENABLE_GC == 0
272     LV_MEM_CUSTOM_FREE(e);
273 #else
274     LV_MEM_CUSTOM_FREE((void *)data);
275 #endif /*LV_ENABLE_GC*/
276 #endif
277 }
278 
279 /**
280  * Reallocate a memory with a new size. The old content will be kept.
281  * @param data pointer to an allocated memory.
282  * Its content will be copied to the new memory block and freed
283  * @param new_size the desired new size in byte
284  * @return pointer to the new memory
285  */
286 
287 #if LV_ENABLE_GC == 0
288 
lv_mem_realloc(void * data_p,size_t new_size)289 void * lv_mem_realloc(void * data_p, size_t new_size)
290 {
291 
292 #ifdef LV_ARCH_64
293     /*Round the size up to 8*/
294     new_size = (new_size + 7) & (~0x7);
295 #else
296     /*Round the size up to 4*/
297     new_size = (new_size + 3) & (~0x3);
298 #endif
299 
300     /*data_p could be previously freed pointer (in this case it is invalid)*/
301     if(data_p != NULL) {
302         lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *)data_p - sizeof(lv_mem_header_t));
303         if(e->header.s.used == 0) {
304             data_p = NULL;
305         }
306     }
307 
308     uint32_t old_size = _lv_mem_get_size(data_p);
309     if(old_size == new_size) return data_p; /*Also avoid reallocating the same memory*/
310 
311 #if LV_MEM_CUSTOM == 0
312     /* Truncate the memory if the new size is smaller. */
313     if(new_size < old_size) {
314         lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *)data_p - sizeof(lv_mem_header_t));
315         ent_trunc(e, new_size);
316         return &e->first_data;
317     }
318 #endif
319 
320     void * new_p;
321     new_p = lv_mem_alloc(new_size);
322     if(new_p == NULL) {
323         LV_LOG_WARN("Couldn't allocate memory");
324         return NULL;
325     }
326 
327     if(data_p != NULL) {
328         /*Copy the old data to the new. Use the smaller size*/
329         if(old_size != 0) {
330             _lv_memcpy(new_p, data_p, LV_MATH_MIN(new_size, old_size));
331             lv_mem_free(data_p);
332         }
333     }
334 
335 
336     return new_p;
337 }
338 
339 #else /* LV_ENABLE_GC */
340 
lv_mem_realloc(void * data_p,size_t new_size)341 void * lv_mem_realloc(void * data_p, size_t new_size)
342 {
343     void * new_p = LV_MEM_CUSTOM_REALLOC(data_p, new_size);
344     if(new_p == NULL) LV_LOG_WARN("Couldn't allocate memory");
345     return new_p;
346 }
347 
348 #endif /* lv_enable_gc */
349 
350 /**
351  * Join the adjacent free memory blocks
352  */
lv_mem_defrag(void)353 void lv_mem_defrag(void)
354 {
355 #if LV_MEM_CUSTOM == 0
356     lv_mem_ent_t * e_free;
357     lv_mem_ent_t * e_next;
358     e_free = ent_get_next(NULL);
359 
360     while(1) {
361         /*Search the next free entry*/
362         while(e_free != NULL) {
363             if(e_free->header.s.used != 0) {
364                 e_free = ent_get_next(e_free);
365             }
366             else {
367                 break;
368             }
369         }
370 
371         if(e_free == NULL) return;
372 
373         /*Joint the following free entries to the free*/
374         e_next = ent_get_next(e_free);
375         while(e_next != NULL) {
376             if(e_next->header.s.used == 0) {
377                 e_free->header.s.d_size += e_next->header.s.d_size + sizeof(e_next->header);
378             }
379             else {
380                 break;
381             }
382 
383             e_next = ent_get_next(e_next);
384         }
385 
386         if(e_next == NULL) return;
387 
388         /*Continue from the lastly checked entry*/
389         e_free = e_next;
390     }
391 #endif
392 }
393 
lv_mem_test(void)394 lv_res_t lv_mem_test(void)
395 {
396 #if LV_MEM_CUSTOM == 0
397     lv_mem_ent_t * e;
398     e = ent_get_next(NULL);
399     while(e) {
400         if(e->header.s.d_size > LV_MEM_SIZE) {
401             return LV_RES_INV;
402         }
403         uint8_t * e8 = (uint8_t *) e;
404         if(e8 + e->header.s.d_size > work_mem + LV_MEM_SIZE) {
405             return LV_RES_INV;
406         }
407         e = ent_get_next(e);
408     }
409 #endif
410     return LV_RES_OK;
411 }
412 
413 /**
414  * Give information about the work memory of dynamic allocation
415  * @param mon_p pointer to a dm_mon_p variable,
416  *              the result of the analysis will be stored here
417  */
lv_mem_monitor(lv_mem_monitor_t * mon_p)418 void lv_mem_monitor(lv_mem_monitor_t * mon_p)
419 {
420     /*Init the data*/
421     _lv_memset(mon_p, 0, sizeof(lv_mem_monitor_t));
422 #if LV_MEM_CUSTOM == 0
423     lv_mem_ent_t * e;
424     e = NULL;
425 
426     e = ent_get_next(e);
427 
428     while(e != NULL) {
429         if(e->header.s.used == 0) {
430             mon_p->free_cnt++;
431             mon_p->free_size += e->header.s.d_size;
432             if(e->header.s.d_size > mon_p->free_biggest_size) {
433                 mon_p->free_biggest_size = e->header.s.d_size;
434             }
435         }
436         else {
437             mon_p->used_cnt++;
438         }
439 
440         e = ent_get_next(e);
441     }
442     mon_p->total_size = LV_MEM_SIZE;
443     mon_p->max_used = mem_max_size;
444     mon_p->used_pct   = 100 - (100U * mon_p->free_size) / mon_p->total_size;
445     if(mon_p->free_size > 0) {
446         mon_p->frag_pct   = (uint32_t)mon_p->free_biggest_size * 100U / mon_p->free_size;
447         mon_p->frag_pct   = 100 - mon_p->frag_pct;
448     }
449     else {
450         mon_p->frag_pct   = 0; /*no fragmentation if all the RAM is used*/
451     }
452 #endif
453 }
454 
455 /**
456  * Give the size of an allocated memory
457  * @param data pointer to an allocated memory
458  * @return the size of data memory in bytes
459  */
460 
461 #if LV_ENABLE_GC == 0
462 
_lv_mem_get_size(const void * data)463 uint32_t _lv_mem_get_size(const void * data)
464 {
465     if(data == NULL) return 0;
466     if(data == &zero_mem) return 0;
467 
468     lv_mem_ent_t * e = (lv_mem_ent_t *)((uint8_t *)data - sizeof(lv_mem_header_t));
469 
470     return e->header.s.d_size;
471 }
472 
473 #else /* LV_ENABLE_GC */
474 
_lv_mem_get_size(const void * data)475 uint32_t _lv_mem_get_size(const void * data)
476 {
477     return LV_MEM_CUSTOM_GET_SIZE(data);
478 }
479 
480 #endif /*LV_ENABLE_GC*/
481 
482 /**
483  * Get a temporal buffer with the given size.
484  * @param size the required size
485  */
_lv_mem_buf_get(uint32_t size)486 void * _lv_mem_buf_get(uint32_t size)
487 {
488     if(size == 0) return NULL;
489 
490     /*Try small static buffers first*/
491     uint8_t i;
492     if(size <= MEM_BUF_SMALL_SIZE) {
493         for(i = 0; i < sizeof(mem_buf_small) / sizeof(mem_buf_small[0]); i++) {
494             if(mem_buf_small[i].used == 0) {
495                 mem_buf_small[i].used = 1;
496                 return mem_buf_small[i].p;
497             }
498         }
499     }
500 
501     /*Try to find a free buffer with suitable size */
502     int8_t i_guess = -1;
503     for(i = 0; i < LV_MEM_BUF_MAX_NUM; i++) {
504         if(LV_GC_ROOT(_lv_mem_buf[i]).used == 0 && LV_GC_ROOT(_lv_mem_buf[i]).size >= size) {
505             if(LV_GC_ROOT(_lv_mem_buf[i]).size == size) {
506                 LV_GC_ROOT(_lv_mem_buf[i]).used = 1;
507                 return LV_GC_ROOT(_lv_mem_buf[i]).p;
508             }
509             else if(i_guess < 0) {
510                 i_guess = i;
511             }
512             /*If size of `i` is closer to `size` prefer it*/
513             else if(LV_GC_ROOT(_lv_mem_buf[i]).size < LV_GC_ROOT(_lv_mem_buf[i_guess]).size) {
514                 i_guess = i;
515             }
516         }
517     }
518 
519     if(i_guess >= 0) {
520         LV_GC_ROOT(_lv_mem_buf[i_guess]).used = 1;
521         return LV_GC_ROOT(_lv_mem_buf[i_guess]).p;
522     }
523 
524 
525     /*Reallocate a free buffer*/
526     for(i = 0; i < LV_MEM_BUF_MAX_NUM; i++) {
527         if(LV_GC_ROOT(_lv_mem_buf[i]).used == 0) {
528             LV_GC_ROOT(_lv_mem_buf[i]).used = 1;
529             LV_GC_ROOT(_lv_mem_buf[i]).size = size;
530             /*if this fails you probably need to increase your LV_MEM_SIZE/heap size*/
531             LV_GC_ROOT(_lv_mem_buf[i]).p = lv_mem_realloc(LV_GC_ROOT(_lv_mem_buf[i]).p, size);
532             if(LV_GC_ROOT(_lv_mem_buf[i]).p == NULL) {
533                 LV_DEBUG_ASSERT(false, "Out of memory, can't allocate a new  buffer (increase your LV_MEM_SIZE/heap size", 0x00);
534             }
535             return  LV_GC_ROOT(_lv_mem_buf[i]).p;
536         }
537     }
538 
539     LV_DEBUG_ASSERT(false, "No free buffer. Increase LV_DRAW_BUF_MAX_NUM.", 0x00);
540     return NULL;
541 }
542 
543 /**
544  * Release a memory buffer
545  * @param p buffer to release
546  */
_lv_mem_buf_release(void * p)547 void _lv_mem_buf_release(void * p)
548 {
549     uint8_t i;
550 
551     /*Try small static buffers first*/
552     for(i = 0; i < sizeof(mem_buf_small) / sizeof(mem_buf_small[0]); i++) {
553         if(mem_buf_small[i].p == p) {
554             mem_buf_small[i].used = 0;
555             return;
556         }
557     }
558 
559     for(i = 0; i < LV_MEM_BUF_MAX_NUM; i++) {
560         if(LV_GC_ROOT(_lv_mem_buf[i]).p == p) {
561             LV_GC_ROOT(_lv_mem_buf[i]).used = 0;
562             return;
563         }
564     }
565 
566     LV_LOG_ERROR("lv_mem_buf_release: p is not a known buffer")
567 }
568 
569 /**
570  * Free all memory buffers
571  */
_lv_mem_buf_free_all(void)572 void _lv_mem_buf_free_all(void)
573 {
574     uint8_t i;
575     for(i = 0; i < sizeof(mem_buf_small) / sizeof(mem_buf_small[0]); i++) {
576         mem_buf_small[i].used = 0;
577     }
578 
579     for(i = 0; i < LV_MEM_BUF_MAX_NUM; i++) {
580         if(LV_GC_ROOT(_lv_mem_buf[i]).p) {
581             lv_mem_free(LV_GC_ROOT(_lv_mem_buf[i]).p);
582             LV_GC_ROOT(_lv_mem_buf[i]).p = NULL;
583             LV_GC_ROOT(_lv_mem_buf[i]).used = 0;
584             LV_GC_ROOT(_lv_mem_buf[i]).size = 0;
585         }
586     }
587 }
588 
589 #if LV_MEMCPY_MEMSET_STD == 0
590 /**
591  * Same as `memcpy` but optimized for 4 byte operation.
592  * @param dst pointer to the destination buffer
593  * @param src pointer to the source buffer
594  * @param len number of byte to copy
595  */
_lv_memcpy(void * dst,const void * src,size_t len)596 LV_ATTRIBUTE_FAST_MEM void * _lv_memcpy(void * dst, const void * src, size_t len)
597 {
598     uint8_t * d8 = dst;
599     const uint8_t * s8 = src;
600 
601     lv_uintptr_t d_align = (lv_uintptr_t)d8 & ALIGN_MASK;
602     lv_uintptr_t s_align = (lv_uintptr_t)s8 & ALIGN_MASK;
603 
604     /*Byte copy for unaligned memories*/
605     if(s_align != d_align) {
606         while(len > 32) {
607             REPEAT8(COPY8);
608             REPEAT8(COPY8);
609             REPEAT8(COPY8);
610             REPEAT8(COPY8);
611             len -= 32;
612         }
613         while(len) {
614             COPY8
615             len--;
616         }
617         return dst;
618     }
619 
620 
621     /*Make the memories aligned*/
622     if(d_align) {
623         d_align = ALIGN_MASK + 1 - d_align;
624         while(d_align && len) {
625             COPY8;
626             d_align--;
627             len--;
628         }
629     }
630 
631     uint32_t * d32 = (uint32_t *)d8;
632     const uint32_t * s32 = (uint32_t *)s8;
633     while(len > 32) {
634         REPEAT8(COPY32)
635         len -= 32;
636     }
637 
638     while(len > 4) {
639         COPY32;
640         len -= 4;
641     }
642 
643     d8 = (uint8_t *)d32;
644     s8 = (const uint8_t *)s32;
645     while(len) {
646         COPY8
647         len--;
648     }
649 
650     return dst;
651 }
652 
653 
654 /**
655  * Same as `memset` but optimized for 4 byte operation.
656  * @param dst pointer to the destination buffer
657  * @param v value to set [0..255]
658  * @param len number of byte to set
659  */
_lv_memset(void * dst,uint8_t v,size_t len)660 LV_ATTRIBUTE_FAST_MEM void _lv_memset(void * dst, uint8_t v, size_t len)
661 {
662 
663     uint8_t * d8 = (uint8_t *) dst;
664 
665     uintptr_t d_align = (lv_uintptr_t) d8 & ALIGN_MASK;
666 
667     /*Make the address aligned*/
668     if(d_align) {
669         d_align = ALIGN_MASK + 1 - d_align;
670         while(d_align && len) {
671             *d8 = v;
672             d8++;
673             len--;
674             d_align--;
675         }
676     }
677 
678     uint32_t v32 = v + (v << 8) + (v << 16) + (v << 24);
679 
680     uint32_t * d32 = (uint32_t *)d8;
681 
682     while(len > 32) {
683         SET32(v32);
684         SET32(v32);
685         SET32(v32);
686         SET32(v32);
687         SET32(v32);
688         SET32(v32);
689         SET32(v32);
690         SET32(v32);
691         len -= 32;
692     }
693 
694     while(len > 4) {
695         SET32(v32);
696         len -= 4;
697     }
698 
699 
700     d8 = (uint8_t *)d32;
701     while(len) {
702         *d8 = v;
703         d8++;
704         len--;
705     }
706 }
707 
708 /**
709  * Same as `memset(dst, 0x00, len)` but optimized for 4 byte operation.
710  * @param dst pointer to the destination buffer
711  * @param len number of byte to set
712  */
_lv_memset_00(void * dst,size_t len)713 LV_ATTRIBUTE_FAST_MEM void _lv_memset_00(void * dst, size_t len)
714 {
715     uint8_t * d8 = (uint8_t *) dst;
716     uintptr_t d_align = (lv_uintptr_t) d8 & ALIGN_MASK;
717 
718 
719     /*Make the address aligned*/
720     if(d_align) {
721         d_align = ALIGN_MASK + 1 - d_align;
722         while(d_align && len) {
723             *d8 = 0x00;
724             d8++;
725             len--;
726             d_align--;
727         }
728     }
729 
730     uint32_t * d32 = (uint32_t *)d8;
731     while(len > 32) {
732         SET32(0);
733         SET32(0);
734         SET32(0);
735         SET32(0);
736         SET32(0);
737         SET32(0);
738         SET32(0);
739         SET32(0);
740         len -= 32;
741     }
742 
743     while(len > 4) {
744         SET32(0);
745         len -= 4;
746     }
747 
748 
749     d8 = (uint8_t *)d32;
750     while(len) {
751         *d8 = 0;
752         d8++;
753         len--;
754     }
755 }
756 
757 /**
758  * Same as `memset(dst, 0xFF, len)` but optimized for 4 byte operation.
759  * @param dst pointer to the destination buffer
760  * @param len number of byte to set
761  */
_lv_memset_ff(void * dst,size_t len)762 LV_ATTRIBUTE_FAST_MEM void _lv_memset_ff(void * dst, size_t len)
763 {
764     uint8_t * d8 = (uint8_t *) dst;
765     uintptr_t d_align = (lv_uintptr_t) d8 & ALIGN_MASK;
766 
767 
768     /*Make the address aligned*/
769     if(d_align) {
770         d_align = ALIGN_MASK + 1 - d_align;
771         while(d_align && len) {
772             *d8 = 0xFF;
773             d8++;
774             len--;
775             d_align--;
776         }
777     }
778 
779     uint32_t * d32 = (uint32_t *)d8;
780     while(len > 32) {
781         SET32(0xFFFFFFFF);
782         SET32(0xFFFFFFFF);
783         SET32(0xFFFFFFFF);
784         SET32(0xFFFFFFFF);
785         SET32(0xFFFFFFFF);
786         SET32(0xFFFFFFFF);
787         SET32(0xFFFFFFFF);
788         SET32(0xFFFFFFFF);
789         len -= 32;
790     }
791 
792     while(len > 4) {
793         SET32(0xFFFFFFFF);
794         len -= 4;
795     }
796 
797 
798     d8 = (uint8_t *)d32;
799     while(len) {
800         *d8 = 0xFF;
801         d8++;
802         len--;
803     }
804 }
805 
806 #endif /*LV_MEMCPY_MEMSET_STD*/
807 
808 /**********************
809  *   STATIC FUNCTIONS
810  **********************/
811 
812 #if LV_MEM_CUSTOM == 0
813 /**
814  * Give the next entry after 'act_e'
815  * @param act_e pointer to an entry
816  * @return pointer to an entry after 'act_e'
817  */
ent_get_next(lv_mem_ent_t * act_e)818 static lv_mem_ent_t * ent_get_next(lv_mem_ent_t * act_e)
819 {
820     lv_mem_ent_t * next_e = NULL;
821 
822     if(act_e == NULL) { /*NULL means: get the first entry*/
823         next_e = (lv_mem_ent_t *)work_mem;
824     }
825     else {   /*Get the next entry */
826         uint8_t * data = &act_e->first_data;
827         next_e         = (lv_mem_ent_t *)&data[act_e->header.s.d_size];
828 
829         if(&next_e->first_data >= &work_mem[LV_MEM_SIZE]) next_e = NULL;
830     }
831 
832     return next_e;
833 }
834 
835 /**
836  * Try to do the real allocation with a given size
837  * @param e try to allocate to this entry
838  * @param size size of the new memory in bytes
839  * @return pointer to the allocated memory or NULL if not enough memory in the entry
840  */
ent_alloc(lv_mem_ent_t * e,size_t size)841 static void * ent_alloc(lv_mem_ent_t * e, size_t size)
842 {
843     void * alloc = NULL;
844     /*If the memory is free and big enough then use it */
845     if(e->header.s.used == 0 && e->header.s.d_size >= size) {
846         /*Truncate the entry to the desired size */
847         ent_trunc(e, size);
848         e->header.s.used = 1;
849 
850         /*Save the allocated data*/
851         alloc = &e->first_data;
852     }
853 
854     return alloc;
855 }
856 
857 /**
858  * Truncate the data of entry to the given size
859  * @param e Pointer to an entry
860  * @param size new size in bytes
861  */
ent_trunc(lv_mem_ent_t * e,size_t size)862 static void ent_trunc(lv_mem_ent_t * e, size_t size)
863 {
864 
865 #ifdef LV_ARCH_64
866     /*Round the size up to 8*/
867     size = (size + 7) & (~0x7);
868 #else
869     /*Round the size up to 4*/
870     size = (size + 3) & (~0x3);
871 #endif
872 
873     /*Don't let empty space only for a header without data*/
874     if(e->header.s.d_size == size + sizeof(lv_mem_header_t)) {
875         size = e->header.s.d_size;
876     }
877 
878     /* Create the new entry after the current if there is space for it */
879     if(e->header.s.d_size != size) {
880         uint8_t * e_data             = &e->first_data;
881         lv_mem_ent_t * after_new_e   = (lv_mem_ent_t *)&e_data[size];
882         after_new_e->header.s.used   = 0;
883         after_new_e->header.s.d_size = (uint32_t)e->header.s.d_size - size - sizeof(lv_mem_header_t);
884     }
885 
886     /* Set the new size for the original entry */
887     e->header.s.d_size = (uint32_t)size;
888 }
889 
890 #endif
891