wip
This commit is contained in:
@@ -1,97 +0,0 @@
|
||||
# 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は恒等マッピングを提供しているため、物理アドレスへの直接アクセスが可能
|
||||
Reference in New Issue
Block a user