FreeBSD啟動扇區(qū)代碼分析(ver5.2.1) 2007-04-27 來源:cnfug 作者: 關鍵詞: FreeBSD代碼BSD扇區(qū)分析 FreeBSD完整的內核代碼在FreeBSD的/sys目錄下。其中,FreeBSD 的 Boot Manager代碼是 sys/boot/i386/boot0/boot0.s,它是FreeBSD自帶的Boot Manager,其功
2007-04-27 來源:cnfug 作者:
關鍵詞: FreeBSD 代碼 BSD 扇區(qū) 分析
FreeBSD完整的內核代碼在FreeBSD的 “/sys”目錄下。其中,FreeBSD 的 Boot Manager代碼是 sys/boot/i386/boot0/boot0.s,它是FreeBSD自帶的Boot Manager,其功能雖然不如Linux的lilo和Grub功能強大,但它只需按一個鍵就可以引導,界面直觀。小小的512字節(jié),可以給你一個簡單明 了的啟動選擇界面,還能記住你上次的選擇。以下,就對此代碼進行詳細分析:
當我們打開計算機電源時,計算機嘰嘰嘎嘎進行設備和內 存檢測過后就讀取硬盤或者軟盤的引導扇區(qū),這個扇區(qū)只有512字節(jié),顯然這512字節(jié)不能夠有多大作用,這512字節(jié)的代碼被BIOS放在地址從 0x0000:0x7c00開始處。然后直接跳轉到0x0000:0x7c00處去執(zhí)行。以上工作是BIOS 干的,你什么也不用作。操作系統需要通過這個引導扇區(qū)代碼再裝載操作系統的其他部分。 在還沒有跳轉到這段代碼之前,也就是BIOS把磁盤的引導扇區(qū)讀入到內存之后,其DL和ES、SI寄存器的內容如下: DL:表示啟動設備,例如,如果計算機是從軟盤啟動的則DL=0,若是從IDE的C、D盤(嚴格來說是物理磁盤一和物理磁盤二,而不是邏輯磁盤分區(qū))啟動 的則DL分別為0x80和0x81。如果是從硬盤啟動的話,ES:SI是指向BIOS中的硬盤分區(qū)表存放的地址。
好了,我們現在已經知道,計算機的BIOS已經把引導扇區(qū)的512字節(jié)的內容讀入到了0:0x7c00處,然后就跳轉到0:0x7C00處去執(zhí)行,也就是執(zhí)行引導扇區(qū)代碼,引導扇區(qū)代碼boot0執(zhí)行代碼dump如下(它很有用,以后我們還不時回頭來看):
560)this.style.width=560;''
onmousewheel = ''javascript:return big(this)'' height=517 alt=""
src="http://images.51cto.com/files/uploadimg/20051027/104330627.gif"
width=590 border=0>
上圖中的4x16個字節(jié)是保留的4個分區(qū)信息
下面,我們對FreeBSD啟動扇區(qū)代碼boot0.s進行逐步分析。boot0.s代碼如下:
#
# Copyright (c) 1998 Robert Nordier
# All rights reserved.
#
# Redistribution and use in source and binary forms are freely
# permitted provided that the above copyright notice and this
# paragraph and the following disclaimer are duplicated in all
# such forms.
#
# This software is provided "AS IS" and without any express or
# implied warranties, including, without limitation, the implied
# warranties of merchantability and fitness for a particular
# purpose.
#
以上的Coyright就不用翻譯了。
# $FreeBSD: src/sys/boot/i386/boot0/boot0.s,v 1.27 2003/11/20 20:28:18 jhb Exp $
以上供版本管理軟件使用
# A 512-byte boot manager.
.set NHRDRV,0x475 # Number of hard drives
.set ORIGIN,0x600 # Execution address
.set FAKE,0x800 # Partition entry
.set LOAD,0x7c00 # Load address
.set PRT_OFF,0x1be # Partition table
.set TBL0SZ,0x3 # Table 0 size
.set TBL1SZ,0xb # Table 1 size
.set MAGIC,0xaa55 # Magic: bootable
.set B0MAGIC,0xbb66 # Identification
.set KEY_ENTER,0x1c # Enter key scan code
.set KEY_F1,0x3b # F1 key scan code
.set KEY_1,0x02 # #1 key scan code
#
# Addresses in the sector of embedded data values.
# Accessed with negative offsets from the end of the relocated sector (%ebp).
#
.set _NXTDRV,-0x48 # Next drive
.set _OPT,-0x47 # Default option
.set _SETDRV,-0x46 # Drive to force
.set _FLAGS,-0x45 # Flags
.set _TICKS,-0x44 # Timeout ticks
.set _FAKE,0x0 # Fake partition entry
.set _MNUOPT,0xc # Menu options
以上是定義相關的參數值,例如“.set NHRDRV,0x475”類似于C語言中的“#define NHRDRV 0x475”
.globl start # Entry point
.code16 # This runs in real mode
#
# Initialise segments and registers to known values.
# segments start at 0.
# The stack is immediately below the address we were loaded to.
#
start:
cld # String ops inc
xorw %ax,%ax # Zero
movw %ax,%es # Address
movw %ax,%ds # data
movw %ax,%ss # Set up
movw $LOAD,%sp # stack
以上代碼:
1)首先使用“cld”指令清除方向標志,使得以下的進行“rep”操作時SI和DI的值遞增。
2)使ax清零,并使除代碼段cs外的另外兩個數據段寄存器es、ds和堆棧段ss清零。當然,此時cs
由于reset或初始上電已經為零了。
3)BIOS已經把引導扇區(qū)的512字節(jié)的內容讀入到了0:0x7c00處,movw $LOAD,%sp 使得堆棧指針指向扇區(qū)
代碼(或曰本段代碼 0:0x7c00)的頂部。雖然堆棧向下生長可能會影響代碼的內容,但下面我
們馬上就把位于0:7c00處代碼移到其他地方去執(zhí)行。
#
# Copy this code to the address it was linked for
#
movw %sp,%si # Source
movw $start,%di # Destination
movw $0x100,%cx # Word count
rep # Relocate
movsw # code
把位于0:7c00處的代碼搬移到0:0x600處。注意,此時由于代碼連接的重定向,$start=0x600。
#
# Set address for variable space beyond code, and clear it.
# Notice that this is also used to point to the values embedded in the block,
# by using negative offsets.
movw %di,%bp # Address variables
movb $0x8,%cl # Words to clear
rep # Zero
stosw # them
通過以上一段代碼的執(zhí)行,本代碼已被搬移到0:0x600處,此時si=di=0x600+0x100,以上代碼
把di的值保存到bp,bp此時指向本程序搬移后的未用的空間的首部,且把此bp所指的16字節(jié)空間
清零。以上過程如下圖所示:
┏>0:0x600 ┏━━━━━┓
┃ ┃ ┃
┃ ┃ 搬 ┃
┃ ┃ 移 ┃
┃ ┃ 之 ┃
┃ ┃ 后 ┃
┃ ┃ 的 ┃
┃ ┃ 代 ┃
┃ ┃ 碼 ┃
┃ ┃ ┃
┃ 0:0x7ff ┣━━━━━┫
┃ ┃ 0 ┃<-bp指向這里(0:0x800),以此開始的16字節(jié)被清零。
┃ ┣━━━━━┫以下所稱的fake partition entry就是指這里。
┃ ┃ 0 ┃
┃ ┣━━━━━┫
┃ ┃ 0 ┃
┃ ┣━━━━━┫
┃ ┃ 0 ┃
┃ ┣━━━━━┫
┃ ┃ 0 ┃
┃ ┣━━━━━┫
┃ ┃ 0 ┃
┃ ┣━━━━━┫
┃ ┃ 0 ┃
┃ ┣━━━━━┫
┃ ┃ 0 ┃
┃ ┣━━━━━┫
┃ ┃ 0 ┃
┃ ┣━━━━━┫
┃ ┃ 0 ┃
┃ ┣━━━━━┫
┃ ┃ 0 ┃
┃ ┣━━━━━┫
┃ ┃ 0 ┃
┃ ┣━━━━━┫
┃ ┃ 0 ┃
┃ ┣━━━━━┫
┃ ┃ 0 ┃
┃ ┣━━━━━┫
┃ ┃ 0 ┃
┃ ┣━━━━━┫
┃ ┃ 0 ┃
┃ ┗━━━━━┛
0:0x7c00 ┏━━━━━┓ ┛
┃ ┃
┃ 搬 ┃
┃ 移 ┃
┃ 之 ┃
┃ 前 ┃
┃ 的 ┃
┃ 代 ┃
┃ 碼 ┃
┃ ┃
0:0x7dff ┗━━━━━┛
圖(二)
#
# Relocate to the new copy of the code.
#
incb -0xe(%di) # Sector number
jmp main-LOAD+ORIGIN # To relocated code
把以上清零的16字節(jié)的第二個字節(jié)置為1,表示我們已經讀取了一個分區(qū)。然后跳轉到搬
移之后的新代碼的main處執(zhí)行。
#
# Check what flags were loaded with us, specifically, Use a predefined Drive.
# If what the bios gives us is bad, use the ''0'' in the block instead, as well.
#
main:
testb $0x20,_FLAGS(%bp) # Set number drive?
jnz main.1 # Yes
testb %dl,%dl # Drive number valid?
js main.2 # Possibly (0x80 set)
main.1:
movb _SETDRV(%bp),%dl # Drive number to use
上面說過,BIOS把磁盤的引導扇區(qū)讀入到內存之后,其dl的內容表示啟動設備,但我們安裝好FreeBSD
之后,我們可以改變此引導扇區(qū)的內容,其中的一個改變就是可以使我們可以“手動指定”我們實際安
裝FreeBSD的分區(qū),如果我們希望指定FreeBSD所在的boot分區(qū),那么我們在bp-0x45處的位置
(即_FLAGS(%bp)處)的bit 0x20置1,那么上面的“movb _SETDRV(%bp),%dl”一句中movb
_SETDRV(%bp),%dl(即bp-0x46)即指向我們“手動指定”FreeBSD所在分區(qū)代碼,例如,IDE的C、D
盤(嚴格來說是第一個物理磁盤的第一個和第二個分區(qū))的代碼分別為 0x80和0x81。如果沒有“手動指
定”啟動分區(qū),那么,我們缺省使用機器當前啟動的分區(qū),上面說過,機器當前啟動的分區(qū)代碼放在dl中。
因為FreeBSD Boot Manager 不可能安裝到軟盤(如果從軟盤啟動則dl為0),所以,使用testb %dl,%dl
來判斷驅動器代碼是否合法(volid)。
有關_FLAGS(%bp)中其他bit位表示的意義,在隨后的代碼分析中慢慢給你道來。
#
# Whatever we decided to use, now store it into the fake
# partition entry that lives in the data space above us.
#
main.2:
movb %dl,_FAKE(%bp) # Save drive number
callw putn # To new line
pushw %dx # Save drive number
以上第一句把FreeBSD啟動分區(qū)的代碼保存到_FAKE(%bp)(bp-0)處,也就是說,上圖(二)的bp
處保存的是FreeBSD啟動分區(qū)的代碼(_FAKE=0)。
“callw putn”一句在屏幕上打印“回車”和“換行”,“pushw %dx”一句把啟動分區(qū)
的值壓入堆棧。
#
# Start out with a pointer to the 4th byte of the first table entry
# so that after 4 iterations it''s beyond the end of the sector.
# and beyond a 256 byte boundary and has overflowed 8 bits (see next comment).
# (remember that the table starts 2 bytes earlier than you would expect
# as the bootable flag is after it in the block)
#
movw $(partbl+0x4),%bx # Partition table (+4)
xorw %dx,%dx # Item number
以上代碼首先把%bx指向分區(qū)表partbl的的第四個字節(jié),這里存放的是分區(qū)類型,如82表示
Linux Native分區(qū)83表示Linux Swap 分區(qū),有關分區(qū)表的細節(jié)請詳見本文的尾部。然后dx清零,
此后,dx將作為遍歷磁盤分區(qū)的列舉代號使用。啟動分區(qū)代碼dl的原來的值在上面已經壓入
了堆棧保存。
#
# Loop around on the partition table, printing values until we
# pass a 256 byte boundary. The end of loop test is at main.5.
#
main.3:
movb %ch,-0x4(%bx) # Zero active flag (ch == 0)
btw %dx,_FLAGS(%bp) # Entry enabled?
jnc main.5 # No
上面首先使得第一個分區(qū)的活動標志為0,標志它不為活動標志,因為ch的值為0。至
于第二句“btw %dx,_FLAGS(%bp)”中的_FLAGS(%bp)是上面我們說到的“手動指定我們
實際安裝FreeBSD的分區(qū)代碼”。其中的bit 0x20我們在上面已經提到過。_FLAGS(%bp)
中的其他位表示是否我們需要檢查相應的磁盤分區(qū)。缺省情況下,我們需要檢查所有
的磁盤分區(qū)。檢查磁盤分區(qū)看是否有可以啟動的磁盤分區(qū),例如,可能磁盤上的某個
分區(qū)為WindowsXP或者是Linux等。如果我們沒有改變在磁盤上該處的值,則相應的bit
位的值為0,表示所有的分區(qū)都要檢查(因為此時_FLAGS(%bp)中的值為0),否則,
只針對FLAGS(%bp)中相應的bit位未被設置為1的分區(qū)進行檢查。
大家知道,FreeBSD Manager啟動時可能出現以下的提示:
F1 FreeBSD
F2 ??
F3 BSD
F4 ??
Default F1
其中,上面的提示中出現了令人討厭的“??”,為了避免出現“??”的提示,我們可以設置相應的
第一分區(qū)和第四分區(qū)不檢查,就需要正確設置_FLAGS(%bp)中的bit位。設置好后,屏幕可能
出現以下的提示:
F1 FreeBSD
F2 BSD
Default F1
#
# If any of the entries in the table are
# the same as the ''type'' in the slice table entry,
# then this is an empty or non bootable partition. Skip it.
#
movb (%bx),%al # Load type
movw $tables,%di # Lookup tables
movb $TBL0SZ,%cl # Number of entries
repne # Exclude
scasb # partition?
je main.5 # Yes
我們從上面已經知道起始(%bx)指向的是MBR中分區(qū)信息1(16字節(jié))的位置(見圖(三)),
以上代碼在“忽略的分區(qū)類型$tables”中查找看是否本分區(qū)是不可啟動的或者不合法的分區(qū)。
不可啟動的或者不合法的分區(qū)類型有3($TBL0SZ=3)個,它們是“0x0, 0x5, 0xf”,見下面的
$tables處。如果是不可啟動的或者不合法的分區(qū)類型則跳轉到main.5,進行下一輪循環(huán)。
#
# Now scan the table of known types
#
movb $TBL1SZ,%cl # Number of entries
repne # Known
scasb # type?
jne main.4 # No
#
# If it matches get the matching element in the
# next array. if it doesn''t, we are already
# pointing at its first element which points to a "?".
#
addw $TBL1SZ,%di # Adjust
main.4:
movb (%di),%cl # Partition
addw %cx,%di # description
callw putx # Display it
上面檢查看所檢查的分區(qū)類型是否為我們知道的分區(qū)類型,知道的分區(qū)類型有11($TBL1SZ=0xb)
個,它們是:“0x1, 0x4, 0x6, 0xb, 0xc, 0xe, 0x83,0x9f, 0xa5, 0xa6, 0xa9”,見
下面的$tables處。如果不是以上的類型,則跳轉到main.4。那么,(%di)所指的字串是“??”,
如果分區(qū)類型是“0x1, 0x4, 0x6, 0xb, 0xc, 0xe, 0x83,0x9f, 0xa5, 0xa6, 0xa9”
之一,則(%di)所指的字串是“DOS”、“Linux”、“FreeBSD”或“BSD”等。
見下面的“os_misc”、“os_dos”、“os_linux”、“os_freebsd”、“os_bsd”等
標記。
callw putx調用putx函數,在屏幕上打印:“Fx XXX”。其中XXX為DOS”、“Linux”、
“FreeBSD”或“BSD”等。
main.5:
incw %dx # Next item
addb $0x10,%bl # Next entry
jnc main.3 # Till done
遍歷磁盤分區(qū)的舉代號dx加1,重復下一輪循環(huán)查找。bl加上0x10(0x10=16)表示尋址到下
一個分區(qū)信息(加16字節(jié))入口。循環(huán)直到255字節(jié)邊界。
#
# Passed a 256 byte boundary..
# table is finished.
# Add one to the drive number and check it is valid,
#
popw %ax # Drive number
subb $0x80-0x1,%al # Does next
cmpb NHRDRV,%al # drive exist? (from BIOS?)
jb main.6 # Yes
“popw %ax”把上面壓入堆棧的bx(當前的啟動扇區(qū))值彈出到ax中。例如,如果計算機是從軟盤
啟動的則dl=0,若是從IDE的C、D盤啟動的則dl分別為 0x80和0x81。然而,FreeBSD的Boot Manerger不能夠
安裝到軟盤上,所以,dl只能為0x80、0x81,0x82...等。
在計算機的BIOS地址0:0x475處存放的是計算機的硬盤的數目,“subb $0x80-0x1,%al”一句等于“sub
$0x79,%al”,例如,即當前驅動器如果是C盤,則al的值是ox80-0x79=1,然后再與計算機的硬盤的數目比
較,如果當前所在硬盤不是最后一個硬盤,則直接跳轉到main.6。如果當前所在硬盤是最后一個硬盤,則繼
續(xù)執(zhí)行。
# If not then if there is only one drive,
# Don''t display drive as an option.
#
decw %ax # Already drive 0?
jz main.7 # Yes
如果只有一個硬盤,則直接跳轉到main.7,這樣,本計算機只有一個硬盤,所以不用顯示其他
磁盤相關的提示。
# If it was illegal or we cycled through them,
# then go back to drive 0.
#
xorb %al,%al # Drive 0
下面的內容表示多于一個磁盤的情況。此時“al”清0,與磁盤列舉相關。
#
# Whatever drive we selected, make it an ascii digit and save it back
# to the "next drive" location in the loaded block in case we
# want to save it for next time.
# This also is part of the printed drive string so add 0x80 to indicate
# end of string.
#
main.6:
addb $''0''|0x80,%al # Save next
movb %al,_NXTDRV(%bp) # drive number
movw $drive,%di # Display
callw putx # item
首先,在_NXTDR(%bp)處置入“0字符高位置1”的字符,以代表第二個驅動器,
然后在屏幕上顯示“Fx Drive”,表示更換另外的磁盤啟動。注意,在調用
putx之前,di中保存的是下面字串“Drive ”的首地址。dl中存放的是當前
遍歷的到的可啟動的或者合法的分區(qū)類型遞增序數,al與dl是不同的,al是ASCII碼,
dl是“Fx”中的x值。
#
# Now that we''ve printed the drive (if we needed to), display a prompt.
# Get ready for the input byt noting the time.
#
main.7:
movw $prompt,%si # Display
callw putstr # prompt
movb _OPT(%bp),%dl # Display
decw %si # default
callw putkey # key
xorb %ah,%ah # BIOS: Get
int $0x1a # system time
movw %dx,%di # Ticks when
addw _TICKS(%bp),%di # timeout
上面的代碼首先在屏幕上打印出字符串“Default: ”,缺省啟動的磁盤號放在
“_OPT(%bp)”中,這里有個小小的技巧,在執(zhí)行“decw %si”和“callw putkey”
兩句后屏幕會顯示“Fx”,x是_OPT(%bp)的ASCII。
然后取得當前的tickes放到%di中,等待用戶按鍵超時的時間從_TICKS(%bp)中取出,
加到當前的tickes即是最后超時時間到的tickes。
#
# Busy loop, looking for keystrokes but
# keeping one eye on the time.
#
main.8:
movb $0x1,%ah # BIOS: Check
int $0x16 # for keypress
jnz main.11 # Have one
xorb %ah,%ah # BIOS: Get
int $0x1a # system time
cmpw %di,%dx # Timeout?
jb main.8 # No
等待用戶按下“Fx”鍵,同時檢查當前等待是否超時,如果有用戶按鍵則跳轉到main.11,
如果超時時間不到則繼續(xù)等待。
#
# If timed out or defaulting, come here.
#
main.9:
movb _OPT(%bp),%al # Load default
jmp main.12 # Join common code
超時時間到,此時表示用戶使用缺省分區(qū)啟動,把缺省的啟動分區(qū)號置入al中,然后跳轉
到main.12。
#
# User''s last try was bad, beep in displeasure.
# Since nothing was printed, just continue on as if the user
# hadn''t done anything. This gives the effect of the user getting a beep
# for all bad keystrokes but no action until either the timeout
# occurs or the user hits a good key.
#
main.10:
movb $0x7,%al # Signal
callw putchr # error
用戶輸入錯誤,只是響鈴提示,其他什么也不發(fā)生。
#
# Get the keystroke.
#
main.11:
xorb %ah,%ah # BIOS: Get
int $0x16 # keypress
movb %ah,%al # Scan code
用戶按下了一個鍵,把鍵值掃描碼放到al中。
#
# If it''s CR act as if timed out.
#
cmpb $KEY_ENTER,%al # Enter pressed?
je main.9 # Yes
如果用戶按下“Enter”鍵,和超時等同處理,這樣,就啟動缺省的boot分區(qū)。
#
# Otherwise check if legal
# If not ask again.
#
subb $KEY_F1,%al # Less F1 scan code
cmpb $0x4,%al # F1..F5?
jna main.12 # Yes
subb $(KEY_1 - KEY_F1),%al # Less #1 scan code
cmpb $0x4,%al # #1..#5?
ja main.10 # No
如果是除“Enter”鍵外其他的鍵,則檢查是不是F1...F5鍵,如果不是,
表示輸入不合法,跳回到main.10處理。
#
# We have a selection.
# but if it''s a bad selection go back to complain.
# The bits in MNUOPT were set when the options were printed.
# Anything not printed is not an option.
#
main.12:
cbtw # Option
btw %ax,_MNUOPT(%bp) # enabled?
jnc main.10 # No
如果是F1...F5鍵,則檢查是否在我們提示的范圍內,其中,_MNUOPT(%bp)的相應
bit位為1,表示是一個合法的選項,如果不是,跳回到 main.10處理。
#
# Save the info in the original tables
# for rewriting to the disk.
#
movb %al,_OPT(%bp) # Save option
把我們按下的F1...F5鍵保存到_OPT(%bp)位置。
movw $FAKE,%si # Partition for write
movb (%si),%dl # Drive number
把原來的啟動分區(qū)代碼取回到dl中。
movw %si,%bx # Partition for read
cmpb $0x4,%al # F5 pressed?
pushf # Save
je main.13 # Yes
如果我們按下的是F5鍵則直接跳轉到main.13處理。
shlb $0x4,%al # Point to
addw $partbl,%ax # selected
xchgw %bx,%ax # partition
movb $0x80,(%bx) # Flag active
上面,我們從按鍵Fx選擇中得到圖(三)中的我們選擇的四個分區(qū)信息中的某一分區(qū)信息,
上面計算出的bx為我們選擇的分區(qū)信息的首地址,我們把此選擇到的分區(qū)信息的第一個
個字節(jié)置為0x80表示它是當前的活動分區(qū)。
#
# If not asked to do a write-back (flags 0x40) don''t do one.
#
main.13:
pushw %bx # Save
testb $0x40,_FLAGS(%bp) # No updates?
jnz main.14 # Yes
movw $start,%bx # Data to write
movb $0x3,%ah # Write sector
callw intx13 # to disk
檢查回寫標志_FLAGS(%bp)的bit位0x40為,如果設置的是可回寫,則把當前選擇到的boot
分區(qū)作為下次缺省的啟動分區(qū)。
main.14:
popw %si # Restore
popf # Restore
#
# If going to next drive, replace drive with selected one.
# Remember to un-ascii it. Hey 0x80 is already set, cool!
#
jne main.15 # If not F5
恢復上面保存的si和標志寄存器的內容。如果不是按鍵F5,則直接跳轉到main.15去執(zhí)行。
movb _NXTDRV(%bp),%dl # Next drive
subb $''0'',%dl # number
否則的話,我們選擇下一個驅動器作為啟動盤。
#
# load selected bootsector to the LOAD location in RAM.
# If it fails to read or isn''t marked bootable, treat it
# as a bad selection.
# XXX what does %si carry?
#
main.15:
movw $LOAD,%bx # Address for read
movb $0x2,%ah # Read sector
callw intx13 # from disk
jc main.10 # If error
把我們上面選擇到的分區(qū)讀到0x7c00處,就象我們剛剛才加電啟動一樣,只是活動分區(qū)改變
了而已。如果發(fā)生讀錯誤則直接跳轉到main.10。使用戶重新選擇啟動分區(qū)。
cmpw $MAGIC,0x1fe(%bx) # Bootable?
jne main.10 # No
判斷引導扇區(qū)的最后兩個字節(jié)是否是“0x55AA”,如果不是,則表示此扇區(qū)是不可引導的,或
不合法的引導扇區(qū)則直接跳轉到main.10。使用戶重新選擇啟動分區(qū)。
pushw %si # Save
movw $crlf,%si # Leave some
callw puts # space
popw %si # Restore
打印“回車”和“換行”。
jmp *%bx # Invoke bootstrap
跳轉到我們選擇的引導扇區(qū)去執(zhí)行。整個Boot Manager代碼到此執(zhí)行完畢。
#
# Display routines
#
putkey:
movb $''F'',%al # Display
callw putchr # ''F''
movb $''1'',%al # Prepare
addb %dl,%al # digit
jmp putstr.1 # Display the rest
“putkey”函數在屏幕上打印“F1”、“F2”或“F3”等。如果dl為0則打印“F1”,
如果dl為1則打印“F2”,如果dl為3則打印“F3”。和調用“putstr”在屏幕上打印
es:si指向的以最高位置1為結束字符的字符串。
#
# Display the option and note that it is a valid option.
# That last point is a bit tricky..
#
putx: #首先,把_MNUOPT(%bp)的第dx位(bit)置1,表示此菜單選項被顯示。然后在
屏幕上打印空格和es:di指向的以最高位置1為結束字符的字符串。
btsw %dx,_MNUOPT(%bp) # Enable menu option
movw $item,%si # Display
callw putkey # key
movw %di,%si # Display the rest
puts: #調用“putstr”在屏幕上打印es:si指向的以最高位置1為結束字符的字符串。
callw putstr # Display string
putn: #“putn”打印“回車/換行”后在屏幕上打印es:si指向的以最高位置1為結束字符的字符串。
movw $crlf,%si # To next line
putstr: #“putstr”在屏幕上打印es:si指向的以最高位置1為結束字符的字符串。
lodsb # Get byte
testb $0x80,%al # End of string?
jnz putstr.2 # Yes
putstr.1:
callw putchr # Display char
jmp putstr # Continue
putstr.2:
andb $~0x80,%al # Clear MSB
putchr:
pushw %bx # Save
movw $0x7,%bx # Page:attribute
movb $0xe,%ah # BIOS: Display
int $0x10 # character
popw %bx # Restore
retw # To caller
“putchr”在屏幕上顯示“al”中的字符。
# One-sector disk I/O routine
intx13:
movb 0x1(%si),%dh # Load head
movw 0x2(%si),%cx # Load cylinder:sector
movb $0x1,%al # Sector count
pushw %si # Save
movw %sp,%di # Save
testb $0x80,_FLAGS(%bp) # Use packet interface?
jz intx13.1 # No
pushl $0x0 # Set the
pushl 0x8(%si) # LBA address
pushw %es # Set the transfer
pushw %bx # buffer address
push $0x1 # Block count
push $0x10 # Packet size
movw %sp,%si # Packet pointer
decw %ax # Verify off
orb $0x40,%ah # Use disk packet
intx13.1:
int $0x13 # BIOS: Disk I/O
movw %di,%sp # Restore
popw %si # Restore
retw # To caller
# Menu strings
item:
.ascii " "; .byte '' ''|0x80
prompt:
.ascii "/nDefault:"; .byte '' ''|0x80
crlf:
.ascii "/r"; .byte ''/n''|0x80
# Partition type tables
tables:
#
# These entries identify invalid or NON BOOT types and partitions.
#
.byte 0x0, 0x5, 0xf
#
# These values indicate bootable types we know the names of
#
.byte 0x1, 0x4, 0x6, 0xb, 0xc, 0xe, 0x83
.byte 0x9f, 0xa5, 0xa6, 0xa9
#
# These are offsets that match the known names above and point to the strings
# that will be printed.
#
.byte os_misc-. # Unknown
.byte os_dos-. # DOS
.byte os_dos-. # DOS
.byte os_dos-. # DOS
.byte os_dos-. # Windows
.byte os_dos-. # Windows
.byte os_dos-. # Windows
.byte os_linux-. # Linux
.byte os_bsd-. # BSD/OS
.byte os_freebsd-. # FreeBSD
.byte o
(完)
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com