Linux啟動流程

bug--maker發表於2018-09-18
  • 作業系統的啟動流程
  • 作業系統啟動的流程:post-->BIOS(Boot Sequence)--->MBR(boot loader,446)-->kernel---> initrd ---> 查詢根檔案系統,啟動根檔案系統-->init(使用者空間的第一個程式);
  • post加電自檢:將BIOS 中的程式對映進CPU可以查詢的記憶體中的地址空間, ROM 對映進RAM裡面,這些指令用於完成硬體裝置的檢查;
  • 關於bootloader:
    • 對於不同的作業系統來說是不同的,LinuxWindowsbootloader是不同的,windows預設是鎖定MBR的,不允許其他的操作來替換;Linux支援的bootloader包括LILO(Linux Loader),不支援大硬碟或者分割槽,嵌入式一般使用這個;
    • GRUB(Grand Unified bootloader):包含兩個階段;
      這裡寫圖片描述
      • stage1 :裝載在MBR中了,目的是用來引導第二個階段的;
      • stage1.5:其中為了識別常用的stage2的檔案系統,引入stage1.5,用於支援常見的檔案系統;
      • stage2:第二個階段在/boot/grub/stage2裡面,MBR 第一階段所訪問的/boot/grub/是一個基本磁碟裝置,可以進行硬訪問,第二個階段是不受 446位元組的大小限制的設別,可以進行硬訪問;
        這裡寫圖片描述
      • grubstage2階段的配置檔案/boot/grub/grub.conf:
        • default=0:表示預設啟動第一個作業系統;
        • timeout:等待使用者選擇的超時時長
        • splashimage=:用於指定背景圖圖片;
        • Hiddenmenu:表示隱藏選單;
        • title:表示核心標題,作業系統標題;
        • root:表示核心檔案所在的裝置,如果grub找不到kernel的位置,需要進入救援模式來手動探測核心所在的位置;grub識別硬碟都是按照 hd開頭,第一個為hd0;
        • kernel:一行表示kernel檔案路徑以及傳遞給核心的引數;這一行和/proc/cmdline檔案是一致的;這個knernel是直接通過訪問核心所在的分割槽來訪問的,並不銅鼓根檔案系統,因為i這時,根檔案系統還沒有被識別;如果沒有進行單獨分割槽,就需要使用/boot/
        • initrd:表示ram disk檔案路徑,是在作業系統安裝的最後生成的,裡面各種檔案,除了核心檔案之外都有;
        • /boot:是一個獨立的分割槽,grub訪問核心時,檔案系統還沒有載入,所以直接訪問磁碟上的/boot,就不需要根來查詢對應目錄,也就不需要載入核心檔案系統這個操作;
      • grub的應用:編輯介面:在系統啟動過程中,按e進入編輯介面;a可以用於修改核心引數;c:可以用於進入命令列介面;b:用於進行重新啟動;
        • 如果需要新增grub密碼:在title上面新增password,使用命令grub-MD5-crypt:可以用於新增grub加密後的密碼,格式為password --md5;
        • 如果密碼檔案放在了title下面.表示在裝載核心時,需要輸入密碼;
  • BIOS:裡面設定這作業系統的順序,一次去查詢這些裝置的MBR,bootloader查詢作業系統所在的分割槽,並且載入核心,轉載進入記憶體;最後kernel 獲得控制權,識別檔案系統,探測核心,識別關鍵裝置;
  • 檢視系統的執行級別:
    • who -r:用於檢視當前系統的執行級別;
    • runlevel:也是用於檢視當前系統的執行級別的,前面的N表示沒有進行級別切換;
      這裡寫圖片描述
  • grub的損壞和修復:
    • 使用命令破壞前446個位元組, dd if/dev/zero of=/dev/sda count=1 bs=400,建議使用虛擬機器進行測試,不要再真機上面進行測試;
    • 使用 sync進行同步;
    • root(hd0,0)硬碟等裝置,通常被grub識別為hd開頭的裝置,通常MBR位置0分割槽;
    • setup(hd0)安裝:
    • 或者直接使用grub-install –root-directory=/grub所在的位置;往其他硬碟上裝載grub;
    • 建立三個分割槽:建立一個boot目錄,掛載一塊磁碟,使用命令grub-install-root-directory=/mnt/dev/hda;
    • 編輯/mnt/boot/grub/grub.conf
    • 新增:
