使用Bochs學習硬件原理


什么是Bochs?

簡單地說,Bochs是一款仿真軟件,可以用軟件的方式模擬硬件的工作。同類軟件有Qemu,仿真軟件與虛擬機(hypervisor)還不完全相同,仿真軟件是完全軟件模擬硬件,而虛擬機軟件(比如Vmware, VirtualBox)是利用主機的硬件進行工作。

Bochs的主頁地址:http://bochs.sourceforge.net/

Bochs軟件的下載地址:http://sourceforge.net/projects/bochs/files/bochs/

Bochs的使用

Bochs的使用依賴配置文件,通過配置文件指定不同的硬件,以及指定存儲介質的映像文件(BIOS的ROM文件、磁盤文件等)。

在Windows環境下安裝過Bochs后,在配置文件上右鍵菜單會出現Run, Debug的菜單選項,從而啟動運行或者調試。

Bochs調試器

Bochs的調試器命令與gdb命令十分相似,但是更加強大。簡單介紹幾條命令的使用:

   1: #流程控制
   2: c             #continue, 繼續執行
   3: s [count]     #step, 單步執行count次
   4: #斷點
   5: vb seg:off    #設置邏輯地址斷點
   6: lb addr       #設置物理地址斷點
   7: info break    #查看斷點
   8: d n           #刪除斷點
   9: #查看內存
  10: x/n[bhwg][xduotc] #查看內存
  11: [bhwg]        #顯示單元大小,分別代表byte, half, word, giant word
  12: [xduotc]      #顯示格式,分別代表hex, dec, unsigned, octal, binary, char
  13: #查看寄存器
  14: r             #查看基本寄存器
  15: sreg          #查看段寄存器

 

更多的命令,請輸入help查看。

在Windows環境下編譯Bochs源代碼

首先說一下編譯源碼的動機,當我們安裝了Bochs之后就已經可以使用它來運行或者調試一個被仿真的系統了。 這種調試類似於gdb,調試目標是運行在Bochs之上的系統。

然而,我們知道,既然Bochs是一個開源的項目,以通過軟件的方式仿真了硬件系統,那么我們就可以通過查看Bochs的源碼來學習相關的硬件知識(比如Intel體系結構,BIOS,DMA等)了。

從上面的下載地址下載一份源代碼,解壓后,能看到vs2008/bochs.sln文件,從而打開Visual Studio項目進行編譯。

默認配置選項中沒有包含對bochsdbg的支持,因此我們需要重新運行configure程序,悲劇的是configure是Linux下面的程序,我們可以通過以下方式來達到同樣的目的:

  1. 1. 安裝mingw,以及msys,將msys/bin目錄添加到系統PATH環境變量中;
  2. 2. 修改源碼目錄下的.conf.win32_vcpp文件,添加
       1: --enable-debugger --enable-disasm
  3. 3. 打開Visual Studio的Prompt命令行,cd到源碼目錄下,運行
       1: bash.exe .conf.win32_vcpp

完成以上步驟之后,就可以編譯出具有debug功能的Bochs可執行程序了。

Bochs是怎樣處理調試命令的?

我們可以在位置上設置斷點:

   1: void bx_dbg_user_input_loop(void) /*dbg_main.cc*/

然后在調試窗口中輸入命令

   1: r

程序會在這兩個斷點處中斷,這個bx_dbg_user_input_loop函數就是不斷接收調試命令的循環體,它會把接收到的調試命令經過lex&yacc框架進行解析,然后調用到相應的handler來處理調試請求。

這些handler都在debug.h文件中進行聲明,比如處理r命令的handler定義為

   1: void bx_dbg_info_registers_command(int);

在該函數的定義處設置斷點,我們就能夠了解到Bochs是怎樣處理r這樣的調試請求的。

通過跟蹤幾個調試命令的實現,我們發現了三個重要的全局變量:

   1: BOCHSAPI BX_CPU_C bx_cpu;
   2: BOCHSAPI BX_MEM_C bx_mem;
   3: bx_devices_c bx_devices;

分別保存着用來描述CPU、內存和外部設備的數據結構。

指令IN和OUT是如何處理的?

由於我們希望通過Bochs來學習硬件相關的內容,所以會對IN和OUT這兩條指令很感興趣,因為CPU就是通過這兩條指令與外部設備之間進行協調工作的。

我們通過嘗試,找到了下面這個函數

   1: /*
   2:  * Write a byte of data to the IO memory address space.
   3:  */
   4:  
   5:   void BX_CPP_AttrRegparmN(3)
   6: bx_devices_c::outp(Bit16u addr, Bit32u value, unsigned io_len)

bx_devices會在內部維護一個外設端口對應的讀和寫的handler的數組

   1: struct io_handler_struct **read_port_to_handler;
   2: struct io_handler_struct **write_port_to_handler;

這是兩個二維指針數組,用端口號作為下標可以找到某個端口對應的讀寫處理函數,默認會把每個handler都設置成io_write_handlers

   1: /* set handlers to the default one */
   2:  for (i=0; i < PORTS; i++) {
   3:    read_port_to_handler[i] = &io_read_handlers;
   4:    write_port_to_handler[i] = &io_write_handlers;
   5:  }

通過查找函數

   1: #define DEV_register_ioread_handler(b,c,d,e,f) bx_devices.register_io_read_handler(b,c,d,e,f)
   2: #define DEV_register_iowrite_handler(b,c,d,e,f) bx_devices.register_io_write_handler(b,c,d,e,f)

我們可以找到哪些設備支持了自己的IO讀寫功能,以及其對應的handler。

以DMA為例,我們可以找到如下的注冊handler代碼

   1: // 0000..000F
   2: for (i=0x0000; i<=0x000F; i++) {
   3:   DEV_register_ioread_handler(this, read_handler, i, "DMA controller", 1);
   4:   DEV_register_iowrite_handler(this, write_handler, i, "DMA controller", 3);
   5: }
   6:  
   7: // 00080..008F
   8: for (i=0x0080; i<=0x008F; i++) {
   9:   DEV_register_ioread_handler(this, read_handler, i, "DMA controller", 1);
  10:   DEV_register_iowrite_handler(this, write_handler, i, "DMA controller", 3);
  11: }
  12:  
  13: // 000C0..00DE
  14: for (i=0x00C0; i<=0x00DE; i+=2) {
  15:   DEV_register_ioread_handler(this, read_handler, i, "DMA controller", 1);
  16:   DEV_register_iowrite_handler(this, write_handler, i, "DMA controller", 3);
  17: }

只要在DMA模塊的read_handler和write_handler處理設置斷點,我們就可以動態地調試DMA的處理邏輯了。

 

經過了以上的准備工作之后,我們就可以開始調試一個具體的系統了。我是以DLX為目標進行調試的,在調試過程中,我們可以一步一步地了解到從計算機加電后執行BIOS開機自檢程序,到加載MBR,通過LILO一步一步地把Linux操作系統啟動起來的全過程,一個奇妙的旅程即將開始!

 

有人已經這樣做了,並且根據Bochs的代碼,出了一本書:http://www.mouseos.com/books/x86-64/index.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM