天天看點

linux img 核心啟動,linux的啟動流程(initrd.img)

http://www.ibm.com/developerworks/cn/linux/l-initrd.html

一、從哪裡到哪裡

本文旨在描述linux中核心如何調用啟動,然後如何從img的檔案系統切換到硬碟的過程。

描述起于:linux-2.6.11/init/main.c中函數 static int init(void * unused)

描述止于:/etc/rc.d/rc.sysinit檔案的被調用

二、描寫流程

在linux代碼linux-2.6.11/init/main.c中init這個函數被調用時,初始啟動的檔案

系統鏡像:/boot/initrd-2.6.11.12.img(以2.6.11.12核心為例)已被grub加載到

記憶體中,并已挂載到根目錄上("/")。

1、我們先來看看initrd-2.6.11.12.img到底是個什麼東西:

[[email protected] tmp]# cd /tmp

[[email protected] tmp]# cp /boot/initrd-2.6.11.12.img /tmp/initrd-2.6.11.12.gz

[[email protected] tmp]# gunzip initrd-2.6.11.12.gz

解壓縮後的檔案為:

[[email protected] tmp]# ls -l initrd-2.6.11.12

-rw-r--r-- 1 root root 846848 7月 31 17:01 initrd-2.6.11.12

是一個CPIO格式的檔案,該檔案格式是種檔案鏡像讓我們将它解開到一個目錄中看看

其中的具體内容:

[[email protected] tmp]# mkdir initrd

[[email protected] tmp]# cd initrd

[[email protected] initrd]# cpio -i < ../initrd-2.6.11.12

1654 blocks

[[email protected] initrd]# ls

bin bootsplash dev etc init lib loopfs proc sbin sys sysroot

[[email protected] initrd]# find .

.

./lib

./bin

./bin/nash

./bin/insmod

./bin/modprobe

./bin/hotplug

./etc

./dev

./dev/console

./dev/null

./dev/ram

./dev/systty

./dev/tty1

./dev/tty2

./dev/tty3

./dev/tty4

./loopfs

./proc

./sys

./sysroot

./sbin

./init

./bootsplash

可見該鏡像檔案目錄中包括:

/bin 目錄下的四個用于啟動和切換到硬碟上的程式:

nash(用于處理根目錄下的/init腳本)、insmod和modprobe來加載核心驅動、hotplug用

于外設的拔插處理。

/dev 目錄下的八個裝置檔案

/init 是個nash的啟動腳本檔案

/bootsplash 是核心打了bootsplash更新檔後,會在對該檔案進行讀取操作,然後将該檔案

中包含的圖檔檔案在啟動時顯示。

[[email protected] initrd]# dmesg | grep -i bootsplash

bootsplash 3.1.6-2004/03/31: looking for picture... silentjpeg size 36270 bytes,

...found (1024x768, 19600 bytes, v3).

核心的這個裝載資訊就是在處理該檔案。(具體的bootsplash的使用和建立這裡不細說)。

附:CPIO檔案的打包

[[email protected] initrd]# cd /tmp/initrd

[[email protected] initrd]# rm ../initrd-2.6.11.12

[[email protected] initrd]# find . | cpio -c -o > ../initrd-2.6.11.12

1654 blocks

[[email protected] initrd]# gzip ../initrd-2.6.11.12

[[email protected] initrd]# mv ../initrd-2.6.11.12.gz ../initrd-2.6.11.12.img

2、回到核心init函數中,看看如何調用/boot/initrd-2.6.11.12.img中/init腳本的

....

// 這裡判斷在grub裝載的/boot/initrd-2.6.11.12.img中是否有"/init"這個檔案?

if (sys_access((const char __user *) "/init", 0) == 0)

execute_command = "/init"

else

....

// 如果有"/init"這個檔案就先運作它。

if (execute_command)

run_init_process(execute_command);

run_init_process("/sbin/init");

run_init_process("/etc/init");

run_init_process("/bin/init");

run_init_process("/bin/sh");

panic("No init found. Try passing init= option to kernel");

由代碼我們看到kernel會先判斷并運作/boot/initrd-2.6.11.12.img中的/init檔案,我們

來看看該/boot/initrd-2.6.11.12.img/init檔案的内容,我們上面已将該檔案展開到目錄

/tmp/initrd中:

[[email protected] initrd]# cat ./init

#!/bin/nash # 該檔案是個nash的腳本檔案

# 挂接proc檔案系統

mount -t proc /proc /proc

# 不輸出nash調試資訊,由/proc/cmdline決定,cat /proc/cmdline我的啟動參數

# 輸出ro root=/dev/hda3 vga=791 splash=silent,如果該指令行中帶了quiet參

# 數,則不輸出nash提示資訊。

setquiet

# 提示資訊(這裡提示因該放到上面去,mkinitrd-4.2.17-2mgc.rpm包中原來如是,

# 筆誤?為什麼這裡牽涉到mkinitrd這個包類?因為:/boot/initrd-2.6.11.12.img

# 檔案由下面指令生成:mkinitrd /boot/initrd-2.6.11.12.img 2.6.11.12)

echo Mounted /proc filesystem

# 挂接sys檔案系統

echo Mounting sysfs

mount -t sysfs /sys /sys

# 建立/dev臨時目錄

echo Creating /dev

mount -o mode=0755 -t tmpfs /dev /dev

# 建立裝置檔案(這些裝置檔案在切換到硬碟後,由/etc/rc.sysinit中start_udev

# 重新建立)

mknod /dev/console c 5 1

mknod /dev/null c 1 3

mknod /dev/zero c 1 5

# 建立僞終端目錄

mkdir /dev/pts

