Skip to content

Commit 51e4de2

Browse files
author
Louis Jenkins
committed
I managed to implement a very basic and minimal heap that can allocate
virtual memory, although I'm more than a bit skeptical on whether it works as it should or not. I'll experiment with it... for now, I know that memory allocated is available now, as it does not page fault when I do so.
1 parent 08c66f5 commit 51e4de2

File tree

14 files changed

+778
-340
lines changed

14 files changed

+778
-340
lines changed

MoltarOS.sublime-workspace

Lines changed: 322 additions & 41 deletions
Large diffs are not rendered by default.

src/kernel/include/drivers/kbd_hal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ static struct {
2222
// Note: All the above is packed into 1 byte. :)
2323

2424
// Bit array of currently pressed keys
25-
uint8_t pressed[BIT_ARRAY_SZ(256)];
25+
uint8_t pressed[BITMAP_SIZE(256)];
2626
} KBD_STATE;
2727

2828
#endif /* endif MOLTAROS_KBD_HAL_H */

src/kernel/include/kernel/mem.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#ifndef MOLTAROS_MEM_H
2+
#define MOLTAROS_MEM_H
3+
4+
#include <stddef.h>
5+
#include <stdint.h>
6+
7+
extern uint32_t PAGE_SIZE;
8+
9+
void mem_init();
10+
11+
void *kmalloc(size_t sz);
12+
13+
void kfree(void *ptr);
14+
15+
#endif /* endif MOLTAROS_MEM_H */

