From 412c3bacc0762c9283771f5133f01c1e7721b9bf Mon Sep 17 00:00:00 2001 From: Karina Date: Fri, 26 Dec 2025 07:18:02 +0400 Subject: [PATCH] feat: pmm --- CMakeLists.txt | 2 +- bootloader/src/main.c | 2 +- kernel/CMakeLists.txt | 1 + kernel/include/math.h | 9 +++- kernel/include/panic.h | 3 +- kernel/include/pmm.h | 19 +++++++ kernel/include/types.h | 28 +++++++++++ kernel/linker.ld | 4 ++ kernel/src/kmain.c | 18 +++++-- kernel/src/modules/console.c | 35 ++++++++++--- kernel/src/modules/interrupts.c | 2 +- kernel/src/modules/panic.c | 72 +++++++++++++++++--------- kernel/src/modules/pmm.c | 89 +++++++++++++++++++++++++++++++++ 13 files changed, 243 insertions(+), 41 deletions(-) create mode 100644 kernel/include/pmm.h create mode 100644 kernel/src/modules/pmm.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 412739c..18c03bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ add_subdirectory(kernel) find_program(MCOPY_EXE mcopy) find_program(MKFS_EXE mkfs.fat) find_program(QEMU_EXE qemu-system-x86_64) -set(OVMF_PATH "/usr/share/qemu/ovmf-x86_64.bin" CACHE FILEPATH "Path to OVMF bios") +set(OVMF_PATH "/usr/share/edk2/ovmf/OVMF_CODE.fd" CACHE FILEPATH "Path to OVMF bios") if(MCOPY_EXE AND MKFS_EXE) set(IMG_FILE "${CMAKE_BINARY_DIR}/termOS.img") diff --git a/bootloader/src/main.c b/bootloader/src/main.c index 77d1b2b..34181aa 100644 --- a/bootloader/src/main.c +++ b/bootloader/src/main.c @@ -44,7 +44,7 @@ int main() uint64_t kernel_size = file_info->FileSize; uintn_t kernel_size_read = (uintn_t)kernel_size; efi_physical_address_t kernel_addr = 0x100000; - uintn_t pages = (kernel_size + 0xFFF) / 0x1000; + uintn_t pages = (kernel_size + 0xFFF) / 0x1000 + 32; status = gBS->AllocatePages(AllocateAddress, EfiLoaderData, pages, &kernel_addr); if (EFI_ERROR(status)) { diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index ddf01bc..1379a0a 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -15,6 +15,7 @@ add_executable(kernel src/modules/gdt.c src/modules/idt.c src/modules/interrupts.c + src/modules/pmm.c src/modules/memory.c src/modules/serial.c src/modules/console.c diff --git a/kernel/include/math.h b/kernel/include/math.h index 3cd2eea..382868e 100644 --- a/kernel/include/math.h +++ b/kernel/include/math.h @@ -1,9 +1,16 @@ #include "types.h" +#define MAX(a, b) ({ \ + auto _a = (a); \ + auto _b = (b); \ + _a > _b ? _a : _b; \ +}) + static inline int abs(int n) { return (n < 0) ? -n : n; } static inline i64 i64abs(i64 n) { return (n < 0) ? -n : n; -} \ No newline at end of file +} + diff --git a/kernel/include/panic.h b/kernel/include/panic.h index e3f8835..92f8d10 100644 --- a/kernel/include/panic.h +++ b/kernel/include/panic.h @@ -3,7 +3,8 @@ #define PANIC_H #include "types.h" -__attribute__((noreturn)) void panic(Registers *regs); +__attribute__((noreturn)) void panic_exception(Registers *regs); +__attribute__((noreturn)) void panic(const char* msg); extern const char* exception_messages[]; diff --git a/kernel/include/pmm.h b/kernel/include/pmm.h new file mode 100644 index 0000000..79ef573 --- /dev/null +++ b/kernel/include/pmm.h @@ -0,0 +1,19 @@ +#ifndef PMM_H +#define PMM_H + +#include "types.h" +#include "../common/bootinfo.h" + +#define PAGE_SIZE 4096 +#define BLOCKS_PER_BYTE 8 + +#define BITMAP_BYTE_INDEX(addr) ((addr / PAGE_SIZE) / BLOCKS_PER_BYTE) +#define BITMAP_BIT_OFFSET(addr) ((addr / PAGE_SIZE) % BLOCKS_PER_BYTE) +#define BITMAP_TEST(bitmap, addr) (bitmap[BITMAP_BYTE_INDEX(addr)] & (1 << BITMAP_BIT_OFFSET(addr))) +#define BITMAP_SET(bitmap, addr) (bitmap[BITMAP_BYTE_INDEX(addr)] |= (1 << BITMAP_BIT_OFFSET(addr))) +#define BITMAP_UNSET(bitmap, addr) (bitmap[BITMAP_BYTE_INDEX(addr)] &= ~(1 << BITMAP_BIT_OFFSET(addr))) + +void pmm_init(BI_MemoryMap mmap); +u8* get_bitmap(); + +#endif \ No newline at end of file diff --git a/kernel/include/types.h b/kernel/include/types.h index 78d9e66..9e557a0 100644 --- a/kernel/include/types.h +++ b/kernel/include/types.h @@ -20,4 +20,32 @@ typedef struct { u64 rip, cs, rflags, rsp, ss; // Pushed by CPU } Registers; +typedef struct { + u32 type; + u32 pad; + u64 physical_start; + u64 virtual_start; + u64 number_of_pages; + u64 attribute; +} __attribute__((packed)) efi_memory_descriptor_k; + +typedef enum { + EfiReservedMemoryType, + EfiLoaderCode, + EfiLoaderData, + EfiBootServicesCode, + EfiBootServicesData, + EfiRuntimeServicesCode, + EfiRuntimeServicesData, + EfiConventionalMemory, + EfiUnusableMemory, + EfiACPIReclaimMemory, + EfiACPIMemoryNVS, + EfiMemoryMappedIO, + EfiMemoryMappedIOPortSpace, + EfiPalCode, + EfiPersistentMemory, + EfiMaxMemoryType +} EFI_MEMORY_TYPE; + #endif \ No newline at end of file diff --git a/kernel/linker.ld b/kernel/linker.ld index 3b5b372..e765b06 100644 --- a/kernel/linker.ld +++ b/kernel/linker.ld @@ -3,6 +3,7 @@ ENTRY(_start) SECTIONS { . = 0x100000; + _kernel_start = .; .text : { *(.text.entry) @@ -26,6 +27,9 @@ SECTIONS *(.stack) } + . = ALIGN(4096); + _kernel_end = .; + /DISCARD/ : { *(.note*) *(.comment*) diff --git a/kernel/src/kmain.c b/kernel/src/kmain.c index 9d5f541..8d88dbc 100644 --- a/kernel/src/kmain.c +++ b/kernel/src/kmain.c @@ -1,20 +1,25 @@ #include "../../common/bootinfo.h" -#include "console.h" #include "types.h" #include "shitgui.h" #include "serial.h" +#include "console.h" #include "panic.h" // IWYU pragma: keep -#include "../data/logo.h" #include "gdt.h" #include "idt.h" +#include "pmm.h" + +#include "../data/logo.h" + int rectest(int a) { volatile int b = a + 1; return rectest(b * 2); } +extern u64 _kernel_end; + void kmain(Bootinfo* info) { u32 *fb = (u32*)info->framebuffer.base; if (!fb) return; @@ -42,8 +47,13 @@ void kmain(Bootinfo* info) { kprintf("Welcome to ^ptermOS^0!!!\n"); SG_Point text_normal_point = {0, 120}; // not nice to hardcode nums like that but we have what we have console_set_cursor_pos(&text_normal_point); + + pmm_init(info->mem); - kprintf("MemoryMap located at ^g%x^0; \nMemory map size is ^g%x^0\n", (u64)info->mem.map, (u64)info->mem.map_size); + kprintf("MemoryMap located at ^g%x^0 (^r%X^0); \ + \nMemory map size is ^g%x^0\ + \nKernel ends at ^g%x^0\ + \nBITMAP located at ^g%x^0", (u64)info->mem.map, (u64)info->mem.map,(u64)info->mem.map_size, &_kernel_end, get_bitmap()); // kfetch(); @@ -52,7 +62,7 @@ void kmain(Bootinfo* info) { // rectest(0); - // __asm__("ud2"); // panic :( + // __asm__("ud2"); // panic :( while (1) { __asm__("hlt"); } } \ No newline at end of file diff --git a/kernel/src/modules/console.c b/kernel/src/modules/console.c index 04dd7db..5dfd40c 100644 --- a/kernel/src/modules/console.c +++ b/kernel/src/modules/console.c @@ -7,8 +7,13 @@ #include #define COLOR_RED 0xFF5555 +#define COLOR_VERYRED 0xFF0000 #define COLOR_GREEN 0x08bf39 +#define COLOR_VERYGREEN 0x00FF00 +#define COLOR_TURQUOISE 0x5effaf #define COLOR_BLUE 0x5555FF +#define COLOR_VERYBLUE 0x0000FF +#define COLOR_LIGHTBLUE 0x3890e8 #define COLOR_YELLOW 0xFFFF55 #define COLOR_CYAN 0x55FFFF #define COLOR_MAGENTA 0xFF55FF @@ -98,24 +103,29 @@ static void print_dec(const i64 n) { } } -static void print_hex(u64 u) { +static void print_hex(u64 u, u8 padding) { console_putc('0'); console_putc('x'); if (u == 0) { console_putc('0'); + for (i32 i = 1; i < padding; i++) console_putc('0'); return; } - char buffer[16]; + char buffer[16] = {0}; i32 i = 0; - while (u > 0) { + do { i32 digit = u % 16; - if (digit < 10) { buffer[i] = digit + '0'; } - else { buffer[i] = digit - 10 + 'A'; } + if (digit < 10) buffer[i++] = digit + '0'; + else buffer[i++] = digit - 10 + 'A'; u /= 16; - i++; + } while (u > 0); + + while(i < padding) { + console_putc('0'); + padding--; } while (--i >= 0) { @@ -123,6 +133,7 @@ static void print_hex(u64 u) { } } + void kprintf(const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -149,9 +160,14 @@ void kprintf(const char *fmt, ...) { } case 'x': { u64 num = va_arg(args, u64); - print_hex(num); + print_hex(num, 0); break; } + case 'X' : { + u64 num = va_arg(args, u64); + print_hex(num, 16); + break; + } default: { console_putc(fmt[i]); break; @@ -161,8 +177,13 @@ void kprintf(const char *fmt, ...) { i++; switch (fmt[i]) { case 'r': console_set_color(COLOR_RED); break; + case 'R': console_set_color(COLOR_VERYRED); break; case 'g': console_set_color(COLOR_GREEN); break; + case 'G': console_set_color(COLOR_VERYGREEN); break; + case 't': console_set_color(COLOR_TURQUOISE); break; case 'b': console_set_color(COLOR_BLUE); break; + case 'B': console_set_color(COLOR_VERYBLUE); break; + case 'l': console_set_color(COLOR_LIGHTBLUE); break; case 'y': console_set_color(COLOR_YELLOW); break; case 'c': console_set_color(COLOR_CYAN); break; case 'm': console_set_color(COLOR_MAGENTA); break; diff --git a/kernel/src/modules/interrupts.c b/kernel/src/modules/interrupts.c index b512f4a..cb94907 100644 --- a/kernel/src/modules/interrupts.c +++ b/kernel/src/modules/interrupts.c @@ -2,5 +2,5 @@ #include "types.h" void isr_handler_c(Registers *regs) { - panic(regs); + panic_exception(regs); } \ No newline at end of file diff --git a/kernel/src/modules/panic.c b/kernel/src/modules/panic.c index 765a5d8..1b8de37 100644 --- a/kernel/src/modules/panic.c +++ b/kernel/src/modules/panic.c @@ -5,7 +5,6 @@ #include "shitgui.h" const char* fun_messages[] = { - "Ooops! All red!", "Execution finished abnormally with code: 0x_x", "It's definitely your fault.", "No more Roblox!", @@ -28,12 +27,12 @@ const char* fun_messages[] = { "Code have been eaten by Aliens", "That's all, folks!", "Raiden, answer me, Raiden, respond! Raiden?! RAIDEEEEEEEEEN!", - "Fatal error has been occurred. Your device will be terminated in 30 seconds.", + "Fatal error has been occurred.\n\t\t\t\t Your device will be terminated in 30 seconds.", "I'll be back", "Hastla la vista, baby", "Ti chego mne tut nagovoril...", - "Your access has been denied because of your region. Please, use Chultem VPN and try again later.", - "Fatal error has been occurred. Your device will be transformed into Niva in a few seconds.", + "Your access has been denied because of your region.\n\t\t\t\tPlease, use Chultem VPN and try again later.", + "Fatal error has been occurred. \n\t\t\t\tYour device will be transformed into Niva in a few seconds.", "Have you tried turning it off and on again?", "Put it in rice maybe?", "Just hit the monitor, it usually helps", @@ -82,8 +81,14 @@ const char* exception_messages[] = { "Reserved" }; -__attribute__((noreturn)) void panic(Registers *regs) { - console_clear(0xFF0000); +__attribute__((noreturn)) void die() { + while (1) { + __asm__ volatile ("cli; hlt"); + } +} + +void draw_panic_bg() { + console_clear(0x101010); console_set_color(0xFFFFFF); SG_Point p = console_get_dimensions(); @@ -97,32 +102,49 @@ __attribute__((noreturn)) void panic(Registers *regs) { u8 rand_num = shitrand() % msg_count; kprintf("\n\n"); - kprintf("\t\t\t\tKERNEL PANIC :( \n"); + kprintf("\t\t\t\t^tKERNEL PANIC^w :( \n"); kprintf("\t\t--------------------------------\n"); - kprintf("\t\t\t\t%s\n", fun_messages[rand_num]); + kprintf("\t\t\t\t^r%s^w\n", fun_messages[rand_num]); kprintf("\t\t--------------------------------\n"); - kprintf("\t\tCPU EXCEPTION: %s (%d)\n", exception_messages[regs->int_no], regs->int_no); - if (regs->err_code) kprintf("\t\tError Code: %x\n", regs->err_code); - kprintf("\t\tInstruction Pointer (RIP): %x\n", regs->rip); - kprintf("\t\tCode Segment (CS): %x\n", regs->cs); - kprintf("\t\tFlags (RFLAGS): %x\n", regs->rflags); - kprintf("\t\tStack Pointer (RSP): %x\n", regs->rsp); +} + +__attribute__((noreturn)) void panic_exception(Registers *regs) { + draw_panic_bg(); + + kprintf("\t\t^yCPU EXCEPTION^w: ^m%s^w (%d)\n", exception_messages[regs->int_no], regs->int_no); + if (regs->err_code) kprintf("\t\t^yError Code^w: %X\n", regs->err_code); + kprintf("\t\t^yInstruction Pointer^w (^yRIP^w): %X\n", regs->rip); + kprintf("\t\t^yCode Segment^w (^yCS^w): %X\n", regs->cs); + kprintf("\t\t^yFlags^w (^yRFLAGS^w): %X\n", regs->rflags); + kprintf("\t\t^yStack Pointer^w (^yRSP^w): %X\n", regs->rsp); if (regs->int_no == 14) { u64 cr2; __asm__ volatile("mov %%cr2, %0" : "=r"(cr2)); - kprintf("\t\tFaulting Address (CR2): %x\n", cr2); + kprintf("\t\t^yFaulting Address^w (^yCR2^w): %X\n", cr2); } kprintf("\t\t--------------------------------\n"); - kprintf("\t\t\t\tREGSISTERS\n"); + kprintf("\t\t\t\t^yREGSISTERS^w\n"); kprintf("\t\t--------------------------------\n"); - kprintf("\t\tRAX=%x, RBX=%x, RCX=%x, RDX=%x\n", regs->rax, regs->rbx, regs->rcx, regs->rdx); - kprintf("\t\tRSI=%x, RDI=%x, RBP=%x, R8=%x\n", regs->rsi, regs->rdi, regs->rbp, regs->r8); - kprintf("\t\tR9=%x, R10=%x, R11=%x, R12=%x\n", regs->r9, regs->r10, regs->r11, regs->r12); - kprintf("\t\tR13=%x, R14=%x, R15=%x\n", regs->r13, regs->r14, regs->r15); + kprintf("\t\t^yRAX^w=%X, ^yRBX^w=%X\n", regs->rax, regs->rbx); + kprintf("\t\t^yRCX^w=%X, ^yRDX^w=%X\n", regs->rcx, regs->rdx); + kprintf("\t\t^yRSI^w=%X, ^yRDI^w=%X\n", regs->rsi, regs->rdi); + kprintf("\t\t^yRBP^w=%X, ^yR8^w =%X\n", regs->rbp, regs->r8); + kprintf("\t\t^yR9^w =%X, ^yR10^w=%X \n", regs->r9, regs->r10); + kprintf("\t\t^yR11^w=%X, ^yR12^w=%X\n", regs->r11, regs->r12); + kprintf("\t\t^yR13^w=%X, ^yR14^w=%X\n", regs->r13, regs->r14); + kprintf("\t\t^yR15^w=%X\n",regs->r15); kprintf("\t\t--------------------------------\n"); - kprintf("\t\t\t\tSystem halted.\n"); + kprintf("\t\t\t\t^tSystem halted.^w\n"); + + die(); +} - while (1) { - __asm__ volatile ("cli; hlt"); - } -} \ No newline at end of file +__attribute__((noreturn)) void panic(const char* msg) { + draw_panic_bg(); + + kprintf("\t\t^yReason^w: %s\n", msg); + kprintf("\t\t--------------------------------\n"); + kprintf("\t\t\t\t^tSystem halted.^w\n"); + + die(); +} \ No newline at end of file diff --git a/kernel/src/modules/pmm.c b/kernel/src/modules/pmm.c new file mode 100644 index 0000000..82012e5 --- /dev/null +++ b/kernel/src/modules/pmm.c @@ -0,0 +1,89 @@ +#include "pmm.h" +#include "bootinfo.h" +#include "panic.h" +#include "types.h" +#include "memory.h" // IWYU pragma: keep // clangd is stupid af +#include "math.h" + +#define SAFE_SPACE_START_ADDR 0x100000 + +extern u64 _kernel_start; +extern u64 _kernel_end; + +u8* bitmap = nullptr; +u64 bitmap_size_g = 0; + +void pmm_init(BI_MemoryMap mmap) { + u64 descriptors_count = mmap.map_size / mmap.descriptor_size; + u64 max_physical_address = 0; + + for (u64 i = 0; i < descriptors_count; i++) { + efi_memory_descriptor_k* descriptor = (efi_memory_descriptor_k*)((u8*)mmap.map + (i * mmap.descriptor_size)); + u64 nominee = descriptor->physical_start + descriptor->number_of_pages * PAGE_SIZE; + max_physical_address = MAX(nominee, max_physical_address); + } + + u64 pages_count = max_physical_address / PAGE_SIZE; + u64 bitmap_size = (pages_count + 7) / 8; + efi_memory_descriptor_k* desc_to_save = nullptr; + + for (u64 i = 0; i < descriptors_count; i++) { + efi_memory_descriptor_k* descriptor = (efi_memory_descriptor_k*)((u8*)mmap.map + (i * mmap.descriptor_size)); + // scary + if ((descriptor->type == EfiConventionalMemory) && \ + ((descriptor->number_of_pages * PAGE_SIZE) >= bitmap_size) && \ + (descriptor->physical_start >= SAFE_SPACE_START_ADDR)) { + desc_to_save = descriptor; + break; + } + } + + if (desc_to_save == nullptr) { + panic("Not enough RAM for bitmap!"); + } + + bitmap = (u8*)desc_to_save->physical_start; + bitmap_size_g = bitmap_size; + + memset(bitmap, 0xFF, bitmap_size); + + for (u64 i = 0; i < descriptors_count; i++) { + efi_memory_descriptor_k* descriptor = (efi_memory_descriptor_k*)((u8*)mmap.map + (i * mmap.descriptor_size));// this shit will haunt my dreams + if (descriptor->type != EfiConventionalMemory) continue; + u64 start_addr = descriptor->physical_start; + u64 end_addr = start_addr + (descriptor->number_of_pages * PAGE_SIZE); + for (u64 j = start_addr; j < end_addr; j += PAGE_SIZE) BITMAP_UNSET(bitmap, j); + } + + u64 k_start = (u64)&_kernel_start; + u64 k_end = (u64)&_kernel_end; + + u64 bitmap_start = (u64)bitmap; + u64 bitmap_end = bitmap_start + bitmap_size_g; + + for (u64 i = 0; i < SAFE_SPACE_START_ADDR; i += PAGE_SIZE) BITMAP_SET(bitmap, i); // mem, that addr < 1MB is NOT safe to use on x86 + for (u64 i = k_start; i < k_end; i += PAGE_SIZE) BITMAP_SET(bitmap, i); + for (u64 i = bitmap_start; i < bitmap_end; i += PAGE_SIZE) BITMAP_SET(bitmap, i); +} + +void* pmm_alloc_page() { + for (u64 i = 0; i < bitmap_size_g; i++) { + if (bitmap[i] == 0xFF) continue; + for (u64 j = 0; j < 8; j++) { + u64 addr = (i * 8 + j) * PAGE_SIZE; + if ((bitmap[i] & (1 << j)) == 0) { + BITMAP_SET(bitmap, addr); + return (void*)addr; + } + } + } + return nullptr; +} + +void pmm_free_page(void* addr) { + BITMAP_UNSET(bitmap, (u64)addr); +} + +u8* get_bitmap() { + return bitmap; +} \ No newline at end of file