- Added first-fit free-list allocator with block splitting and coalescing. Provides kmalloc(), kfree(), and kcalloc() for kernel-space dynamic memory. - Each block carries an inline header with a magic value (0xCAFEBABE) for heap corruption detection, plus double-free checking. - Memory is obtained from the paging subsystem in 4 KiB page increments. All allocations are 8-byte aligned with a 16-byte minimum block size. - Created freestanding string.c with memset, memcpy, memmove, memcmp, strlen, strcmp, strncmp, strcpy, strncpy — replacing the unavailable libc implementations. - Added documentation in docs/kmalloc.md. Tested: kmalloc(64) returns 0xD0001010 (in kernel heap) and kfree succeeds. Works with both 4 MiB and 128 MiB RAM.
62 lines
2.1 KiB
Markdown
62 lines
2.1 KiB
Markdown
# Kernel Memory Allocator (kmalloc)
|
|
|
|
## Overview
|
|
|
|
The kernel memory allocator provides `kmalloc()` and `kfree()` for dynamic memory allocation within the kernel. It uses the paging subsystem to obtain physical memory on demand.
|
|
|
|
## Architecture
|
|
|
|
### Free-List Allocator
|
|
|
|
The allocator maintains a singly-linked free list of available memory blocks, ordered by address. Each block carries an inline header:
|
|
|
|
```c
|
|
typedef struct block_header {
|
|
uint32_t size; // Usable bytes (excludes header)
|
|
uint32_t magic; // 0xCAFEBABE for integrity checking
|
|
struct block_header *next; // Next free block (free list only)
|
|
uint8_t is_free; // 1 = free, 0 = allocated
|
|
} block_header_t;
|
|
```
|
|
|
|
### Allocation Strategy
|
|
|
|
1. **First-fit search:** Walk the free list for the first block with `size >= requested`.
|
|
2. **Block splitting:** If the found block is significantly larger than needed, it is split into the allocated portion and a new free block.
|
|
3. **Page expansion:** If no suitable block exists, a new 4 KiB page is obtained from `paging_alloc_page()`.
|
|
|
|
All allocations are 8-byte aligned. Minimum block size is 16 bytes to limit fragmentation.
|
|
|
|
### Deallocation
|
|
|
|
1. The block header is located by subtracting `sizeof(block_header_t)` from the user pointer.
|
|
2. The block's magic number is verified to detect corruption.
|
|
3. The block is inserted back into the free list in address order.
|
|
4. **Coalescing:** Adjacent free blocks are merged to reduce fragmentation.
|
|
|
|
### Integrity Checks
|
|
|
|
- A magic value (`0xCAFEBABE`) in each block header detects heap corruption.
|
|
- Double-free is detected by checking the `is_free` flag.
|
|
|
|
## API
|
|
|
|
```c
|
|
void init_kmalloc(void);
|
|
void *kmalloc(size_t size);
|
|
void kfree(void *ptr);
|
|
void *kcalloc(size_t count, size_t size);
|
|
```
|
|
|
|
## Key Files
|
|
|
|
- `src/kmalloc.c` / `src/kmalloc.h` — Allocator implementation.
|
|
- `src/string.c` — Freestanding `memset`, `memcpy`, `strlen`, etc.
|
|
- `src/paging.c` — Provides physical page backing.
|
|
|
|
## Limitations
|
|
|
|
- Maximum single allocation is ~4080 bytes (one page minus header).
|
|
- No multi-page allocations for large objects.
|
|
- Free virtual addresses are not reused after `paging_free_page()`.
|