電腦啓動以後,最先由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
|
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,是由加載到內存的中斷例程完成內容填充的。至於從哪裏找到硬盤數據,會是在自檢的時候?不追究了。