使用Bochs學習硬件原理

什麼是Bochs?

簡單地說,Bochs是一款仿真軟件,能夠用軟件的方式模擬硬件的工做。同類軟件有Qemu,仿真軟件與虛擬機(hypervisor)還不徹底相同,仿真軟件是徹底軟件模擬硬件,而虛擬機軟件(好比Vmware, VirtualBox)是利用主機的硬件進行工做。html

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

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

Bochs的使用

Bochs的使用依賴配置文件,經過配置文件指定不一樣的硬件,以及指定存儲介質的映像文件(BIOS的ROM文件、磁盤文件等)。數據結構

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

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之上的系統。oop

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

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

默認配置選項中沒有包含對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

相關文章
相關標籤/搜索