diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 5990f8f..bfa74ae 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -21,7 +21,7 @@ jobs: run: | sudo apt-get update sudo apt-get install -y \ - meson \ + python3-pip \ nasm \ xorriso \ grub-pc-bin \ @@ -30,6 +30,7 @@ jobs: mtools \ lld \ llvm \ + pip3 install meson>=1.4.0 - name: Compile & Link run: | diff --git a/.gitignore b/.gitignore index 7220fe0..a6e036c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ isodir .idea Meson-Build Makefile -CMakeLists.txt *build* target .venv diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7aebb5f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,340 @@ +cmake_minimum_required(VERSION 3.20) +project(voidframe VERSION 0.0.2 LANGUAGES C CXX ASM_NASM) +enable_language(ASM_NASM) +# ============================================================================ +# Tool Dependencies +# ============================================================================ +set(CMAKE_C_COMPILER clang) +set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_LINKER ld.lld) +set(CMAKE_ASM_NASM_COMPILER nasm) + +find_program(LLVM_OBJDUMP llvm-objdump) +find_program(GRUB_MKRESCUE grub-mkrescue) +find_program(QEMU_IMG qemu-img) +find_program(MKFS_FAT mkfs.fat) +find_program(MKFS_EXT2 mkfs.ext2) +find_program(QEMU_SYSTEM_X86_64 qemu-system-x86_64) + +# ============================================================================ +# Build Configuration +# ============================================================================ +option(EXCLUDE_EXTRA_OBJECTS "Exclude extra objects from the build" OFF) +option(AUTOMATIC_POST "Run POST automatically on boot" OFF) +option(DEBUG_SYMBOLS "Enable debug symbols" ON) +option(STACK_PROTECTION "Enable stack protection" ON) + +# ============================================================================ +# Compiler Flags +# ============================================================================ +add_compile_options(-m64 -O2 -fno-omit-frame-pointer -finline-functions -foptimize-sibling-calls -nostdinc -nostdlib -fno-builtin -ffreestanding -mno-red-zone -mserialize -fPIE -fPIC -mcmodel=kernel -fcf-protection=full -fvisibility=hidden) + +if(STACK_PROTECTION) + add_compile_options(-fstack-protector-strong -D_FORTIFY_SOURCE=2) +endif() + +if(DEBUG_SYMBOLS) + add_compile_options(-g -DDEBUG) +endif() + +set(CMAKE_CXX_FLAGS_INIT "${CMAKE_C_FLAGS_INIT} -fno-exceptions -fno-rtti -fno-threadsafe-statics") +set(CMAKE_ASM_NASM_FLAGS_INIT " -f elf64") + +# ============================================================================ +# VoidFrame Configuration Flags +# ============================================================================ +add_compile_definitions( + VF_CONFIG_ENABLE_XHCI + VF_CONFIG_ENABLE_VIRTIO + VF_CONFIG_ENABLE_ISA + VF_CONFIG_ENABLE_LPT + VF_CONFIG_ENABLE_PCI + VF_CONFIG_ENABLE_PS2 + VF_CONFIG_ENABLE_IDE + VF_CONFIG_ENABLE_VFCOMPOSITOR + VF_CONFIG_ENABLE_AHCI + VF_CONFIG_ENABLE_GENERIC_SOUND + VF_CONFIG_RTC_CENTURY + VF_CONFIG_LOAD_MB_MODULES + VF_CONFIG_ENFORCE_MEMORY_PROTECTION + VF_CONFIG_VM_HOST + VF_CONFIG_SNOOZE_ON_BOOT + VF_CONFIG_PROCINFO_CREATE_DEFAULT + VF_CONFIG_USE_VFSHELL + VF_CONFIG_USE_DYNAMOX + VF_CONFIG_USE_ASTRA + VF_CONFIG_USE_CERBERUS + VF_CONFIG_CERBERUS_STACK_PROTECTION + VF_CONFIG_SCHED_MLFQ +) + +if(EXCLUDE_EXTRA_OBJECTS) + add_compile_definitions(VF_CONFIG_EXCLUDE_EXTRA_OBJECTS) +endif() + +if(AUTOMATIC_POST) + add_compile_definitions(VF_CONFIG_AUTOMATIC_POST) +endif() + +set(CMAKE_ASM_NASM_FLAGS "${CMAKE_ASM_NASM_FLAGS} -DVF_CONFIG_VESA_FB") + +# ============================================================================ +# Source Files Organization +# ============================================================================ +set(ASM_SOURCES + arch/x86_64/asm/pxs.asm + arch/x86_64/idt/IdtLoad.asm + arch/x86_64/gdt/GdtTssFlush.asm + arch/x86_64/interrupts/Interrupts.asm + arch/x86_64/syscall/SyscallEntry.asm + include/Switch.asm +) + +set(KERNEL_CORE_SOURCES + kernel/core/Kernel.c + kernel/core/Panic.c + kernel/core/Compositor.c + kernel/core/InitRD.c +) + +set(SCHED_SOURCES + kernel/sched/MLFQ.c +) + +set(KERNEL_ETC_SOURCES + kernel/etc/Shell.c + kernel/etc/Console.c + kernel/etc/Format.c + kernel/etc/VBEConsole.c + kernel/etc/Editor.c + kernel/etc/StringOps.c + kernel/etc/POST.c +) + +set(ATOMIC_IPC_SOURCES + kernel/atomic/Atomics.c + kernel/ipc/Ipc.c +) + +set(EXECF_SOURCES + kernel/execf/elf/ELFloader.c + kernel/execf/pe/PEloader.c + kernel/execf/aout/AoutLoader.c + kernel/execf/ExecLoader.c +) + +set(MM_SOURCES + mm/PMem.c + mm/MemOps.c + mm/KernelHeap.c + mm/VMem.c + mm/StackGuard.c + mm/MemPool.c + mm/trace/StackTrace.c + mm/security/Cerberus.c + mm/PageFaultHandler.c +) + +set(FS_SOURCES + fs/VFRFS.c + fs/FAT/FAT1x.c + fs/EXT/Ext2.c + fs/Iso9660.c + fs/VFS.c + fs/BlockDevice.c + fs/FileSystem.c + fs/MBR.c +) + +set(DRIVER_SOURCES + drivers/APIC.c + drivers/TSC.c + drivers/ACPI.c + drivers/Serial.c + drivers/PS2.c + drivers/Ide.c + drivers/Vesa.c + drivers/PCI/PCI.c + drivers/RTC/Rtc.c + drivers/ethernet/realtek/RTL8139.c + drivers/ethernet/intel/E1000.c + drivers/ethernet/interface/Ip.c + drivers/ethernet/interface/Arp.c + drivers/ethernet/interface/Icmp.c + drivers/ethernet/Network.c + drivers/xHCI/xHCI.c + drivers/ISA/ISA.c + drivers/sound/SB16.c + drivers/sound/Generic.c + drivers/storage/AHCI.c + drivers/LPT/LPT.c + drivers/virtio/VirtioBlk.c + drivers/vmware/SVGAII.c +) + +set(ARCH_SOURCES + arch/x86_64/idt/Idt.c + arch/x86_64/gdt/Gdt.c + arch/x86_64/interrupts/Interrupts.c + arch/x86_64/syscall/Syscall.c + arch/x86_64/features/x64.c +) + +set(INCLUDE_SOURCES + include/ctype.c + include/Font.c +) + +set(CPP_SOURCES + ports/6502/6502.cpp +) + +set(C_SOURCES + ${KERNEL_CORE_SOURCES} + ${SCHED_SOURCES} + ${KERNEL_ETC_SOURCES} + ${ATOMIC_IPC_SOURCES} + ${EXECF_SOURCES} + ${MM_SOURCES} + ${FS_SOURCES} + ${DRIVER_SOURCES} + ${ARCH_SOURCES} + ${INCLUDE_SOURCES} +) + +set(OBJ_SOURCES) +if(NOT EXCLUDE_EXTRA_OBJECTS) + set(OBJ_SOURCES + kernel/etc/objects/splash1.o + kernel/etc/objects/panic.o + ) +endif() + +# ============================================================================ +# Build Include Directories +# ============================================================================ +include_directories( + . + include + kernel/atomic + kernel/core + kernel/ipc + kernel/sched + kernel/etc + kernel/execf + kernel/execf/elf + kernel/execf/pe + kernel/execf/aout + drivers + drivers/PCI + drivers/ethernet + drivers/ethernet/intel + drivers/ethernet/realtek + drivers/ethernet/interface + drivers/RTC + drivers/xHCI + drivers/ISA + drivers/sound + drivers/storage + drivers/virtio + drivers/vmware + fs + fs/FAT + fs/EXT + mm + mm/trace + mm/security + ports/6502 + ports + arch/x86_64/features + arch/x86_64/gdt + arch/x86_64/idt + arch/x86_64/interrupts + arch/x86_64/syscall +) + +# ============================================================================ +# Kernel Linking +# ============================================================================ +add_executable(voidframe.krnl + ${C_SOURCES} + ${CPP_SOURCES} + ${ASM_SOURCES} + ${OBJ_SOURCES} +) + +set_target_properties(voidframe.krnl PROPERTIES + OUTPUT_NAME "voidframe.krnl" + LINK_FLAGS "-T ${CMAKE_CURRENT_SOURCE_DIR}/voidframe.ld -melf_x86_64" +) + +# ============================================================================ +# ISO Creation +# ============================================================================ +add_custom_command( + OUTPUT VoidFrame.iso + COMMAND sh -c "cd ${CMAKE_CURRENT_BINARY_DIR} && mkdir -p isodir/boot/grub isodir/EFI/BOOT isodir/bin && cp $ isodir/boot/voidframe.krnl && cp ${CMAKE_CURRENT_SOURCE_DIR}/grub.cfg isodir/boot/grub/grub.cfg && cp ${CMAKE_CURRENT_SOURCE_DIR}/grub.cfg isodir/EFI/BOOT/grub.cfg && ${GRUB_MKRESCUE} --modules=\"multiboot2 part_msdos part_gpt fat\" --fonts=\"\" --locales=\"\" -o VoidFrame.iso isodir" + DEPENDS voidframe.krnl + COMMENT "Building VoidFrame.iso" +) + +add_custom_target(iso ALL DEPENDS VoidFrame.iso) + +# ============================================================================ +# Run Targets +# ============================================================================ +add_custom_target(run + COMMAND ${QEMU_SYSTEM_X86_64} + -cpu max + -vga vmware + -enable-kvm + -cdrom ${CMAKE_CURRENT_BINARY_DIR}/VoidFrame.iso + -debugcon file:bootstrap.log + -serial stdio + -no-reboot -no-shutdown + -m 4G + -drive file=VoidFrameDisk.img,if=ide + -drive file=SataDisk.img,if=none,id=sata0 + -device ahci,id=ahci + -device ide-hd,drive=sata0,bus=ahci.0 + -boot d + -device rtl8139 + -device e1000 + -device nec-usb-xhci,id=xhci + -device ich9-intel-hda + -usb -device usb-tablet + -audio pa,id=myaudio + -device sb16,iobase=0x220,irq=5,dma=1,dma16=5 + -parallel file:printer.out + -drive file=VirtioDisk.img,format=raw,id=virtio_disk,if=none + -device virtio-blk-pci,drive=virtio_disk,disable-legacy=on + DEPENDS iso +) + +add_custom_target(runmin + COMMAND ${QEMU_SYSTEM_X86_64} + -cdrom ${CMAKE_CURRENT_BINARY_DIR}/VoidFrame.iso + -nographic + -debugcon file:bootstrap.log + -serial file:serial.log + -no-reboot -no-shutdown + -m 4G + -boot d + DEPENDS iso +) + +add_custom_target(img + COMMAND sh -c "${QEMU_IMG} create -f qcow2 VoidFrameDisk.img 16G && ${MKFS_EXT2} VoidFrameDisk.img" + COMMENT "Creating disk images" +) + +add_custom_target(extra-img + COMMAND sh -c "${QEMU_IMG} create -f raw VirtioDisk.img 128M && ${MKFS_FAT} -F 16 VirtioDisk.img && ${QEMU_IMG} create -f raw SataDisk.img 128M && ${MKFS_FAT} -F 16 SataDisk.img" + COMMENT "Creating extra disk images" +) + +add_custom_target(dump + COMMAND sh -c "${LLVM_OBJDUMP} -d $ > voidframe.dump && ${LLVM_OBJDUMP} -t $ > voidframe.sym" + DEPENDS voidframe.krnl + COMMENT "Generating disassembly and symbols" +) diff --git a/arch/x86_64/asm/pxs.asm b/arch/x86_64/asm/pxs.asm index a2f93cb..1daa3ca 100644 --- a/arch/x86_64/asm/pxs.asm +++ b/arch/x86_64/asm/pxs.asm @@ -6,6 +6,7 @@ header_start: ; checksum = -(magic + arch + length) dd -(0xE85250D6 + 0 + (header_end - header_start)) +%ifdef VF_CONFIG_VESA_FB ; Framebuffer tag - request specific graphics mode align 8 framebuffer_tag_start: @@ -24,6 +25,7 @@ vbe_tag_start: dw 0 ; flags dd vbe_tag_end - vbe_tag_start ; size vbe_tag_end: +%endif ; End tag - required align 8 @@ -94,7 +96,7 @@ start: mov cr4, eax debug_print '3' ; PAE Enabled - ; Setup page tables + ; Setup initial 4GB page tables (we'll expand this later in C) ; Zero out the tables first mov edi, pml4_table mov ecx, 4096 * 6 ; 6 pages to clear (PML4, PDP, PD1, PD2, PD3, PD4) @@ -108,7 +110,7 @@ start: mov cr3, eax debug_print '4' ; CR3 Loaded - ; Map the first 4GB of memory + ; Map the first 4GB of memory (minimum for boot) ; PML4[0] -> PDP Table mov edi, pml4_table lea eax, [pdp_table + 3] ; Address of PDP table + Present, R/W flags @@ -184,6 +186,185 @@ start: jmp gdt64.code:long_mode +; Parse multiboot memory map and find highest available address +; Returns: highest_phys_addr in [highest_phys_addr_low:highest_phys_addr_high] +parse_memory_map: + pusha + + ; Get multiboot info pointer + mov esi, [multiboot_info] + + ; Skip multiboot header (8 bytes: total_size + reserved) + add esi, 8 + + ; Initialize highest address to 0 + mov dword [highest_phys_addr_low], 0 + mov dword [highest_phys_addr_high], 0 + +.find_mmap_tag: + ; Check if we've reached end tag (type = 0) + cmp dword [esi], 0 + je .parse_done + + ; Check if this is memory map tag (type = 6) + cmp dword [esi], 6 + je .process_mmap + + ; Move to next tag (aligned to 8 bytes) + mov eax, [esi + 4] ; Get tag size + add eax, 7 ; Round up to 8-byte boundary + and eax, ~7 + add esi, eax + jmp .find_mmap_tag + +.process_mmap: + ; ESI points to memory map tag + mov ecx, [esi + 4] ; Get tag size + sub ecx, 16 ; Subtract tag header size + mov edx, [esi + 12] ; Get entry size + add esi, 16 ; Skip to first entry + +.process_entry: + cmp ecx, 0 + jle .parse_done + + ; Check if this is available memory (type = 1) + cmp dword [esi + 16], 1 + jne .next_entry + + ; Calculate end address (base + length) + mov eax, [esi] ; base_addr_low + mov ebx, [esi + 4] ; base_addr_high + add eax, [esi + 8] ; + length_low + adc ebx, [esi + 12] ; + length_high (with carry) + + ; Compare with current highest address + cmp ebx, [highest_phys_addr_high] + ja .update_highest + jb .next_entry + + ; High parts equal, compare low parts + cmp eax, [highest_phys_addr_low] + jbe .next_entry + +.update_highest: + mov [highest_phys_addr_low], eax + mov [highest_phys_addr_high], ebx + +.next_entry: + add esi, edx ; Move to next entry + sub ecx, edx ; Decrease remaining size + jmp .process_entry + +.parse_done: + popa + ret + +; Setup dynamic paging based on detected physical memory +setup_dynamic_paging: + pusha + + ; Calculate how much memory we need to map (round up to 1GB boundary) + mov eax, [highest_phys_addr_low] + mov ebx, [highest_phys_addr_high] + + ; For simplicity, cap at 64GB to avoid too many page tables + cmp ebx, 0x10 ; 64GB = 0x1000000000 + jb .size_ok + mov ebx, 0x10 + mov eax, 0 + +.size_ok: + ; Round up to 1GB boundary (0x40000000) + add eax, 0x3FFFFFFF + adc ebx, 0 + and eax, 0xC0000000 ; Clear lower 30 bits + + ; Store the total size to map + mov [memory_to_map_low], eax + mov [memory_to_map_high], ebx + + ; Calculate number of 1GB regions needed + ; Each PDP entry covers 1GB, so we need (total_size / 1GB) entries + push edx + mov edx, ebx ; High part + mov eax, eax ; Low part already in eax + mov ecx, 0x40000000 ; 1GB + div ecx ; EAX = number of 1GB regions + pop edx + + ; Cap at 512 entries (512GB max) + cmp eax, 512 + jbe .pdp_entries_ok + mov eax, 512 + +.pdp_entries_ok: + mov [num_pdp_entries], eax + + ; Zero out initial page tables + mov edi, pml4_table + mov ecx, 4096 * 6 ; Clear PML4, PDP, and 4 initial PD tables + xor eax, eax + rep stosb + debug_print 'Z' ; Page Tables Zeroed + + ; Set CR3 to PML4 + mov eax, pml4_table + mov cr3, eax + debug_print '4' ; CR3 Loaded + + ; Setup PML4[0] -> PDP Table + mov edi, pml4_table + lea eax, [pdp_table + 3] + mov [edi], eax + + ; Setup PDP entries and corresponding PD tables + mov edi, pdp_table + mov esi, pd_table ; Start with first PD table + mov ecx, [num_pdp_entries] + +.setup_pdp_loop: + push ecx + + ; Link PDP entry to PD table + lea eax, [esi + 3] ; PD table address + flags + mov [edi], eax + + ; Fill the PD table with 2MB pages + push edi + push esi + mov edi, esi ; EDI = current PD table + mov ebx, 512 ; 512 entries per PD table + + ; Calculate starting physical address for this PD table + mov eax, [num_pdp_entries] + sub eax, ecx ; Current PDP index + push edx + mov edx, 0x40000000 ; 1GB per PDP entry + mul edx ; EAX = starting physical address + pop edx + or eax, 0x83 ; Add Present + Writable + Large page flags + +.fill_pd_loop: + mov [edi], eax ; Store PDE + add edi, 8 ; Next PDE + add eax, 0x200000 ; Next 2MB physical address + dec ebx + jnz .fill_pd_loop + + pop esi + pop edi + + ; Move to next PDP entry and PD table + add edi, 8 ; Next PDP entry + add esi, 4096 ; Next PD table + + pop ecx + loop .setup_pdp_loop + + popa + ret + check_and_enable_features: ; Test for CPUID capability (ID bit in EFLAGS) pushfd @@ -304,6 +485,8 @@ pd_table: resb 4096 pd_table2: resb 4096 pd_table3: resb 4096 pd_table4: resb 4096 +; Reserve space for up to 64 additional PD tables (64GB support) +pd_tables_extended: resb (4096 * 60) align 16 stack_bottom: resb 16384 ; 16KB stack @@ -311,4 +494,11 @@ stack_top: section .data multiboot_magic: dd 0 -multiboot_info: dq 0 ; The info pointer can be a 64-bit address, use dq \ No newline at end of file +multiboot_info: dq 0 ; The info pointer can be a 64-bit address, use dq + +; Dynamic memory mapping variables +highest_phys_addr_low: dd 0 +highest_phys_addr_high: dd 0 +memory_to_map_low: dd 0 +memory_to_map_high: dd 0 +num_pdp_entries: dd 0 \ No newline at end of file diff --git a/kernel/core/Kernel.c b/kernel/core/Kernel.c index 69f7bd7..2f6e1b5 100644 --- a/kernel/core/Kernel.c +++ b/kernel/core/Kernel.c @@ -404,6 +404,14 @@ void PXS1(const uint32_t info) { PrintKernel("System: Initializing memory...\n"); MemoryInit(g_multiboot_info_addr); PrintKernelSuccess("System: Memory initialized\n"); + + // Update dynamic identity mapping size based on detected memory + extern uint64_t g_identity_map_size; + extern uint64_t total_pages; + g_identity_map_size = total_pages * PAGE_SIZE; + PrintKernel("System: Identity mapping size set to "); + PrintKernelInt(g_identity_map_size / (1024 * 1024)); + PrintKernel("MB\n"); // Create new PML4 with memory validation (ensure identity-mapped physical page) void* pml4_phys = NULL; @@ -639,8 +647,6 @@ static InitResultT PXS2(void) { PrintKernel("Info: Initializing PC Speaker...\n"); PCSpkr_Init(); PrintKernelSuccess("System: PC Speaker initialized\n"); - - PrintKernel("Info: Initializing AHCI Driver...\n"); #endif #ifdef VF_CONFIG_ENABLE_VMWARE_SVGA_II diff --git a/meson.build b/meson.build index 4d3020f..4f34ba2 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,6 @@ project('voidframe', 'c', 'cpp', version : '0.0.2-development3', + meson_version : '>= 1.4.0', default_options : [ 'c_std=c11', 'cpp_std=c++17', @@ -113,6 +114,12 @@ vf_config_optional = [ # '-DVF_CONFIG_PANIC_OVERRIDE', ] +vf_config_asm = [ + '-DVF_CONFIG_VESA_FB', +] + +asm_flags += vf_config_asm + vf_config_flags = vf_config_base if exclude_extra_objects vf_config_flags += ['-DVF_CONFIG_EXCLUDE_EXTRA_OBJECTS'] @@ -322,7 +329,7 @@ foreach asm_file : asm_sources asm_objects += asm_obj endforeach -# Function to compile C files +# Function to compile C files c_objects = [] foreach c_file : c_sources obj_name = '@0@_c.o'.format(c_file.full_path().split('/')[-1].split('.')[0]) diff --git a/mm/PMem.c b/mm/PMem.c index b6a5524..d71b7c4 100644 --- a/mm/PMem.c +++ b/mm/PMem.c @@ -5,12 +5,13 @@ #include "Multiboot2.h" #include "Spinlock.h" -// Max 4GB memory for now (1M pages) +// Support up to 128GB memory with dynamic bitmap allocation #define MAX_PAGE_BUFFER_OVERHEAD (1024 * 1024) // 1MB -#define MAX_PAGES ((4ULL * 1024 * 1024 * 1024 / PAGE_SIZE) + MAX_PAGE_BUFFER_OVERHEAD) +#define MAX_SUPPORTED_MEMORY (128ULL * 1024 * 1024 * 1024) // 128GB +#define MAX_PAGES (MAX_SUPPORTED_MEMORY / PAGE_SIZE) #define MAX_BITMAP_SIZE (MAX_PAGES / 8) #define BITMAP_WORD_SIZE 64 -#define BITMAP_WORDS (MAX_BITMAP_SIZE / 8) +#define MAX_BITMAP_WORDS (MAX_BITMAP_SIZE / 8) extern uint8_t _kernel_phys_start[]; extern uint8_t _kernel_phys_end[]; @@ -19,8 +20,9 @@ static uint64_t allocation_count = 0; static uint64_t free_count = 0; static uint64_t huge_pages_allocated = 0; -// Use 64-bit words for faster bitmap operations -static uint64_t page_bitmap[BITMAP_WORDS]; +// Use dynamic bitmap allocation based on actual memory size +static uint64_t* page_bitmap = NULL; +static uint64_t bitmap_words = 0; uint64_t total_pages = 0; static uint64_t used_pages = 0; static volatile int memory_lock = 0; @@ -31,12 +33,14 @@ volatile mcs_node_t* memory_mcs_lock = NULL; // Fast bitmap operations using 64-bit words static inline void MarkPageUsed(uint64_t page_idx) { - if (page_idx >= total_pages) return; + if (page_idx >= total_pages || !page_bitmap) return; uint64_t word_idx = page_idx / 64; uint64_t bit_idx = page_idx % 64; uint64_t mask = 1ULL << bit_idx; + if (word_idx >= bitmap_words) return; // Safety check + if (!(page_bitmap[word_idx] & mask)) { page_bitmap[word_idx] |= mask; used_pages++; @@ -44,12 +48,14 @@ static inline void MarkPageUsed(uint64_t page_idx) { } static inline void MarkPageFree(uint64_t page_idx) { - if (page_idx >= total_pages) return; + if (page_idx >= total_pages || !page_bitmap) return; uint64_t word_idx = page_idx / 64; uint64_t bit_idx = page_idx % 64; uint64_t mask = 1ULL << bit_idx; + if (word_idx >= bitmap_words) return; // Safety check + if (page_bitmap[word_idx] & mask) { page_bitmap[word_idx] &= ~mask; used_pages--; @@ -57,10 +63,13 @@ static inline void MarkPageFree(uint64_t page_idx) { } int IsPageFree(uint64_t page_idx) { - if (page_idx >= total_pages) return 0; + if (page_idx >= total_pages || !page_bitmap) return 0; uint64_t word_idx = page_idx / 64; uint64_t bit_idx = page_idx % 64; + + if (word_idx >= bitmap_words) return 0; // Safety check + return !(page_bitmap[word_idx] & (1ULL << bit_idx)); } @@ -71,7 +80,6 @@ static inline int FindFirstFreeBit(uint64_t word) { } int MemoryInit(uint32_t multiboot_info_addr) { - FastMemset(page_bitmap, 0, sizeof(page_bitmap)); used_pages = 0; allocation_failures = 0; @@ -96,19 +104,60 @@ int MemoryInit(uint32_t multiboot_info_addr) { tag = (struct MultibootTag*)((uint8_t*)tag + ((tag->size + 7) & ~7)); } - total_pages = max_physical_address / PAGE_SIZE; + total_pages = (max_physical_address + PAGE_SIZE - 1) / PAGE_SIZE; + + // Cap at MAX_PAGES to prevent excessive memory usage if (total_pages > MAX_PAGES) { total_pages = MAX_PAGES; - PrintKernelWarning("[WARN] Memory detected exceeds MAX_PAGES, capping at "); + PrintKernelWarning("Memory detected exceeds MAX_PAGES, capping at "); PrintKernelInt(MAX_PAGES * PAGE_SIZE / (1024 * 1024)); PrintKernel("MB\n"); } - PrintKernel("Info: Total physical memory detected: "); - PrintKernelInt(total_pages * PAGE_SIZE / (1024 * 1024)); - PrintKernel("MB ( "); - PrintKernelInt(total_pages); - PrintKernel(" pages)\n"); + // Calculate bitmap size needed + bitmap_words = (total_pages + 63) / 64; // Round up to 64-bit word boundary + uint64_t bitmap_size_bytes = bitmap_words * sizeof(uint64_t); + + PrintKernelF("Info: Usable memory detected: %d MB (%d pages)", + (max_physical_address) / (1024 * 1024), + max_physical_address / PAGE_SIZE); + + PrintKernel("Info: Bitmap size: "); + PrintKernelInt(bitmap_size_bytes / 1024); + PrintKernel("KB ("); + PrintKernelInt(bitmap_words); + PrintKernel(" words)\n"); + + // Allocate bitmap memory from a high memory location to avoid conflicts + // Find a suitable location above 16MB but within identity-mapped space + uint64_t bitmap_start = 0x1000000; // Start searching at 16MB + uint64_t identity_limit = total_pages * PAGE_SIZE; // Don't go beyond detected memory + + // Make sure we don't exceed reasonable limits + if (identity_limit > MAX_SUPPORTED_MEMORY) { + identity_limit = MAX_SUPPORTED_MEMORY; + } + + // Align bitmap to page boundary and ensure it fits in identity-mapped space + bitmap_start = (bitmap_start + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + if (bitmap_start + bitmap_size_bytes > identity_limit) { + PrintKernelError("ERROR: Cannot fit bitmap in available memory space\n"); + return -1; + } + + page_bitmap = (uint64_t*)bitmap_start; + FastMemset(page_bitmap, 0, bitmap_size_bytes); + + // Reserve the bitmap memory itself + uint64_t bitmap_start_page = bitmap_start / PAGE_SIZE; + uint64_t bitmap_end_page = (bitmap_start + bitmap_size_bytes + PAGE_SIZE - 1) / PAGE_SIZE; + + PrintKernel("Info: Bitmap located at 0x"); + PrintKernelHex(bitmap_start); + PrintKernel(" - 0x"); + PrintKernelHex(bitmap_start + bitmap_size_bytes); + PrintKernel("\n"); tag = (struct MultibootTag*)(uintptr_t)(multiboot_info_addr + 8); // Reset tag pointer while (tag->type != MULTIBOOT2_TAG_TYPE_END) { @@ -146,6 +195,16 @@ int MemoryInit(uint32_t multiboot_info_addr) { MarkPageUsed(i); } + // Reserve the bitmap memory itself + for (uint64_t i = bitmap_start_page; i < bitmap_end_page; i++) { + MarkPageUsed(i); + } + PrintKernel("Info: Reserved bitmap pages from "); + PrintKernelInt(bitmap_start_page); + PrintKernel(" to "); + PrintKernelInt(bitmap_end_page); + PrintKernel("\n"); + // 2. Reserve the physical memory used by the kernel itself. const uint64_t kernel_start_addr = (uint64_t)_kernel_phys_start; const uint64_t kernel_end_addr = (uint64_t)_kernel_phys_end; @@ -175,7 +234,10 @@ int MemoryInit(uint32_t multiboot_info_addr) { } + void* AllocPage(void) { + if (!page_bitmap) return NULL; // Safety check + irq_flags_t flags = SpinLockIrqSave(&memory_lock); // Check low memory condition @@ -190,10 +252,9 @@ void* AllocPage(void) { // Fast word-based search from hint uint64_t start_word = next_free_hint / 64; - uint64_t total_words = (total_pages + 63) / 64; // Search from hint word onwards - for (uint64_t word_idx = start_word; word_idx < total_words; word_idx++) { + for (uint64_t word_idx = start_word; word_idx < bitmap_words; word_idx++) { if (page_bitmap[word_idx] != ~0ULL) { // Not all bits set int bit_pos = FindFirstFreeBit(page_bitmap[word_idx]); if (bit_pos >= 0) { diff --git a/mm/VMem.c b/mm/VMem.c index f18c368..db38a84 100644 --- a/mm/VMem.c +++ b/mm/VMem.c @@ -1,6 +1,3 @@ -// -// Created by Atheria on 7/15/25. -// #include "VMem.h" #include "Atomics.h" #include "Console.h" @@ -9,6 +6,9 @@ #include "Panic.h" #include "Spinlock.h" +// Global variable for dynamic identity mapping size +uint64_t g_identity_map_size = 4ULL * 1024 * 1024 * 1024; // Default to 4GB, will be updated during init + static VirtAddrSpace kernel_space; static volatile int vmem_lock = 0; static uint64_t vmem_allocations = 0; diff --git a/mm/VMem.h b/mm/VMem.h index 43cd6f0..5e9f95a 100644 --- a/mm/VMem.h +++ b/mm/VMem.h @@ -12,7 +12,9 @@ #define PAGE_SIZE 4096 #define PAGE_SHIFT 12 #define PAGE_MASK 0xFFF -#define IDENTITY_MAP_SIZE (4ULL * 1024 * 1024 * 1024) // Match bootstrap +// Dynamic identity mapping size - determined at boot time +extern uint64_t g_identity_map_size; +#define IDENTITY_MAP_SIZE g_identity_map_size // Page table entry flags #define PAGE_PRESENT 0x001