歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux內核 >> Linux內核啟動過程分析

Linux內核啟動過程分析

日期:2017/2/28 14:27:07   编辑:Linux內核

1、Linux內核啟動協議
閱讀文檔\linux-2.6.35\Documentation\x86\boot.txt
傳統支持Image和zImage內核的啟動裝載內存布局(2.4以前的內核裝載就是這樣的布局):
| |
0A0000 +------------------------+
| Reserved for BIOS | Do not use. Reserved for BIOS EBDA.
09A000 +------------------------+
| Command line |
| Stack/heap | For use by the kernel real-mode code.
098000 +------------------------+
| Kernel setup | The kernel real-mode code.
090200 +------------------------+
| Kernel boot sector | The kernel legacy boot sector.
090000 +------------------------+
| Protected-mode kernel | The bulk of the kernel image.
010000 +------------------------+
| Boot loader | <- Boot sector entry point 0000:7C00
001000 +------------------------+
| Reserved for MBR/BIOS |
000800 +------------------------+
| Typically used by MBR |
000600 +------------------------+
| BIOS use only |
000000 +------------------------+
當使用bzImage時,保護模式的內核會被重定位到0x1000000(高端內存),內核實模式的代碼(boot sector,setup和stack/heap)會被編譯成可重定位到0x100000與低端內存底端之間的任何地址處。不幸的是,在2.00和2.01版的引導協議中,0x90000+的內存區域仍然被使用在內核的內部。2.02版的引導協議解決了這個問題。boot loader應該使BIOS的12h中斷調用來檢查低端內存中還有多少內存可用。
人們都希望“內存上限”,即boot loader觸及的低端內存最高處的指針,盡可能地低,因為一些新的BIOS開始分配一些相當大的內存,所謂的擴展BIOS數據域,幾乎快接近低端內存的最高處了。
不幸的是,如果BIOS 12h中斷報告說內存的數量太小了,則boot loader除了報告一個錯誤給用戶外,什麼也不會做。因此,boot loader應該被設計成占用盡可能少的低端內存。對zImage和以前的bzImage,這要求數據能被寫到x090000段,boot loader應該確保不會使用0x9A000指針以上的內存;很多BIOS在這個指針以上會終止。
對一個引導協議>=2.02的現代bzImage內核,其內存布局使用以下格式:
| Protected-mode kernel |
100000 +------------------------+
| I/O memory hole |
0A0000 +------------------------+
| Reserved for BIOS | Leave as much as possible unused
~ ~
| Command line | (Can also be below the X+10000 mark)
X+10000 +------------------------+
| Stack/heap | For use by the kernel real-mode code.
X+08000 +------------------------+
| Kernel setup | The kernel real-mode code.
| Kernel boot sector | The kernel legacy boot sector.
X +------------------------+
| Boot loader | <- Boot sector entry point 0000:7C00
001000 +------------------------+
| Reserved for MBR/BIOS |
000800 +------------------------+
| Typically used by MBR |
000600 +------------------------+
| BIOS use only |
000000 +------------------------+
這裡程序段地址是由grub的大小來決定的。地址X應該在bootloader所允許的范圍內盡可能地低。
2、BIOS POST過程
傳統意義上,由於CPU加電之後,CPU只能訪問ROM或者RAM裡的數據,而這個時候是沒有計算機操作系統的,所以需要有一段程序能夠完成加載存儲在非易失性存儲介質(比如硬盤)上的操作系統到RAM中的功能。這段程序存儲在ROM裡,BIOS就是這類程序中的一種。對於BIOS,主要由兩家制造商制造,駐留在主板的ROM裡。有了BIOS,硬件制造商可以只需要關注硬件而不需要關注軟件。BIOS的服務程序,是通過調用中斷服務程序來實現的。BIOS加載bootloader程序,Bootloader也可以通過BIOS提供的中斷,向BIOS獲取系統的信息。整個過程如下:
(1)電源啟動時鐘發生器並在總線上產生一個#POWERGOOD的中斷。
(2)產生CPU的RESET中斷(此時CPU處於8086工作模式)。
(3)進入BIOS POST代碼處:%ds=%es=%fs=%gs=%ss=0,%cs=0xFFFF0000,%eip = 0x0000FFF0 (ROM BIOS POST code,指令指針eip,數據段寄存器ds,代碼段寄存器cs)。
(4)在中斷無效狀態下執行所有POST檢查。
(5)在地址0初始化中斷向量表IVT。
(6)0x19中斷:以啟動設備號為參數調用BIOS啟動裝載程序。這個程序從啟動設備(硬盤)的0扇面1扇區讀取數據到內存物理地址0x7C00處開始裝載。這個0扇面1扇區稱為Boot sector(引導扇區),共512字節,也稱為MBR。
就是說,CPU 在 BIOS 的入口(CS:IP=FFFF:0000)處執行BIOS的匯編程序,BIOS程序功能有系統硬件的檢測,提供中斷訪問接口以訪問硬件。而後被BIOS程序通過中斷0x19調用磁盤MBR上的bootloader程序,將bootloader程序加載到ox7c00處,而後跳轉到0x7c00,這樣,位於 0x7c00處的bootloader程序,就可以執行了。
從BIOS執行MBR中的bootloader程序開始,就是linux的代碼在做的事情了。
3、Bootloader過程
bootloader程序是為計算機加載(load)計算機操作系統的。boot(引導)是bootstrap的簡寫,bootstrap是引導指令的意思。bootloader程序通常位於硬盤上,被BIOS調用,用於加載內核。在PC機上常見的bootloader主要有grub、lilo、syslinux等。
GRUB(GRand Unified Bootloader)是當前linux諸多發行版本默認的引導程序。嵌入式系統上,最常見的bootloader是U-BOOT。這樣的bootloader一般位於MBR的最前部。在linux系統中,bootloader也可以寫入文件系統所在分區中。比如,grub程序就非常強大。Gurb運行後,將初始化設置內核運行所需的環境。然後加載內核鏡像。
grub磁盤引導全過程:
(1)stage1: grub讀取磁盤第一個512字節(硬盤的0道0面1扇區,被稱為MBR(主引導記錄),也稱為bootsect)。MBR由一部分bootloader的引導代碼、分區表和魔數三部分組成。
(2)stage1_5: 識別各種不同的文件系統格式。這使得grub識別到文件系統。
(3)stage2: 加載系統引導菜單(/boot/grub/menu.lst或grub.lst),加載內核vmlinuz和RAM磁盤initrd。
4、內核啟動過程
內核映像文件vmlinuz:包含有linux內核的靜態鏈接的可執行文件,傳統上,vmlinux被稱為可引導的內核鏡像。vmlinuz是vmlinux的壓縮文件。其構成如下:
(1)第一個512字節(以前是在arch/i386/boot/bootsect.S);
(2)第二個,一段代碼,若干個不多於512字節的段(以前是在arch/i386/boot/setup.S);
(3)保護模式下的內核代碼(在arch/x86/boot/main.c)。
bzImage文件:使用make bzImage命令編譯內核源代碼,可以得到采用zlib算法壓縮的zImage文件,即big zImage文件。老的zImage解壓縮內核到低端內存,bzImage則解壓縮內核到高端內存(1M(0x100000)以上),在保護模式下執行。bzImage文件一般包含有vmlinuz、bootsect.o、setup.o、解壓縮程序misc.o、以及其他一些相關文件(如piggy.o)。注意,在Linux 2.6內核中,bootsect.S和setup.S被整合為header.S。
initramfs(或initrd)文件:initrd是initialized ram disk的意思。主要用於加載硬件驅動模塊,輔助內核的啟動,掛載真正的根文件系統。


