.text .globl start .code16 start: movb $0xE, %ah # write character in text mode for int 10h movb $'H', %al # write 'H', 'e', 'l', 'l', 'o' int $0x10 movb $'e', %al int $0x10 movb $'l', %al int $0x10 ... 省略 ... ret # Fill NOP instruction (opcde = 0x90) till base offset 0x1FE. .org 0x1FE, 0x90 # This indicates boot disk boot_flag: .word 0xAA55在 x86 開機的情境中,x86 CPU 會先執行位址 0xFFFF0 的程式,這就是 BIOS ROM 的進入點,一旦完畢後 (事實上,本世紀的 x86 BIOS 已複雜到難以用一句話描述行為,包含 Windows 95 與 GNU/Linux 等完整的作業系統,都可燒入至 BIOS ROM 之中,藉此提供快速啟動作業系統的某些服務之用),執行權會試著交棒給 boot loader 或作業系統。BIOS 的設計會依設定的順序,查驗各別開機磁碟裝置 (如 floppy, hard disk, CD-ROM 等等) 的起始單元,並載入其內容的 512 bytes 至記憶體位址 0x0000:7c00,從而跳躍到該位址並執行,也就將控制權從 BIOS ROM 移轉到 boot loader 或作業系統主體,詳情可參閱 [X86 開機流程小記] 與 [Linux/x86 開機流程:自 MBR 到 init]。
AS = as LD = ld OBJCOPY = objcopy .S.o: $(AS) -a $< -o $*.o > $*.map all: disk.img disk.img: boot.out $(OBJCOPY) -O binary -j .text $< $@ boot.out: boot.o ${LD} -r -Ttext 0x7c00 -e _start -s -o boot.out boot.o clean: rm -f disk.img boot.out boot.o boot.map編譯過程如下:
$ make clean all rm -f desk.img boot.out boot.o boot.map as -a boot.S -o boot.o > boot.map ld -r -Ttext 0x7c00 -e _start -s -o boot.out boot.o objcopy -O binary -j .text boot.out disk.img注意到剛剛提及,BIOS 在控制權移轉時,會「載入各別開機磁碟裝置起始內容的 512 bytes 至記憶體位址 0x0000:7c00」,所以,在 GNU linker (ld) 的選項中,筆者特別讓組合語言的進入點 _start 對齊 .text 區域,也就是位址 0x7c00。最後,呼叫 objcopy 轉換目標程式碼為二進位格式,填入 boot sector 可接受的格式,這時可透過 qemu 來模擬開機的過程:
$ qemu -hda disk.img其模擬的畫面大致如下:
25 0026 B06C movb $'l', %al 26 0028 CD10 int $0x10 27 002a B064 movb $'d', %al 28 002c CD10 int $0x10 29 002e C3 ret 30 31 # Fill NOP instruction (opcde = 0x90) till base offset 0x1FE. 32 002f 90909090 .org 0x1FE, 0x90 32 90909090 32 90909090 32 90909090 32 90909090 33 34 # This indicates boot disk 35 01fe 55AA boot_flag: .word 0xAA55由上述表示可見,十六進位的 1FE + 2 bytes (作為識別用的 0x55 與 0xAA),就等於十進位的 512 bytes,透過假指令,中間填補的 NOP 指令。
不好意思,能否請教一個低檔次的問題...
philippe asm # qemu -hda disk.img
qemu: could not open disk image disk.img
Qemu-0.9.1, 在 Gentoo 下執行. 謝謝 ^^
由 ljmid 發表於 June 20, 2008 05:10 PM@ljmid,
感謝回報,請試著執行以下指令,看是否為以下輸出:
$ od disk.img | head
0000000 007264 044260 010315 062660 010315 066260 010315 066260
0000020 010315 067660 010315 020260 010315 053660 010315 067660
0000040 010315 071260 010315 066260 010315 062260 010315 110303
0000060 110220 110220 110220 110220 110220 110220 110220 110220
*
0000760 110220 110220 110220 110220 110220 110220 110220 125125
0001000
若非,可能是建構過程出問題
由 jserv 發表於 June 20, 2008 10:11 PMHi jserv,
To prevent keyin error, I just downloaded your tar.bz2 and typed make. Failed ... I wonder if there's something wrong with Gentoo or there's compatibility problem...
philippe hello-boot # hexdump disk.img
0000000 0eb4 48b0 10cd 65b0 10cd 6cb0 10cd 6cb0
0000010 10cd 6fb0 10cd 20b0 10cd 57b0 10cd 6fb0
0000020 10cd 72b0 10cd 6cb0 10cd 64b0 10cd 90c3
0000030 9090 9090 9090 9090 9090 9090 9090 9090
*
00001f0 9090 9090 9090 9090 9090 9090 9090 aa55
0000200
Thanks ... I'll trace it.
Just for your reference:
philippe hello-boot # ls -l
total 24
-rw-r--r-- 1 ljm ljm 266 Jun 20 02:54 Makefile
-rw-r--r-- 1 ljm ljm 564 Jun 20 02:30 boot.S
-rw-r--r-- 1 root root 1555 Jun 23 09:36 boot.map
-rw-r--r-- 1 root root 1002 Jun 23 09:36 boot.o
-rw-r--r-- 1 root root 976 Jun 23 09:36 boot.out
-rw-r--r-- 1 root root 512 Jun 23 09:36 disk.img
@ljmid,
Your generated image looks fine. Could you check qemu as well? Trying to invoke with other x86 system emulator would be a good idea to clarify.
由 jserv 發表於 June 23, 2008 12:33 PMhello-boot.tar.bz2 不能下載?
由 tank 發表於 July 1, 2008 02:38 PMHi Jserv,
很有趣,下載 qemu for Win32 來執行同一個 disk.img 沒問題。只有 Gentoo 下的不能跑而已... 晚點來試試 redhat hmm...
jserv大您好:
小弟最近在研究booting跟虛擬機器,所以才會找到您這篇文章,
小弟有個疑問就是如果我是用 -kernel 指定kernel給他並附-initrd 的話,那qemu是會跟host 機器取得memory 後將kernel的前512byte 丟到0x7c00的位置去執行嗎?我看kernel的 head.S _start 也是指到這個位置,關於這一段流程(qemu跟host取的記憶體區塊到run initrd)有沒有什麼資料可以參考或是我可以從qemu的哪個地方開始看起呢?第一次發問如果有不得體的地方請多多見諒