寫作業系統之搭建開發環境

東小夫 發表於 2021-10-14

本篇和大家分享搭建寫作業系統的開發環境,然後建立一個軟盤,再用匯編程式碼列印一個“Hello World”。

本篇目標

  1. 搭建開發環境。
  2. 建立虛擬軟盤。
  3. 執行一個最最簡單的作業系統。

開發環境

開發機器

我的開發環境如下:

  1. 物理機是Macbook。
  2. 在Macbook上執行vmware,建立一個虛擬機器vm。虛擬機器的配置是:記憶體2G,硬碟25G。
  3. 在vm安裝64位的centos8系統。一定要安裝GUI。

nasm

安裝

yum install nams

bochs

這又是一個虛擬機器。我們自己寫的作業系統將在這個虛擬機器上除錯、執行。

安裝

請安裝兩個版本,一個用於從彙編程式碼的層面除錯作業系統,記作bochs;另一個用於使用gdb從C語言層面除錯作業系統,記作bochs-gdb。

記得給bochs-gdb建立一個軟連結,這樣在執行bochs-gdb時可以直接使用bochs-gdb而不必寫出那一長串的安裝路徑。

bochs

下載連結

https://jaist.dl.sourceforge.net/project/bochs/bochs/2.6.11/bochs-2.6.11-1.x86_64.rpm

請參考下面的命令安裝:

root# rpm -i bochs-2.6.11-1.x86_64.rpm

我之前安裝的筆記丟失。這是我從bochs官網文件中查到的用rpm方式安裝的命令。

這個版本的bochs有兩個配置檔案:

  1. bochsrc,用於正常執行bochs。
  2. bochsrc-debug,在以斷點除錯彙編程式碼的模式啟動時使用這個配置檔案。

配置檔案bochsrc的內容如下:

###############################################################
# Configuration file for Bochs
###############################################################

# how much memory the emulated machine will have
megs: 32

# filename of ROM images
romimage: file=/usr/local/share/bochs/BIOS-bochs-latest
vgaromimage: file=/usr/local/share/bochs/VGABIOS-lgpl-latest

# what disk images will be used
# floppya: 1_44=freedos.img, status=inserted
# floppyb: 1_44=pm.img, status=inserted
floppya: 1_44="a.img", status=inserted

ata0-master: type=disk, path="80m.img", mode=flat
#ata0-slave: type=disk, path="80n.img", mode=flat

# choose the boot disk.
boot: a
# boot: floppy
# where do we send log messages?
log: bochsout.txt

# disable the mouse
mouse: enabled=0
#magic_break:enabled=1
# enable key mapping, using US layout as default.

keyboard: keymap=/usr/local/share/bochs/keymaps/x11-pc-us.map

配置檔案bochsrc-debug的內容如下:

###############################################################
# Configuration file for Bochs
###############################################################

# how much memory the emulated machine will have
megs: 32

# filename of ROM images
romimage: file=/usr/local/share/bochs/BIOS-bochs-latest
vgaromimage: file=/usr/local/share/bochs/VGABIOS-lgpl-latest

# what disk images will be used
# floppya: 1_44=freedos.img, status=inserted
# floppyb: 1_44=pm.img, status=inserted
floppya: 1_44="a.img", status=inserted

# choose the boot disk.
boot: a
# boot: floppy
# where do we send log messages?
log: bochsout.txt

# disable the mouse
mouse: enabled=0
magic_break:enabled=1
# enable key mapping, using US layout as default.

# gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0

keyboard: keymap=/usr/local/share/bochs/keymaps/x11-pc-us.map

# magic_break:enable=1

bochsrc相比,bochsrc-debug中多了一句

magic_break:enabled=1

這句的作用是開啟彙編程式碼的斷點除錯功能。

bochs-gdb

https://udomain.dl.sourceforge.net/project/bochs/bochs/2.6.11/bochs-2.6.11.tar.gz

進入bochs的原始碼包,執行下面的命令:

# 把/home/cg/tools/bochs-2.6.11換成你自己的開發機器上的安裝目錄
./configure --prefix=/home/cg/tools/bochs-2.6.11 --enable-plugins   --enable-x86-64   --enable-cpp  --enable-disasm   --enable-gdb-stub --enable-x86-debugger --enable-e1000 
make
make install

建立用於啟動bochs-gdb的配置檔案gdb-bochsrc,檔案中的內容如下:

###############################################################
# Configuration file for Bochs
###############################################################

# how much memory the emulated machine will have
megs: 32

# filename of ROM images
romimage: file=/usr/local/share/bochs/BIOS-bochs-latest
vgaromimage: file=/usr/local/share/bochs/VGABIOS-lgpl-latest

