linux 0.11 bootsect.s中的BIOS部分解讀

        電腦啓動以後,最先由BIOS自檢然後加載磁盤第一扇區數據到內存中,然後把CPU第一條指令設置到這塊內存後由CPU執行餘下的操作。以下來探索一下,BIOS究竟做了什麼,怎麼工作的。我參考的資料是維基百科:http://en.wikipedia.org/wiki/BIOS  http://en.wikipedia.org/wiki/BIOS_interrupt_call

After completing the POST, the motherboard BIOS scans for extension ROMs in an area of the "upper memory area" space and runs each ROM found, in order. To discover memory-mapped ISA option ROMs during the boot process, BIOS implementations scan real-mode address space from 0x0C0000 to 0x0F0000 on 2 KiB boundaries, looking for a ROMsignature: 0x55 followed by 0xAA. In a valid expansion ROM, this signature is followed by a single byte indicating the number of 512-byte blocks it occupies in real memory. The next byte contains an offset describing the option ROM's entry point. A checksum of the specified number of 512-byte blocks is calculated, and if the ROM has a valid checksum the BIOS transfers control to the specified entry address. At this point, the expansion ROM code takes over,using BIOS services to register interrupt vectors for use by post-boot applications, to provide a user configuration interface, or to display diagnostic information.       

    自檢不是這裏說的重點,跳過不說;BIOS自檢後,已經收集到從哪一個盤啓動的信息;

 For a disk drive or a device that logically emulates a disk drive, such as an USB Flash drive or perhaps a tape drive, to perform this check the BIOS attempts to load the first sector (boot sector) from the disk to memory address 0x007C00, and checks for the boot sector signature 0x55 0xAA in the last two bytes of the (512 byte long) sector. If the sector cannot be read (due to a missing or blank disk, or due to a hardware failure), or if the sector does not end with the boot signature, the BIOS considers the disk unbootable and proceeds to check the next device.

    BIOS會嘗試從第一啓動盤的第一個扇區讀取數據寫到物理內存的0x007c00這個位置;然後檢查內存中的0x007dfe和0x007dff上是0x55 0xaa,這個算是啓動扇區的簽名,如果沒有這個標誌,就認爲這個讀取到的數據是不正確的啓動數據。如果無法讀取指定第一個啓動盤的第一個扇區數據或檢測啓動扇區簽名不正確,或者校驗和不對,那麼就會認爲這個啓動盤無法啓動,轉而去檢查第二啓動盤。

    從這裏來解析linux0.11裏的bootsect.s中的代碼段:

SETUPLEN = 4				! nr of setup-sectors
BOOTSEG  = 0x07c0			! original address of boot-sector
INITSEG  = 0x9000			! we move boot here - out of the way
SETUPSEG = 0x9020			! setup starts here
SYSSEG   = 0x1000			! system loaded at 0x10000 (65536).
ENDSEG   = SYSSEG + SYSSIZE		! where to stop loading

! ROOT_DEV:	0x000 - same type of floppy as boot.
!		0x301 - first partition on first drive etc
ROOT_DEV = 0x306

entry start
start:
	mov	ax,#BOOTSEG
	mov	ds,ax
	mov	ax,#INITSEG
	mov	es,ax
	mov	cx,#256
	sub	si,si
	sub	di,di
	rep
	movw
	jmpi	go,INITSEG
go:	mov	ax,cs
	mov	ds,ax
	mov	es,ax
! put stack at 0x9ff00.
	mov	ss,ax
	mov	sp,#0xFF00		! arbitrary value >>512

BOOTSEG設置爲0x07c0是對應的實模式內存地址的段地址;這個值是由於BIOS的規定而設置的。BIOS從第一扇區把bootsect的代碼加載到了0x07c0段後,然後從start開始執行;接下來的有一個int 13需要再分析。

! load the setup-sectors directly after the bootblock.
! Note that 'es' is already set up.

load_setup:
	mov	dx,#0x0000		! drive 0, head 0
	mov	cx,#0x0002		! sector 2, track 0
	mov	bx,#0x0200		! address = 512, in INITSEG
	mov	ax,#0x0200+SETUPLEN	! service 2, nr of sectors
	int	0x13			! read it
	jnc	ok_load_setup		! ok - continue
	mov	dx,#0x0000
	mov	ax,#0x0000		! reset the diskette
	int	0x13
	j	load_setup
這裏使用了BIOS中斷INT 0x13將seetup模塊從磁盤第2個扇區開始讀到0x90200開始處,共讀4個扇區。那麼,來看一下BIOS的中斷機制以及其中的int 0x13是怎麼操作運行的。參考 http://en.wikipedia.org/wiki/BIOS_interrupt_call