defaultlt=0
timeout=5
title Fake linux
root(hd0,0)
kernel /vmlinux
initrd /initrd.img
  • 再次強調一下千萬不要拿grub.conf開玩笑,不然系統就毀了;否則就得自己寫一個;使用 find (hd0,0)/ 來查詢核心所在的位置;首先指定root (hd0,0) 在執行 kernel/vmlinux-2.6-補全檔案所在的位置;在指定 initrd /initrd-2.6-補全,然後使用boot 進行重啟;

  • 核心初始化的過程:

    • 1.裝置探測;
    • 2.驅動初始化,需要從initrd 檔案中裝在驅動模組,redhat6 稱為initramfs
    • 3.以只讀方式掛載根檔案系統;
    • 4.裝載第一個程式init,PID1的程式;
  • /sbin/init:通常讀取的檔案是/etc/inittab

    • upstart:一個可執行程式,速度比較快redhat6.0以後開始使用,可以用於並行啟動程式;
    • systemd:並行啟動多個程式的init程式,並行能力更強,但是可能不太穩定,基於事件啟動;redhat5redhat6上面的init程式是不相同的,配置檔案也不相同;init 都是inittaab切割後的各種片,每一個檔案都是基於事件驅動的方式來啟動的;
  • redhat5/etc/inittab檔案:
    這裡寫圖片描述

    • 三個冒號分開的四段:
      • ID:表示識別符號,必須與每一行都不相同;
      • runlevel:表示在那個級別下執行這個動作;
      • action:表示執行的動作,什麼時候執行這個動作;
        • sysinit:表示系統初始化;
        • wait:表示級別切換到次級別時,執行一次;
        • respawn:一旦程式終止,會重新啟動;
      • process:要執行的程式程式;如果不指定級別,表示的就是所有級別;
    • K開頭的表示停止,S開頭的表示啟動,檔案裡面的大多數表示的是連結檔案,其實各個執行的級別後面代表的都是一個個服務或者指令碼檔案,然後通過一個指令碼來同一控制這些指令碼的執行;
    • /etc/inittab執行的任務:
      • 1.設定預設的執行級別;
      • 2.執行系統的初始化指令碼;
      • 3.執行指定執行級別對應目錄下的指令碼;
      • 4.設定 Ctrl+Alt+delete 組合鍵的操作;
      • 5.啟動虛擬終端(2345);
      • 6.啟動圖形終端(5級別);
      • 7.定義UPS電源在電源故障時,恢復時執行的指令碼
  • /etc/rc.d/rc.sysinit完成的任務:

#!/bin/bash
#
# /etc/rc.d/rc.sysinit - run once at boot time
#
# Taken in part from Miquel van Smoorenburg's bcheckrc.
#

HOSTNAME=$(/bin/hostname)

set -m

if [ -f /etc/sysconfig/network ]; then
    . /etc/sysconfig/network
fi
if [ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]; then
    HOSTNAME=localhost
fi

if [ ! -e /proc/mounts ]; then
	mount -n -t proc /proc /proc
	mount -n -t sysfs /sys /sys >/dev/null 2>&1
fi
if [ ! -d /proc/bus/usb ]; then
	modprobe usbcore >/dev/null 2>&1 && mount -n -t usbfs /proc/bus/usb /proc/bus/usb
else
	mount -n -t usbfs /proc/bus/usb /proc/bus/usb
fi

#remount /dev/shm to set attributes from fstab #669700
mount -n -o remount /dev/shm >/dev/null 2>&1
#remount /proc to set attributes from fstab #984003
mount -n -o remount /proc >/dev/null 2>&1

