-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathheap_malloc.c
264 lines (226 loc) · 7.88 KB
/
heap_malloc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
#include "heap_malloc.h"
/* This structure must be 4-byte aligned. */
typedef struct {
volatile u8* next;
volatile u8* previous;
u32 size;
} heap_record_t;
#ifdef _HEAP_64
#define ptr_size u64
#else
#define ptr_size u32
#endif
#define mem_ptr ptr_size*
#define HEAP_REC_SIZE sizeof(heap_record_t)
#define HEAP_PICKET_SIZE sizeof(ptr_size)
#define HEAP_PICKET_VALUE 0x00464200 /* "\0BF\0" */
#define HEAP_PICKET_RESET 0xffffffff
/**
*
* heap_open
*
* Initialize the heap memory. This function depends on the required ZTE
* heap library wrapper functions to be implemented.
*
*/
void heap_open(void) {
/* Variable Declarations */
volatile mem_ptr picket;
volatile heap_record_t* heapRec;
ptr_size heap_ulHeapMemoryBegin;
volatile u8* heap_heapBegin;
/* Acquire numbers from the wrapper functions. */
heap_ulHeapMemoryBegin = (ptr_size)heap_settings_memoryBegin();
heap_heapBegin = (volatile u8*)heap_ulHeapMemoryBegin;
/* Put a dummy record to memory. */
picket = (mem_ptr)heap_heapBegin;
*picket = HEAP_PICKET_VALUE;
heapRec = (heap_record_t*)(heap_heapBegin + HEAP_PICKET_SIZE);
heapRec->next = 0;
heapRec->previous = 0;
heapRec->size = 0;
picket = (mem_ptr)(heap_heapBegin + HEAP_PICKET_SIZE + HEAP_REC_SIZE);
*picket = HEAP_PICKET_VALUE;
}
/**
*
* heap_malloc
*
* Implementation of a standard malloc() function to allocate memory.
*
* @param allocSize the size of memory in bytes to allocate
* @return pointer to the allocated memory
*
*/
void* heap_malloc(u32 allocSize) {
/* Variable Declarations */
volatile char* retPointer;
ptr_size allocSize4;
volatile heap_record_t* heapRec;
volatile heap_record_t* heapRecNew;
volatile heap_record_t* heapRecNext;
volatile heap_record_t* lastBestFitHeapRec;
ptr_size lastBestFitRate;
ptr_size currentFitRate;
volatile mem_ptr picket;
ptr_size freeSize;
ptr_size requiredSize;
ptr_size currentHeapMemoryTop;
ptr_size heap_ulHeapMemoryLimit;
u8 heap_bHeapMemorySPShared;
ptr_size heap_ulHeapMemoryBegin;
volatile u8* heap_heapBegin;
/* Initialize */
heap_ulHeapMemoryLimit = heap_settings_memoryLimit();
heap_bHeapMemorySPShared = heap_settings_shared();
heap_ulHeapMemoryBegin = (ptr_size)heap_settings_memoryBegin();
heap_heapBegin = (volatile u8*)heap_ulHeapMemoryBegin;
/* Basic checking. */
if (allocSize == 0) {
return (NULL_POINTER);
}
/* Allocate size must be 4-byte alignment. */
allocSize4 = allocSize - (allocSize & 0x3);
if (allocSize4 < allocSize) {
allocSize4 += 4;
}
/* Prepare for walking. */
heapRec = (heap_record_t*)(heap_heapBegin + HEAP_PICKET_SIZE);
requiredSize = allocSize4 + 2 * HEAP_PICKET_SIZE + HEAP_REC_SIZE;
lastBestFitHeapRec = NULL_POINTER;
lastBestFitRate = 0xfffffffe;
/* Walking. */
do {
/* Check if heapRec is located at the correct memory range. */
if (heap_bHeapMemorySPShared) {
/* The heap memory pool is shared with stack memory so get the */
/* current stack pointer. */
currentHeapMemoryTop = heap_settings_getStackPointer();
/* Put the space reserved for user stack. */
currentHeapMemoryTop -= heap_ulHeapMemoryLimit;
} else {
/* The heap memory pool is dedicated so get the top memory pointer
*/
currentHeapMemoryTop =
heap_ulHeapMemoryBegin + heap_ulHeapMemoryLimit;
}
if (((ptr_size)heapRec) <
(((ptr_size)heap_ulHeapMemoryBegin) + HEAP_PICKET_SIZE)) {
return (NULL_POINTER);
}
if ((((ptr_size)heapRec) + HEAP_REC_SIZE + HEAP_PICKET_SIZE) >=
currentHeapMemoryTop) {
return (NULL_POINTER);
}
/* Check picket for access violation check. */
picket = (mem_ptr)(((volatile u8*)heapRec) - HEAP_PICKET_SIZE);
if (*picket != HEAP_PICKET_VALUE) {
return (NULL_POINTER);
}
picket =
(mem_ptr)(((volatile u8*)heapRec) + HEAP_REC_SIZE + heapRec->size);
if (*picket != HEAP_PICKET_VALUE) {
return (NULL_POINTER);
}
/* Find the size of the next free block. */
if (((ptr_size)(heapRec->next)) > 0) {
freeSize = ((ptr_size)(heapRec->next)) - ((ptr_size)heapRec) -
2 * HEAP_PICKET_SIZE - HEAP_REC_SIZE - heapRec->size;
} else {
/* Get the available size for a new block. */
freeSize = ((ptr_size)(currentHeapMemoryTop)) -
((ptr_size)heapRec) - HEAP_PICKET_SIZE - HEAP_REC_SIZE -
heapRec->size;
}
/* Go for best fit. */
if (requiredSize == freeSize) {
/* Perfect match. */
lastBestFitHeapRec = heapRec;
/* Stop walking. */
break;
} else if (requiredSize < freeSize) {
/* Check fit rate. */
currentFitRate = freeSize - requiredSize;
if (currentFitRate < lastBestFitRate) {
lastBestFitHeapRec = heapRec;
lastBestFitRate = currentFitRate;
}
}
heapRec = (heap_record_t*)heapRec->next;
} while (((ptr_size)heapRec) > 0);
/* Allocate the new block. */
if (lastBestFitHeapRec == NULL_POINTER) {
retPointer = NULL_POINTER;
} else {
heapRec = lastBestFitHeapRec;
heapRecNext = (heap_record_t*)heapRec->next;
heapRecNew = (heap_record_t*)(((volatile u8*)heapRec) + HEAP_REC_SIZE +
heapRec->size + 2 * HEAP_PICKET_SIZE);
/* Set picket. */
picket = (mem_ptr)(((volatile u8*)heapRecNew) - HEAP_PICKET_SIZE);
*picket = HEAP_PICKET_VALUE;
heapRecNew->next = (u8*)heapRecNext;
heapRecNew->previous = (u8*)heapRec;
heapRecNew->size = allocSize4;
picket =
(mem_ptr)(((volatile u8*)heapRecNew) + HEAP_REC_SIZE + allocSize4);
*picket = HEAP_PICKET_VALUE;
/* Link heap record. */
heapRec->next = (u8*)heapRecNew;
if (((ptr_size)heapRecNext) > 0) {
heapRecNext->previous = (u8*)heapRecNew;
}
/* Set buffer pointer. */
retPointer = ((volatile char*)heapRecNew) + HEAP_REC_SIZE;
}
return ((void*)retPointer);
}
/**
*
* heap_free
*
* Implementation of a standard free() function to free allocated memory.
*
* @param beFree pointer to memory to free
*
*/
void heap_free(void* beFree) {
/* Variable Declarations */
volatile heap_record_t* heapRec;
volatile heap_record_t* heapRecNext;
volatile heap_record_t* heapRecPrevious;
volatile mem_ptr picket1;
volatile mem_ptr picket2;
ptr_size heap_ulHeapMemoryBegin = (ptr_size)heap_settings_memoryBegin();
/* beFree basic checking. Return if incorrect. */
if (((ptr_size)beFree) < heap_ulHeapMemoryBegin) {
return;
}
/* Addressing the memory location. */
heapRec = ((heap_record_t*)(((volatile u8*)beFree) - HEAP_REC_SIZE));
picket1 = (mem_ptr)(((volatile u8*)heapRec) - HEAP_PICKET_SIZE);
picket2 =
(mem_ptr)(((volatile u8*)heapRec) + HEAP_REC_SIZE + heapRec->size);
/* Check picket first, if not match then do nothing. */
if (*picket1 != HEAP_PICKET_VALUE) {
return;
}
if (*picket2 != HEAP_PICKET_VALUE) {
return;
}
/* Set record first. */
heapRecPrevious = (heap_record_t*)heapRec->previous;
heapRecNext = (heap_record_t*)heapRec->next;
/* Reset picket value. */
*picket1 = HEAP_PICKET_RESET;
*picket2 = HEAP_PICKET_RESET;
/* Relink record. */
heapRecPrevious->next = (u8*)heapRecNext;
if (((ptr_size)heapRecNext) > 0) {
heapRecNext->previous = (u8*)heapRecPrevious;
}
/* Reset heap record. */
heapRec->next = 0;
heapRec->previous = 0;
heapRec->size = 0;
}