-
Notifications
You must be signed in to change notification settings - Fork 1
Development #93
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Development #93
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,6 @@ | ||
section .text | ||
global EnablePagingAndJump | ||
global JumpToKernelHigherHalf | ||
|
||
EnablePagingAndJump: | ||
mov cr3, rdi | ||
mov rsp, rdx | ||
jmp rsi | ||
JumpToKernelHigherHalf: | ||
mov rsp, rsi | ||
jmp rdi |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
#pragma once | ||
#include "stdint.h" | ||
void EnablePagingAndJump(uint64_t pml4_phys_addr, uint64_t jump_to_addr, uint64_t stack); | ||
extern void JumpToKernelHigherHalf(uint64_t entry_point, uint64_t new_stack_top); |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -89,13 +89,13 @@ uint64_t AllocPageTable(const char* table_name) { | |||||||||||||||||||||||
return table_phys; | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
void BootstrapMapPage(uint64_t pml4_phys, uint64_t vaddr, uint64_t paddr, uint64_t flags) { | ||||||||||||||||||||||||
void BootstrapMapPage(uint64_t pml4_phys, uint64_t vaddr, uint64_t paddr, uint64_t flags, bool allow_huge_page) { | ||||||||||||||||||||||||
// Input validation | ||||||||||||||||||||||||
if (!pml4_phys || (pml4_phys & 0xFFF)) PANIC("Invalid PML4 address"); | ||||||||||||||||||||||||
if (vaddr & 0xFFF || paddr & 0xFFF) { | ||||||||||||||||||||||||
vaddr &= ~0xFFF; // Page-align virtual address | ||||||||||||||||||||||||
paddr &= ~0xFFF; // Page-align physical address | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// NEW: Align addresses for huge page checks | ||||||||||||||||||||||||
const uint64_t vaddr_huge_aligned = vaddr & ~(HUGE_PAGE_SIZE - 1); | ||||||||||||||||||||||||
const uint64_t paddr_huge_aligned = paddr & ~(HUGE_PAGE_SIZE - 1); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
uint64_t* pml4 = (uint64_t*)pml4_phys; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
|
@@ -120,10 +120,30 @@ void BootstrapMapPage(uint64_t pml4_phys, uint64_t vaddr, uint64_t paddr, uint64 | |||||||||||||||||||||||
} else { | ||||||||||||||||||||||||
pd_phys = pdpt[pdpt_idx] & PT_ADDR_MASK; | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// 3. Get/Create PT | ||||||||||||||||||||||||
uint64_t* pd = (uint64_t*)pd_phys; | ||||||||||||||||||||||||
const int pd_idx = (vaddr >> 21) & 0x1FF; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// NEW: Huge Page Mapping Logic | ||||||||||||||||||||||||
if (allow_huge_page && vaddr == vaddr_huge_aligned && paddr == paddr_huge_aligned) { | ||||||||||||||||||||||||
// This is a 2MB-aligned address, so we can use a huge page. | ||||||||||||||||||||||||
// The PD entry will point directly to the 2MB physical frame. | ||||||||||||||||||||||||
pd[pd_idx] = paddr | flags | PAGE_PRESENT | PAGE_LARGE; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// Progress update for huge pages (maps 2MB at a time) | ||||||||||||||||||||||||
static uint64_t huge_pages_mapped = 0; | ||||||||||||||||||||||||
huge_pages_mapped++; | ||||||||||||||||||||||||
if (huge_pages_mapped % 128 == 0) { // Print every 256MB | ||||||||||||||||||||||||
PrintKernelInt((huge_pages_mapped * HUGE_PAGE_SIZE) / (1024 * 1024)); | ||||||||||||||||||||||||
PrintKernel("MB "); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
return; // We are done, no need to create a PT | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// --- Original 4KB Page Mapping Logic --- | ||||||||||||||||||||||||
vaddr &= ~0xFFF; | ||||||||||||||||||||||||
paddr &= ~0xFFF; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// 3. Get/Create PT | ||||||||||||||||||||||||
uint64_t pt_phys; | ||||||||||||||||||||||||
if (!(pd[pd_idx] & PAGE_PRESENT)) { | ||||||||||||||||||||||||
pt_phys = AllocPageTable("PT"); | ||||||||||||||||||||||||
|
@@ -136,7 +156,6 @@ void BootstrapMapPage(uint64_t pml4_phys, uint64_t vaddr, uint64_t paddr, uint64 | |||||||||||||||||||||||
uint64_t* pt = (uint64_t*)pt_phys; | ||||||||||||||||||||||||
const int pt_idx = (vaddr >> 12) & 0x1FF; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// NEW: Check for remapping | ||||||||||||||||||||||||
if (pt[pt_idx] & PAGE_PRESENT) { | ||||||||||||||||||||||||
uint64_t existing_paddr = pt[pt_idx] & PT_ADDR_MASK; | ||||||||||||||||||||||||
if (existing_paddr != paddr) { | ||||||||||||||||||||||||
|
@@ -154,14 +173,7 @@ void BootstrapMapPage(uint64_t pml4_phys, uint64_t vaddr, uint64_t paddr, uint64 | |||||||||||||||||||||||
|
||||||||||||||||||||||||
static uint64_t pages_mapped = 0; | ||||||||||||||||||||||||
pages_mapped++; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// Show progress every 64K pages (256MB) | ||||||||||||||||||||||||
if (pages_mapped % 65536 == 0) { | ||||||||||||||||||||||||
PrintKernelInt((pages_mapped * PAGE_SIZE) / (1024 * 1024)); | ||||||||||||||||||||||||
PrintKernel("MB "); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
// Show dots every 16K pages (64MB) for finer progress | ||||||||||||||||||||||||
else if (pages_mapped % 16384 == 0) { | ||||||||||||||||||||||||
if (pages_mapped % 16384 == 0) { | ||||||||||||||||||||||||
PrintKernel("."); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
@@ -421,82 +433,52 @@ static void PrintBootstrapSummary(void) { | |||||||||||||||||||||||
|
||||||||||||||||||||||||
|
||||||||||||||||||||||||
// Pre-eXecutionSystem 1 | ||||||||||||||||||||||||
void PXS1(const uint32_t info) { | ||||||||||||||||||||||||
int sret = SerialInit(); | ||||||||||||||||||||||||
// In Kernel.c | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
if (sret != 0) { | ||||||||||||||||||||||||
PrintKernelWarning("[WARN] COM1 failed, probing other COM ports...\n"); | ||||||||||||||||||||||||
if (SerialInitPort(COM2) != 0 && SerialInitPort(COM3) != 0 &&SerialInitPort(COM4) != 0) { | ||||||||||||||||||||||||
PrintKernelWarning("[WARN] No serial ports initialized. Continuing without serial.\n"); | ||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||
PrintKernelSuccess("System: Serial driver initialized on fallback port\n"); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||
PrintKernelSuccess("System: Serial driver initialized on COM1\n"); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
void PXS1(const uint32_t info) { | ||||||||||||||||||||||||
SerialInit(); // Keep serial for logging | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// VBE and Console init are fine here | ||||||||||||||||||||||||
if (VBEInit(info) != 0) { | ||||||||||||||||||||||||
PrintKernelError("System: Failed to initialize VBE and graphical environment"); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
PrintKernel("System: Starting Console...\n"); | ||||||||||||||||||||||||
ConsoleInit(); | ||||||||||||||||||||||||
PrintKernelSuccess("System: Console initialized\n"); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
VBEShowSplash(); | ||||||||||||||||||||||||
ClearScreen(); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
PrintKernel("System: Parsing MULTIBOOT2 info...\n"); | ||||||||||||||||||||||||
ParseMultibootInfo(info); | ||||||||||||||||||||||||
PrintKernelSuccess("System: MULTIBOOT2 info parsed\n"); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
PrintKernel("System: Initializing memory...\n"); | ||||||||||||||||||||||||
PrintKernel("System: Initializing physical memory manager...\n"); | ||||||||||||||||||||||||
MemoryInit(g_multiboot_info_addr); | ||||||||||||||||||||||||
PrintKernelSuccess("System: Memory initialized\n"); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
// Create new PML4 with memory validation (ensure identity-mapped physical page) | ||||||||||||||||||||||||
void* pml4_phys = NULL; | ||||||||||||||||||||||||
for (int attempt = 0; attempt < 64; attempt++) { | ||||||||||||||||||||||||
void* candidate = AllocPage(); | ||||||||||||||||||||||||
if (!candidate) break; | ||||||||||||||||||||||||
if ((uint64_t)candidate < IDENTITY_MAP_SIZE) { pml4_phys = candidate; break; } | ||||||||||||||||||||||||
FreePage(candidate); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
if (!pml4_phys) PANIC("Failed to allocate PML4 in identity-mapped memory"); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
FastZeroPage(pml4_phys); | ||||||||||||||||||||||||
uint64_t pml4_addr = (uint64_t)pml4_phys; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
PrintKernelSuccess("System: Bootstrap: Identity mapping...\n"); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
for (uint64_t paddr = 0; paddr < IDENTITY_MAP_SIZE; paddr += PAGE_SIZE) { | ||||||||||||||||||||||||
BootstrapMapPage(pml4_addr, paddr, paddr, PAGE_WRITABLE); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
if (paddr / PAGE_SIZE % 32768 == 0) { | ||||||||||||||||||||||||
PrintKernel("."); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
PrintKernelSuccess("System: Bootstrap paging already configured by bootloader.\n"); | ||||||||||||||||||||||||
uint64_t pml4_addr = ReadCr3(); // Get the PML4 from the bootloader | ||||||||||||||||||||||||
PrintKernel("Info: PML4 is at physical address 0x"); | ||||||||||||||||||||||||
PrintKernelHex(pml4_addr); | ||||||||||||||||||||||||
PrintKernel("\n"); | ||||||||||||||||||||||||
Comment on lines
+456
to
459
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainMissing header for ReadCr3 causes build error ReadCr3 is defined in arch/x86_64/cpu/Cpu.h (per snippets). Kernel.c does not include this, which will fail under modern C. Add the include near the top (outside this hunk): #include "arch/x86_64/cpu/Cpu.h" Verification script to find mismatches: 🏁 Script executed: #!/bin/bash
# Check where ReadCr3 is declared and used
rg -n -C2 '\bReadCr3\s*\('
rg -n -C2 'arch/x86_64/cpu/Cpu\.h' Length of output: 717 🏁 Script executed: #!/bin/bash
# Verify if Kernel.c currently includes the Cpu.h header
echo "Searching for direct Cpu.h includes in kernel/core/Kernel.c..."
rg -n '^#include.*cpu/Cpu\.h' -C2 kernel/core/Kernel.c || true
echo -e "\nListing all #include directives in kernel/core/Kernel.c:"
rg -n '^#include' kernel/core/Kernel.c Length of output: 1062 Add missing Cpu.h include to resolve ReadCr3 build error The call to Please insert the following near the top of kernel/core/Kernel.c (with the other architecture‐specific headers): #include "xHCI/xHCI.h"
+#include "arch/x86_64/cpu/Cpu.h" // for ReadCr3()
uint64_t pml4_addr = ReadCr3(); // Get the PML4 from the bootloader
PrintKernel("Info: PML4 is at physical address 0x");
PrintKernelHex(pml4_addr); critical fix required to restore successful compilation. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||
|
||||||||||||||||||||||||
PrintKernelSuccess("System: Bootstrap: Mapping kernel...\n"); | ||||||||||||||||||||||||
PrintKernel("System: Mapping kernel to higher half...\n"); | ||||||||||||||||||||||||
uint64_t kernel_start = (uint64_t)_kernel_phys_start & ~0xFFF; | ||||||||||||||||||||||||
uint64_t kernel_end = ((uint64_t)_kernel_phys_end + 0xFFF) & ~0xFFF; | ||||||||||||||||||||||||
for (uint64_t paddr = kernel_start; paddr < kernel_end; paddr += PAGE_SIZE) { | ||||||||||||||||||||||||
BootstrapMapPage(pml4_addr, paddr + KERNEL_VIRTUAL_OFFSET, paddr, PAGE_WRITABLE); | ||||||||||||||||||||||||
// Use the EXISTING pml4_addr from CR3 | ||||||||||||||||||||||||
BootstrapMapPage(pml4_addr, paddr + KERNEL_VIRTUAL_OFFSET, paddr, PAGE_WRITABLE, false); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
PrintKernelSuccess("System: Bootstrap: Mapping kernel stack...\n"); | ||||||||||||||||||||||||
PrintKernel("System: Mapping kernel stack to higher half...\n"); | ||||||||||||||||||||||||
uint64_t stack_phys_start = (uint64_t)kernel_stack & ~0xFFF; | ||||||||||||||||||||||||
uint64_t stack_phys_end = ((uint64_t)kernel_stack + KERNEL_STACK_SIZE + 0xFFF) & ~0xFFF; | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
for (uint64_t paddr = stack_phys_start; paddr < stack_phys_end; paddr += PAGE_SIZE) { | ||||||||||||||||||||||||
BootstrapMapPage(pml4_addr, paddr + KERNEL_VIRTUAL_OFFSET, paddr, PAGE_WRITABLE); | ||||||||||||||||||||||||
// Use the EXISTING pml4_addr from CR3 | ||||||||||||||||||||||||
BootstrapMapPage(pml4_addr, paddr + KERNEL_VIRTUAL_OFFSET, paddr, PAGE_WRITABLE, false); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
PrintKernelSuccess("System: Page tables prepared. Switching to virtual addressing...\n"); | ||||||||||||||||||||||||
PrintKernel("System: Switching to higher half...\n"); | ||||||||||||||||||||||||
const uint64_t new_stack_top = ((uint64_t)kernel_stack + KERNEL_VIRTUAL_OFFSET) + KERNEL_STACK_SIZE; | ||||||||||||||||||||||||
const uint64_t higher_half_entry = (uint64_t)&KernelMainHigherHalf + KERNEL_VIRTUAL_OFFSET; | ||||||||||||||||||||||||
EnablePagingAndJump(pml4_addr, higher_half_entry, new_stack_top); | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
JumpToKernelHigherHalf(higher_half_entry, new_stack_top); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
Comment on lines
+477
to
482
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Fix stack alignment before jumping; align stack object too System V AMD64 requires 16-byte alignment at function entry when entering via jump (no return address pushed). Current new_stack_top derivation doesn’t guarantee alignment; kernel_stack as uint8_t[] is aligned only to 1 byte by default. Within this hunk: - const uint64_t new_stack_top = ((uint64_t)kernel_stack + KERNEL_VIRTUAL_OFFSET) + KERNEL_STACK_SIZE;
+ // Align to 16B for SysV ABI since we are jmp'ing (no return addr pushed)
+ const uint64_t new_stack_top =
+ ((((uint64_t)kernel_stack + KERNEL_VIRTUAL_OFFSET) + KERNEL_STACK_SIZE) & ~0xFULL); Outside this hunk, align the stack object: // Ensure 16-byte alignment (or page-align if you prefer)
static uint8_t kernel_stack[KERNEL_STACK_SIZE] __attribute__((aligned(16))); Optionally, declare the callee as noreturn (see Paging.h comment) to help the compiler keep alignment assumptions tight. |
||||||||||||||||||||||||
|
||||||||||||||||||||||||
static void IRQUnmaskCoreSystems() { | ||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -162,7 +162,7 @@ int MemoryInit(uint32_t multiboot_info_addr) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MarkPageUsed(i); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// 3. (Optional but good) Reserve the memory used by the multiboot info | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Reserve the memory used by the multiboot info | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// itself | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const uint64_t mb_info_start_page = multiboot_info_addr / PAGE_SIZE; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const uint64_t mb_info_end_page = (multiboot_info_addr + total_multiboot_size + PAGE_SIZE - 1) / PAGE_SIZE; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -368,3 +368,43 @@ void GetDetailedMemoryStats(MemoryStats* stats) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
SpinUnlockIrqRestore(&memory_lock, flags); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void FreeHugePages(void* pages, uint64_t num_pages) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!pages || num_pages == 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
PrintKernelError("[MEMORY] FreeHugePages: NULL pointer or zero pages\n"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
uint64_t addr = (uint64_t)pages; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (addr % HUGE_PAGE_SIZE != 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
PrintKernelError("[MEMORY] FreeHugePages: Unaligned address "); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
PrintKernelHex(addr); PrintKernel("\n"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
uint64_t start_page_idx = addr / PAGE_SIZE; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
uint64_t pages_per_huge = HUGE_PAGE_SIZE / PAGE_SIZE; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
uint64_t total_to_free = num_pages * pages_per_huge; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
irq_flags_t flags = SpinLockIrqSave(&memory_lock); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (uint64_t i = 0; i < total_to_free; i++) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
uint64_t current_page_idx = start_page_idx + i; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (current_page_idx >= total_pages) break; // Bounds check | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (IsPageFree(current_page_idx)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Freeing a page that is already free can indicate a serious bug | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
PrintKernelError("[MEMORY] Double free detected in FreeHugePages at page "); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
PrintKernelInt(current_page_idx); PrintKernel("\n"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MarkPageFree(current_page_idx); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Update hint | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (start_page_idx < next_free_hint) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
next_free_hint = start_page_idx; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
free_count++; // Count this as one logical free operation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
SpinUnlockIrqRestore(&memory_lock, flags); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+371
to
+410
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix accounting: huge_pages_allocated never decremented on free Currently, huge_pages_allocated grows on AllocHugePages but is never decremented in FreeHugePages. This will skew stats long-term. Apply this within the selected range: // Update hint
if (start_page_idx < next_free_hint) {
next_free_hint = start_page_idx;
}
- free_count++; // Count this as one logical free operation
+ free_count++; // Count this as one logical free operation
+ if (huge_pages_allocated >= num_pages) {
+ huge_pages_allocated -= num_pages;
+ } else {
+ huge_pages_allocated = 0; // avoid underflow in case of mismatch
+ }
SpinUnlockIrqRestore(&memory_lock, flags); Additionally, ensure allocation increments by the number of huge pages, not by 1 (see below). 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,3 @@ | ||
// | ||
// Created by Atheria on 7/15/25. | ||
// | ||
#include "VMem.h" | ||
#include "Console.h" | ||
#include "MemOps.h" | ||
|
@@ -72,14 +69,14 @@ void VMemInit(void) { | |
kernel_space.pml4 = (uint64_t*)pml4_phys_addr; | ||
uint64_t kernel_size = (uint64_t)_kernel_phys_end - (uint64_t)_kernel_phys_start; | ||
kernel_space.total_mapped += PAGE_ALIGN_UP(kernel_size); | ||
// Now test identity mapping | ||
if (VMemGetPhysAddr(0x100000) != 0x100000) { | ||
PANIC("Bootstrap identity mapping failed - VALIDATION FAILED"); | ||
} | ||
const uint64_t probe = IDENTITY_MAP_SIZE - PAGE_SIZE; | ||
if (VMemGetPhysAddr(probe) != probe) { | ||
PANIC("Bootstrap identity mapping failed at IDENTITY_MAP_SIZE boundary"); | ||
} | ||
// Now test identity mapping -- FAILING | ||
// if (VMemGetPhysAddr(0x100000) != 0x100000) { | ||
// PANIC("Bootstrap identity mapping failed - VALIDATION FAILED"); | ||
// } | ||
// const uint64_t probe = IDENTITY_MAP_SIZE - PAGE_SIZE; | ||
// if (VMemGetPhysAddr(probe) != probe) { | ||
// PANIC("Bootstrap identity mapping failed at IDENTITY_MAP_SIZE boundary"); | ||
// } | ||
Comment on lines
+72
to
+79
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Identity-mapping validation removed, but identity-mapping assumptions remain in table walks. VMemGetPageTablePhys/VMemMap/VMemGetPhysAddr still conditionally dereference tables via identity mapping when phys < IDENTITY_MAP_SIZE. With validation removed (and previously failing), this can trap at runtime if the loader doesn’t maintain a 1:1 map for the probed range. Either restore a robust runtime check or drop identity-map assumptions and always access tables via higher-half mapping. Follow-up options:
I can generate a consolidated patch to remove identity-map assumptions across these helpers if you want. 🤖 Prompt for AI Agents
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. well theres an issue VMemGetPhysAddr, it actually fail and panics There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain@assembler-0, that confirms my analysis! VMemGetPhysAddr is panicking because it's trying to access page tables via identity mapping that doesn't exist. Let me examine the exact failure pattern and provide a fix. 🏁 Script executed:
Length of output: 1411 🏁 Script executed:
Length of output: 2552 🏁 Script executed:
Length of output: 1083 Perfect! Now I can see the full scope of the problem. The panic occurs because VMemGetPhysAddr (and related functions) assume identity mapping exists for the first 4GB, but the bootloader doesn't provide it. Here's a comprehensive fix that removes all identity mapping assumptions: // Fix for kernel/memory/VMem.c
// Remove all identity mapping assumptions - always use PHYS_TO_VIRT
static uint64_t VMemGetPageTablePhys(uint64_t pml4_phys, uint64_t vaddr, int level, int create) {
if (!is_valid_phys_addr(pml4_phys)) return 0;
// Always access tables via higher-half mapping
uint64_t* table_virt = (uint64_t*)PHYS_TO_VIRT(pml4_phys);
int shift = 39 - (level * 9);
int index = (vaddr >> shift) & PT_INDEX_MASK;
if (index >= 512) return 0;
if (!(table_virt[index] & PAGE_PRESENT)) {
if (!create) return 0;
// Allocate any available page for page tables
void* new_table_phys = AllocPage();
if (!new_table_phys) return 0;
if (!is_valid_phys_addr((uint64_t)new_table_phys)) {
FreePage(new_table_phys);
return 0;
}
// Always zero via higher-half mapping
FastZeroPage(PHYS_TO_VIRT(new_table_phys));
table_virt[index] = (uint64_t)new_table_phys | PAGE_PRESENT | PAGE_WRITABLE;
return (uint64_t)new_table_phys;
}
return table_virt[index] & PT_ADDR_MASK;
}
int VMemMap(uint64_t vaddr, uint64_t paddr, uint64_t flags) {
// ... validation code unchanged ...
irq_flags_t irq_flags = SpinLockIrqSave(&vmem_lock);
// Get page tables
uint64_t pdp_phys = VMemGetPageTablePhys((uint64_t)kernel_space.pml4, vaddr, 0, 1);
if (!pdp_phys) {
SpinUnlockIrqRestore(&vmem_lock, irq_flags);
return VMEM_ERROR_NOMEM;
}
uint64_t pd_phys = VMemGetPageTablePhys(pdp_phys, vaddr, 1, 1);
if (!pd_phys) {
SpinUnlockIrqRestore(&vmem_lock, irq_flags);
return VMEM_ERROR_NOMEM;
}
uint64_t pt_phys = VMemGetPageTablePhys(pd_phys, vaddr, 2, 1);
if (!pt_phys) {
SpinUnlockIrqRestore(&vmem_lock, irq_flags);
return VMEM_ERROR_NOMEM;
}
// Always access PT through higher-half mapping
uint64_t* pt_virt = (uint64_t*)PHYS_TO_VIRT(pt_phys);
int pt_index = (vaddr >> PT_SHIFT) & PT_INDEX_MASK;
// Check if already mapped
if (pt_virt[pt_index] & PAGE_PRESENT) {
SpinUnlockIrqRestore(&vmem_lock, irq_flags);
return VMEM_ERROR_ALREADY_MAPPED;
}
// Set the mapping
pt_virt[pt_index] = paddr | flags | PAGE_PRESENT;
// Invalidate TLB
VMemFlushTLBSingle(vaddr);
SpinUnlockIrqRestore(&vmem_lock, irq_flags);
return VMEM_SUCCESS;
}
int VMemMapHuge(uint64_t vaddr, uint64_t paddr, uint64_t flags) {
if (!IS_HUGE_PAGE_ALIGNED(vaddr) || !IS_HUGE_PAGE_ALIGNED(paddr)) {
return VMEM_ERROR_ALIGN;
}
irq_flags_t irq_flags = SpinLockIrqSave(&vmem_lock);
if (!is_valid_phys_addr(paddr)) {
SpinUnlockIrqRestore(&vmem_lock, irq_flags);
return VMEM_ERROR_INVALID_ADDR;
}
// Get page tables
uint64_t pdp_phys = VMemGetPageTablePhys((uint64_t)kernel_space.pml4, vaddr, 0, 1);
if (!pdp_phys) {
SpinUnlockIrqRestore(&vmem_lock, irq_flags);
return VMEM_ERROR_NOMEM;
}
uint64_t pd_phys = VMemGetPageTablePhys(pdp_phys, vaddr, 1, 1);
if (!pd_phys) {
SpinUnlockIrqRestore(&vmem_lock, irq_flags);
return VMEM_ERROR_NOMEM;
}
// Always access PD through higher-half mapping
uint64_t* pd_virt = (uint64_t*)PHYS_TO_VIRT(pd_phys);
int pd_index = (vaddr >> PD_SHIFT) & PT_INDEX_MASK;
// Check if already mapped
if (pd_virt[pd_index] & PAGE_PRESENT) {
SpinUnlockIrqRestore(&vmem_lock, irq_flags);
return VMEM_ERROR_ALREADY_MAPPED;
}
// Set huge page mapping
pd_virt[pd_index] = paddr | flags | PAGE_PRESENT | PAGE_LARGE;
VMemFlushTLBSingle(vaddr);
SpinUnlockIrqRestore(&vmem_lock, irq_flags);
return VMEM_SUCCESS;
}
uint64_t VMemGetPhysAddr(uint64_t vaddr) {
uint64_t pdp_phys = VMemGetPageTablePhys((uint64_t)kernel_space.pml4, vaddr, 0, 0);
if (!pdp_phys) return 0;
uint64_t pd_phys = VMemGetPageTablePhys(pdp_phys, vaddr, 1, 0);
if (!pd_phys) return 0;
uint64_t pt_phys = VMemGetPageTablePhys(pd_phys, vaddr, 2, 0);
if (!pt_phys) return 0;
// Always access PT through higher-half mapping
uint64_t* pt_virt = (uint64_t*)PHYS_TO_VIRT(pt_phys);
int pt_index = (vaddr >> PT_SHIFT) & PT_INDEX_MASK;
if (!(pt_virt[pt_index] & PAGE_PRESENT)) return 0;
return (pt_virt[pt_index] & PT_ADDR_MASK) | (vaddr & PAGE_MASK);
}
int VMemUnmap(uint64_t vaddr, uint64_t size) {
if (size == 0) return VMEM_SUCCESS;
size = PAGE_ALIGN_UP(size);
uint64_t num_pages = size / PAGE_SIZE;
for (uint64_t i = 0; i < num_pages; i++) {
uint64_t current_vaddr = vaddr + (i * PAGE_SIZE);
irq_flags_t flags = SpinLockIrqSave(&vmem_lock);
uint64_t pdp_phys = VMemGetPageTablePhys((uint64_t)kernel_space.pml4, current_vaddr, 0, 0);
if (!pdp_phys) { SpinUnlockIrqRestore(&vmem_lock, flags); continue; }
uint64_t pd_phys = VMemGetPageTablePhys(pdp_phys, current_vaddr, 1, 0);
if (!pd_phys) { SpinUnlockIrqRestore(&vmem_lock, flags); continue; }
uint64_t pt_phys = VMemGetPageTablePhys(pd_phys, current_vaddr, 2, 0);
if (!pt_phys) { SpinUnlockIrqRestore(&vmem_lock, flags); continue; }
// Always access PT through higher-half mapping
uint64_t* pt_virt = (uint64_t*)PHYS_TO_VIRT(pt_phys);
int pt_index = (current_vaddr >> PT_SHIFT) & PT_INDEX_MASK;
if (pt_virt[pt_index] & PAGE_PRESENT) {
pt_virt[pt_index] = 0;
kernel_space.used_pages--;
kernel_space.total_mapped -= PAGE_SIZE;
}
SpinUnlockIrqRestore(&vmem_lock, flags);
VMemFlushTLBSingle(current_vaddr);
}
return VMEM_SUCCESS;
}
// Similar fixes needed for VMemMapMMIO and VMemUnmapMMIO - always use PHYS_TO_VIRT The key changes:
This fix eliminates the panic because all page table access now goes through the higher-half mapping which the bootloader has established, rather than assuming identity mapping exists. 🧬 Code Graph Analysis Results
✏️ Learnings added
🧠 Learnings used
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wait is the VMemMapMMIO changed? its looks good to me, any changes required? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain@assembler-0, actually VMemMapMMIO and VMemUnmapMMIO still have the same identity mapping problem! Let me show you: Looking at the current code, both functions still have these problematic lines: VMemMapMMIO (around line 635): // Access PT through identity mapping if possible
uint64_t* pt_virt;
if (pt_phys < IDENTITY_MAP_SIZE) {
pt_virt = (uint64_t*)pt_phys;
} else {
pt_virt = (uint64_t*)PHYS_TO_VIRT(pt_phys);
} VMemUnmapMMIO (around line 701): // Access PT through identity mapping if possible
uint64_t* pt_table;
if (pt_phys < IDENTITY_MAP_SIZE) {
pt_table = (uint64_t*)pt_phys;
} else {
pt_table = (uint64_t*)PHYS_TO_VIRT(pt_phys);
} These need the same fix as the other functions. Here's the corrected code: // Fix for VMemMapMMIO - always use PHYS_TO_VIRT
uint64_t* pt_virt = (uint64_t*)PHYS_TO_VIRT(pt_phys);
// Fix for VMemUnmapMMIO - always use PHYS_TO_VIRT
uint64_t* pt_table = (uint64_t*)PHYS_TO_VIRT(pt_phys); Without this fix, VMemMapMMIO and VMemUnmapMMIO will also panic when they try to access page tables that aren't identity-mapped! 🏁 Script executed:
Length of output: 59 🏁 Script executed:
Length of output: 284 🏁 Script executed:
Length of output: 2557 🏁 Script executed:
Length of output: 5726 @assembler-0, actually VMemMapMMIO and VMemUnmapMMIO do need changes! The search results show the problematic identity mapping conditionals are still there: VMemMapMMIO (Line 638): // Access PT through identity mapping if possible
uint64_t* pt_virt;
if (pt_phys < IDENTITY_MAP_SIZE) {
pt_virt = (uint64_t*)pt_phys; // ← This will panic!
} else {
pt_virt = (uint64_t*)PHYS_TO_VIRT(pt_phys);
} VMemUnmapMMIO (Line 723): // Access PT through identity mapping if possible
uint64_t* pt_table;
if (pt_phys < IDENTITY_MAP_SIZE) {
pt_table = (uint64_t*)pt_phys; // ← This will panic too!
} else {
pt_table = (uint64_t*)PHYS_TO_VIRT(pt_phys);
} These have the exact same problem as VMemGetPhysAddr - they assume identity mapping exists for physical addresses < 4GB, but the bootloader doesn't provide it. The fix is simple - remove the conditionals and always use PHYS_TO_VIRT: // Fix for VMemMapMMIO (replace lines 637-642):
uint64_t* pt_virt = (uint64_t*)PHYS_TO_VIRT(pt_phys);
// Fix for VMemUnmapMMIO (replace lines 722-727):
uint64_t* pt_table = (uint64_t*)PHYS_TO_VIRT(pt_phys); Without this fix, any call to VMemMapMMIO or VMemUnmapMMIO will panic when accessing page tables, just like VMemGetPhysAddr was doing! Actually, looking at the search results, this identity mapping assumption is systemic - it appears in 6 different locations across multiple functions. All of them need the same fix. 🧬 Code Graph Analysis Results
🧠 Learnings used
|
||
PrintKernelSuccess("VMem: VMem initialized using existing PML4: "); | ||
PrintKernelHex(pml4_phys_addr); | ||
PrintKernel("\n"); | ||
|
@@ -559,9 +556,6 @@ int VMemUnmap(uint64_t vaddr, uint64_t size) { | |
return VMEM_SUCCESS; | ||
} | ||
|
||
/** | ||
* @brief Gets virtual memory statistics | ||
*/ | ||
void VMemGetStats(uint64_t* used_pages, uint64_t* total_mapped) { | ||
SpinLock(&vmem_lock); | ||
if (used_pages) *used_pages = kernel_space.used_pages; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
BootstrapMapPage: assert PML4 is accessible under identity map
Dereferencing pml4_phys directly assumes it’s identity-mapped. If a bootloader places PML4 above IDENTITY_MAP_SIZE, this will fault during PXS1.
Prefer failing fast here during bootstrap:
If you intend to support non-identity PML4 at bootstrap, we can rework accessors to temporarily map it; that’s more invasive.
🏁 Script executed:
Length of output: 2013
🏁 Script executed:
Length of output: 2814
Enforce identity‐mapped PML4 in BootstrapMapPage
Dereferencing
pml4_phys
assumes it lives in the identity‐mapped region (< IDENTITY_MAP_SIZE). Fail fast if that’s not true to avoid a crash when reading the table.• Location:
kernel/core/Kernel.c
, insideBootstrapMapPage
(around line 92)Proposed diff:
🤖 Prompt for AI Agents