. /etc/init.d/functions
* 1.啟用`udev` 和 `selinux`;
* 2.根據`/etc/systl.conf`檔案來設定核心引數;
* 3.設定時區時鐘;
* 4.裝載鍵盤對映;
* 5.啟用交換分割槽;
* 6.設定主機名;
* 7.根檔案系統檢測,並且以只讀方式重新掛載;
* 8.啟用`RAID`裝置和`LVM`裝置;
* 9.啟用磁碟配額;
* 10.根據`/etc/fstab`,檢查並掛載其他檔案系統;
* 11.清理過期的的鎖和`PID`檔案;
  • init:使用者空間的主導程式,使用者空間的管理都由init管理;

  • 核心的設計風格

  • 在核心啟動之前,檔案系統是沒有啟動的,核心所在的分割槽是由bootloader來識別的,所以bootloader需要來識別檔案系統;根檔案系統是訪問其他目錄或者檔案的入口,根檔案系統是自引用的,這個過程由核心完成,核心必須可以探測訪問核心所在的分割槽,但是由於磁碟硬體的不同,這些驅動不可以全部做入核心,所以存在兩種核心設計理念;

  • 單核心設計:把所有功能都做進核心,檔案系統,程式管理等功能,邏輯上簡單,但是導致核心系統十分龐大;

  • 微核心設計:將上述功能做成一個子系統,驅動程式,檔案系統作為子系統,一個子系統壞掉,不影響正常啟動,彼此之間的協調很複雜;

  • Linux 是單核心設計支援LWP輕量級程式,Linux對於執行緒的支援並不是很好;核心程式碼十分龐大,按照自己的實際需要進行編譯安裝,Linux同時也引入了微核心的思想;核心的設計是模組化的,有核心和其他模組組成,核心核心可以動態的載入所需要的核心模組,在/lib/modules/裡面核心版本號命名的目錄/模組之間是有依賴關係,有一個檔案來解決依賴;命令一般為 vmlunuz-2.6.32目錄在裡面有檔案系統,驅動程式,加密解密程式等;

  • linux採用模組化設計,由核心模組和外為模組組成;

    • 核心的核心功能稱為ko,核心核心本身很小,在需要使用的時候,如果已經完成過編譯,就只需要進行載入就可以了;
    • 外圍模組: 大多數模組都在目錄/lib/modules/核心版本號碼裡面,也就是核心所需要的模組在某個裝置上,而訪問該裝置的驅動程式也在這個裝置上;
    • 所以需要在核心和需要訪問的是裝置之間新增一個程式檔案,這個檔案不是事先編譯好的,而這個程式檔案,也就是這個檔案並不是事先在編譯核心是就提供的,而是根據核心和BISO生成的相關硬體配置資訊,在安裝作業系統時生成的一個檔案,這個裝置可以成為橋接裝置;
      • 這個裝置檔案提供一個獨立的檔案系統,用於核心來訪問,這是一個偽檔案系統,用於臨時的根切換,同時將該檔案系統的/proc, /sys , /dev,轉到真正的根檔案系統;
    • redhat6bash-shell使用的是命令chroot,但是在rhel5上面使用的是nash提供的命令switch-root,
  • /lib/modules/核心版本號碼:
    這裡寫圖片描述

    • dep:表示的都是核心依賴檔案;
    • alias:表示的是核心別名檔案;
    • map:表示的是核心對映關係;
    • kernel:
      這裡寫圖片描述
      • arch:表示和平臺相關的檔案;
      • crypto:表示和加解密相關的檔案;
      • drivers:表示和驅動相關的檔案;
      • fs:表示和檔案系統相關的檔案;
      • lib:表示依賴的庫檔案;
      • mm:表示的是記憶體管理相關的檔案;
      • net:表示網路相關的檔案,通常是驅動協議,不是驅動程式;
      • sound:表示和聲音相關的檔案;
  • nash shell 中提供了一個switch root來完成根切換;偽檔案系統裡面的檔案可以講記憶體中的一段空間模擬成硬碟來使用,這段空間稱為ramdisk 或者 ram filesystem,使用這段空間來展開偽檔案系統中的檔案,核心訪問根檔案系統需要驅動程式和檔案系統來進行訪問;

  • 這段地址空間在rhel5上面稱為ramdisk--->initrd,在rhel6上面ramfs-->initramfs

  • 使用者空間的命令用於實現根切換的命令是chroot;

    • 首先建立一個目錄chroot
    • 然後建立/bin/bash,在chroot裡面的目錄,也就是./bin/bash
    • 使用ldd /bin/bash依賴的庫檔案,並且建立庫檔案的相對目錄,複製庫檔案到對應的目錄裡面;
    • 按照上面的過程同時還可以複製一些常見的命令檔案過去,在這個目錄底下,就可以執行這些檔案;
      這裡寫圖片描述
  • bootloader是完成kernelinitrd的載入的,最後將initrd交給kernel使用;

  • Init的功能:

    • 定義作業系統的執行級別:
      • 0:表示halt,表示停止作業系統,但是不關閉電源;
      • 1:single user root表示單使用者模式,直接登入管理員,不適用密碼登入,使用s或者 S或者single都可以進入單使用者模式;
      • 2: multi user root:表示多使用者模式,啟用網路功能,但是不啟用NFS等網路檔案系統;
      • 3:multi user root:多使用者模式,啟用正常的系統功能,但是是文字模式;
      • 4:reserved:保留級別,暫時沒有定義;
      • 5:multi user root:多使用者啟動圖形介面;
      • 6:reboot:重啟,如果定義為這個級別,系統會一直重新啟動;
  • /etc/rc.d/rc.sysinit檔案的內容:

    • Si::sysinit:/etc/rc.d/rc.sysinit.完成OS的初始化,裡面對應的K開頭的檔案和S開頭的檔案,都是按照級別等級需要執行的,這些指令碼都是Linux執行的服務指令碼,對於這些指令碼至少需要接受四個引數:start stop restart status,以及reload configtest;
    • 指令碼的規範:
      • 服務指令碼都有相同意義的兩行chkconfig:用來定義定義這個指令碼來建立一個連結,三組數字分別表示為:
        • 啟動的執行級別:也就是這些程式在哪些執行級別下面執行;
        • SS啟動的優先順序:表示相對於其他應用程式的啟動優先順序;
        • KK關閉的優先順序:表示相對於其他應用程式的關閉優先順序別;
        • description:這個指令碼檔案完成的工作的一個大致的介紹;
    • chkconfig命令為此指令碼來建立連結時,runlevels表示建立預設為S開頭的連線,除此之外的級別預設建立為K開頭的連結;S後面的啟動優先順序為SS所表示的數字,K後面關閉優先順序為KK所代表的數字;runlevel後面可以為表示預設沒有開頭為S的連結;
    • chkconfig命令:
      • --list:用於列出所有獨立守護程式的啟動設定,可以使用chkconfig –list SERVICE_NAME檢視某個具體的服務;
      • --add SERVICE_NAME:用於自動建立服務指令碼所使用的連結;
      • --del SERVICE_NAME:用於刪除服務的連結檔案;
      • --level runlecvels SERVICE_NAME {on | off}:用於指定在那個級別開啟或者關閉,如果省略級別指定預設為2345級別;
    • /etc/rc.d/rc.local檔案,本質上是一個連結檔案
      • 系統最後執行的一個指令碼,可以用於自定義一些自己需要的服務,不方便寫成指令碼的
        服務,感覺很有用;
  • 使用chkconfig管理的服務通常稱為獨立守護服務,就是自己來管理自己應該在那些級別下面啟動,在那些情況下開啟;

  • 守護程式型別

  • 獨立守護程式:服務的關閉啟動等是自己進行管理,這種型別的程式適合於長時線上的服務;

  • 瞬時守護程式:不需要關聯至執行級別;由xinetd來負責進行管理,xinetd也稱為超級守護程式,但是超級守護程式xinetd是需要關聯至執行級別的,超級守護程式是記錄自己守護的瞬時守護程式是按需進行開啟的,當需要訪問時,xinetd通知相關的瞬時守護程式,完成服務後,瞬時守護程式就會關閉;
    這裡寫圖片描述

相關文章