例如,我電腦上的grub啟動項如下(在/boot/grub/grub.lst中):

title Fedora (2.6.35.10-74.fc14.i686)
root (hd0,0)
kernel /vmlinuz-2.6.35.10-74.fc14.i686 ro root=/dev/mapper/VolGroup-lv_root rd_LVM_LV=VolGroup/lv_root rd_LVM_LV=VolGroup/lv_swap rd_NO_LUKS rd_NO_MD rd_NO_DM LANG=zh_CN.UTF-8 KEYBOARDTYPE=pc KEYTABLE=us rhgb quiet
initrd /initramfs-2.6.35.10-74.fc14.i686.img

內核的執行參數可以控制內核的行為,比如ro參數告訴內核,以只讀方式掛載根分區,而quiet則告訴內核,啟動的時候不要打印任何信息。這些參數不光影響內核的執行,大多數的發行版也使用這些參數控制啟動完畢以後後續的動作。這些參數可以在任何時候從/proc/cmdline 這個文件中獲得。現在,grub找到了內核(hd0,0)/boot/vmlinuz-2.6.35.10-74.fc14.i686,它將整個電腦的控制權交給了這個程序,內核開始進行各種初始化的動作,你可以將quiet參數去掉,以便看看內核都做了哪些事情,也可以在系統啟動成功以後,使用dmesg這個命令查看內核啟動的時候,都打印了哪些東西。
啟動過程是和體系結構相關的,對於2.6內核,x86體系結構,CPU在上電初始化時,指令寄存器CS:EIP總是被初始化為固定值,這就是CPU復位後的第一條指令的地址。對於32位地址總線的系統來說,4GB的物理空間至少被劃分為兩個部分,一部分是內存的地址空間,另外一部分地址空間用於對BIOS芯片存儲單元進行尋址。x86復位後工作在實模式下,該模式下CPU的尋址空間為1MB。CS:IP的復位值是FFFF:0000,物理地址為FFFF0。主板設計者必須保證把這個物理地址映射到BIOS芯片上,而不是RAM上。
裝載Linux內核的第一步應該是加載實模式代碼(boot sector和setup代碼),然後檢查偏移0x01f1處的頭部(header)中的各個參數值。實模式的代碼總共有32K,但是boot loader可以選擇只裝載前面的兩個扇區(1K),然後檢查bootup扇區的大小。
header中各個域的格式如下:

