xv6のブートプロセスには、idewait()という関数が入っている。IDEコントローラを監視して、BSYではなくなったら、次に進むようになっている。 IDEのコントローラの詳細については、以下を参照した。もちろん、これがMIPSのアーキテクチャと異っていることは100も承知だ。だが、とりあえず確実な情報として、x86で動作しているものをそのまま移植したい。
Input/output base address - Wikipedia, the free encyclopedia
まずは、IDEのセカンダリのIRQアドレスが1f0-1f7であることが分かった。次に、xv6がアクセスしている0x1f7について調査してみる。
Status Byte In the following table you will find the layout of the so-called Status Byte. Bit Abbreviation Function 0 ERR Indicates an error occurred. Send a new command to clear it (or nuke it with a Software Reset). 3 DRQ Set when the drive has PIO data to transfer, or is ready to accept PIO data. 4 SRV Overlapped Mode Service Request. 5 DF Drive Fault Error (does not set ERR). 6 RDY Bit is clear when drive is spun down, or after an error. Set otherwise. 7 BSY Indicates the drive is preparing to send/receive data (wait for it to clear). In case of 'hang' (it never clears), do a software reset.
なるほど、7ビット目であるBSYが0で、6ビット目であるRDYが1になるまで、idewaitは待つわけか。では、早速IDEコントローラをそのように実装しよう。
MemResult ModuleIde::LoadData (Addr_t addr, Size_t size, Word_t *data) { switch (addr) { case 0xb40001f0: // Data Port fprintf (m_debug_fp, "<IDE: DataPort(0x%08x) Load>\n", addr); *data = m_sys_reg[0]; break; case 0xb40001f1: // Features Error Information fprintf (m_debug_fp, "<IDE: Feat/ErrInfo(0x%08x) Load>\n", addr); *data = m_sys_reg[1]; break; case 0xb40001f2: // Sector Count fprintf (m_debug_fp, "<IDE: SectorCount(0x%08x) Load>\n", addr); *data = m_sys_reg[2]; break; case 0xb40001f3: // Sector Number LBAlo fprintf (m_debug_fp, "<IDE: SecNum:LBAlo(0x%08x) Load>\n", addr); *data = m_sys_reg[3]; break; case 0xb40001f4: // Sector Number LBAmid fprintf (m_debug_fp, "<IDE: SecNum:LBAmid(0x%08x) Load>\n", addr); *data = m_sys_reg[4]; break; case 0xb40001f5: // Sector Number LBAhi fprintf (m_debug_fp, "<IDE: SecNum:LBAhi(0x%08x) Load>\n", addr); *data = m_sys_reg[5]; break; case 0xb40001f6: // Drive/Head Port fprintf (m_debug_fp, "<IDE: Drive/HeadPort(0x%08x) Load>\n", addr); *data = m_sys_reg[6]; break; case 0xb40001f7: // CmdPrt/RegStatusPort fprintf (m_debug_fp, "<IDE: CommandPort:RegularStatus(0x%08x) Load>\n", addr); *data = m_sys_reg[7]; break; } return MemNoExcept; }
実装としてはイマイチだが、とりあえずはこれで要件は満たされる。 という訳で、改造したシミュレータを使って再度xv6をブートさせると、、、
swimmer_mips --binfile kernel --out debug.log --debug_func --debug_gvar --init_pc 0x80100000 --max 1000000 xv6... cpu0: panic: kfree 80104344 8050d678 65 0 0 0 0 0 0 0v
ありゃー、panicを起こした。。。でも、何となく何ができるのか分かってきたぞ。今度はこれを追い掛ける。