# what disk images will be used
# floppya: 1_44=freedos.img, status=inserted
# floppyb: 1_44=pm.img, status=inserted
floppya: 1_44="a.img", status=inserted

ata0-master: type=disk, path="80m.img", mode=flat

# choose the boot disk.
boot: a
# boot: floppy
# where do we send log messages?
log: bochsout.txt

# disable the mouse
mouse: enabled=0
# magic_break:enabled=1
# enable key mapping, using US layout as default.

gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0

keyboard: keymap=/usr/local/share/bochs/keymaps/x11-pc-us.map

配置GDB除錯的語句是:

gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0

如果能正常啟動bochs-gdb,暫時不必關注其他語句的作用。等到以後用到再瞭解也不遲。

執行

# 正常啟動
bochs -f bochsrc
# 以斷點除錯彙編程式碼的模式啟動
bochs -f bochsrc-debug
# 以gdb除錯C程式碼的模式啟動
bochs-gdb -f gdb-bochsrc

執行上面命令中任何一個之後,如果出現下面的輸出資訊,你的bochs就安裝成功了。

注意,要在你的虛擬機器vm上執行上面的命令。

[[email protected] v1]# bochs
========================================================================
                     Bochs x86 Emulator 2.6.11.svn
             Built from SVN snapshot after release 2.6.11
                  Compiled on Jul 14 2020 at 17:19:17
========================================================================
00000000000i[      ] LTDL_LIBRARY_PATH not set. using compile time default '/usr/local/lib/bochs/plugins'
00000000000i[      ] BXSHARE not set. using compile time default '/usr/local/share/bochs'
00000000000i[      ] lt_dlhandle is 0x1551860
00000000000i[PLUGIN] loaded plugin libbx_unmapped.so
00000000000i[      ] lt_dlhandle is 0x15521a0
00000000000i[PLUGIN] loaded plugin libbx_biosdev.so
00000000000i[      ] lt_dlhandle is 0x1552b20
00000000000i[PLUGIN] loaded plugin libbx_speaker.so
00000000000i[      ] lt_dlhandle is 0x1553930
00000000000i[PLUGIN] loaded plugin libbx_extfpuirq.so
00000000000i[      ] lt_dlhandle is 0x15541b0
00000000000i[PLUGIN] loaded plugin libbx_parallel.so
00000000000i[      ] lt_dlhandle is 0x1555e10
00000000000i[PLUGIN] loaded plugin libbx_serial.so
00000000000i[      ] lt_dlhandle is 0x155a210
00000000000i[PLUGIN] loaded plugin libbx_iodebug.so
00000000000i[      ] reading configuration from bochsrc
------------------------------
Bochs Configuration: Main Menu
------------------------------

This is the Bochs Configuration Interface, where you can describe the
machine that you want to simulate.  Bochs has already searched for a
configuration file (typically called bochsrc.txt) and loaded it if it
could be found.  When you are satisfied with the configuration, go
ahead and start the simulation.

You can also start bochs with the -q option to skip these menus.

1. Restore factory default configuration
2. Read options from...
3. Edit options
4. Save options to...
5. Restore the Bochs state from...
6. Begin simulation
7. Quit now

Please choose one: [6]

按下Enter鍵,如果看到下面的畫面,說明你的bochs可以正常使用了。

注意,按下Enter鍵後,bochs可能會是一塊黑屏,需要你在終端輸入c,然後再次按下Enter鍵。

寫作業系統之搭建開發環境

雜項

安裝上面的說明安裝好開發環境後,我們的開發模式將會是下面這樣的:

  1. 專案程式碼也就是作業系統程式碼在虛擬機器上,例如,我的程式碼在虛擬機器上的目錄是:/home/cg/os/os-ebook
  2. 在物理機上使用終端連線到虛擬機器,然後在這個終端上執行編譯程式碼的命令。我也用這個終端使用vim寫專案程式碼。
  3. 在虛擬機器的終端上執行執行bochs的命令。

虛擬軟盤

使用bximage建立虛擬軟盤,過程如下:

[[email protected] v30]# bximage
========================================================================
                                bximage
  Disk Image Creation / Conversion / Resize and Commit Tool for Bochs
         $Id: bximage.cc 13481 2018-03-30 21:04:04Z vruppert $
========================================================================

1. Create new floppy or hard disk image
2. Convert hard disk image to other format (mode)
3. Resize hard disk image
4. Commit 'undoable' redolog to base image
5. Disk image info

0. Quit

Please choose one [0] 1

Create image

Do you want to create a floppy disk image or a hard disk image?
Please type hd or fd. [hd] fd

Choose the size of floppy disk image to create.
Please type 160k, 180k, 320k, 360k, 720k, 1.2M, 1.44M, 1.68M, 1.72M, or 2.88M.
 [1.44M]

