tiqwab / xv6-rust

xv6 implementation in rust
MIT License
6 stars 1 forks source link

Fix end symbol to set the last of kernel address #23

Closed tiqwab closed 4 years ago

tiqwab commented 4 years ago

pipe 追加した直後くらいに make DEBUG=1 qemuls | wc すると変な仮想アドレスにアクセスしてしまうバグがあった。

 $ ls | wc
 ...
 panicked at 'PhysAddr(0xffc00000) is too high', src/pmap.rs:167:9

panicked 後に gdb から SIGINT 送って backtrace を確認した。

 (gdb) c
 Continuing.
 ^C
 Program received signal SIGINT, Interrupt.
 The target architecture is assumed to be i386
 => 0xf01001cf <rust_begin_unwind+303>: jmp    0xf01001cf <rust_begin_unwind+303>
 0xf01001cf in rust_begin_unwind (info=0xeffff258) at src/lib.rs:70
 70     loop {}
 (gdb) backtrace 
 #0  0xf01001cf in rust_begin_unwind (info=0xeffff258) at src/lib.rs:70
 #1  0xf0155b3d in core::panicking::panic_fmt ()
 #2  0xf01494e7 in xv6_rust::pmap::PhysAddr::to_va (self=0xeffff324) at src/pmap.rs:167
 #3  0xf014cf10 in xv6_rust::pmap::PageAllocator::alloc (self=0xf01af724 <xv6_rust::pmap::PAGE_ALLOCATOR+4>, 
     flag=xv6_rust::pmap::AllocFlag::AllocZero) at src/pmap.rs:1006
 #4  0xf0149cfe in xv6_rust::pmap::PageDirectory::walk (self=0xeec06000, va=..., should_create=true, 
     allocator=0xf01af724 <xv6_rust::pmap::PAGE_ALLOCATOR+4>) at src/pmap.rs:330
 #5  0xf014a4ae in xv6_rust::pmap::PageDirectory::insert (self=0xeec06000, pa=..., va=..., perm=6, 
     allocator=0xf01af724 <xv6_rust::pmap::PAGE_ALLOCATOR+4>) at src/pmap.rs:430
 #6  0xf014a733 in xv6_rust::pmap::PageDirectory::region_alloc (self=0xeec06000, va=..., len=4096) at src/pmap.rs:453
 #7  0xf0129997 in xv6_rust::env::exec (path=0xeffff864 "wc\000", argv=..., 
     env=0xf015de4c <xv6_rust::env::ENV_TABLE+900>) at src/env.rs:693
 #8  0xf0137d21 in xv6_rust::sysfile::exec (orig_path=0x802025 <error: Cannot access memory at address 0x802025>, 
     orig_argv=...) at src/sysfile.rs:385
 #9  0xf0147d54 in xv6_rust::syscall::syscall (syscall_no=7, a1=8396837, a2=8396837, a3=0, a4=0, a5=0)
     at src/syscall.rs:146
 #10 0xf011b7a0 in xv6_rust::trap::trap_dispatch (tf=0xf015de4c <xv6_rust::env::ENV_TABLE+900>) at src/trap.rs:373
 #11 0xf011bca1 in trap (orig_tf=0xefffffbc) at src/trap.rs:442
 #12 0xf014efe9 in _alltraps () at src/alltraps.S:22
 #13 0xefffffbc in ?? ()
 Backtrace stopped: previous frame inner to this frame (corrupt stack?)

PageAllocator の alloc で失敗しているっぽい。 alloc 時の挙動を見るためにログを追加してみた。

 ...
 [PageAllocator] alloc. pp: 0xf01aa4f0, phys: 9e000, page_free_list: 0xf01aa4f8
 [PageAllocator] alloc. pp: 0xf01aa4f8, phys: 9f000, page_free_list: 0xf01b0f50
 [PageAllocator] alloc. pp: 0xf01b0f50, phys: dea000, page_free_list: 0xf01a8000
 [PageAllocator] alloc. pp: 0xf01a8000, phys: ffc00000, page_free_list: 0x0
 panicked at 'PhysAddr(0xffc00000) is too high', src/pmap.rs:167:9

最後から 2 つ目で設定している page_free_list (次に alloc したときに手に入れる PageInfo, つまり物理ページ) がおかしい。 0xf01a8000 というのは end symbol (kernel の末尾として kernel.ld で設定している) 0xf01a9000 よりも前なのでそのアドレスを alloc してはいけない。 ただ調べるとどうやら悪いのは alloc というより end symbol の位置っぽい。というのは objdump によれば kernel が end よりも後にもロードされることになっているので。

 $ objdump -p target/i686-xv6rust/debug/xv6-rust

 target/i686-xv6rust/debug/xv6-rust:     file format elf32-i386

 Program Header:
     LOAD off    0x00001000 vaddr 0xf0100000 paddr 0x00100000 align 2**12
          filesz 0x0005b000 memsz 0x0005b000 flags r-x
     LOAD off    0x0005c000 vaddr 0xf015b000 paddr 0x0015b000 align 2**12
          filesz 0x000000a8 memsz 0x000000a8 flags rw-
     LOAD off    0x0005c0a8 vaddr 0xf015b0a8 paddr 0x0015b0a8 align 2**12
          filesz 0x00001f58 memsz 0x00001f58 flags r-x
     LOAD off    0x0005e000 vaddr 0xf015d000 paddr 0x0015d000 align 2**12
          filesz 0x0004b00c memsz 0x00092001 flags rw-
    RELRO off    0x0005c000 vaddr 0xf015b000 paddr 0x0015b000 align 2**0
          filesz 0x000000a8 memsz 0x00001000 flags r--
    STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**0
          filesz 0x00000000 memsz 0x00000000 flags rw-

LOAD 4 つ目から 0xf015d000 + 0x00092001 = 0xf01ef001 であり、上の end より明らかに大きい。

kernel.ld を JOS のそれと比べるといくつか省略していた section があったのでそれを追加したところ修正された。恐らくエラーの原因は kernel の bss 領域を PageInfo の一部として不正に使ってしまったせいだった。

 $ objdump -x target/i686-xv6rust/debug/xv6-rust | grep end
 ...
 f01ee23e g       .bss  00000000 end

 $ objdump -p target/i686-xv6rust/debug/xv6-rust
 ...
     LOAD off    0x0005c000 vaddr 0xf015b000 paddr 0x0015b000 align 2**12
          filesz 0x0004b00c memsz 0x00094000 flags rw-

(0xf01ee23e を PGSIZE で切り上げれば 0xf01ef000 なので ok)

なお追加した section のうち実際に存在していたのは .bss.* のみだった。これがどのオブジェクトファイル由来か調べるまではやっていないが、とりあえずこれらも原則加えると思ってしまっていいのかなと。