mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-21 10:40:00 +00:00
Stage 2
This commit is contained in:
2
Makefile
2
Makefile
@@ -68,6 +68,8 @@ SOURCES := \
|
||||
clks/kernel/log.c \
|
||||
clks/kernel/limine_requests.c \
|
||||
clks/kernel/tty.c \
|
||||
clks/kernel/pmm.c \
|
||||
clks/kernel/heap.c \
|
||||
clks/lib/string.c \
|
||||
clks/drivers/serial/serial.c \
|
||||
clks/drivers/video/framebuffer.c \
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
|
||||
clks_bool clks_boot_base_revision_supported(void);
|
||||
const struct limine_framebuffer *clks_boot_get_framebuffer(void);
|
||||
const struct limine_memmap_response *clks_boot_get_memmap(void);
|
||||
|
||||
#endif
|
||||
19
clks/include/clks/heap.h
Normal file
19
clks/include/clks/heap.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef CLKS_HEAP_H
|
||||
#define CLKS_HEAP_H
|
||||
|
||||
#include <clks/types.h>
|
||||
|
||||
struct clks_heap_stats {
|
||||
usize total_bytes;
|
||||
usize used_bytes;
|
||||
usize free_bytes;
|
||||
u64 alloc_count;
|
||||
u64 free_count;
|
||||
};
|
||||
|
||||
void clks_heap_init(void);
|
||||
void *clks_kmalloc(usize size);
|
||||
void clks_kfree(void *ptr);
|
||||
struct clks_heap_stats clks_heap_get_stats(void);
|
||||
|
||||
#endif
|
||||
@@ -23,6 +23,24 @@
|
||||
0xa3148604f6fab11bULL \
|
||||
}
|
||||
|
||||
#define LIMINE_MEMMAP_REQUEST \
|
||||
{ \
|
||||
LIMINE_COMMON_MAGIC, \
|
||||
LIMINE_REQUEST_MAGIC, \
|
||||
0x67cf3d9d378a806fULL, \
|
||||
0xe304acdfc50c3c62ULL \
|
||||
}
|
||||
|
||||
#define LIMINE_MEMMAP_USABLE 0ULL
|
||||
#define LIMINE_MEMMAP_RESERVED 1ULL
|
||||
#define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2ULL
|
||||
#define LIMINE_MEMMAP_ACPI_NVS 3ULL
|
||||
#define LIMINE_MEMMAP_BAD_MEMORY 4ULL
|
||||
#define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5ULL
|
||||
#define LIMINE_MEMMAP_EXECUTABLE_AND_MODULES 6ULL
|
||||
#define LIMINE_MEMMAP_FRAMEBUFFER 7ULL
|
||||
#define LIMINE_MEMMAP_RESERVED_MAPPED 8ULL
|
||||
|
||||
struct limine_framebuffer {
|
||||
void *address;
|
||||
u64 width;
|
||||
@@ -53,4 +71,22 @@ struct limine_framebuffer_request {
|
||||
struct limine_framebuffer_response *response;
|
||||
};
|
||||
|
||||
struct limine_memmap_entry {
|
||||
u64 base;
|
||||
u64 length;
|
||||
u64 type;
|
||||
};
|
||||
|
||||
struct limine_memmap_response {
|
||||
u64 revision;
|
||||
u64 entry_count;
|
||||
struct limine_memmap_entry **entries;
|
||||
};
|
||||
|
||||
struct limine_memmap_request {
|
||||
u64 id[4];
|
||||
u64 revision;
|
||||
struct limine_memmap_response *response;
|
||||
};
|
||||
|
||||
#endif
|
||||
21
clks/include/clks/pmm.h
Normal file
21
clks/include/clks/pmm.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef CLKS_PMM_H
|
||||
#define CLKS_PMM_H
|
||||
|
||||
#include <clks/limine.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_PAGE_SIZE 4096ULL
|
||||
|
||||
struct clks_pmm_stats {
|
||||
u64 managed_pages;
|
||||
u64 free_pages;
|
||||
u64 used_pages;
|
||||
u64 dropped_pages;
|
||||
};
|
||||
|
||||
void clks_pmm_init(const struct limine_memmap_response *memmap);
|
||||
u64 clks_pmm_alloc_page(void);
|
||||
void clks_pmm_free_page(u64 phys_addr);
|
||||
struct clks_pmm_stats clks_pmm_get_stats(void);
|
||||
|
||||
#endif
|
||||
176
clks/kernel/heap.c
Normal file
176
clks/kernel/heap.c
Normal file
@@ -0,0 +1,176 @@
|
||||
#include <clks/heap.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_HEAP_ARENA_SIZE (1024ULL * 1024ULL)
|
||||
#define CLKS_HEAP_ALIGN 16ULL
|
||||
#define CLKS_HEAP_MAGIC 0x434C454F4E4F534FULL
|
||||
|
||||
struct clks_heap_block {
|
||||
usize size;
|
||||
clks_bool is_free;
|
||||
struct clks_heap_block *next;
|
||||
struct clks_heap_block *prev;
|
||||
u64 magic;
|
||||
};
|
||||
|
||||
static u8 clks_heap_arena[CLKS_HEAP_ARENA_SIZE] __attribute__((aligned(16)));
|
||||
static struct clks_heap_block *clks_heap_head = CLKS_NULL;
|
||||
static clks_bool clks_heap_ready = CLKS_FALSE;
|
||||
|
||||
static usize clks_heap_used_bytes = 0;
|
||||
static u64 clks_heap_alloc_count = 0;
|
||||
static u64 clks_heap_free_count = 0;
|
||||
|
||||
static usize clks_heap_align_up(usize value) {
|
||||
return (value + (CLKS_HEAP_ALIGN - 1ULL)) & ~(CLKS_HEAP_ALIGN - 1ULL);
|
||||
}
|
||||
|
||||
static void clks_heap_split_block(struct clks_heap_block *block, usize need_size) {
|
||||
usize min_tail_size = sizeof(struct clks_heap_block) + CLKS_HEAP_ALIGN;
|
||||
|
||||
if (block->size < (need_size + min_tail_size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
u8 *new_block_addr = (u8 *)block + sizeof(struct clks_heap_block) + need_size;
|
||||
struct clks_heap_block *new_block = (struct clks_heap_block *)new_block_addr;
|
||||
|
||||
new_block->size = block->size - need_size - sizeof(struct clks_heap_block);
|
||||
new_block->is_free = CLKS_TRUE;
|
||||
new_block->next = block->next;
|
||||
new_block->prev = block;
|
||||
new_block->magic = CLKS_HEAP_MAGIC;
|
||||
|
||||
if (block->next != CLKS_NULL) {
|
||||
block->next->prev = new_block;
|
||||
}
|
||||
|
||||
block->next = new_block;
|
||||
block->size = need_size;
|
||||
}
|
||||
}
|
||||
|
||||
static void clks_heap_merge_next(struct clks_heap_block *block) {
|
||||
struct clks_heap_block *next = block->next;
|
||||
|
||||
if (next == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (next->is_free == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (next->magic != CLKS_HEAP_MAGIC) {
|
||||
return;
|
||||
}
|
||||
|
||||
block->size += sizeof(struct clks_heap_block) + next->size;
|
||||
block->next = next->next;
|
||||
|
||||
if (next->next != CLKS_NULL) {
|
||||
next->next->prev = block;
|
||||
}
|
||||
}
|
||||
|
||||
void clks_heap_init(void) {
|
||||
clks_memset(clks_heap_arena, 0, sizeof(clks_heap_arena));
|
||||
|
||||
clks_heap_head = (struct clks_heap_block *)clks_heap_arena;
|
||||
clks_heap_head->size = CLKS_HEAP_ARENA_SIZE - sizeof(struct clks_heap_block);
|
||||
clks_heap_head->is_free = CLKS_TRUE;
|
||||
clks_heap_head->next = CLKS_NULL;
|
||||
clks_heap_head->prev = CLKS_NULL;
|
||||
clks_heap_head->magic = CLKS_HEAP_MAGIC;
|
||||
|
||||
clks_heap_used_bytes = 0;
|
||||
clks_heap_alloc_count = 0;
|
||||
clks_heap_free_count = 0;
|
||||
clks_heap_ready = CLKS_TRUE;
|
||||
}
|
||||
|
||||
void *clks_kmalloc(usize size) {
|
||||
struct clks_heap_block *current;
|
||||
usize aligned_size;
|
||||
|
||||
if (clks_heap_ready == CLKS_FALSE) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
aligned_size = clks_heap_align_up(size);
|
||||
current = clks_heap_head;
|
||||
|
||||
while (current != CLKS_NULL) {
|
||||
if (current->magic != CLKS_HEAP_MAGIC) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
if (current->is_free == CLKS_TRUE && current->size >= aligned_size) {
|
||||
clks_heap_split_block(current, aligned_size);
|
||||
current->is_free = CLKS_FALSE;
|
||||
clks_heap_used_bytes += current->size;
|
||||
clks_heap_alloc_count++;
|
||||
return (void *)((u8 *)current + sizeof(struct clks_heap_block));
|
||||
}
|
||||
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
void clks_kfree(void *ptr) {
|
||||
struct clks_heap_block *block;
|
||||
|
||||
if (clks_heap_ready == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ptr == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
block = (struct clks_heap_block *)((u8 *)ptr - sizeof(struct clks_heap_block));
|
||||
|
||||
if (block->magic != CLKS_HEAP_MAGIC) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (block->is_free == CLKS_TRUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
block->is_free = CLKS_TRUE;
|
||||
|
||||
if (clks_heap_used_bytes >= block->size) {
|
||||
clks_heap_used_bytes -= block->size;
|
||||
} else {
|
||||
clks_heap_used_bytes = 0;
|
||||
}
|
||||
|
||||
clks_heap_free_count++;
|
||||
|
||||
clks_heap_merge_next(block);
|
||||
|
||||
if (block->prev != CLKS_NULL && block->prev->is_free == CLKS_TRUE) {
|
||||
clks_heap_merge_next(block->prev);
|
||||
}
|
||||
}
|
||||
|
||||
struct clks_heap_stats clks_heap_get_stats(void) {
|
||||
struct clks_heap_stats stats;
|
||||
|
||||
stats.total_bytes = CLKS_HEAP_ARENA_SIZE - sizeof(struct clks_heap_block);
|
||||
stats.used_bytes = clks_heap_used_bytes;
|
||||
stats.free_bytes = stats.total_bytes - stats.used_bytes;
|
||||
stats.alloc_count = clks_heap_alloc_count;
|
||||
stats.free_count = clks_heap_free_count;
|
||||
|
||||
return stats;
|
||||
}
|
||||
@@ -1,14 +1,20 @@
|
||||
#include <clks/boot.h>
|
||||
#include <clks/cpu.h>
|
||||
#include <clks/framebuffer.h>
|
||||
#include <clks/heap.h>
|
||||
#include <clks/kernel.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/pmm.h>
|
||||
#include <clks/serial.h>
|
||||
#include <clks/tty.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
void clks_kernel_main(void) {
|
||||
const struct limine_framebuffer *boot_fb;
|
||||
const struct limine_memmap_response *boot_memmap;
|
||||
struct clks_pmm_stats pmm_stats;
|
||||
struct clks_heap_stats heap_stats;
|
||||
void *heap_probe = CLKS_NULL;
|
||||
|
||||
clks_serial_init();
|
||||
|
||||
@@ -24,7 +30,7 @@ void clks_kernel_main(void) {
|
||||
clks_tty_init();
|
||||
}
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE1 START");
|
||||
clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE2 START");
|
||||
|
||||
if (boot_fb == CLKS_NULL) {
|
||||
clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE");
|
||||
@@ -41,6 +47,36 @@ void clks_kernel_main(void) {
|
||||
clks_log(CLKS_LOG_INFO, "ARCH", "AARCH64 ONLINE");
|
||||
#endif
|
||||
|
||||
boot_memmap = clks_boot_get_memmap();
|
||||
|
||||
if (boot_memmap == CLKS_NULL) {
|
||||
clks_log(CLKS_LOG_ERROR, "MEM", "NO LIMINE MEMMAP RESPONSE");
|
||||
clks_cpu_halt_forever();
|
||||
}
|
||||
|
||||
clks_pmm_init(boot_memmap);
|
||||
pmm_stats = clks_pmm_get_stats();
|
||||
|
||||
clks_log_hex(CLKS_LOG_INFO, "PMM", "MANAGED_PAGES", pmm_stats.managed_pages);
|
||||
clks_log_hex(CLKS_LOG_INFO, "PMM", "FREE_PAGES", pmm_stats.free_pages);
|
||||
clks_log_hex(CLKS_LOG_INFO, "PMM", "USED_PAGES", pmm_stats.used_pages);
|
||||
clks_log_hex(CLKS_LOG_INFO, "PMM", "DROPPED_PAGES", pmm_stats.dropped_pages);
|
||||
|
||||
clks_heap_init();
|
||||
heap_stats = clks_heap_get_stats();
|
||||
|
||||
clks_log_hex(CLKS_LOG_INFO, "HEAP", "TOTAL_BYTES", heap_stats.total_bytes);
|
||||
clks_log_hex(CLKS_LOG_INFO, "HEAP", "FREE_BYTES", heap_stats.free_bytes);
|
||||
|
||||
heap_probe = clks_kmalloc(128);
|
||||
|
||||
if (heap_probe == CLKS_NULL) {
|
||||
clks_log(CLKS_LOG_ERROR, "HEAP", "KMALLOC SELFTEST FAILED");
|
||||
} else {
|
||||
clks_log(CLKS_LOG_INFO, "HEAP", "KMALLOC SELFTEST OK");
|
||||
clks_kfree(heap_probe);
|
||||
}
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "TTY", "VIRTUAL TTY0 READY");
|
||||
clks_log(CLKS_LOG_DEBUG, "KERNEL", "IDLE LOOP ENTER");
|
||||
|
||||
|
||||
@@ -14,6 +14,13 @@ CLKS_USED static volatile struct limine_framebuffer_request limine_framebuffer_r
|
||||
.response = CLKS_NULL,
|
||||
};
|
||||
|
||||
CLKS_USED static volatile struct limine_memmap_request limine_memmap_request
|
||||
__attribute__((section(".limine_requests"))) = {
|
||||
.id = LIMINE_MEMMAP_REQUEST,
|
||||
.revision = 0,
|
||||
.response = CLKS_NULL,
|
||||
};
|
||||
|
||||
CLKS_USED static volatile u64 limine_requests_end[]
|
||||
__attribute__((section(".limine_requests_end"))) = LIMINE_REQUESTS_END_MARKER;
|
||||
|
||||
@@ -34,3 +41,13 @@ const struct limine_framebuffer *clks_boot_get_framebuffer(void) {
|
||||
|
||||
return request->response->framebuffers[0];
|
||||
}
|
||||
|
||||
const struct limine_memmap_response *clks_boot_get_memmap(void) {
|
||||
volatile struct limine_memmap_request *request = &limine_memmap_request;
|
||||
|
||||
if (request->response == CLKS_NULL) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
return request->response;
|
||||
}
|
||||
105
clks/kernel/pmm.c
Normal file
105
clks/kernel/pmm.c
Normal file
@@ -0,0 +1,105 @@
|
||||
#include <clks/pmm.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_PMM_MAX_TRACKED_PAGES 262144ULL
|
||||
#define CLKS_PMM_MIN_USABLE_ADDR 0x100000ULL
|
||||
|
||||
static u64 clks_pmm_free_stack[CLKS_PMM_MAX_TRACKED_PAGES];
|
||||
static u64 clks_pmm_free_top = 0;
|
||||
static u64 clks_pmm_managed_pages = 0;
|
||||
static u64 clks_pmm_dropped_pages = 0;
|
||||
|
||||
static u64 clks_align_up_u64(u64 value, u64 alignment) {
|
||||
return (value + alignment - 1ULL) & ~(alignment - 1ULL);
|
||||
}
|
||||
|
||||
static u64 clks_align_down_u64(u64 value, u64 alignment) {
|
||||
return value & ~(alignment - 1ULL);
|
||||
}
|
||||
|
||||
void clks_pmm_init(const struct limine_memmap_response *memmap) {
|
||||
u64 i;
|
||||
|
||||
clks_pmm_free_top = 0;
|
||||
clks_pmm_managed_pages = 0;
|
||||
clks_pmm_dropped_pages = 0;
|
||||
clks_memset(clks_pmm_free_stack, 0, sizeof(clks_pmm_free_stack));
|
||||
|
||||
if (memmap == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < memmap->entry_count; i++) {
|
||||
const struct limine_memmap_entry *entry = memmap->entries[i];
|
||||
u64 start;
|
||||
u64 end;
|
||||
u64 addr;
|
||||
|
||||
if (entry == CLKS_NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry->type != LIMINE_MEMMAP_USABLE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
start = clks_align_up_u64(entry->base, CLKS_PAGE_SIZE);
|
||||
end = clks_align_down_u64(entry->base + entry->length, CLKS_PAGE_SIZE);
|
||||
|
||||
if (end <= start) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (addr = start; addr < end; addr += CLKS_PAGE_SIZE) {
|
||||
if (addr < CLKS_PMM_MIN_USABLE_ADDR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_pmm_free_top < CLKS_PMM_MAX_TRACKED_PAGES) {
|
||||
clks_pmm_free_stack[clks_pmm_free_top] = addr;
|
||||
clks_pmm_free_top++;
|
||||
clks_pmm_managed_pages++;
|
||||
} else {
|
||||
clks_pmm_dropped_pages++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u64 clks_pmm_alloc_page(void) {
|
||||
if (clks_pmm_free_top == 0) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
clks_pmm_free_top--;
|
||||
return clks_pmm_free_stack[clks_pmm_free_top];
|
||||
}
|
||||
|
||||
void clks_pmm_free_page(u64 phys_addr) {
|
||||
if (phys_addr == 0ULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((phys_addr & (CLKS_PAGE_SIZE - 1ULL)) != 0ULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_pmm_free_top >= CLKS_PMM_MAX_TRACKED_PAGES) {
|
||||
return;
|
||||
}
|
||||
|
||||
clks_pmm_free_stack[clks_pmm_free_top] = phys_addr;
|
||||
clks_pmm_free_top++;
|
||||
}
|
||||
|
||||
struct clks_pmm_stats clks_pmm_get_stats(void) {
|
||||
struct clks_pmm_stats stats;
|
||||
|
||||
stats.managed_pages = clks_pmm_managed_pages;
|
||||
stats.free_pages = clks_pmm_free_top;
|
||||
stats.used_pages = clks_pmm_managed_pages - clks_pmm_free_top;
|
||||
stats.dropped_pages = clks_pmm_dropped_pages;
|
||||
|
||||
return stats;
|
||||
}
|
||||
35
docs/stage2.md
Normal file
35
docs/stage2.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# CLeonOS Stage2
|
||||
|
||||
## Stage Goal
|
||||
- Introduce foundational memory management for CLKS.
|
||||
- Initialize physical memory manager (PMM) from Limine memmap.
|
||||
- Add kernel heap allocator (`clks_kmalloc`/`clks_kfree`) without external libc.
|
||||
- Emit memory statistics via kernel log during boot.
|
||||
|
||||
## Acceptance Criteria
|
||||
- Kernel receives valid Limine memmap response.
|
||||
- PMM initializes and prints managed/free/used/dropped page counts.
|
||||
- Heap initializes and prints total/free bytes.
|
||||
- `clks_kmalloc` self-test allocates and frees successfully.
|
||||
- Kernel still reaches idle loop without panic.
|
||||
|
||||
## Build Targets
|
||||
- `make setup`
|
||||
- `make iso`
|
||||
- `make run`
|
||||
- `make debug`
|
||||
|
||||
## QEMU Command
|
||||
- `qemu-system-x86_64 -M q35 -m 1024M -cdrom build/CLeonOS-x86_64.iso -serial stdio`
|
||||
|
||||
## Common Bugs and Debugging
|
||||
- `NO LIMINE MEMMAP RESPONSE`:
|
||||
- Check Limine protocol entry in `configs/limine.conf` and ensure `protocol: limine` is used.
|
||||
- PMM managed pages are 0:
|
||||
- Validate `LIMINE_MEMMAP_REQUEST` ID and section placement in `limine_requests.c`.
|
||||
- Heap self-test failed:
|
||||
- Inspect `heap.c` block split/merge logic and verify allocator init was called.
|
||||
- Limine panic about ELF segment permissions:
|
||||
- Ensure linker sections are page-aligned and segment permissions do not share pages.
|
||||
- Limine artifacts missing during ISO packaging:
|
||||
- Verify `make setup` completed and `limine/bin/*` files exist.
|
||||
Reference in New Issue
Block a user