# 建立共享記憶體目錄

mkdir /dev/shm

# 這裡是調用的nash中的makedevs指令裝載硬碟等塊裝置,不裝載其他裝置隻裝載

# 硬碟等塊裝置

echo Starting udev

# 告訴核心當發現新拔插裝置時用"/sbin/hotplug"程式來處理

echo -n "/sbin/hotplug" > /proc/sys/kernel/hotplug

makedevs

makedevs # 這裡多搞一次沒必要

echo Creating root device

# 由grub啟動指令行root=/dev/hda3來聯接裝置/dev/root到root變量所指定的啟動

# 裝置,見下面我的grub啟動參數:

# kernel /boot/vmlinuz-2.6.11.12 ro root=/dev/hda3 vga=791 splash=silent

mkrootdev /dev/root

# 挂接/dev/root目錄

echo Mounting root filesystem

mount -o defaults --ro -t ext3 /dev/root /sysroot

echo Switching to new root

# 切換根目錄到裝置/dev/root目錄,運作完該指令根目錄"/"->"/dev/hda3"

switchroot --movedev /sysroot

由上面的注釋我們大概能夠明白./init腳本的基本運作流程:

a、裝載基本的核心系統檔案和裝置檔案

b、根據grub的啟動指令行參數,判斷root根檔案裝置,參看/boot/grub/grub.conf檔案中制定

的參數,該參數在核心啟動後可有cat /proc/cmdline顯示出來,nash和其他的一些程式也是通

過讀該系統檔案來去核心啟動參數的。

c、在将從grub啟動參數中獲得根裝置并将其與/dev/root裝置聯接以後,通過nash的switchroot

指令将/dev/root裝置挂接到根目錄上("/")

看看這樣操作後,留下的痕迹:

[[email protected] initrd]# ls -l /dev/root

lrwxrwxrwx 1 root root 9 7月 31 12:06 /dev/root -> /dev/hda3

[[email protected] initrd]# mount

/dev/hda3 on / type ext3 (rw)

到此為止,已将硬碟裝置裝載到根目錄下了,進而取代了原來有initrd.img檔案的根位置。

3、再回頭看看核心中main.c中init函數,看看如何調用/sbin/init處理/etc/inittab檔案

....

// 如果有"/init"這個檔案就先運作它。

if (execute_command)

run_init_process(execute_command);

run_init_process("/sbin/init");

run_init_process("/etc/init");

run_init_process("/bin/init");

run_init_process("/bin/sh");

panic("No init found. Try passing init= option to kernel");

我們已經運作完run_init_process(execute_command);這裡了,然後繼續運作:

run_init_process("/sbin/init");

run_init_process("/etc/init");

run_init_process("/bin/init");

run_init_process("/bin/sh");

/sbin/init這個檔案在SysVinit-2.85-34mgc.rpm這個包中,該程式的主要處理代碼在檔案:

sysvinit-2.85/src/init.c中,該檔案主要查找和處理/etc/inittab檔案,按照該檔案的内容

依次做處理。

[[email protected] initrd]# cat /etc/inittab

#

# inittab This file describes how the INIT process should set up

# the system in a certain run-level.

#

# Author: Miquel van Smoorenburg, # Modified for RHS Linux by Marc Ewing and Donnie Barnes

#

# Default runlevel. The runlevels used by RHS are:

# 0 - halt (Do NOT set initdefault to this)

# 1 - Single user mode

# 2 - Multiuser, without NFS (The same as 3, if you do not have networking)

# 3 - Full multiuser mode

# 4 - unused

# 5 - X11

# 6 - reboot (Do NOT set initdefault to this)

#

id:5:initdefault: # /sbin/init 根據這裡判斷啟動的級别

# System initialization.

si::sysinit:/etc/rc.d/rc.sysinit # /sbin/init 會最先運作這個系統配置檔案

l0:0:wait:/etc/rc.d/rc 0 # /sbin/init 根據上面取得的級别運作相應

l1:1:wait:/etc/rc.d/rc 1 # 目錄下的啟動腳本

l2:2:wait:/etc/rc.d/rc 2

l3:3:wait:/etc/rc.d/rc 3

l4:4:wait:/etc/rc.d/rc 4

l5:5:wait:/etc/rc.d/rc 5

l6:6:wait:/etc/rc.d/rc 6

# Trap CTRL-ALT-DELETE

ca::ctrlaltdel:/sbin/shutdown -t3 -r now # 設定關機熱鍵

# When our UPS tells us power has failed, assume we have a few minutes

# of power left. Schedule a shutdown for 2 minutes from now.

# This does, of course, assume you have powerd installed and your

# UPS connected and working correctly.

pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"

# If power was restored before the shutdown kicked in, cancel it.

pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"

# Run gettys in standard runlevels

1:2345:respawn:/sbin/mingetty tty1 # 建立6個登陸控制終端可以通過CTRL-ALT-F?

2:2345:respawn:/sbin/mingetty tty2 # 切換,'?'表示第幾個登陸控制台,比如第1

3:2345:respawn:/sbin/mingetty tty3 # 個為F1,第2個為F2依次類推。F7為X11控制

4:2345:respawn:/sbin/mingetty tty4 # 台,後面就沒有了,是以在X下可以很靈活

5:2345:respawn:/sbin/mingetty tty5 # 的切換到控制台下面操作。

6:2345:respawn:/sbin/mingetty tty6

# Run xdm in runlevel 5

x:5:once:/etc/X11/prefdm -nodaemon

通過核心中對/sbin/init的調用現在已經執行/etc/rc.d/rc.sysinit操作了。

閱讀(897) | 評論(0) | 轉發(0) |

繼續閱讀