歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux內核

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