Offset/Size Proto Name Meaning

01F1/1 ALL(1 setup_sects The size of the setup in sectors
01F2/2 ALL root_flags If set, the root is mounted readonly
01F4/4 2.04+ syssize The size of the 32-bit code in 16-byte paras
01F8/2 ALL ram_size DO NOT USE - for bootsect.S use only
01FA/2 ALL vid_mode Video mode control
01FC/2 ALL root_dev Default root device number
01FE/2 ALL boot_flag 0xAA55 magic number
0200/2 2.00+ jump Jump instruction
0202/4 2.00+ header Magic signature "HdrS"
0206/2 2.00+ version Boot protocol version supported
0208/4 2.00+ realmode_swtch Boot loader hook (see below)
020C/2 2.00+ start_sys_seg The load-low segment (0x1000) (obsolete)
020E/2 2.00+ kernel_version Pointer to kernel version string
0210/1 2.00+ type_of_loader Boot loader identifier
0211/1 2.00+ loadflags Boot protocol option flags
0212/2 2.00+ setup_move_size Move to high memory size (used with hooks)
0214/4 2.00+ code32_start Boot loader hook (see below)
0218/4 2.00+ ramdisk_image initrd load address (set by boot loader)
021C/4 2.00+ ramdisk_size initrd size (set by boot loader)
0220/4 2.00+ bootsect_kludge DO NOT USE - for bootsect.S use only
0224/2 2.01+ heap_end_ptr Free memory after setup end
0226/1 2.02+ ext_loader_ver Extended boot loader version
0227/1 2.02+ ext_loader_type Extended boot loader ID
0228/4 2.02+ cmd_line_ptr 32-bit pointer to the kernel command line
022C/4 2.03+ ramdisk_max Highest legal initrd address
0230/4 2.05+ kernel_alignment Physical addr alignment required for kernel
0234/1 2.05+ relocatable_kernel Whether kernel is relocatable or not
0235/1 2.10+ min_alignment Minimum alignment, as a power of two
0236/2 N/A pad3 &nbsp; &nbsp; &nbsp; &nbsp; Unused
0238/4 2.06+ cmdline_size Maximum size of the kernel command line
023C/4 2.07+ hardware_subarch Hardware subarchitecture
0240/8 2.07+ hardware_subarch_data Subarchitecture-specific data
0248/4 2.08+ payload_offset Offset of kernel payload
024C/4 2.08+ payload_length Length of kernel payload
0250/8 2.09+ setup_data 64-bit physical pointer to linked list of struct setup_data
0258/8 2.10+ pref_address Preferred loading address
0260/4 2.10+ init_size Linear memory required during initialization

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-10/108033p2.htm

Copyright © Linux教程網 All Rights Reserved