1 /*
2  * Copyright (C) 2015-2017 Alibaba Group Holding Limited
3  */
4 
5 #ifndef K_MM_H
6 #define K_MM_H
7 
8 
9 #ifdef __cplusplus
10 extern "C" {
11 #endif
12 
13 /** @addtogroup aos_rhino mm
14  *  Heap memory management.
15  *
16  *  @{
17  */
18 
19 #if (RHINO_CONFIG_MM_TLF > 0)
20 #define KMM_ERROR_LOCKED        1
21 #define KMM_ERROR_UNLOCKED      0
22 
23 #if (RHINO_CONFIG_MM_DEBUG && (RHINO_CONFIG_MM_TRACE_LVL > 0))
24 #define KMM_BT_SET_BY_KV        1
25 #endif
26 
27 /**
28  * Heap useage size statistic
29  */
30 #define K_MM_STATISTIC          1
31 
32 /**
33  * Memory buffer align to MM_ALIGN_SIZE
34  */
35 #define MM_ALIGN_BIT            3
36 #define MM_ALIGN_SIZE           (1 << MM_ALIGN_BIT)
37 #define MM_ALIGN_MASK           (MM_ALIGN_SIZE - 1)
38 #define MM_ALIGN_UP(a)          (((a) + MM_ALIGN_MASK) & ~MM_ALIGN_MASK)
39 #define MM_ALIGN_DOWN(a)        ((a) & ~MM_ALIGN_MASK)
40 
41 /**
42  * Max size of memory buffer
43  */
44 #define MM_MAX_BIT              RHINO_CONFIG_MM_MAXMSIZEBIT
45 #define MM_MAX_SIZE             (1 << MM_MAX_BIT)
46 
47 /**
48  * Min size of memory buffer
49  */
50 #define MM_MIN_BIT              RHINO_CONFIG_MM_MINISIZEBIT
51 #define MM_MIN_SIZE             (1 << (MM_MIN_BIT - 1))
52 
53 /**
54  * Size level of memory buffer
55  */
56 #define MM_BIT_LEVEL            (MM_MAX_BIT - MM_MIN_BIT + 2)
57 
58 /**
59  * Min size of memory heap
60  */
61 #define MM_MIN_HEAP_SIZE        1024
62 
63 /* magic word for check overwrite or corrupt */
64 #define MM_DYE_USED             0xFEFE
65 #define MM_DYE_FREE             0xABAB
66 
67 #define MM_OWNER_ID_SELF        0xFF
68 
69 #define MM_CURSTAT_MASK         0x1
70 #define MM_PRESTAT_MASK         0x2
71 
72 /* bit 0 */
73 #define MM_BUFF_FREE            1
74 #define MM_BUFF_USED            0
75 
76 /* bit 1 */
77 #define MM_BUFF_PREV_FREE       2
78 #define MM_BUFF_PREV_USED       0
79 
80 
81 /**
82  * Buffer head size
83  */
84 #define MMLIST_HEAD_SIZE        (MM_ALIGN_UP(sizeof(k_mm_list_t) - sizeof(free_ptr_t)))
85 /**
86  * Buffer payload size
87  */
88 #define MM_GET_BUF_SIZE(blk)    ((blk)->buf_size & (~MM_ALIGN_MASK))
89 /**
90  * Buffer head + payload size
91  */
92 #define MM_GET_BLK_SIZE(blk)    (MM_GET_BUF_SIZE(blk) + MMLIST_HEAD_SIZE)
93 
94 /**
95  * Get next buffer head addr
96  */
97 #define MM_GET_NEXT_BLK(blk)    ((k_mm_list_t *)((blk)->mbinfo.buffer + MM_GET_BUF_SIZE(blk)))
98 /**
99  * Get this buffer head addr
100  */
101 #define MM_GET_THIS_BLK(buf)    ((k_mm_list_t *)((char *)(buf)-MMLIST_HEAD_SIZE))
102 
103 #define MM_LAST_BLK_MAGIC       0x11224433
104 
105 #if (RHINO_CONFIG_MM_REGION_MUTEX == 0)
106 /**
107  * MM critical section strategy:
108  * Interrupt mask for single core, and busy-waiting spinlock for multi-core
109  */
110 #define MM_CRITICAL_ENTER(pmmhead,flags_cpsr) krhino_spin_lock_irq_save(&(pmmhead->mm_lock),flags_cpsr);
111 #define MM_CRITICAL_EXIT(pmmhead,flags_cpsr)  krhino_spin_unlock_irq_restore(&(pmmhead->mm_lock),flags_cpsr);
112 #else /* (RHINO_CONFIG_MM_REGION_MUTEX != 0) */
113 /**
114  * MM critical section strategy:
115  * Task blocked
116  */
117 #define MM_CRITICAL_ENTER(pmmhead,flags_cpsr)                        \
118     do {                                                             \
119         (void)flags_cpsr;                                            \
120         CPSR_ALLOC();                                                \
121         RHINO_CRITICAL_ENTER();                                      \
122         if (g_intrpt_nested_level[cpu_cur_get()] > 0u) {             \
123             k_err_proc(RHINO_NOT_CALLED_BY_INTRPT);                  \
124         }                                                            \
125         RHINO_CRITICAL_EXIT();                                       \
126         krhino_mutex_lock(&(pmmhead->mm_mutex), RHINO_WAIT_FOREVER); \
127     } while (0);
128 #define MM_CRITICAL_EXIT(pmmhead,flags_cpsr)                         \
129     do {                                                             \
130         (void)flags_cpsr;                                            \
131         krhino_mutex_unlock(&(pmmhead->mm_mutex));                   \
132     } while (0);
133 #endif
134 
135 /**
136  * free buffer list
137  */
138 typedef struct free_ptr_struct {
139     struct k_mm_list_struct *prev;
140     struct k_mm_list_struct *next;
141 } free_ptr_t;
142 
143 /**
144  * memory buffer head
145  */
146 #define ALIGN_UP_2(a) ((a % 2 == 0) ? a : (a + 1))
147 
148 typedef struct k_mm_list_struct {
149 #if (RHINO_CONFIG_MM_DEBUG > 0)
150     uint16_t dye;
151     uint8_t owner_id;
152     uint8_t trace_id;
153     size_t owner;
154 #if (RHINO_CONFIG_MM_TRACE_LVL > 0)
155     void  *trace[ALIGN_UP_2(RHINO_CONFIG_MM_TRACE_LVL)];
156 #endif
157 #endif
158     struct k_mm_list_struct *prev;
159     /**<
160      * buffer payload size, and:
161      * bit 0 indicates whether the block is used and
162      * bit 1 allows to know whether the previous block is free
163      */
164     size_t buf_size;
165     union {
166         free_ptr_t free_ptr;    /**< when buffer is free, add to free list */
167         uint8_t    buffer[1];   /**< when buffer is alloced, payload start */
168     } mbinfo;
169 } k_mm_list_t;
170 
171 /**
172  * memory region info
173  * Heap can contain multiple regoins
174  */
175 typedef struct k_mm_region_info_struct {
176     k_mm_list_t                    *end;
177     struct k_mm_region_info_struct *next;
178 } k_mm_region_info_t;
179 
180 /**
181  * memory heap info
182  * heap contains:
183  * ---------------------------------------------------------------------------
184  * | k_mm_head | k_mm_list_t | k_mm_region_info_t | free space | k_mm_list_t |
185  * ---------------------------------------------------------------------------
186  */
187 typedef struct {
188 #if (RHINO_CONFIG_MM_REGION_MUTEX > 0)
189     kmutex_t mm_mutex;
190 #else
191     kspinlock_t mm_lock;
192 #endif
193 
194     k_mm_region_info_t *regioninfo; /**< Heap can contain multiple regoins */
195 
196 #if (RHINO_CONFIG_MM_BLK > 0)
197     void *fix_pool;                 /**< heap can contain one fix pool, deal with little buffer */
198 #endif
199 
200 #if (K_MM_STATISTIC > 0)
201     size_t used_size;
202     size_t maxused_size;
203     size_t free_size;
204     size_t alloc_times[MM_BIT_LEVEL]; /* number of times for each TLF level */
205 #endif
206     /**< msb (MM_BIT_LEVEL-1) <-> lsb 0, one bit match one freelist */
207     uint32_t free_bitmap;
208     /**<
209      * freelist[N]: contain free blks at level N,
210      * 2^(N + MM_MIN_BIT) <= level N buffer size < 2^(1 + N + MM_MIN_BIT)
211      */
212     k_mm_list_t *freelist[MM_BIT_LEVEL];
213 } k_mm_head;
214 
215 /**
216  * internal funcs
217  */
218 kstat_t krhino_init_mm_head(k_mm_head **ppmmhead, void *addr, size_t len);
219 kstat_t krhino_deinit_mm_head(k_mm_head *mmhead);
220 kstat_t krhino_add_mm_region(k_mm_head *mmhead, void *addr, size_t len);
221 
222 void *k_mm_alloc(k_mm_head *mmhead, size_t size);
223 void  k_mm_free(k_mm_head *mmhead, void *ptr);
224 void *k_mm_realloc(k_mm_head *mmhead, void *oldmem, size_t new_size);
225 
226 /**
227  * Memory buffer allocation.
228  *
229  * @param[in]  size  size of the mem to malloc
230  *
231  * @return  buffer address or NULL
232  */
233 void *krhino_mm_alloc(size_t size);
234 
235 /**
236  * Memory buffer free.
237  *
238  * @param[in]  ptr  buffer address
239  *
240  * @return  none
241  */
242 void krhino_mm_free(void *ptr);
243 
244 /**
245  * Memory buffer realloc.
246  *
247  * @param[in]  oldmem   oldmem buffer address
248  * @param[in]  newsize  size of the mem to malloc
249  *
250  * @return  buffer address or NULL
251  */
252 void *krhino_mm_realloc(void *oldmem, size_t newsize);
253 
254 /**
255  * Get the max free buffer size.
256  *
257  * @param[in]  NULL
258  *
259  * @return  the max free buffer size
260  */
261 size_t krhino_mm_max_free_size_get(void);
262 
263 #else
264 
265 #include <stdlib.h>
266 
267 /**
268  * do not use os heap management
269  */
270 
271 #define krhino_mm_alloc   malloc
272 #define krhino_mm_free    free
273 #define krhino_mm_realloc realloc
274 
275 #endif /* RHINO_CONFIG_MM_TLF > 0 */
276 
277 /** @} */
278 
279 #ifdef __cplusplus
280 }
281 #endif
282 
283 #endif /* K_MM_H */
284 
285