本篇和大家分享搭建寫操作系統的開發環境,然后建立一個軟盤,再用匯編代碼打印一個“Hello World”。
本篇目標
- 搭建開發環境。
- 建立虛擬軟盤。
- 運行一個最最簡單的操作系統。
開發環境
開發機器
我的開發環境如下:
- 物理機是Macbook。
- 在Macbook上運行
vmware
,建立一個虛擬機vm。虛擬機的配置是:內存2G,硬盤25G。 - 在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有兩個配置文件:
bochsrc
,用於正常運行bochs。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上執行上面的命令。
[root@localhost 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]
按下回車鍵,如果看到下面的畫面,說明你的bochs可以正常使用了。
注意,按下回車鍵后,bochs可能會是一塊黑屏,需要你在終端輸入
c
,然后再次按下回車鍵。
雜項
安裝上面的說明安裝好開發環境后,我們的開發模式將會是下面這樣的:
- 項目代碼也就是操作系統代碼在虛擬機上,例如,我的代碼在虛擬機上的目錄是:
/home/cg/os/os-ebook
。 - 在物理機上使用終端連接到虛擬機,然后在這個終端上執行編譯代碼的命令。我也用這個終端使用vim寫項目代碼。
- 在虛擬機的終端上執行運行bochs的命令。
虛擬軟盤
使用bximage
創建虛擬軟盤,過程如下:
[root@localhost 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
。
[root@localhost 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 $@
在物理機上的終端執行make
,過程如下:
[root@localhost 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個字節完成下面的任務:
- 安裝
FAT12
文件系統的相關數據,就是boot.asm
中的BS_OEMName
等數據。 - 把loader加載到內存中。
loader是什么?它是一個二進制程序,作用是把操作系統內核加載到內存中。
是的,loader的主要作用也是加載其他二進制文件到內存中,但是會復雜一些。
對了,boot.asm中使用的編程語言是一種叫做nasm
的匯編語言。它的官網是:https://nasm.us/index.php 。
好了,本篇到這里就結束了,祝讀者朋友們一切順利!反正我當初是非常不順利的。