|
@@ -5,6 +5,7 @@
|
5
|
5
|
|
6
|
6
|
struct heap_block {
|
7
|
7
|
size_t size;
|
|
8
|
+ unsigned int align;
|
8
|
9
|
char data[0];
|
9
|
10
|
};
|
10
|
11
|
|
|
@@ -12,7 +13,7 @@ struct heap_block {
|
12
|
13
|
extern char _text[];
|
13
|
14
|
extern char _end[];
|
14
|
15
|
|
15
|
|
-static unsigned long heap_start, heap_end, heap_ptr;
|
|
16
|
+static physaddr_t heap_start, heap_end, heap_ptr;
|
16
|
17
|
|
17
|
18
|
/*
|
18
|
19
|
* Find the largest contiguous area of memory that I can use for the
|
|
@@ -21,8 +22,8 @@ static unsigned long heap_start, heap_end, heap_ptr;
|
21
|
22
|
*/
|
22
|
23
|
static void init_heap ( void ) {
|
23
|
24
|
unsigned int i;
|
24
|
|
- unsigned long eb_start, eb_end;
|
25
|
|
- unsigned long size;
|
|
25
|
+ physaddr_t eb_start, eb_end;
|
|
26
|
+ physaddr_t size;
|
26
|
27
|
|
27
|
28
|
size = 0;
|
28
|
29
|
|
|
@@ -31,8 +32,8 @@ static void init_heap ( void ) {
|
31
|
32
|
eb_end = virt_to_phys ( _end );
|
32
|
33
|
|
33
|
34
|
for ( i = 0 ; i < meminfo.map_count ; i++ ) {
|
34
|
|
- unsigned long r_start, r_end, r_size;
|
35
|
|
- unsigned long pre_eb, post_eb;
|
|
35
|
+ physaddr_t r_start, r_end, r_size;
|
|
36
|
+ physaddr_t pre_eb, post_eb;
|
36
|
37
|
|
37
|
38
|
/* Get start and end addresses of the region */
|
38
|
39
|
if ( meminfo.map[i].type != E820_RAM )
|
|
@@ -84,14 +85,19 @@ static void init_heap ( void ) {
|
84
|
85
|
* Allocate a block from the heap.
|
85
|
86
|
*
|
86
|
87
|
*/
|
|
88
|
+static inline physaddr_t block_alloc_addr ( physaddr_t heap_ptr,
|
|
89
|
+ size_t size, unsigned int align ) {
|
|
90
|
+ return ( ( ( heap_ptr - size ) & ~( align - 1 ) )
|
|
91
|
+ - sizeof ( struct heap_block ) );
|
|
92
|
+}
|
|
93
|
+
|
87
|
94
|
void * emalloc ( size_t size, unsigned int align ) {
|
88
|
|
- physaddr_t addr;
|
89
|
95
|
struct heap_block *block;
|
|
96
|
+ physaddr_t addr;
|
90
|
97
|
|
91
|
98
|
ASSERT ( ( align & ( align - 1 ) ) == 0 );
|
92
|
|
-
|
93
|
|
- addr = ( ( ( heap_ptr - size ) & ~( align - 1 ) )
|
94
|
|
- - sizeof ( struct heap_block ) );
|
|
99
|
+
|
|
100
|
+ addr = block_alloc_addr ( heap_ptr, size, align );
|
95
|
101
|
if ( addr < heap_start ) {
|
96
|
102
|
DBG ( "HEAP no space for %x bytes (alignment %d) in [%x,%x)\n",
|
97
|
103
|
size, align, heap_start, heap_ptr );
|
|
@@ -100,6 +106,7 @@ void * emalloc ( size_t size, unsigned int align ) {
|
100
|
106
|
|
101
|
107
|
block = phys_to_virt ( addr );
|
102
|
108
|
block->size = ( heap_ptr - addr );
|
|
109
|
+ block->align = align;
|
103
|
110
|
DBG ( "HEAP allocated %x bytes (alignment %d) at %x [%x,%x)\n",
|
104
|
111
|
size, align, virt_to_phys ( block->data ), addr, heap_ptr );
|
105
|
112
|
heap_ptr = addr;
|
|
@@ -119,6 +126,10 @@ void * emalloc_all ( size_t *size ) {
|
119
|
126
|
* Free a heap block
|
120
|
127
|
*
|
121
|
128
|
*/
|
|
129
|
+static inline physaddr_t block_free_addr ( size_t size ) {
|
|
130
|
+ return heap_ptr + size;
|
|
131
|
+}
|
|
132
|
+
|
122
|
133
|
void efree ( void *ptr ) {
|
123
|
134
|
struct heap_block *block;
|
124
|
135
|
|
|
@@ -126,7 +137,7 @@ void efree ( void *ptr ) {
|
126
|
137
|
|
127
|
138
|
block = ( struct heap_block * )
|
128
|
139
|
( ptr - offsetof ( struct heap_block, data ) );
|
129
|
|
- heap_ptr += block->size;
|
|
140
|
+ heap_ptr = block_free_addr ( block->size );
|
130
|
141
|
|
131
|
142
|
DBG ( "HEAP freed %x [%x,%x)\n", virt_to_phys ( ptr ),
|
132
|
143
|
virt_to_phys ( block ), heap_ptr );
|
|
@@ -145,4 +156,52 @@ void efree_all ( void ) {
|
145
|
156
|
heap_ptr = heap_end;
|
146
|
157
|
}
|
147
|
158
|
|
|
159
|
+/*
|
|
160
|
+ * Resize a heap block
|
|
161
|
+ *
|
|
162
|
+ */
|
|
163
|
+void * erealloc ( void *ptr, size_t size ) {
|
|
164
|
+ struct heap_block *old_block;
|
|
165
|
+ size_t old_size;
|
|
166
|
+ unsigned int old_align;
|
|
167
|
+ physaddr_t new_addr;
|
|
168
|
+ size_t move_size;
|
|
169
|
+
|
|
170
|
+ /* Get descriptor of the old block */
|
|
171
|
+ old_block = ( struct heap_block * )
|
|
172
|
+ ( ptr - offsetof ( struct heap_block, data ) );
|
|
173
|
+ old_size = old_block->size;
|
|
174
|
+ old_align = old_block->align;
|
|
175
|
+
|
|
176
|
+ /* Check that allocation is going to succeed */
|
|
177
|
+ new_addr = block_alloc_addr ( block_free_addr ( old_size ),
|
|
178
|
+ size, old_align );
|
|
179
|
+ if ( new_addr < heap_start ) {
|
|
180
|
+ DBG ( "HEAP no space for %x bytes (alignment %d) in [%x,%x)\n",
|
|
181
|
+ size, align, heap_start, block_free_addr ( old_size ) );
|
|
182
|
+ return NULL;
|
|
183
|
+ }
|
|
184
|
+
|
|
185
|
+ /* Free the old block */
|
|
186
|
+ efree ( ptr );
|
|
187
|
+
|
|
188
|
+ /* Move the data. Do this *before* allocating the new block,
|
|
189
|
+ * because the new block's descriptor may overwrite the old
|
|
190
|
+ * block's data, if the new block is smaller than the old
|
|
191
|
+ * block.
|
|
192
|
+ */
|
|
193
|
+ move_size = size + sizeof ( struct heap_block );
|
|
194
|
+ if ( old_size < move_size )
|
|
195
|
+ move_size = old_size;
|
|
196
|
+ memmove ( phys_to_virt ( new_addr ), old_block, move_size );
|
|
197
|
+
|
|
198
|
+ /* Allocate the new block. This must succeed, because we
|
|
199
|
+ * already checked that there was sufficient space.
|
|
200
|
+ */
|
|
201
|
+ ptr = emalloc ( size, old_align );
|
|
202
|
+ ASSERT ( ptr != NULL );
|
|
203
|
+
|
|
204
|
+ return ptr;
|
|
205
|
+}
|
|
206
|
+
|
148
|
207
|
INIT_FN ( INIT_HEAP, init_heap, efree_all, NULL );
|