298 lines
6.7 KiB
Markdown
298 lines
6.7 KiB
Markdown
# Aios Troubleshooting Guide
|
||
|
||
## Common Issues and Solutions
|
||
|
||
### 1. Page Table Panic Error (`page_table*.rs`)
|
||
|
||
#### Problem
|
||
QEMUでAiosを実行すると、以下のようなパニックが発生する:
|
||
|
||
```
|
||
panicked at 'page_table*.rs:105:25'
|
||
```
|
||
|
||
#### Root Cause
|
||
この問題は主にシェル機能とキーボード入力の実装時に発生する。具体的な原因:
|
||
|
||
1. **ポートI/O競合**: PS/2キーボードのポートアクセス(0x60, 0x64)がbootloaderクレートと競合
|
||
2. **メモリアクセス違反**: unsafe なポートアクセスがページテーブルの整合性を破壊
|
||
3. **割り込み処理**: キーボード割り込みの不適切な処理
|
||
|
||
#### Solution Steps
|
||
|
||
**Step 1: 問題の特定**
|
||
```rust
|
||
// 危険なポートアクセス例
|
||
unsafe fn inb(port: u16) -> u8 {
|
||
let result: u8;
|
||
core::arch::asm!(
|
||
"in al, dx",
|
||
out("al") result,
|
||
in("dx") port,
|
||
);
|
||
result
|
||
}
|
||
```
|
||
|
||
**Step 2: 安全な実装への移行**
|
||
```rust
|
||
// 安全なポートアクセス(遅延付き)
|
||
unsafe fn try_inb(port: u16) -> Option<u8> {
|
||
// Add delay to avoid rapid polling
|
||
for _ in 0..1000 {
|
||
core::arch::asm!("nop");
|
||
}
|
||
|
||
let result: u8;
|
||
core::arch::asm!(
|
||
"in al, dx",
|
||
out("al") result,
|
||
in("dx") port,
|
||
options(nomem, nostack, preserves_flags)
|
||
);
|
||
Some(result)
|
||
}
|
||
```
|
||
|
||
**Step 3: 完全な対策**
|
||
最終的に、以下の基本的なアプローチで解決:
|
||
|
||
```rust
|
||
/// Check if there's data in keyboard buffer
|
||
pub fn has_key() -> bool {
|
||
unsafe {
|
||
let status: u8;
|
||
core::arch::asm!(
|
||
"in al, 0x64",
|
||
out("al") status,
|
||
options(nomem, nostack, preserves_flags)
|
||
);
|
||
(status & 1) != 0
|
||
}
|
||
}
|
||
|
||
/// Read raw scancode from keyboard
|
||
pub fn read_scancode() -> u8 {
|
||
unsafe {
|
||
let scancode: u8;
|
||
core::arch::asm!(
|
||
"in al, 0x60",
|
||
out("al") scancode,
|
||
options(nomem, nostack, preserves_flags)
|
||
);
|
||
scancode
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Prevention
|
||
- `options(nomem, nostack, preserves_flags)` を必ず使用
|
||
- ポーリング頻度を制限(1000サイクル毎など)
|
||
- エラーハンドリングの実装
|
||
- 段階的テスト(まずデバッグ版で検証)
|
||
|
||
---
|
||
|
||
### 2. Keyboard Input Not Working
|
||
|
||
#### Problem
|
||
キーボード入力が QEMU で認識されない問題。
|
||
|
||
#### Symptoms
|
||
- QEMUは正常に起動する
|
||
- 画面表示は正常
|
||
- キーを押しても反応しない
|
||
- スキャンコードが取得できない
|
||
|
||
#### Root Causes
|
||
|
||
**Cause 1: QEMUのフォーカス問題**
|
||
- QEMUウィンドウにフォーカスがない
|
||
- マウスキャプチャが無効
|
||
|
||
**Cause 2: ポーリング頻度の問題**
|
||
```rust
|
||
// 問題のあるコード
|
||
if counter % 50000 == 0 {
|
||
// キーボードチェックの頻度が低すぎ
|
||
}
|
||
```
|
||
|
||
**Cause 3: スキャンコードマッピングの不備**
|
||
```rust
|
||
// 不完全なマッピング
|
||
static SCANCODE_TO_ASCII: [u8; 128] = [
|
||
// 配列サイズが127で不一致
|
||
];
|
||
```
|
||
|
||
#### Solutions
|
||
|
||
**Solution 1: QEMUの正しい起動**
|
||
```bash
|
||
# GTK表示でフォーカス確保
|
||
qemu-system-x86_64 \
|
||
-drive format=raw,file="$BOOT_IMAGE" \
|
||
-display gtk
|
||
|
||
# または、nographic を避ける
|
||
qemu-system-x86_64 \
|
||
-drive format=raw,file="$BOOT_IMAGE"
|
||
```
|
||
|
||
**Solution 2: 適切なポーリング頻度**
|
||
```rust
|
||
loop {
|
||
if keyboard_basic::has_key() {
|
||
let scancode = keyboard_basic::read_scancode();
|
||
// 即座に処理
|
||
}
|
||
|
||
// 軽い遅延のみ
|
||
for _ in 0..1000 {
|
||
unsafe { core::arch::asm!("nop"); }
|
||
}
|
||
}
|
||
```
|
||
|
||
**Solution 3: 段階的デバッグ**
|
||
|
||
**Phase 1: スキャンコード確認**
|
||
```rust
|
||
// デバッグ版でスキャンコードを表示
|
||
if keyboard_basic::has_key() {
|
||
let scancode = keyboard_basic::read_scancode();
|
||
print_hex(scancode); // 16進数で表示
|
||
}
|
||
```
|
||
|
||
**Phase 2: キーリリース除外**
|
||
```rust
|
||
// キープレスのみ処理(bit 7 = 0)
|
||
if (scancode & 0x80) == 0 {
|
||
// キープレス処理
|
||
}
|
||
```
|
||
|
||
**Phase 3: 完全なマッピング**
|
||
```rust
|
||
pub fn scancode_to_char(scancode: u8) -> Option<char> {
|
||
match scancode {
|
||
0x1E => Some('a'),
|
||
0x30 => Some('b'),
|
||
// ... 全てのキーをマッピング
|
||
0x1C => Some('\n'), // Enter
|
||
_ => None,
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Verification Steps
|
||
|
||
1. **基本テスト**: スキャンコード表示版でキー入力確認
|
||
2. **マッピングテスト**: 特定キー(a, enter等)の動作確認
|
||
3. **シェルテスト**: コマンド入力・実行の確認
|
||
|
||
#### Working Configuration
|
||
|
||
最終的に動作した設定:
|
||
|
||
```rust
|
||
// keyboard_basic.rs
|
||
pub fn has_key() -> bool {
|
||
unsafe {
|
||
let status: u8;
|
||
core::arch::asm!("in al, 0x64", out("al") status, options(nomem, nostack, preserves_flags));
|
||
(status & 1) != 0
|
||
}
|
||
}
|
||
|
||
// メインループ
|
||
loop {
|
||
if keyboard_basic::has_key() {
|
||
let scancode = keyboard_basic::read_scancode();
|
||
if scancode != last_scancode && (scancode & 0x80) == 0 {
|
||
if let Some(ch) = keyboard_basic::scancode_to_char(scancode) {
|
||
process_char(ch);
|
||
}
|
||
}
|
||
}
|
||
// 軽い遅延
|
||
for _ in 0..1000 {
|
||
unsafe { core::arch::asm!("nop"); }
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3. Build Errors
|
||
|
||
#### Type Mismatch in Arrays
|
||
```rust
|
||
// Error: expected array with size 128, found 127
|
||
static SCANCODE_TO_ASCII: [u8; 128] = [...]; // 要素が127個
|
||
|
||
// Solution: 正確な要素数
|
||
static SCANCODE_TO_ASCII: [u8; 128] = [
|
||
// 128個の要素を確保
|
||
0, 27, b'1', ..., 0 // 最後に0で埋める
|
||
];
|
||
```
|
||
|
||
#### Unused Imports
|
||
```rust
|
||
// Warning: unused import
|
||
use core::convert::TryFrom; // 削除
|
||
|
||
// Warning: unused import
|
||
use crate::keyboard; // 使用しない場合は削除
|
||
```
|
||
|
||
---
|
||
|
||
### 4. QEMU-specific Issues
|
||
|
||
#### Display Problems
|
||
```bash
|
||
# 問題: nographic で表示されない
|
||
qemu-system-x86_64 -kernel kernel.bin -nographic
|
||
|
||
# 解決: 標準表示を使用
|
||
qemu-system-x86_64 -kernel kernel.bin
|
||
```
|
||
|
||
#### Mouse Capture
|
||
```
|
||
# QEMUでマウスキャプチャを有効化
|
||
Ctrl+Alt+G (toggle mouse capture)
|
||
```
|
||
|
||
#### Exit QEMU
|
||
```
|
||
# QEMUの終了方法
|
||
Ctrl+A, X # または
|
||
Alt+F4 # ウィンドウを閉じる
|
||
```
|
||
|
||
---
|
||
|
||
### Best Practices
|
||
|
||
1. **段階的実装**
|
||
- 静的表示 → スキャンコード確認 → 完全シェル
|
||
|
||
2. **デバッグ情報の表示**
|
||
- スキャンコードの16進表示
|
||
- ポーリング回数のカウンタ
|
||
- キー受信回数の表示
|
||
|
||
3. **安全なポートアクセス**
|
||
- `options(nomem, nostack, preserves_flags)` 使用
|
||
- 適切な遅延の実装
|
||
- エラーハンドリング
|
||
|
||
4. **テスト環境**
|
||
- QEMUの適切な起動オプション
|
||
- フォーカスの確保
|
||
- 段階的な機能テスト |