3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 #ifndef CONFIG_MEM_ZALLOC
33 /* use small (32K) heap for 16-bit compilers,
34 large (500K) heap for 32-bit compilers */
36 #define HEAP_SIZE 0x100000
38 #define HEAP_SIZE 8192u
41 #define MALLOC_MAGIC 0x6D92 /* must be < 0x8000 */
43 typedef struct _malloc
/* Turbo C DJGPP/GCC */
45 size_t size
; /* 2 bytes 4 bytes */
46 struct _malloc
*next
; /* 2 bytes 4 bytes */
47 unsigned magic
: 15; /* 2 bytes total 4 bytes total */
49 } malloc_t
; /* total 6 bytes 12 bytes */
51 static char *g_heap_bot
, *g_kbrk
, *g_heap_top
;
53 MUTEX_CREATE (mutex_malloc
);
54 MUTEX_CREATE (mutex_free
);
56 /*****************************************************************************
57 *****************************************************************************/
58 static void kdump_heap (void)
60 unsigned blks_used
= 0, blks_free
= 0;
61 size_t bytes_used
= 0, bytes_free
= 0;
65 for (m
= (malloc_t
*)g_heap_bot
; m
!= NULL
; m
= m
->next
) {
67 DPRINT (DBG_MM
| DBG_KMEM
, "blk %5p: %6u bytes %s", m
,
68 m
->size
, m
->used
? "used" : "free");
72 bytes_used
+= m
->size
;
75 bytes_free
+= m
->size
;
79 DPRINT (DBG_MM
| DBG_KMEM
, "blks: %6u used, %6u free, %6u total", blks_used
,
80 blks_free
, blks_used
+ blks_free
);
81 DPRINT (DBG_MM
| DBG_KMEM
, "bytes: %6u used, %6u free, %6u total", bytes_used
,
82 bytes_free
, bytes_used
+ bytes_free
);
83 DPRINT (DBG_MM
| DBG_KMEM
, "g_heap_bot=0x%p, g_kbrk=0x%p, g_heap_top=0x%p",
84 g_heap_bot
, g_kbrk
, g_heap_top
);
86 total
= (bytes_used
+ bytes_free
) +
87 (blks_used
+ blks_free
) * sizeof(malloc_t
);
89 if(total
!= g_kbrk
- g_heap_bot
)
90 DPRINT (DBG_MM
| DBG_KMEM
, "*** some heap memory is not accounted for");
93 /*****************************************************************************
94 POSIX sbrk() looks like this
96 Mine is a bit different so I can signal the calling function
97 if more memory than desired was allocated (e.g. in a system with paging)
98 If your kbrk()/sbrk() always allocates the amount of memory you ask for,
99 this code can be easily changed.
101 int brk( void *sbrk( void *kbrk(
102 function void *adr); int delta); int *delta);
103 ---------------------- ------------ ------------ -------------
105 return value if error -1 -1 NULL
106 get break value . sbrk(0) int x=0; kbrk(&x);
107 set break value to X brk(X) sbrk(X - sbrk(0)) int x=X, y=0; kbrk(&x) - kbrk(&y);
108 enlarge heap by N bytes . sbrk(+N) int x=N; kbrk(&x);
109 shrink heap by N bytes . sbrk(-N) int x=-N; kbrk(&x);
110 can you tell if you're
112 than you wanted? no no yes
113 *****************************************************************************/
114 static void *kbrk (int *delta
)
116 static char heap
[HEAP_SIZE
];
118 char *new_brk
, *old_brk
;
120 /* heap doesn't exist yet */
121 if(g_heap_bot
== NULL
) {
122 g_heap_bot
= g_kbrk
= heap
;
123 g_heap_top
= g_heap_bot
+ HEAP_SIZE
;
126 new_brk
= g_kbrk
+ (*delta
);
128 /* too low: return NULL */
129 if(new_brk
< g_heap_bot
)
132 /* too high: return NULL */
133 if(new_brk
>= g_heap_top
)
136 /* success: adjust brk value... */
140 /* ...return actual delta... (for this sbrk(), they are the same)
141 (*delta) = (*delta); */
142 /* ...return old brk value */
146 /*****************************************************************************
147 kmalloc() and kfree() use g_heap_bot, but not g_kbrk nor g_heap_top
148 *****************************************************************************/
149 void *kmalloc (size_t size
)
151 //kprintf ("kmalloc (): %d\n", size);
160 mutex_lock (&mutex_malloc
);
162 total_size
= size
+ sizeof (malloc_t
);
164 /* search heap for free block (FIRST FIT) */
165 m
= (malloc_t
*) g_heap_bot
;
167 /* g_heap_bot == 0 == NULL if heap does not yet exist */
169 if (m
->magic
!= MALLOC_MAGIC
) {
170 kprintf ("*** kernel heap is corrupt in kmalloc()\n");
171 mutex_lock (&mutex_malloc
);
175 for (; m
->next
!= NULL
; m
= m
->next
) {
179 /* prevent before page fault :-B */
180 if (m
== (malloc_t
*) ~0)
183 /* size == m->size is a perfect fit */
187 /* otherwise, we need an extra sizeof(malloc_t) bytes for the header
188 of a second, free block */
189 if (total_size
> m
->size
)
192 /* create a new, smaller free block after this one */
193 n
= (malloc_t
*) ((char *) m
+ total_size
);
194 n
->size
= m
->size
- total_size
;
196 n
->magic
= MALLOC_MAGIC
;
199 /* reduce the size of this block and mark it used */
205 mutex_unlock (&mutex_malloc
);
207 return (char *) m
+ sizeof (malloc_t
);
211 /* use kbrk() to enlarge (or create!) heap */
217 DPRINT (DBG_MM
| DBG_KMEM
, "kbrk () == NULL");
218 mutex_unlock (&mutex_malloc
);
226 n
->magic
= MALLOC_MAGIC
;
229 /* did kbrk() return the exact amount of memory we wanted?
230 cast to make "gcc -Wall -W ..." shut the hell up */
231 if ((int) total_size
== delta
)
234 /* it returned more than we wanted (it will never return less):
235 create a new, free block */
236 m
= (malloc_t
*)((char *)n
+ total_size
);
237 m
->size
= delta
- total_size
- sizeof(malloc_t
);
239 m
->magic
= MALLOC_MAGIC
;
245 mutex_unlock (&mutex_malloc
);
247 return (char *) n
+ sizeof (malloc_t
);
249 /*****************************************************************************
250 *****************************************************************************/
251 void kfree (void *blk
)
256 mutex_lock (&mutex_free
);
260 /* get address of header */
261 m
= (malloc_t
*)((char *) blk
- sizeof(malloc_t
));
263 if (m
->magic
!= MALLOC_MAGIC
) {
264 kprintf ("*** attempt to kfree() block at 0x%p "
265 "with bad magic value\n", blk
);
269 /* find this block in the heap */
270 n
= (malloc_t
*)g_heap_bot
;
272 if (n
->magic
!= MALLOC_MAGIC
) {
273 kprintf ("*** kernel heap is corrupt in kfree()\n");
277 for (; n
!= NULL
; n
= n
->next
) {
282 /* not found? bad pointer or no heap or something else? */
284 kprintf ("*** attempt to kfree() block at 0x%p "
285 "that is not in the heap\n", blk
);
287 mutex_unlock (&mutex_free
);
294 /* coalesce adjacent free blocks Hard to spell, hard to do */
295 for (m
= (malloc_t
*)g_heap_bot
; m
!= NULL
; m
= m
->next
) {
296 while (!m
->used
&& m
->next
!= NULL
&& !m
->next
->used
) {
297 /* resize this block */
298 m
->size
+= sizeof(malloc_t
) + m
->next
->size
;
299 /* merge with next block */
300 m
->next
= m
->next
->next
;
305 mutex_unlock (&mutex_free
);
307 /*****************************************************************************
308 *****************************************************************************/
309 void *krealloc (void *blk
, size_t size
)
314 /* size == 0: free block */
321 /* allocate new block */
322 new_blk
= kmalloc (size
);
324 /* if allocation OK, and if old block exists, copy old block to new */
325 if (new_blk
!= NULL
&& blk
!= NULL
) {
326 m
= (malloc_t
*) ((char *) blk
- sizeof (malloc_t
));
328 if (m
->magic
!= MALLOC_MAGIC
) {
329 kprintf ("*** attempt to krealloc() block at 0x%p with bad magic value\n", blk
);
333 /* copy minimum of old and new block sizes */
337 memcpy (new_blk
, blk
, size
);
339 /* free the old block */
347 /*****************************************************************************
348 *****************************************************************************/
349 unsigned short kmem_get ()
352 register unsigned long *mem
;
353 unsigned long mem_count
, a
, mem_end
, bse_end
;
354 unsigned short memkb
;
355 unsigned char irq1
, irq2
;
369 // store a copy of CR0
370 asm volatile ("movl %%cr0, %%eax;" : "=a"(cr0
));
372 // invalidate the cache
373 // write-back and invalidate the cache
374 asm volatile ("wbinvd;");
376 // plug cr0 with just PE/CD/NW
377 // cache disable(486+), no-writeback(486+), 32bit mode(386+)
378 asm volatile ("movl %%eax, %%cr0;" ::
379 "a" (cr0
| 0x00000001 | 0x40000000 | 0x20000000));
384 mem_count
+= 1024*1024;
385 mem
= (unsigned long *) mem_count
;
391 /* the empty asm calls tell gcc not to rely on whats in its registers
392 as saved variables (this gets us around GCC optimisations) */
393 asm (";" ::: "memory");
394 if (*mem
!= 0x55AA55AA)
400 if (*mem
!=0xAA55AA55)
404 asm (";":::"memory");
406 } while (memkb
< 4096 && mem_count
!= 0);
408 asm volatile ("movl %%eax, %%cr0;" :: "a" (cr0
));
410 mem_end
= memkb
<< 20;
411 mem
= (unsigned long *) 0x413;
412 bse_end
= ((*mem
) &0xFFFF) << 6;
422 void *sbrk (int *delta
)
424 static char heap
[HEAP_SIZE
];
426 char *new_brk
, *old_brk
;
428 /* heap doesn't exist yet */
429 if(g_heap_bot
== NULL
) {
430 g_heap_bot
= g_kbrk
= heap
;
431 g_heap_top
= g_heap_bot
+ HEAP_SIZE
;
434 new_brk
= g_kbrk
+ (*delta
);
435 /* too low: return NULL */
436 if(new_brk
< g_heap_bot
)
439 /* too high: return NULL */
440 if(new_brk
>= g_heap_top
)
443 /* success: adjust brk value... */
447 /* .. return actual delta... (for this sbrk(), they are the same)
448 .. return old brk value */
452 /*****************************************************************************
453 *****************************************************************************/
456 unsigned blks_used
= 0, blks_free
= 0;
457 size_t bytes_used
= 0, bytes_free
= 0;
461 for (m
= (malloc_t
*)g_heap_bot
; m
!= NULL
; m
= m
->next
) {
462 /*DPRINT (DBG_MM | DBG_KMEM, "blk %5p: %6u bytes %s\n", m,
463 m->size, m->used ? "used" : "free");*/
467 bytes_used
+= m
->size
;
470 bytes_free
+= m
->size
;
474 DPRINT (DBG_MM
| DBG_KMEM
, "blks: %6u used, %6u free, %6u total", blks_used
,
475 blks_free
, blks_used
+ blks_free
);
476 DPRINT (DBG_MM
| DBG_KMEM
, "bytes: %6u used, %6u free, %6u total", bytes_used
,
477 bytes_free
, bytes_used
+ bytes_free
);
478 DPRINT (DBG_MM
| DBG_KMEM
, "g_heap_bot=0x%p, g_kbrk=0x%p, g_heap_top=0x%p",
479 g_heap_bot
, g_kbrk
, g_heap_top
);
481 /* we have to increase used memory from user-space apps */
482 bytes_used
+= umem_used () / 1024;
484 printf ("\ttotal\tused\tfree\tshared\tbuffers\tcached\n");
485 printf ("Mem: \t%u\t%u\t%u\t%u\t%u\t%u\n",
486 mem_ext
*1024, bytes_used
/1024, mem_ext
*1024 - bytes_used
/1024, 0, 0, blks_free
);
489 /*****************************************************************************
490 *****************************************************************************/
491 unsigned int init_mm ()
493 //mem_ext = kmem_get (); // get extended memory (in Mb)
501 //file_cache = (char *) kmalloc (sizeof (char));