src/kernel/include/kernel/multiboot.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ static bool multiboot_RAM(struct multiboot_info *mbinfo, uint32_t *start, uint32
6767
// Check if there is a memory mapping available
6868
if (mbinfo->flags & (1 << 6)) {
6969
KLOG("MMAP Entries: %d", mbinfo->mmap_length / 24);
70-
struct multiboot_mmap *mmap = (struct multiboot_mmap *) mbinfo->mmap_addr;
71-
while((uint32_t) mmap < mbinfo->mmap_addr + mbinfo->mmap_length) {
70+
struct multiboot_mmap *mmap = (struct multiboot_mmap *) (0xC0000000 + mbinfo->mmap_addr);
71+
while((uint32_t) mmap - 0xC0000000 < (mbinfo->mmap_addr + mbinfo->mmap_length)) {
7272
KLOG("MMAP Entry: {Type: %s, Start: %x, Length: %x}", mmap->type == MULTIBOOT_MMAP_RAM ? "RAM" : "RESERVED", mmap->start_low, mmap->length_low);
7373
// Jackpot... (The OS is 32-bit, so there is no upper currently.)
7474
if (mmap->type == MULTIBOOT_MMAP_RAM) {

src/kernel/include/mm/alloc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ typedef uint32_t vaddr_t;
1010

1111
void alloc_init();
1212

13-
paddr_t alloc(size_t size, uint32_t *phys_addr, bool aligned);
13+
vaddr_t alloc_block();
1414

1515
#endif

src/kernel/include/mm/heap.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,12 @@ struct memheap {
3232
memblock_t *head;
3333
};
3434

35-
void *kmalloc(size_t size);
35+
void memheap_init(memheap_t *heap);
3636

37-
void kfree(void *ptr);
37+
void memheap_add_block(memheap_t *heap, uintptr_t addr, uint32_t size, uint32_t block_size);
38+
39+
void *memheap_alloc(memheap_t *heap, uint32_t size);
40+
41+
void memheap_free(memheap_t *heap, void *ptr);
3842

3943
#endif /* endif MOLTAROS_MEMORY_MANAGEMENT_H */

src/kernel/kernel/kernel.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <include/kernel/multiboot.h>
1515
#include <include/kernel/logger.h>
1616
#include <include/mm/page.h>
17+
#include <include/kernel/mem.h>
1718
#include <include/helpers.h>
1819

1920
uint32_t PHYSICAL_MEMORY_END;
@@ -81,8 +82,16 @@ static void kernel_keyboard_test() {
8182
void kernel_main(void) {
8283
// KLOG("Initializing Keyboard...");
8384
// keyboard_init();
84-
kernel_clock_test();
85+
// kernel_clock_test();
8586
// KLOG("Initiating Keyboard Test...");
8687
// kernel_keyboard_test();
87-
88+
KLOG("Initializing Heap...");
89+
mem_init();
90+
KLOG("Allocating memory...");
91+
char *str = kmalloc(3);
92+
KLOG("Writing to memory...");
93+
str[0] = 'H';
94+
str[1] = 'i';
95+
str[2] = '\0';
96+
KLOG("String: %s", str);
8897
}

src/kernel/kernel/mem.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include <include/kernel/mem.h>
2+
#include <include/kernel/logger.h>
3+
#include <include/mm/heap.h>
4+
#include <include/mm/alloc.h>
5+
6+
static memheap_t kheap = {0};
7+
8+
static void more_memory() {
9+
memheap_add_block(&kheap, alloc_block(), PAGE_SIZE, 16);
10+
}
11+
12+
void mem_init() {
13+
// Initialize modules we depend on
14+
memheap_init(&kheap);
15+
alloc_init();
16+
17+
// Allocate the first chunk of memory for the kernel heap
18+
more_memory();
19+
}
20+
21+
void *kmalloc(size_t sz) {
22+
// Validate request
23+
if (sz > PAGE_SIZE) {
24+
KPANIC("Bad Allocation Size... Max: %x, Attempt: %x", PAGE_SIZE, sz);
25+
}
26+
27+
// Check allocation of heap and add more if need be
28+
void *data = memheap_alloc(&kheap, sz);
29+
if (!data) {
30+
more_memory();
31+
data = memheap_alloc(&kheap, sz);
32+
}
33+
34+
return data;
35+
}
36+
37+
void kfree(void *ptr) {
38+
memheap_free(&kheap, ptr);
39+
}

src/kernel/mm/alloc.c

Lines changed: 100 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,120 @@
11
#include <include/mm/alloc.h>
2+
#include <include/kernel/logger.h>
3+
#include <include/helpers.h>
24
#include <string.h>
35
#include <stdint.h>
46

7+
const uint32_t PAGE_SIZE = 4 * 1024 * 1024;
8+
const uint32_t NUM_FRAMES = 1024;
9+
static const uint32_t PRESENT = 0x1;
10+
static const uint32_t READ_WRITE = 0x2;
11+
static const uint32_t PAGE_MB = 1 << 7;
12+
13+
// Maximum number of frames is 1024 / 32 = 32, so -1 is a valid error number.
14+
static const uint32_t PAGE_ERR = (uint32_t) -1;
15+
516
// The current physical memory offset we are allocating in memory. This is a very simple allocator
617
// and as such only allocates memory, and never frees it, and so this only ever increases.
7-
uint32_t ALLOC_PHYSICAL_ADDRESS_OFFSET;
8-
9-
static const uint32_t PAGE_ALIGNED = 0xFFFFF000;
10-
static const uint32_t STACK_SIZE = 16 * 1024 * 1024;
18+
static uint32_t physical_address_offset;
19+
static uint32_t *page_directory;
20+
static uint32_t alloc_bitmap[NUM_FRAMES / 32];
1121

1222
extern uint32_t PHYSICAL_MEMORY_START;
1323
extern uint32_t PHYSICAL_MEMORY_END;
1424

25+
static uint32_t index_of(uint32_t frame) {
26+
return frame / 32;
27+
}
28+
29+
static uint32_t first_free_frame() {
30+
// For each bitmapped frame entry
31+
for(uint32_t i = 0; i < index_of(NUM_FRAMES); i++) {
32+
// If all bits are set, then there is nothing here for us
33+
if (alloc_bitmap[i] != 0xFFFFFFFF) {
34+
// We know that at least one bit is free, find it
35+
for (uint32_t j = 0; j < 32; j++) {
36+
uint32_t bit = 0x1 << j;
37+
// If the bit to test for is unset, we found our entry
38+
if (!(alloc_bitmap[i] & bit)) {
39+
return i * 32 + j;
40+
}
41+
}
42+
}
43+
}
44+
45+
return PAGE_ERR;
46+
}
47+
48+
static void debug_pd(uint32_t idx) {
49+
uint32_t cr3;
50+
asm volatile ("mov %%cr3, %0" : "=r" (cr3));
51+
uint32_t *pd = (uint32_t *) (cr3 + 0xC0000000);
52+
uint32_t pde = pd[idx];
53+
54+
uint32_t frame_addr = (pde & 0xFFFFF000);
55+
bool present = pde & PRESENT;
56+
bool rw = pde & READ_WRITE;
57+
bool sz = pde & PAGE_MB;
58+
59+
KLOG("PDE #%d: addr:%x,present:%d,rw:%d,sz:%d", idx, frame_addr, present, rw, sz);
60+
}
61+
1562
void alloc_init() {
16-
ALLOC_PHYSICAL_ADDRESS_OFFSET = PHYSICAL_MEMORY_START + STACK_SIZE;
63+
// Zero necessary fields
64+
physical_address_offset = 0;
65+
memset(alloc_bitmap, 0, index_of(NUM_FRAMES) * sizeof(uint32_t));
66+
67+
// The kernel directory set in page directory neds to get set
68+
BITMAP_SET(alloc_bitmap, 0);
69+
70+
71+
// Obtain the bootstrap page directory stored in CR3 register.
72+
uint32_t cr3;
73+
asm volatile ("mov %%cr3, %0" : "=r" (cr3));
74+
page_directory = (uint32_t *) (cr3 + 0xC0000000);
75+
KLOG("Address of Page Directory: %x", cr3);
1776
}
1877

19-
paddr_t alloc(size_t size, uint32_t *phys_addr, bool aligned) {
20-
// If we need to align it, we need to ensure the pointer is on a 4KB boundary
21-
if (aligned && (ALLOC_PHYSICAL_ADDRESS_OFFSET & ~PAGE_ALIGNED)) {
22-
ALLOC_PHYSICAL_ADDRESS_OFFSET &= PAGE_ALIGNED;
23-
ALLOC_PHYSICAL_ADDRESS_OFFSET += 0x1000;
78+
vaddr_t alloc_block() {
79+
// Obtain the first free frame by cycling through all possible frames for one without it's PRESENT bit set.
80+
bool found = false;
81+
for (int i = 0; i < 1024; i++) {
82+
uint32_t idx = (physical_address_offset / PAGE_SIZE) % NUM_FRAMES;
83+
if (!(page_directory[idx] & PRESENT)) {
84+
uint32_t frame_idx = first_free_frame();
85+
KLOG("Allocation: PDE #%d, Index: %d, Physical Address: %x, Virtual Address: %x", idx, frame_idx, frame_idx * PAGE_SIZE, physical_address_offset);
86+
87+
// Out of Memory
88+
if (frame_idx == PAGE_ERR) {
89+
KPANIC("Could not find a free physical address!");
90+
}
91+
92+
// Claim the frame
93+
BITMAP_SET(alloc_bitmap, frame_idx);
94+
95+
// Mark frame as present and invalidate for TLB
96+
page_directory[idx] = (frame_idx * PAGE_SIZE) | PAGE_MB | PRESENT | READ_WRITE;
97+
asm volatile ("invlpg (%0)" :: "b" (physical_address_offset) : "memory");
98+
99+
100+
debug_pd(idx);
101+
// Exit early
102+
found = true;
103+
break;
104+
}
105+
106+
physical_address_offset += PAGE_SIZE;
24107
}
25108

26-
// If the user wants the actual physical address...
27-
if (phys_addr) {
28-
*phys_addr = ALLOC_PHYSICAL_ADDRESS_OFFSET;
109+
// Out of Memory
110+
if (!found) {
111+
KPANIC("Could not find a free virtual address!");
29112
}
30113

31-
uint32_t retval = ALLOC_PHYSICAL_ADDRESS_OFFSET;
32-
ALLOC_PHYSICAL_ADDRESS_OFFSET += size;
114+
uint32_t retval = physical_address_offset;
115+
physical_address_offset += PAGE_SIZE;
33116

34-
// Clear the memory allocated for the user
35-
memset((void *) retval, 0, size);
117+
// Clear the memory allocated frame for the user
118+
memset((void *) retval, 0, PAGE_SIZE);
36119
return retval;
37120
}

src/kernel/mm/heap.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// Idenitifies that the bitmap's entry is free to use
66
static const uint8_t FREE = 0;
77

8-
static void memheap_init(memheap_t *heap) {
8+
void memheap_init(memheap_t *heap) {
99
heap->head = NULL;
1010
}
1111

@@ -27,7 +27,7 @@ static uint8_t generate_identifier(uint8_t x, uint8_t y) {
2727
return z;
2828
}
2929

30-
static void memheap_add_block(memheap_t *heap, uintptr_t addr, uint32_t size, uint32_t block_size) {
30+
void memheap_add_block(memheap_t *heap, uintptr_t addr, uint32_t size, uint32_t block_size) {
3131
// We reserve the first bytes of memory (pointed to by 'addr') for the superblock itself. Since the superblock
3232
// takes up space, we must make the appropriate corrections to the size.
3333
memblock_t *sblock = (memblock_t *) addr;
@@ -52,7 +52,7 @@ static void memheap_add_block(memheap_t *heap, uintptr_t addr, uint32_t size, ui
5252
sblock->used = block_count;
5353
}
5454

55-
static void *memheap_alloc(memheap_t *heap, uint32_t size) {
55+
void *memheap_alloc(memheap_t *heap, uint32_t size) {
5656
// For each superblock...
5757
for (memblock_t *sblock = heap->head; sblock; sblock = sblock->next) {
5858
// If this superblock is large enough
@@ -101,7 +101,7 @@ static void *memheap_alloc(memheap_t *heap, uint32_t size) {
101101
return NULL;
102102
}
103103

104-
static void memheap_free(memheap_t *heap, void *ptr) {
104+
void memheap_free(memheap_t *heap, void *ptr) {
105105
// For each superblock...
106106
for (memblock_t *sblock = heap->head; sblock; sblock = sblock->next) {
107107
// If the pointer is within the superblock

0 commit comments

Comments
 (0)