From: John Tsiombikas Date: Sun, 18 Aug 2024 23:35:23 +0000 (+0300) Subject: added memory management code, untested, kernel hangs unexpectedly X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=commitdiff_plain;h=9820ae9da3f6b2f8b90dca5e83fbdcf607f8c96d;p=eightysix added memory management code, untested, kernel hangs unexpectedly --- diff --git a/kern/src/asmutil.h b/kern/src/asmutil.h index 6c7a513..82c41f7 100644 --- a/kern/src/asmutil.h +++ b/kern/src/asmutil.h @@ -32,7 +32,7 @@ void getregs(struct wordregs *regs); void getsregs(struct segregs *sregs); #define FP_SEG(x) ((uint16_t)((uint32_t)(x) >> 16)) -#define FP_OFFS(x) ((uint16_t)(x)) +#define FP_OFFS(x) ((uint16_t)((uint32_t)(x) & 0xffff)) #define MK_FP(s, o) (void __far*)(((uint32_t)(s) << 16) | (uint32_t)(o)) #define enable() asm("sti") diff --git a/kern/src/libc/malloc.c b/kern/src/libc/malloc.c new file mode 100644 index 0000000..0f6d493 --- /dev/null +++ b/kern/src/libc/malloc.c @@ -0,0 +1,166 @@ +#ifndef MALLOC_H_ +#define MALLOC_H_ + +#include "malloc.h" +#include "mem.h" +#include "asmutil.h" +#include "dbg.h" + +#define MAGIC_FREE 0xbaadf00d +#define MAGIC_ALLOC 0xdeadbeef + +struct memrange { + unsigned long magic, len; + struct memrange __far *next; + struct memrange __far *prev; +}; +#define DESCSZ sizeof(struct memrange) +#define DESC(p) ((struct memrange __far*)(p) - 1) +#define RNGEND(rng) ((struct memrange __far*)((char __far*)(rng) + (rng)->len)) + +static struct memrange __far *pool; +static unsigned int freemem, num_alloc; + +int kmalloc_init(int numblk) +{ + int first; + + if((first = alloc_blocks(numblk)) == -1) { + return -1; + } + pool->magic = MAGIC_FREE; + pool = MK_FP(first >> 6, 0); + pool->len = (unsigned long)numblk * MEM_BLKSZ; + pool->next = pool->prev = 0; + + freemem = pool->len; + num_alloc = 0; + return 0; +} + +void __far *kmalloc(unsigned long sz) +{ + __far struct memrange *pptr, *newfree; + unsigned long fullsz; + + /* force paragraph-aligned sizes, including memrange desc */ + fullsz = (sz + DESCSZ + 15) & 0xfffffff0ul; + + pptr = pool; + while(pptr) { + if(fullsz <= pptr->len) { + newfree = pptr + fullsz; + newfree->magic = pptr->magic; + newfree->len = pptr->len - fullsz; + newfree->next = pptr->next; + newfree->prev = pptr->prev; + if(newfree->prev) { + newfree->prev->next = newfree; + } else { + pool = newfree; + } + pptr->magic = MAGIC_ALLOC; + pptr->len = fullsz; + pptr->prev = pptr->next = 0; + + freemem -= fullsz; + num_alloc++; + return pptr + 1; + } + + pptr = pptr->next; + } + return 0; +} + +static void assert_magic(struct memrange __far *p, unsigned long expect) +{ + if(p->magic != expect) { + void __far *ptr = p + 1; + panic("kfree: bad magic %lx @ %x:%x (len: %lx)", p->magic, FP_SEG(ptr), + FP_OFFS(ptr), p->len); + } +} + +void kfree(void __far *p) +{ + __far struct memrange *mem, *memend, *cur, *curend, *next, *last; + + mem = DESC(p); + memend = RNGEND(mem); + + if(mem->magic == MAGIC_FREE) { + panic("double kfree %x:%x (len: %lx)", FP_SEG(p), FP_OFFS(p), mem->len); + } else { + assert_magic(mem, MAGIC_ALLOC); + } + mem->magic = MAGIC_FREE; + + freemem -= mem->len; + num_alloc--; + + if(!pool) { + pool = mem; + mem->next = mem->prev = 0; + return; + } + + if(pool > memend) { + /* memory before pool, not adjacent, just prepend */ + assert_magic(pool, MAGIC_FREE); + mem->next = pool; + pool->prev = mem; + pool = mem; + return; + } + + if(pool == memend) { + /* memory adjacent before pool */ + assert_magic(pool, MAGIC_FREE); + mem->len += pool->len; + mem->next = pool->next; + mem->prev = 0; + pool->magic = 0; + pool = mem; + return; + } + + cur = pool; + last = 0; + while(cur && mem > (curend = RNGEND(cur))) { + assert_magic(cur, MAGIC_FREE); + last = cur; + cur = cur->next; + } + + if(!cur) { + /* memory after the end, non-adjacent */ + if(!last) { + panic("unexpected lack of memory ranges in pool"); + } + last->next = mem; + mem->prev = last; + return; + } + + if(curend == mem) { + /* memory adjacent at the end of previous range */ + mem->next = cur->next; + mem->prev = cur; + cur->next = mem; + cur->len += mem->len; + mem->magic = 0; + mem = cur; /* fall through to check adjacency at the other end */ + } + if(memend == (next = cur->next)) { + /* memory adjacent at the start of next range */ + next->magic = 0; + mem->len += next->len; + mem->next = next->next; + if(next->next) { + next->next->prev = mem; + } + } +} + +#endif /* MALLOC_H_ */ diff --git a/kern/src/libc/malloc.h b/kern/src/libc/malloc.h new file mode 100644 index 0000000..d17a209 --- /dev/null +++ b/kern/src/libc/malloc.h @@ -0,0 +1,8 @@ +#ifndef MALLOC_H_ +#define MALLOC_H_ + +int kmalloc_init(int numblk); +void __far *kmalloc(unsigned long sz); +void kfree(void __far *ptr); + +#endif /* MALLOC_H_ */ diff --git a/kern/src/main.c b/kern/src/main.c index b59e371..abd70b5 100644 --- a/kern/src/main.c +++ b/kern/src/main.c @@ -5,6 +5,7 @@ #include "vid.h" #include "ser.h" #include "con.h" +#include "dbg.h" void kmain(void) { diff --git a/kern/src/mem.c b/kern/src/mem.c new file mode 100644 index 0000000..9ec2eea --- /dev/null +++ b/kern/src/mem.c @@ -0,0 +1,102 @@ +#include +#include "mem.h" +#include "malloc.h" +#include "dbg.h" + +#define MEMBLOCKS(x) ((x) >> 10) +#define SEGBLOCKS(x) ((x) << 6) +#define BLKBYTES(x) ((unsigned long)(x) << 10) + +#define MAX_BLOCKS (1048576 / MEM_BLKSZ) +#define BLKMAP_SZ (MAX_BLOCKS / 16) +#define BLKMAP_WIDX(x) ((x) >> 4) +#define BLKMAP_WBIT(x) ((x) & 0xf) + +static uint16_t blkmap[BLKMAP_SZ]; + +static void mark(int blk, int n, int val); +#define mark_alloc(blk, n) mark(blk, n, 1) +#define mark_free(blk, n) mark(blk, n, 0) + + +int mem_init(void) +{ + /* TODO detect amount of memory instead of assuming 640k */ + + /* first segment belongs to the kernel for code/data/stack */ + mark_alloc(0, SEGBLOCKS(1)); + /* mark 640k-1M unavailable */ + mark_alloc(MEMBLOCKS(0xa0000ul), MEMBLOCKS(0x100000ul - 0xa0000ul)); + + /* let the kernel malloc grab 32k */ + return kmalloc_init(32); +} + +int alloc_blocks(int n) +{ + int i, j, blk, idx0, bit0, span = 0; + + if(n <= 0) { + panic("BUG: alloc_blocks(%x)", n); + } + + for(i=0; i> j) & 1) { + /* found allocated block, cancel span */ + span = 0; + } else { + /* found free block, continue span or start it */ + if(!span) { + idx0 = i; + bit0 = j; + } + if(++span >= n) { + /* done! mark as allocated and return first block */ + blk = (idx0 << 4) + bit0; + mark_alloc(blk, span); + return blk; + } + } + } + } + + /* failed to find n consecutive free blocks */ + return -1; +} + +void free_blocks(int blk, int n) +{ + mark_free(blk, n); +} + +static void mark(int blk, int n, int val) +{ + int idx, bit, span; + uint16_t bits; + static const uint16_t spanbits[] = {0, 1, 3, 7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, + 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff}; + + while(n > 0) { + idx = BLKMAP_WIDX(blk); + bit = BLKMAP_WBIT(blk); + span = n; + if(span > 16 - bit) { + span = 16 - bit; + } + bits = spanbits[span] << bit; + + if(val) { + blkmap[idx] |= bits; + } else { + blkmap[idx] &= ~bits; + } + n -= span; + blk += span; + } +} diff --git a/kern/src/mem.h b/kern/src/mem.h new file mode 100644 index 0000000..9a37f19 --- /dev/null +++ b/kern/src/mem.h @@ -0,0 +1,11 @@ +#ifndef MEM_H_ +#define MEM_H_ + +#define MEM_BLKSZ 1024 + +int mem_init(void); + +int alloc_blocks(int n); +void free_blocks(int blk, int n); + +#endif /* MEM_H_ */ diff --git a/kern/src/vid.c b/kern/src/vid.c index 5cbe7b2..59cea2b 100644 --- a/kern/src/vid.c +++ b/kern/src/vid.c @@ -1,6 +1,7 @@ #include #include "vid.h" #include "asmutil.h" +#include "dbg.h" #define CRTC_ADDR_PORT (iobase | 4) #define CRTC_DATA_PORT (iobase | 5)