3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 /* use small (32K) heap for 16-bit compilers,
27 large (500K) heap for 32-bit compilers */
29 #define HEAP_SIZE 500000uL
31 #define HEAP_SIZE 8192u
34 #define MALLOC_MAGIC 0x6D92 /* must be < 0x8000 */
36 typedef struct _malloc
/* Turbo C DJGPP */
38 size_t size
; /* 2 bytes 4 bytes */
39 struct _malloc
*next
; /* 2 bytes 4 bytes */
40 unsigned magic
: 15; /* 2 bytes total 4 bytes total */
42 } malloc_t
; /* total 6 bytes 12 bytes */
44 static char *g_heap_bot
, *g_kbrk
, *g_heap_top
;
45 /*****************************************************************************
46 *****************************************************************************/
47 static void kdump_heap (void)
49 unsigned blks_used
= 0, blks_free
= 0;
50 size_t bytes_used
= 0, bytes_free
= 0;
54 for (m
= (malloc_t
*)g_heap_bot
; m
!= NULL
; m
= m
->next
)
56 DPRINT ("blk %5p: %6u bytes %s\n", m
,
57 m
->size
, m
->used
? "used" : "free");
62 bytes_used
+= m
->size
;
67 bytes_free
+= m
->size
;
71 DPRINT ("blks: %6u used, %6u free, %6u total\n", blks_used
,
72 blks_free
, blks_used
+ blks_free
);
73 DPRINT ("bytes: %6u used, %6u free, %6u total\n", bytes_used
,
74 bytes_free
, bytes_used
+ bytes_free
);
75 DPRINT ("g_heap_bot=0x%p, g_kbrk=0x%p, g_heap_top=0x%p\n",
76 g_heap_bot
, g_kbrk
, g_heap_top
);
78 total
= (bytes_used
+ bytes_free
) +
79 (blks_used
+ blks_free
) * sizeof(malloc_t
);
81 if(total
!= g_kbrk
- g_heap_bot
)
82 DPRINT ("*** some heap memory is not accounted for\n");
84 /*****************************************************************************
85 POSIX sbrk() looks like this
87 Mine is a bit different so I can signal the calling function
88 if more memory than desired was allocated (e.g. in a system with paging)
89 If your kbrk()/sbrk() always allocates the amount of memory you ask for,
90 this code can be easily changed.
92 int brk( void *sbrk( void *kbrk(
93 function void *adr); int delta); int *delta);
94 ---------------------- ------------ ------------ -------------
96 return value if error -1 -1 NULL
97 get break value . sbrk(0) int x=0; kbrk(&x);
98 set break value to X brk(X) sbrk(X - sbrk(0)) int x=X, y=0; kbrk(&x) - kbrk(&y);
99 enlarge heap by N bytes . sbrk(+N) int x=N; kbrk(&x);
100 shrink heap by N bytes . sbrk(-N) int x=-N; kbrk(&x);
101 can you tell if you're
103 than you wanted? no no yes
104 *****************************************************************************/
105 static void *kbrk (int *delta
)
107 static char heap
[HEAP_SIZE
];
109 char *new_brk
, *old_brk
;
111 /* heap doesn't exist yet */
112 if(g_heap_bot
== NULL
)
114 g_heap_bot
= g_kbrk
= heap
;
115 g_heap_top
= g_heap_bot
+ HEAP_SIZE
;
117 new_brk
= g_kbrk
+ (*delta
);
118 /* too low: return NULL */
119 if(new_brk
< g_heap_bot
)
121 /* too high: return NULL */
122 if(new_brk
>= g_heap_top
)
124 /* success: adjust brk value... */
127 /* ...return actual delta... (for this sbrk(), they are the same)
128 (*delta) = (*delta); */
129 /* ...return old brk value */
133 /*****************************************************************************
134 kmalloc() and kfree() use g_heap_bot, but not g_kbrk nor g_heap_top
135 *****************************************************************************/
136 void *kmalloc(size_t size
)
144 total_size
= size
+ sizeof(malloc_t
);
145 /* search heap for free block (FIRST FIT) */
146 m
= (malloc_t
*)g_heap_bot
;
147 /* g_heap_bot == 0 == NULL if heap does not yet exist */
150 if(m
->magic
!= MALLOC_MAGIC
)
151 // panic("kernel heap is corrupt in kmalloc()");
153 kprintf ("*** kernel heap is corrupt in kmalloc()\n");
156 for(; m
->next
!= NULL
; m
= m
->next
)
160 /* size == m->size is a perfect fit */
165 /* otherwise, we need an extra sizeof(malloc_t) bytes for the header
166 of a second, free block */
167 if(total_size
> m
->size
)
169 /* create a new, smaller free block after this one */
170 n
= (malloc_t
*)((char *)m
+ total_size
);
171 n
->size
= m
->size
- total_size
;
173 n
->magic
= MALLOC_MAGIC
;
175 /* reduce the size of this block and mark it used */
180 return (char *)m
+ sizeof(malloc_t
);
183 /* use kbrk() to enlarge (or create!) heap */
192 n
->magic
= MALLOC_MAGIC
;
194 /* did kbrk() return the exact amount of memory we wanted?
195 cast to make "gcc -Wall -W ..." shut the hell up */
196 if((int)total_size
== delta
)
200 /* it returned more than we wanted (it will never return less):
201 create a new, free block */
202 m
= (malloc_t
*)((char *)n
+ total_size
);
203 m
->size
= delta
- total_size
- sizeof(malloc_t
);
205 m
->magic
= MALLOC_MAGIC
;
210 return (char *)n
+ sizeof(malloc_t
);
212 /*****************************************************************************
213 *****************************************************************************/
214 void kfree(void *blk
)
218 /* get address of header */
219 m
= (malloc_t
*)((char *)blk
- sizeof(malloc_t
));
220 if(m
->magic
!= MALLOC_MAGIC
)
221 // panic("attempt to kfree() block at 0x%p "
222 // "with bad magic value", blk);
224 kprintf ("*** attempt to kfree() block at 0x%p "
225 "with bad magic value\n", blk
);
228 /* find this block in the heap */
229 n
= (malloc_t
*)g_heap_bot
;
230 if(n
->magic
!= MALLOC_MAGIC
)
231 // panic("kernel heap is corrupt in kfree()");
233 kprintf ("*** kernel heap is corrupt in kfree()\n");
236 for(; n
!= NULL
; n
= n
->next
)
241 /* not found? bad pointer or no heap or something else? */
243 // panic("attempt to kfree() block at 0x%p "
244 // "that is not in the heap", blk);
246 kprintf ("*** attempt to kfree() block at 0x%p "
247 "that is not in the heap\n", blk
);
252 /* coalesce adjacent free blocks
253 Hard to spell, hard to do */
254 for(m
= (malloc_t
*)g_heap_bot
; m
!= NULL
; m
= m
->next
)
256 while(!m
->used
&& m
->next
!= NULL
&& !m
->next
->used
)
258 /* resize this block */
259 m
->size
+= sizeof(malloc_t
) + m
->next
->size
;
260 /* merge with next block */
261 m
->next
= m
->next
->next
;
265 /*****************************************************************************
266 *****************************************************************************/
267 void *krealloc(void *blk
, size_t size
)
272 /* size == 0: free block */
281 /* allocate new block */
282 new_blk
= kmalloc(size
);
283 /* if allocation OK, and if old block exists, copy old block to new */
284 if(new_blk
!= NULL
&& blk
!= NULL
)
286 m
= (malloc_t
*)((char *)blk
- sizeof(malloc_t
));
287 if(m
->magic
!= MALLOC_MAGIC
)
288 // panic("attempt to krealloc() block at "
289 // "0x%p with bad magic value", blk);
291 kprintf ("*** attempt to krealloc() block at "
292 "0x%p with bad magic value\n", blk
);
295 /* copy minimum of old and new block sizes */
298 memcpy(new_blk
, blk
, size
);
299 /* free the old block */
305 /*****************************************************************************
306 *****************************************************************************/
308 unsigned int init_mm ()
312 //file_cache = (char *) kmalloc (sizeof (char) * 4096);
323 unsigned lifetime
[SLOTS
];
328 memset(lifetime
, 0, sizeof(lifetime
));
329 memset(blk
, 0, sizeof(blk
));
330 for(i
= 0; i
< 1000; i
++)
332 kprintf ("Pass %6u\n", i
);
333 for(j
= 0; j
< SLOTS
; j
++)
341 /* too old; free it */
347 /* alloc new block of random size
348 Note that size_t==unsigned, but kmalloc() uses integer math,
349 so block size must be positive integer */
351 k
= rand() % 40960 + 1;
353 k
= rand() % 4096 + 1;
357 kprintf ("failed to alloc %u bytes\n", k
);
359 /* give it a random lifetime 0-20 */
360 lifetime
[j
] = rand() % 21;
363 /* let's see what we've wrought */
366 /* free everything */
367 for(j
= 0; j
< SLOTS
; j
++)
376 /* after all that, we should have a single, unused block */
380 /*****************************************************************************
381 *****************************************************************************/