What should be the name of the image?
[a.img]

Creating floppy image 'a.img' with 2880 sectors

The following line should appear in your bochsrc:
  floppya: image="a.img", status=inserted

檢視執行bximage的目錄,會發現已經多了一個檔案a.img

[[email protected] v30]# ls -lh a.img
-rw-r-----. 1 root root 1.5M Sep  8 04:15 a.img

a.img就是我們剛剛用bximage建立的虛擬軟盤。

作業系統的最初形態

執行

做完上面一連串有點無聊的準備工作後,我們可以做點有趣的事情了。

新建一個檔案boot.asm,把下面的程式碼複製到boot.asm中。

org 0x7c00

jmp     LABEL_START
nop

        ; 下面是 FAT12 磁碟的頭
        BS_OEMName      DB 'YOUR--OS'   ; OEM String, 必須 8 個位元組
        BPB_BytsPerSec  DW 512          ; 每扇區位元組數
        BPB_SecPerClus  DB 1            ; 每簇多少扇區
        BPB_RsvdSecCnt  DW 1            ; Boot 記錄佔用多少扇區
        BPB_NumFATs     DB 2            ; 共有多少 FAT 表
        BPB_RootEntCnt  DW 224          ; 根目錄檔案數最大值
        BPB_TotSec16    DW 2880         ; 邏輯扇區總數
        BPB_Media       DB 0xF0         ; 媒體描述符
        BPB_FATSz16     DW 9            ; 每FAT扇區數
        BPB_SecPerTrk   DW 18           ; 每磁軌扇區數
        BPB_NumHeads    DW 2            ; 磁頭數(面數)
        BPB_HiddSec     DD 0            ; 隱藏扇區數
        BPB_TotSec32    DD 0            ; wTotalSectorCount為0時這個值記錄扇區數
        BS_DrvNum       DB 0            ; 中斷 13 的驅動器號
        BS_Reserved1    DB 0            ; 未使用
        BS_BootSig      DB 29h          ; 擴充套件引導標記 (29h)
        BS_VolID        DD 0            ; 卷序列號
        BS_VolLab       DB 'YOUR--OS.02'; 卷標, 必須 11 個位元組
        BS_FileSysType  DB 'FAT12   '   ; 檔案系統型別, 必須 8個位元組

message:    db      "Hello,World OS!"
messageLength   equ     $ - message

LABEL_START:
        mov ax, 0xb800
        mov gs, ax
        mov cx, messageLength
        mov di, (80 * 2 + 20) * 2
        mov si, 0
.1:
        cmp     cx, 0
        je      END
        mov al,[message+si]
        mov ah, 0x0E
        mov [gs:di], ax
        add di,2
        dec cx
        inc si
        jmp .1

END:
        jmp $


times   510 - ($ - $$)  db      0
dw      0xAA55

再新建一個檔案Makefile,往裡面填充下面的程式碼。

.PYTHON:everything

everything:boot.bin
        dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc
        sudo mount -o loop a.img /mnt/floppy/
        sudo umount /mnt/floppy
clean:
        rm -rvf *.bin

boot.bin:boot.asm
        nasm $< -o [email protected]

在物理機上的終端執行make,過程如下:

[[email protected] os-ebook]# make
dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc
1+0 records in
1+0 records out
512 bytes copied, 0.000106086 s, 4.8 MB/s
sudo mount -o loop a.img /mnt/floppy/
sudo umount /mnt/floppy

在虛擬機器vm上的終端上執行我們的作業系統,命令如下:

bochs -f bochsrc

如果一切正常的話,會看到下面的畫面。我是看到了,不知各位在自己的電腦上看到相同的畫面沒有。

寫作業系統之搭建開發環境

解說

把上面圖中的那個bochs畫面叫做作業系統實在有點勉強。

事實上,它只是一個引導扇區。雖然它不是作業系統,但作業系統的啟動是從它開始的。

這個引導扇區只有512個位元組,最後兩個位元組必須是55AA

我們要用剩餘的510個位元組完成下面的任務:

  1. 安裝FAT12檔案系統的相關資料,就是boot.asm中的BS_OEMName等資料。
  2. 把loader載入到記憶體中。

loader是什麼?它是一個二進位制程式,作用是把作業系統核心載入到記憶體中。

是的,loader的主要作用也是載入其他二進位制檔案到記憶體中,但是會複雜一些。

對了,boot.asm中使用的程式語言是一種叫做nasm的組合語言。它的官網是:https://nasm.us/index.php

好了,本篇到這裡就結束了,祝讀者朋友們一切順利!反正我當初是非常不順利的。