diff --git a/docs/IMPLEMENTATION_SUMMARY.md b/docs/IMPLEMENTATION_SUMMARY.md index b5a16da..66e25c6 100644 --- a/docs/IMPLEMENTATION_SUMMARY.md +++ b/docs/IMPLEMENTATION_SUMMARY.md @@ -32,10 +32,10 @@ - Files: `kernel/src/memory.c`, `kernel/include/kernel/memory.h` - Functionality: Physical memory and kernel heap management - Features: - - Bitmap-based physical page allocator + - Bitmap-based physical page allocator with UEFI memory map parsing - Bump allocator for kernel heap (1MB) - Memory utilities (memset, memcpy, memcmp) - - Support for up to 64GB RAM + - Support for up to 64GB RAM (automatically detects available memory) #### PCI Bus Support - Files: `kernel/src/pci.c`, `kernel/include/kernel/pci.h` diff --git a/docs/KERNEL_REFERENCE.md b/docs/KERNEL_REFERENCE.md index 3b966e6..5060d1e 100644 --- a/docs/KERNEL_REFERENCE.md +++ b/docs/KERNEL_REFERENCE.md @@ -158,7 +158,7 @@ if (gpu) { - **No Console Module**: As requested, no console.c/h files are created - **Minimal Design**: Only essential features for QT6 Hello World - **Bump Allocator**: Current heap doesn't support freeing (upgrade later if needed) -- **Physical Memory**: Simple bitmap allocator (supports up to 64GB with 2MB bitmap) +- **Physical Memory**: Bitmap allocator with UEFI memory map parsing (supports up to 64GB, auto-detects available RAM) - **PCI Scan**: Scans all 256 buses, 32 devices per bus - **Timer**: Uses PIT in rate generator mode diff --git a/kernel/include/kernel/memory.h b/kernel/include/kernel/memory.h index 551ba33..0c834ba 100644 --- a/kernel/include/kernel/memory.h +++ b/kernel/include/kernel/memory.h @@ -39,8 +39,9 @@ public: /** * @brief Initialize the physical memory manager with boot information - * @param bootInfo Boot information from bootloader (currently unused, assumes up to 64GB) - * @note Currently hardcoded to manage up to 64GB starting at 16MB physical address + * @param bootInfo Boot information from bootloader containing UEFI memory map + * @note Parses the UEFI memory map to detect actual available RAM (up to 64GB) + * @note Falls back to 128MB if memory map is unavailable */ void init(BootInfo* bootInfo); diff --git a/kernel/src/memory.cpp b/kernel/src/memory.cpp index 50d3c11..1cdf1d1 100644 --- a/kernel/src/memory.cpp +++ b/kernel/src/memory.cpp @@ -27,30 +27,120 @@ PhysicalMemoryManager::PhysicalMemoryManager() /** * @brief Initialize the physical memory manager * - * Currently uses a simplified approach: - * - Assumes up to 64GB of usable RAM starting at physical address 16MB (0x01000000) - * - Clears the entire page bitmap to mark all pages as free - * - TODO: Parse the UEFI memory map from bootInfo to properly detect available memory + * Parses the UEFI memory map from the bootloader to detect available physical memory. + * Only considers memory regions that are usable: + * - EfiConventionalMemory (type 7): Free memory available for allocation + * - EfiBootServicesCode (type 3) and EfiBootServicesData (type 4): Reclaimable after boot + * - EfiLoaderCode (type 1) and EfiLoaderData (type 2): Reclaimable after boot * - * The 16MB starting address is chosen to avoid: + * Memory below 16MB (0x01000000) is avoided to prevent conflicts with: * - First 1MB: Legacy BIOS area, video memory, etc. * - 1MB-16MB: Kernel code, boot structures, and reserved areas * - * @param bootInfo Boot information structure (currently unused, TODO: parse memory map) + * @param bootInfo Boot information structure containing UEFI memory map */ void PhysicalMemoryManager::init(BootInfo* bootInfo) { - (void)bootInfo; // TODO: Parse UEFI memory map - - // For now, assume 64GB of usable memory starting at 16MB - // This supports any amount up to 64GB - totalPages = (64ULL * 1024 * 1024 * 1024) / PAGE_SIZE; - - // Clear bitmap + // Clear bitmap - mark all pages as used initially for (uint64_t i = 0; i < BITMAP_SIZE; i++) { - pageBitmap[i] = 0; + pageBitmap[i] = 0xFF; // All bits set = all pages marked as used } usedPages = 0; + totalPages = 0; + + // Define memory region base (16MB) to avoid low memory conflicts + const uint64_t MEMORY_BASE = 0x01000000UL; // 16MB + + // Parse UEFI memory map if available + if (bootInfo && bootInfo->memory_map && bootInfo->memory_map_size > 0) { + uint8_t* map = (uint8_t*)bootInfo->memory_map; + uint64_t descriptor_size = bootInfo->memory_map_descriptor_size; + uint64_t num_descriptors = bootInfo->memory_map_size / descriptor_size; + + // EFI Memory types we consider usable + const uint32_t EfiLoaderCode = 1; + const uint32_t EfiLoaderData = 2; + const uint32_t EfiBootServicesCode = 3; + const uint32_t EfiBootServicesData = 4; + const uint32_t EfiConventionalMemory = 7; + + uint64_t highest_usable_address = 0; + + // First pass: find highest usable address and mark free pages + for (uint64_t i = 0; i < num_descriptors; i++) { + // Cast to EFI_MEMORY_DESCRIPTOR structure + struct { + uint32_t Type; + uint64_t PhysicalStart; + uint64_t VirtualStart; + uint64_t NumberOfPages; + uint64_t Attribute; + }* desc = (decltype(desc))(map + i * descriptor_size); + + // Check if this is a usable memory type + bool is_usable = (desc->Type == EfiConventionalMemory || + desc->Type == EfiBootServicesCode || + desc->Type == EfiBootServicesData || + desc->Type == EfiLoaderCode || + desc->Type == EfiLoaderData); + + if (is_usable) { + uint64_t region_start = desc->PhysicalStart; + uint64_t region_size = desc->NumberOfPages * 4096; // EFI pages are 4KB + uint64_t region_end = region_start + region_size; + + // Only consider memory at or above MEMORY_BASE + if (region_end > MEMORY_BASE) { + uint64_t usable_start = (region_start < MEMORY_BASE) ? MEMORY_BASE : region_start; + uint64_t usable_end = region_end; + + // Track highest address + if (usable_end > highest_usable_address) { + highest_usable_address = usable_end; + } + + // Mark pages in this region as free in the bitmap + uint64_t start_page = (usable_start - MEMORY_BASE) / PAGE_SIZE; + uint64_t end_page = (usable_end - MEMORY_BASE) / PAGE_SIZE; + + for (uint64_t page = start_page; page < end_page; page++) { + uint64_t byte = page / 8; + uint64_t bit = page % 8; + + // Bounds check + if (byte >= BITMAP_SIZE) { + break; + } + + // Mark page as free (clear bit) + pageBitmap[byte] &= ~(1 << bit); + } + } + } + } + + // Calculate total pages based on highest usable address + if (highest_usable_address > MEMORY_BASE) { + totalPages = (highest_usable_address - MEMORY_BASE) / PAGE_SIZE; + + // Cap at bitmap capacity + uint64_t max_pages = BITMAP_SIZE * 8; + if (totalPages > max_pages) { + totalPages = max_pages; + } + } + } + + // Fallback: if no memory map or parsing failed, use safe defaults + if (totalPages == 0) { + // Assume 128MB as a conservative fallback + totalPages = (128 * 1024 * 1024) / PAGE_SIZE; + + // Mark all pages as free + for (uint64_t i = 0; i < BITMAP_SIZE; i++) { + pageBitmap[i] = 0; + } + } } /**