From 7a40a81ae552ae15c3ea33c52bb6e44fe8650f27 Mon Sep 17 00:00:00 2001 From: mii443 Date: Thu, 3 Jul 2025 01:09:55 +0900 Subject: [PATCH] memory allocator --- nel_os_bootloader/qemu.log | 56 ++++++++++++++++++ nel_os_kernel/src/main.rs | 9 ++- nel_os_kernel/src/paging.rs | 2 +- nel_os_kernel/triple_fault_fix.md | 97 +++++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 nel_os_bootloader/qemu.log create mode 100644 nel_os_kernel/triple_fault_fix.md diff --git a/nel_os_bootloader/qemu.log b/nel_os_bootloader/qemu.log new file mode 100644 index 0000000..3fd7b75 --- /dev/null +++ b/nel_os_bootloader/qemu.log @@ -0,0 +1,56 @@ +CPU Reset (CPU 0) +EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000 +ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000 +EIP=00000000 EFL=00000000 [-------] CPL=0 II=0 A20=0 SMM=0 HLT=0 +ES =0000 00000000 00000000 00000000 +CS =0000 00000000 00000000 00000000 +SS =0000 00000000 00000000 00000000 +DS =0000 00000000 00000000 00000000 +FS =0000 00000000 00000000 00000000 +GS =0000 00000000 00000000 00000000 +LDT=0000 00000000 00000000 00000000 +TR =0000 00000000 00000000 00000000 +GDT= 00000000 00000000 +IDT= 00000000 00000000 +CR0=00000000 CR2=00000000 CR3=00000000 CR4=00000000 +DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 +DR6=0000000000000000 DR7=0000000000000000 +CCS=00000000 CCD=00000000 CCO=DYNAMIC +EFER=0000000000000000 +FCW=0000 FSW=0000 [ST=0] FTW=ff MXCSR=00000000 +FPR0=0000000000000000 0000 FPR1=0000000000000000 0000 +FPR2=0000000000000000 0000 FPR3=0000000000000000 0000 +FPR4=0000000000000000 0000 FPR5=0000000000000000 0000 +FPR6=0000000000000000 0000 FPR7=0000000000000000 0000 +XMM00=0000000000000000 0000000000000000 XMM01=0000000000000000 0000000000000000 +XMM02=0000000000000000 0000000000000000 XMM03=0000000000000000 0000000000000000 +XMM04=0000000000000000 0000000000000000 XMM05=0000000000000000 0000000000000000 +XMM06=0000000000000000 0000000000000000 XMM07=0000000000000000 0000000000000000 +CPU Reset (CPU 0) +EAX=00000000 EBX=00000000 ECX=00000000 EDX=00060fb1 +ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000 +EIP=0000fff0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0 +ES =0000 00000000 0000ffff 00009300 +CS =f000 ffff0000 0000ffff 00009b00 +SS =0000 00000000 0000ffff 00009300 +DS =0000 00000000 0000ffff 00009300 +FS =0000 00000000 0000ffff 00009300 +GS =0000 00000000 0000ffff 00009300 +LDT=0000 00000000 0000ffff 00008200 +TR =0000 00000000 0000ffff 00008b00 +GDT= 00000000 0000ffff +IDT= 00000000 0000ffff +CR0=60000010 CR2=00000000 CR3=00000000 CR4=00000000 +DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 +DR6=00000000ffff0ff0 DR7=0000000000000400 +CCS=00000000 CCD=00000000 CCO=DYNAMIC +EFER=0000000000000000 +FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80 +FPR0=0000000000000000 0000 FPR1=0000000000000000 0000 +FPR2=0000000000000000 0000 FPR3=0000000000000000 0000 +FPR4=0000000000000000 0000 FPR5=0000000000000000 0000 +FPR6=0000000000000000 0000 FPR7=0000000000000000 0000 +XMM00=0000000000000000 0000000000000000 XMM01=0000000000000000 0000000000000000 +XMM02=0000000000000000 0000000000000000 XMM03=0000000000000000 0000000000000000 +XMM04=0000000000000000 0000000000000000 XMM05=0000000000000000 0000000000000000 +XMM06=0000000000000000 0000000000000000 XMM07=0000000000000000 0000000000000000 diff --git a/nel_os_kernel/src/main.rs b/nel_os_kernel/src/main.rs index e642492..c22c3a6 100644 --- a/nel_os_kernel/src/main.rs +++ b/nel_os_kernel/src/main.rs @@ -1,6 +1,8 @@ #![no_std] #![no_main] +extern crate alloc; + pub mod allocator; pub mod constant; pub mod logging; @@ -8,6 +10,8 @@ pub mod memory; pub mod paging; pub mod serial; +use alloc::vec; + use core::arch::asm; use core::panic::PanicInfo; use core::ptr::addr_of; @@ -17,7 +21,6 @@ use x86_64::{structures::paging::OffsetPageTable, VirtAddr}; use crate::{ constant::{BANNER, KERNEL_STACK_SIZE, PKG_VERSION}, memory::BitmapMemoryTable, - paging::get_active_level_4_table, }; #[repr(C, align(16))] @@ -107,5 +110,9 @@ pub extern "sysv64" fn main(usable_memory: &nel_os_common::memory::UsableMemory) allocator::init_heap(&mut mapper, &mut bitmap_table).unwrap(); + let mut test_vec = vec![1, 2, 3, 4, 9]; + test_vec.push(10); + info!("Vector test: {:?}", test_vec); + hlt_loop(); } diff --git a/nel_os_kernel/src/paging.rs b/nel_os_kernel/src/paging.rs index 342a9fb..e9e1c69 100644 --- a/nel_os_kernel/src/paging.rs +++ b/nel_os_kernel/src/paging.rs @@ -13,7 +13,7 @@ pub fn init_page_table(frame_allocator: &mut impl FrameAllocator) -> * let (lv4_frame, lv4_table) = new_page_table(frame_allocator); let (lv3_frame, lv3_table) = new_page_table(frame_allocator); - let base_flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::GLOBAL; + let base_flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::ACCESSED; let lv4: &mut PageTable = unsafe { &mut *lv4_table }; diff --git a/nel_os_kernel/triple_fault_fix.md b/nel_os_kernel/triple_fault_fix.md new file mode 100644 index 0000000..ee1d144 --- /dev/null +++ b/nel_os_kernel/triple_fault_fix.md @@ -0,0 +1,97 @@ +# Triple Fault 修正内容 + +## 問題の概要 +`paging::initialize()`関数を実行するとQEMUがトリプルフォルトで落ちる問題が発生していました。 + +## 原因 +1. **カーネルの仮想アドレスを物理アドレスとして使用** + - 静的変数のページテーブルのアドレスをそのまま物理アドレスとして扱っていた + - カーネルは0x100000付近の仮想アドレスで動作しているが、これは物理アドレスではない + +2. **物理アドレス0x0の使用** + - ビットマップメモリアロケータが最初の1MBを予約していなかった + - 物理アドレス0x0にページテーブルを配置しようとしてトリプルフォルト + +3. **不十分なメモリマッピング範囲** + - 最初は4GBまでしかマッピングしていなかった + - ヒープが5GB付近に配置されたためページフォルトが発生 + +## 修正内容 + +### 1. ビットマップメモリアロケータの修正 (memory.rs) +```rust +// 最初の1MB(256ページ)を予約 +const RESERVED_PAGES: usize = 256; // 1MB / 4KB + +let mut table = Self { + used_map, + start: RESERVED_PAGES, // 0ではなく256から開始 + end: usize::MAX, +}; + +// 最初の1MBを明示的に予約済みとしてマーク +for i in 0..RESERVED_PAGES { + table.set_frame(i, false); +} +``` + +### 2. ページテーブル初期化の修正 (paging.rs) +```rust +// 静的変数を削除し、動的に物理メモリを確保 +pub unsafe fn initialize(bitmap_table: &mut BitmapMemoryTable) -> PhysFrame { + let new_frame = unsafe { initialize_identity_mapping(bitmap_table) }; + // ... +} + +unsafe fn initialize_identity_mapping(bitmap_table: &mut BitmapMemoryTable) -> PhysFrame { + // 物理フレームを動的に確保 + let pml4_frame = bitmap_table.allocate_frame().expect("Failed to allocate PML4 frame"); + let pml4_addr = pml4_frame.start_address().as_u64(); + let pml4_table = unsafe { &mut *(pml4_addr as *mut PageTable) }; + *pml4_table = PageTable::new(); + + // PDPテーブルも同様に確保 + let pdp_frame = bitmap_table.allocate_frame().expect("Failed to allocate PDP frame"); + // ... +} +``` + +### 3. メモリマッピング範囲の拡張 +```rust +// 4GBから64GBへ拡張 +// Create identity mapping for first 64GB (64 PDP entries, each covering 1GB) +for i in 0..64 { + // 各1GBエントリに対してページディレクトリを作成 + // ... +} +``` + +### 4. main.rsの修正 +```rust +// bitmap_tableをpaging::initialize()に渡す +let mut mapper = { + unsafe { paging::initialize(&mut bitmap_table) }; + let lv4_table = get_active_level_4_table(); + unsafe { OffsetPageTable::new(lv4_table, VirtAddr::new(0x0)) } +}; +``` + +### 5. unsafe操作の適切な処理 +```rust +// unsafe操作をunsafeブロックで囲む +let new_frame = unsafe { initialize_identity_mapping(bitmap_table) }; + +// raw constを使用してmutable staticへの参照を作成 +PML4_TABLE[0].set_frame(phys_frame(&raw const PDP_TABLE), flags); +``` + +## 結果 +- 物理メモリアロケータが正しく0x208000から物理フレームを割り当てるようになった +- 64GBまでの恒等マッピングにより、5GB付近のヒープアクセスも成功 +- トリプルフォルトが解消され、カーネルが正常に動作するようになった + +## 学んだこと +1. カーネルの仮想アドレスと物理アドレスを区別することの重要性 +2. 低位メモリ(0-1MB)は予約領域として扱うべき +3. ページテーブルのマッピング範囲は使用するメモリ全体をカバーする必要がある +4. UEFIは恒等マッピングを提供しているため、物理アドレスへの直接アクセスが可能 \ No newline at end of file