13h Low Level Disk Services
AH Description
00h Reset Disk Drives
01h Check Drive Status
02h Read Sectors
03h Write Sectors
04h Verify Sectors
05h Format Track
08h Get Drive Parameters
09h Init Fixed Drive Parameters
0Ch Seek To Specified Track
0Dh Reset Fixed Disk Controller
15h Get Drive Type
16h Get Floppy Drive Media Change Status
17h Set Disk Type
18h Set Floppy Drive Media Type
41h Extended Disk Drive (EDD) Installation Check
42h Extended Read Sectors
43h Extended Write Sectors
44h Extended Verify Sectors
45h Lock/Unlock Drive
46h Eject Media
47h Extended Seek
48h Extended Get Drive Parameters
49h Extended Get Media Change Status
4Eh Extended Set Hardware Configuration
可以看到調用int 0x13時,ah = 0x02; 也就是叫中斷處理例程去處理Read Sector功能。其他參數我沒有在維基或別的地方找到答案,直接按趙炯的書上說的:

al = 需要讀出的扇區數量

ch = 磁道號的低8位; cl =開始扇區(位0-5),磁道號高2位(位6-7);

dh = 磁頭號;        dl = 驅動器號(如果是硬盤則位7要置位);

es:bx ->指向數據緩衝區:如果出錯則CF標誌置位,ah中是出錯碼。

    另外問題來了:中斷描述符表在哪裏,中斷處理例程又在哪裏?什麼時候放的?

    根據趙炯書上說明:bootsect代碼爲什麼不把系統模塊直接加載到物理地址0x0000開始處而要在setup程序中再進行移動呢?這是因爲在隨後執行的setup代碼開始部分還需要利用ROM BIOS中的中斷調用來獲取機器的一些參數(比如int0x13獲取setup代碼)。當BIOS初始化時會在物理內存開始處放置一個大小爲0x400字節的中斷向量表,因此需要在使用完BIOS的中斷調用後才能將這個區域覆蓋掉。

    中斷處理例程在哪裏?沒找到依據,有一個網友說在E000:0到F000:0之間。

    中斷到底是中斷CPU還是中斷BIOS?根據維基上的BIOS中斷表,看起來像是BIOS的中斷;但是int 0x13代碼bootsect運行時是在CPU執行的。我沒找到明確答案。


補充:http://book.51cto.com/art/201106/270092.htm

BIOS程序被固化在計算機主機板上的一塊很小的ROM芯片裏。通常,不同的主機板所用的BIOS也有所不同,就啓動部分而言,各種類型的BIOS的基本原理大致相似。爲了便於大家理解,我們選用的BIOS程序只有8KB,所佔地址段爲0xFE000~0xFFFFF,如圖1-1所示。現在CS:IP已經指向了0xFFFF0這個位置,這意味着BIOS開始啓動了。隨着BIOS程序的執行,屏幕上會顯示顯卡的信息、內存的信息……說明BIOS程序在檢測顯卡、內存……這期間,有一項對啓動(boot)操作系統至關重要的工作,那就是BIOS在內存中建立中斷向量表和中斷服務程序。

小貼士

ROM(Read Only Memory):只讀存儲器,現在通常用閃存芯片做ROM。雖然閃存芯片在特定的條件下是可寫的,但在談到主機板上存儲BIOS的閃存芯片時,業內人士把它看作ROM。ROM有一個特性,就是斷電之後仍能保存信息,這一點與硬盤類似。

BIOS程序在內存最開始的位置(即:0x00000)用1KB的內存空間(0x00000~ 0x003FF)構建中斷向量表,並在緊挨着它的位置用256字節的內存空間構建BIOS數據區(0x00400~0x004FF),在大約56KB以後的位置(0x0E05B)加載了8KB左右的與中斷向量表相應的若干中斷服務程序,圖1-2中精確地標註了這些位置。

小貼士

一個容易計算的方法:0x00100是256個字節,0x00400就是4×256字節=1024字節,即1KB。因爲是從0x00000開始計算,所以1KB的高地址端不是0x00400,而是0x00400-1,也就是0x003FF。

 
圖1-2 BIOS在內存中加載中斷向量表和中斷服務程序

中斷向量表中有256箇中斷向量,每個中斷向量佔4個字節,其中兩個字節是CS的值,兩個字節是IP的值,每個中斷向量都指向一個具體的中斷服務程序。

    根據研究查證,中斷向量在BIOS初始化過程中加載到內存當中的,但是我查閱維基上的POST資料,POST過程沒有加載中斷向量和中斷服務程序到內存的過程。按上面的說法,是在初始化過程加載了,現在就不再考究到底是初始化的哪一步加載了。

    中斷例程加載在0xE05B位置(根據不同的BIOS估計有不同吧?)。

    中斷是誰的中斷的問題:只有一個級聯了兩個8295A中斷處理器的中斷處理構件,BIOS中是沒有的。處理BIOS中斷的時候,如int 0x13,是由加載到內存的中斷例程完成內容填充的。至於從哪裏找到硬盤數據,會是在自檢的時候?不追究了。








發佈了169 篇原創文章 · 獲贊 5 · 訪問量 38萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章