Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/mem/heap.c
3694 views
1
/*
2
* Copyright (c) 2018 naehrwert
3
* Copyright (c) 2018-2026 CTCaer
4
*
5
* This program is free software; you can redistribute it and/or modify it
6
* under the terms and conditions of the GNU General Public License,
7
* version 2, as published by the Free Software Foundation.
8
*
9
* This program is distributed in the hope it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12
* more details.
13
*
14
* You should have received a copy of the GNU General Public License
15
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
*/
17
18
#include <string.h>
19
#include "heap.h"
20
#include <gfx_utils.h>
21
22
#define HEAP_USED_MAGIC 0x50414548 // "HEAP".
23
24
heap_t _heap;
25
26
static void _heap_create(void *start)
27
{
28
_heap.start = start;
29
_heap.first = NULL;
30
_heap.last = NULL;
31
}
32
33
// Node info is before node address.
34
static void *_heap_alloc(u32 size)
35
{
36
hnode_t *node, *new_node;
37
38
// Align to cache line size.
39
size = ALIGN(size, sizeof(hnode_t));
40
41
// First allocation.
42
if (!_heap.first)
43
{
44
node = (hnode_t *)_heap.start;
45
node->used = HEAP_USED_MAGIC;
46
node->size = size;
47
node->prev = NULL;
48
node->next = NULL;
49
50
_heap.first = node;
51
_heap.last = node;
52
53
return (void *)node + sizeof(hnode_t);
54
}
55
56
#ifdef BDK_MALLOC_NO_DEFRAG
57
// Get the last allocated block.
58
node = _heap.last;
59
#else
60
// Get first block and find the first available one.
61
node = _heap.first;
62
while (true)
63
{
64
// Check if there's available unused node.
65
if (!node->used && (size <= node->size))
66
{
67
// Size and offset of the new unused node.
68
u32 new_size = node->size - size;
69
new_node = (hnode_t *)((void *)node + sizeof(hnode_t) + size);
70
71
// If there's aligned unused space from the old node,
72
// create a new one and set the leftover size.
73
if (new_size >= (sizeof(hnode_t) << 2))
74
{
75
new_node->used = 0;
76
new_node->size = new_size - sizeof(hnode_t);
77
new_node->next = node->next;
78
79
// Check that we are not on first node.
80
if (new_node->next)
81
new_node->next->prev = new_node;
82
83
new_node->prev = node;
84
node->next = new_node;
85
}
86
else // Unused node size is just enough.
87
size += new_size;
88
89
node->size = size;
90
node->used = HEAP_USED_MAGIC;
91
92
return (void *)node + sizeof(hnode_t);
93
}
94
95
// No unused node found, try the next one.
96
if (node->next)
97
node = node->next;
98
else
99
break;
100
}
101
#endif
102
103
// No unused node found, create a new one.
104
new_node = (hnode_t *)((void *)node + sizeof(hnode_t) + node->size);
105
new_node->used = HEAP_USED_MAGIC;
106
new_node->size = size;
107
new_node->prev = node;
108
new_node->next = NULL;
109
110
node->next = new_node;
111
_heap.last = new_node;
112
113
return (void *)new_node + sizeof(hnode_t);
114
}
115
116
static void _heap_free(void *addr)
117
{
118
hnode_t *node = (hnode_t *)(addr - sizeof(hnode_t));
119
120
// Check if heap owns this address.
121
if (addr < _heap.start || node->used != HEAP_USED_MAGIC)
122
{
123
//! BUGPRINTF("free error: addr %08p, used %08X!\n");
124
return;
125
}
126
127
node->used = 0;
128
129
#ifndef BDK_MALLOC_NO_DEFRAG
130
// Merge with previous node if empty.
131
hnode_t *prev = node->prev;
132
if (prev && !prev->used)
133
{
134
prev->size += node->size + sizeof(hnode_t);
135
prev->next = node->next;
136
137
if (node->next)
138
node->next->prev = prev;
139
140
// Set node to resized one.
141
node = prev;
142
}
143
144
// Merge with next node if empty.
145
hnode_t *next = node->next;
146
if (next && !next->used)
147
{
148
node->size += next->size + sizeof(hnode_t);
149
node->next = next->next;
150
151
if (next->next)
152
next->next->prev = node;
153
}
154
#endif
155
}
156
157
void heap_init(void *base)
158
{
159
_heap_create(base);
160
}
161
162
void heap_set(heap_t *heap)
163
{
164
memcpy(&_heap, heap, sizeof(heap_t));
165
}
166
167
void *malloc(u32 size)
168
{
169
return _heap_alloc(size);
170
}
171
172
void *zalloc(u32 size)
173
{
174
void *buf = (void *)_heap_alloc(size);
175
memset(buf, 0, ALIGN(size, sizeof(hnode_t))); // Clear the aligned size.
176
return buf;
177
}
178
179
void *calloc(u32 num, u32 size)
180
{
181
return zalloc(num * size);
182
}
183
184
void free(void *buf)
185
{
186
_heap_free(buf);
187
}
188
189
void heap_monitor(heap_monitor_t *mon, bool print_node_stats)
190
{
191
u32 count = 0;
192
memset(mon, 0, sizeof(heap_monitor_t));
193
194
hnode_t *node = _heap.first;
195
while (true)
196
{
197
if (node->used)
198
{
199
mon->nodes_used++;
200
mon->used += node->size + sizeof(hnode_t);
201
}
202
else
203
mon->total += node->size + sizeof(hnode_t);
204
205
if (print_node_stats)
206
gfx_printf("%3d - %d, addr: 0x%08X, size: 0x%X\n",
207
count, node->used, (u32)node + sizeof(hnode_t), node->size);
208
209
count++;
210
211
if (node->next)
212
node = node->next;
213
else
214
break;
215
}
216
mon->total += mon->used;
217
mon->nodes_total = count;
218
}
219
220