From 1944184eb7136dd4cb955c6a05165c9f2f931489 Mon Sep 17 00:00:00 2001 From: Han Akbe Date: Sun, 26 Oct 2025 16:46:02 +0500 Subject: [PATCH 1/3] feat(paging): Recursive paging - add recursive paging - write vmem layout - reformat code - refactor types - add _Noreturn to panic - adjust march compile option --- cfg/config.cmake | 2 +- kernel/core/panic.c | 2 +- kernel/include/core/panic.h | 2 +- kernel/include/memory/map.h | 10 ++- kernel/include/memory/pfa.h | 4 +- kernel/include/memory/virtual/layout.h | 28 ++++++++ kernel/include/memory/virtual/paging.h | 2 +- kernel/init/main.c | 12 ++-- kernel/memory/map.c | 22 +++--- kernel/memory/pfa.c | 21 ++++-- kernel/memory/virtual/paging.c | 98 +++++++++++++++++++++----- 11 files changed, 151 insertions(+), 52 deletions(-) create mode 100644 kernel/include/memory/virtual/layout.h diff --git a/cfg/config.cmake b/cfg/config.cmake index c4fede0..6682200 100644 --- a/cfg/config.cmake +++ b/cfg/config.cmake @@ -5,7 +5,7 @@ set(CMAKE_C_STANDARD_REQUIRED ON) add_compile_options( -m32 - -march=i386 + -march=i486 -O2 -g -fno-builtin diff --git a/kernel/core/panic.c b/kernel/core/panic.c index 862956d..318e362 100644 --- a/kernel/core/panic.c +++ b/kernel/core/panic.c @@ -9,7 +9,7 @@ struct stackframe { uint32_t eip; }; -void panic(const char *s) { +_Noreturn void panic(const char *s) { uint32_t ebp, esp; __asm__ volatile("mov %%ebp, %0\n" "mov %%esp, %1\n" diff --git a/kernel/include/core/panic.h b/kernel/include/core/panic.h index c5fe393..46dc19e 100644 --- a/kernel/include/core/panic.h +++ b/kernel/include/core/panic.h @@ -1,6 +1,6 @@ #ifndef PANIC_H #define PANIC_H -void panic(const char *); +_Noreturn void panic(const char *); #endif diff --git a/kernel/include/memory/map.h b/kernel/include/memory/map.h index 6d1c853..66581af 100644 --- a/kernel/include/memory/map.h +++ b/kernel/include/memory/map.h @@ -1,12 +1,12 @@ #ifndef MEMORY_MAP_H #define MEMORY_MAP_H -#define MEMORY_MAP_MAX_SIZE 64 - #include #include #include +#define MEMORY_MAP_MAX_SIZE 64 + typedef enum { MEMORY_FREE, MEMORY_BUSY } memory_t; typedef struct { @@ -19,11 +19,9 @@ void *get_kernel_end(); void mem_map_init(); -void *mem_alloc_size(uint64_t size); - -void *mem_alloc(uint64_t *size); +uintptr_t mem_alloc_size(uint64_t size); -void *mem_alloc_largest(uint64_t *size); +uintptr_t mem_alloc(uint64_t *size); bool mem_has_free(); diff --git a/kernel/include/memory/pfa.h b/kernel/include/memory/pfa.h index 01e56d2..b5c5760 100644 --- a/kernel/include/memory/pfa.h +++ b/kernel/include/memory/pfa.h @@ -5,8 +5,8 @@ void pfa_init(); -uint32_t pf_alloc(); +uintptr_t pf_alloc(); -void pf_free(uint32_t idx); +void pf_free(uintptr_t addr); #endif diff --git a/kernel/include/memory/virtual/layout.h b/kernel/include/memory/virtual/layout.h new file mode 100644 index 0000000..f14c9a7 --- /dev/null +++ b/kernel/include/memory/virtual/layout.h @@ -0,0 +1,28 @@ +#ifndef MEMORY_VIRTUAL_LAYOUT_H +#define MEMORY_VIRTUAL_LAYOUT_H + +#define MEM_VIRT_LAYOUT_NULL_PAGE_START 0x00000000 +#define MEM_VIRT_LAYOUT_NULL_PAGE_END 0x00000FFF + +#define MEM_VIRT_LAYOUT_USERLAND_START 0x00001000 +#define MEM_VIRT_LAYOUT_USERLAND_END 0xBFFFFFFF + +#define MEM_VIRT_LAYOUT_KERNEL_LOW_START 0xC0000000 +#define MEM_VIRT_LAYOUT_KERNEL_LOW_END 0xC03FFFFF + +#define MEM_VIRT_LAYOUT_KERNEL_HEAP_START 0xC0400000 +#define MEM_VIRT_LAYOUT_KERNEL_HEAP_END 0xC13FFFFF + +#define MEM_VIRT_LAYOUT_KERNEL_STACK_GUARD_START 0xC1400000 +#define MEM_VIRT_LAYOUT_KERNEL_STACK_GUARD_END 0xC1400FFF + +#define MEM_VIRT_LAYOUT_KERNEL_STACK_START 0xC1401000 +#define MEM_VIRT_LAYOUT_KERNEL_STACK_END 0xC1402FFF + +#define MEM_VIRT_LAYOUT_RESERVED_START 0xC1403000 +#define MEM_VIRT_LAYOUT_RESERVED_END 0xFFBFFFFF + +#define MEM_VIRT_LAYOUT_PAGE_MAPPING_START 0xFFC00000 +#define MEM_VIRT_LAYOUT_PAGE_MAPPING_END 0xFFFFFFFF + +#endif diff --git a/kernel/include/memory/virtual/paging.h b/kernel/include/memory/virtual/paging.h index f447171..0b79436 100644 --- a/kernel/include/memory/virtual/paging.h +++ b/kernel/include/memory/virtual/paging.h @@ -1,7 +1,7 @@ #ifndef PAGING_H #define PAGING_H -#define PAGING_FIRST_4MIB_MAPPING_ADDR 0xC0000000 +void *paging_addr_phys_to_virt(uintptr_t phys); void paging_init(); diff --git a/kernel/init/main.c b/kernel/init/main.c index 8f70230..ccdbd4a 100644 --- a/kernel/init/main.c +++ b/kernel/init/main.c @@ -28,7 +28,8 @@ int main(void) { printf("Memory map provided by BIOS:\n"); for (size_t i = 0; i < size; i++) { printf("%d) ", i); - printf("0x%x-0x%x ", (uint32_t) e820_map[i].address, (uint32_t) (e820_map[i].address + e820_map[i].length - 1)); + printf("0x%x-0x%x ", (uint32_t) e820_map[i].address, + (uint32_t) (e820_map[i].address + e820_map[i].length - 1)); printf("Type: 0x%x, ", e820_map[i].type); printf("ACPI3 attr: 0x%x", e820_map[i].acpi3_attributes); printf("\n"); @@ -48,7 +49,8 @@ int main(void) { printf("Memory map:\n"); for (size_t i = 0; i < size; i++) { printf("%d) ", i); - printf("0x%x-0x%x ", (uint32_t) memory_map[i].base, (uint32_t) (memory_map[i].base + memory_map[i].length - 1)); + printf("0x%x-0x%x ", (uint32_t) memory_map[i].base, + (uint32_t) (memory_map[i].base + memory_map[i].length - 1)); switch (memory_map[i].type) { case MEMORY_FREE: printf(" FREE"); @@ -67,15 +69,15 @@ int main(void) { { printf("\x1b[33m"); printf("PFA test:\n"); - uint32_t ptrs[100]; + uintptr_t ptrs[100]; printf("Allocating...\n"); - for (size_t i = 0; i < 100; i++) { + for (size_t i = 0; i < sizeof(ptrs) / sizeof(*ptrs); i++) { ptrs[i] = pf_alloc(); } printf("Freeing...\n"); - for (size_t i = 0; i < 100; i++) { + for (size_t i = 0; i < sizeof(ptrs) / sizeof(*ptrs); i++) { pf_free(ptrs[i]); } diff --git a/kernel/memory/map.c b/kernel/memory/map.c index c056e10..3f1e0ef 100644 --- a/kernel/memory/map.c +++ b/kernel/memory/map.c @@ -1,14 +1,14 @@ #include #include #include -#include +#include #include #include extern uint32_t __kernel_end; static void *get_kernel_physical_end() { - return (void *) ((size_t) &__kernel_end - PAGING_FIRST_4MIB_MAPPING_ADDR); + return (void *) ((uintptr_t) &__kernel_end - MEM_VIRT_LAYOUT_KERNEL_LOW_START); } void *get_kernel_end() { @@ -30,7 +30,7 @@ static void append(const memory_block_t *memory_block) { insert(memory_block, map_size); } -static void delete(size_t idx) { +static void delete(const size_t idx) { memmove(&map[idx], &map[idx + 1], (--map_size - idx) * sizeof(memory_block_t)); } @@ -78,32 +78,32 @@ void mem_map_init() { delete (0); } -static void *mem_alloc_common(const size_t *target) { +static uintptr_t mem_alloc_common(const size_t *target) { map[*target].type = MEMORY_BUSY; - return (void *) (size_t) map[*target].base; + return (uintptr_t) map[*target].base; } -void *mem_alloc_size(const uint64_t size) { +uintptr_t mem_alloc_size(const uint64_t size) { size_t target = 0; while (map[target].type != MEMORY_FREE || map[target].length < size) // first fit target++; - void *ptr = mem_alloc_common(&target); + const uintptr_t base = mem_alloc_common(&target); if (split(map[target].base + size, target)) map[target + 1].type = MEMORY_FREE; - return ptr; + return base; } -void *mem_alloc(uint64_t *size) { +uintptr_t mem_alloc(uint64_t *size) { size_t target = 0; while (map[target].type != MEMORY_FREE) target++; - void *ptr = mem_alloc_common(&target); + const uintptr_t base = mem_alloc_common(&target); *size = map[target].length; - return ptr; + return base; } bool mem_has_free() { diff --git a/kernel/memory/pfa.c b/kernel/memory/pfa.c index 6d68267..5959ccc 100644 --- a/kernel/memory/pfa.c +++ b/kernel/memory/pfa.c @@ -17,14 +17,22 @@ static size_t map_size = 0; static uint32_t *bitmap; // 0 - free, 1 - busy static uint32_t last_alloc = 0; +static uintptr_t idx_to_addr(const uint32_t idx) { + return (uintptr_t) idx << 12; +} + +static uint32_t addr_to_idx(const uintptr_t addr) { + return (uint32_t) addr >> 12; +} + void pfa_init() { - bitmap = mem_alloc_size(BITMAP_SIZE * sizeof(uint32_t)) + PAGING_FIRST_4MIB_MAPPING_ADDR; + bitmap = paging_addr_phys_to_virt(mem_alloc_size(BITMAP_SIZE * sizeof(uint32_t))); for (size_t i = 0; i < BITMAP_SIZE; i++) bitmap[i] = 0; while (mem_has_free()) { uint64_t length; - uint64_t base = (size_t) mem_alloc(&length); + uint64_t base = mem_alloc(&length); if (base > 0xFFFFFFFF) break; @@ -89,20 +97,21 @@ static uint32_t pf_alloc_general(const uint32_t start, const uint32_t end, bool return 0; } -uint32_t pf_alloc() { +uintptr_t pf_alloc() { bool found; uint32_t idx = pf_alloc_general(last_alloc, BITMAP_SIZE * sizeof(uint32_t), &found); if (found) - return idx; + return idx_to_addr(idx); idx = pf_alloc_general(0, last_alloc, &found); if (found) - return idx; + return idx_to_addr(idx); panic("PFA: Ran out of page frames"); } -void pf_free(const uint32_t idx) { +void pf_free(const uintptr_t addr) { + const uint32_t idx = addr_to_idx(addr); if (!is_usable(idx << 12)) panic("PFA: Attempt to free reserved memory"); diff --git a/kernel/memory/virtual/paging.c b/kernel/memory/virtual/paging.c index 2fb01ec..aab1342 100644 --- a/kernel/memory/virtual/paging.c +++ b/kernel/memory/virtual/paging.c @@ -1,11 +1,13 @@ +#include #include +#include #include #include #include +#include -#define PAGE_DIRECTORY_SIZE (0x1000 / sizeof(uint32_t)) -#define PAGE_TABLE_SIZE (0x1000 / sizeof(uint32_t)) -#define PAGE_SIZE 0x1000 +#define PAGE_DIRECTORY_SIZE 0x1000 +#define PAGE_TABLE_SIZE 0x1000 #define PAGING_ATTR_PRESENT 0x00000001 #define PAGING_ATTR_READ_WRITE 0x00000002 @@ -13,27 +15,87 @@ #define PAGING_ATTR_DEFAULT (PAGING_ATTR_PRESENT | PAGING_ATTR_READ_WRITE) #define PAGING_ATTR_EMPTY 0x00000000 -static uint32_t *page_directory; -static uint32_t *first_4mib_table; +// Recursive paging +#define PAGE_TABLES_BASE MEM_VIRT_LAYOUT_PAGE_MAPPING_START +#define PAGE_DIRECTORY_IDX 0x3FF +#define PAGE_DIRECTORY_BASE (PAGE_TABLES_BASE + PAGE_DIRECTORY_IDX * PAGE_TABLE_SIZE) -static void *idx_to_ptr(const uint32_t idx) { - return (void *) (idx << 12); +static void load_cr3(const uint32_t page_directory_addr) { + __asm__ volatile("mov %0, %%cr3" : : "r"(page_directory_addr)); } -void paging_init() { - page_directory = idx_to_ptr(pf_alloc()); - for (size_t i = 0; i < PAGE_DIRECTORY_SIZE; i++) { - page_directory[i] = PAGING_ATTR_EMPTY; +static void invlpg(const uint32_t addr) { + __asm__ volatile("invlpg %0" : : "m"(addr)); +} + +static void calc_idxes(const uintptr_t addr, size_t *pd_idx, size_t *pt_idx) { + const size_t idx = (size_t) addr >> 0xC; + *pd_idx = idx >> 0xA; + *pt_idx = idx & 0x3FF; +} + +static void *ptr_for_pde(const size_t pd_idx) { + return (void *) (PAGE_DIRECTORY_BASE + pd_idx * sizeof(uint32_t)); +} + +static void *ptr_for_pt(const size_t pd_idx) { + return (void *) (PAGE_TABLES_BASE + pd_idx * PAGE_TABLE_SIZE); +} + +static void *ptr_for_pte(const size_t pd_idx, const size_t pt_idx) { + return (void *) (PAGE_TABLES_BASE + pd_idx * PAGE_TABLE_SIZE + pt_idx * sizeof(uint32_t)); +} + +static void ensure_pt(const size_t pd_idx) { + uint32_t *pde = ptr_for_pde(pd_idx); + if (*pde & PAGING_ATTR_PRESENT) { + return; } - // Page first 4MiB to high addr - first_4mib_table = idx_to_ptr(pf_alloc()); - for (size_t i = 0; i < PAGE_DIRECTORY_SIZE; i++) { - first_4mib_table[i] = i << 12 | PAGING_ATTR_DEFAULT; + const uintptr_t pt_phys = pf_alloc(); + *pde = pt_phys | PAGING_ATTR_DEFAULT; + + void *pt = ptr_for_pt(pd_idx); + memset(pt, PAGING_ATTR_EMPTY, PAGE_TABLE_SIZE); +} + +static void map_page(uintptr_t phys, uintptr_t virt) { + phys &= 0xFFFFF000; + virt &= 0xFFFFF000; + + size_t pd_idx; + size_t pt_idx; + calc_idxes(virt, &pd_idx, &pt_idx); + + ensure_pt(pd_idx); + + uint32_t *pte = ptr_for_pte(pd_idx, pt_idx); + *pte = phys | PAGING_ATTR_DEFAULT; + invlpg(virt); +} + +void *paging_addr_phys_to_virt(const uintptr_t phys) { + if (phys > MEM_VIRT_LAYOUT_KERNEL_LOW_END - MEM_VIRT_LAYOUT_KERNEL_LOW_START) { + panic("Paging: tried to convert the physical address to virtual, which is out of the low 4 MiB range"); } - page_directory[(PAGING_FIRST_4MIB_MAPPING_ADDR >> 20) / sizeof(uint32_t)] = - ((uint32_t) first_4mib_table) | PAGING_ATTR_DEFAULT; + return (void *) (phys + MEM_VIRT_LAYOUT_KERNEL_LOW_START); +} + +void paging_init() { + const uintptr_t pd_phys = pf_alloc(); + uint32_t *pd = paging_addr_phys_to_virt(pd_phys); + + memset(pd, PAGING_ATTR_EMPTY, PAGE_DIRECTORY_SIZE); + pd[PAGE_DIRECTORY_IDX] = pd_phys | PAGING_ATTR_DEFAULT; + + const uintptr_t low_pt_phys = pf_alloc(); + uint32_t *low_pt = paging_addr_phys_to_virt(low_pt_phys); + + for (unsigned i = 0; i < PAGE_TABLE_SIZE / sizeof(uint32_t); i++) { + low_pt[i] = (i << 0xC) | PAGING_ATTR_DEFAULT; + } + pd[(MEM_VIRT_LAYOUT_KERNEL_LOW_START >> 0x16)] = low_pt_phys | PAGING_ATTR_DEFAULT; - __asm__ volatile("mov %0, %%cr3\n" : : "r"(page_directory)); + load_cr3(pd_phys); } From 1b429cea5625d7119d384b7d941d81ff1c5b13ab Mon Sep 17 00:00:00 2001 From: Han Akbe Date: Sun, 26 Oct 2025 17:07:30 +0500 Subject: [PATCH 2/3] feat(vmem_layout): Stack --- kernel/include/memory/virtual/layout.h | 3 ++ kernel/init/main.c | 66 ++++++++++++++------------ kernel/memory/virtual/paging.c | 5 ++ 3 files changed, 44 insertions(+), 30 deletions(-) diff --git a/kernel/include/memory/virtual/layout.h b/kernel/include/memory/virtual/layout.h index f14c9a7..e56d957 100644 --- a/kernel/include/memory/virtual/layout.h +++ b/kernel/include/memory/virtual/layout.h @@ -25,4 +25,7 @@ #define MEM_VIRT_LAYOUT_PAGE_MAPPING_START 0xFFC00000 #define MEM_VIRT_LAYOUT_PAGE_MAPPING_END 0xFFFFFFFF +// It is defined like this to prevent stack corruption +#define mem_virt_layout_setup_stack() __asm__ volatile("mov %0, %%esp" : : "r"(MEM_VIRT_LAYOUT_KERNEL_STACK_END)); + #endif diff --git a/kernel/init/main.c b/kernel/init/main.c index ccdbd4a..a2ecc11 100644 --- a/kernel/init/main.c +++ b/kernel/init/main.c @@ -6,12 +6,45 @@ #include #include #include +#include #include #include #include #include -int main(void) { +_Noreturn void _main() { + { + printf("\x1b[33m"); + printf("PFA test:\n"); + uintptr_t ptrs[100]; + + printf("Allocating...\n"); + for (size_t i = 0; i < sizeof(ptrs) / sizeof(*ptrs); i++) { + ptrs[i] = pf_alloc(); + } + + printf("Freeing...\n"); + for (size_t i = 0; i < sizeof(ptrs) / sizeof(*ptrs); i++) { + pf_free(ptrs[i]); + } + + printf("\x1b[0m"); + } + + printf("Initializing keyboard...\n"); + keyboard_init(); + + printf("\nWelcome to PRosBSD v.%s!\n\n", VERSION_STRING); + printf("\033[34m * Source Code: \033[0mhttps://github.com/prosdev-org/PRosBSD\n\n"); + + printf("\033[1;32m~$\033[0m "); + + for (;;) { + putchar(getchar()); + } +} + +int main() { vga_tty_clear(); printf("Initializing GDT...\n"); @@ -66,33 +99,6 @@ int main(void) { printf("Initializing Paging...\n"); paging_init(); - { - printf("\x1b[33m"); - printf("PFA test:\n"); - uintptr_t ptrs[100]; - - printf("Allocating...\n"); - for (size_t i = 0; i < sizeof(ptrs) / sizeof(*ptrs); i++) { - ptrs[i] = pf_alloc(); - } - - printf("Freeing...\n"); - for (size_t i = 0; i < sizeof(ptrs) / sizeof(*ptrs); i++) { - pf_free(ptrs[i]); - } - - printf("\x1b[0m"); - } - - printf("Initializing keyboard...\n"); - keyboard_init(); - - printf("\nWelcome to PRosBSD v.%s!\n\n", VERSION_STRING); - printf("\033[34m * Source Code: \033[0mhttps://github.com/prosdev-org/PRosBSD\n\n"); - - printf("\033[1;32m~$\033[0m "); - - for (;;) { - putchar(getchar()); - } + mem_virt_layout_setup_stack(); + _main(); } diff --git a/kernel/memory/virtual/paging.c b/kernel/memory/virtual/paging.c index aab1342..9312f69 100644 --- a/kernel/memory/virtual/paging.c +++ b/kernel/memory/virtual/paging.c @@ -98,4 +98,9 @@ void paging_init() { pd[(MEM_VIRT_LAYOUT_KERNEL_LOW_START >> 0x16)] = low_pt_phys | PAGING_ATTR_DEFAULT; load_cr3(pd_phys); + + // Setting up page frames for stack + for (uintptr_t addr = MEM_VIRT_LAYOUT_KERNEL_STACK_START; addr < MEM_VIRT_LAYOUT_KERNEL_STACK_END; addr += 0x1000) { + map_page(pf_alloc(), addr); + } } From d9f58853a500c70206bc9215ba9fba85338af2b0 Mon Sep 17 00:00:00 2001 From: Han Akbe Date: Sun, 26 Oct 2025 17:15:04 +0500 Subject: [PATCH 3/3] fix(vmem_layout): Align stack by 16 byte boundary --- kernel/include/memory/virtual/layout.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/include/memory/virtual/layout.h b/kernel/include/memory/virtual/layout.h index e56d957..46ff48e 100644 --- a/kernel/include/memory/virtual/layout.h +++ b/kernel/include/memory/virtual/layout.h @@ -17,7 +17,7 @@ #define MEM_VIRT_LAYOUT_KERNEL_STACK_GUARD_END 0xC1400FFF #define MEM_VIRT_LAYOUT_KERNEL_STACK_START 0xC1401000 -#define MEM_VIRT_LAYOUT_KERNEL_STACK_END 0xC1402FFF +#define MEM_VIRT_LAYOUT_KERNEL_STACK_END 0xC1402FF0 #define MEM_VIRT_LAYOUT_RESERVED_START 0xC1403000 #define MEM_VIRT_LAYOUT_RESERVED_END 0xFFBFFFFF