1、Linux 启动信息解析 2 目录 Linux 启动信息解析 .1 目录 2 1.项目需求分析 .3 1.1 项目背景: 3 1.2 时间: 3 1.3 项目要求分析: 3 2Linux 启动过程 .4 2.1 Linux 下各个目录的作用 .4 2.2 Linux 启动过程 .4 2.2.1 Linux 的引导过程 5 2.2.2 运行级别(run level) .5 2.2.3 /etc/rc.d/与/etc/rc.d/init.d 的关系 .5 3. /init/main.c 中 init()函数 .7 4. 启动信息 .10 3 1.项目需求分析 1.1 项目背景: 在学习操作系统中,
2、操作系统的如何启动是一个难点,本文基于 Linux 开 源操作系统,分析了从 BIOS 加载 BOOTLOAD,操作系统接管 CPU 后,init() 函数所做的事情以及如何初始化系统的各种服务以及 SHELL。 1.2 时间: 开始时间: 2010-7-25 结束时间: 2010-7-25 1.3 项目要求分析: 1) 介绍 Linux 启动所需的目录。 2) Linux 启动过程。 3) /etc/rc.d/与 /etc/rc.d/init.d 的关系。 4) 分析 init/main.c 代码中 init()函数。 4 2Linux 启动过程 2.1 Linux 启动所需的目录 init
3、.d/ :各种服务器和程序的二进制文件存放目录。 rcx.d/: 各个启动级别的执行程序连接目录。里头的东西都是指向 init.d/的一 些软连接。 还有三个脚本:rc.sysinit, rc, rc.local 。 /etc/rc.d/init.d/目录下的脚本就类似与 windows 中的注册表,在系统启动的 时候某些指定脚本将被执行。 在 Redhat 中, /etc/rc.d/rc.sysinit 主要做在各个运行模式中相同的初始化工作, 包括: i. 调入 keymap 以及系统字体 ii. 启动 swapping iii. 设置主机名 iv. 设置 NIS 域名 v. 检查(fsc
4、k )并 mount 文件系统 vi. 打开 quota vii. 装载声卡模块 viii. 设置系统时钟 ix. 等等。 2.2 Linux 启动过程 redhat 的启动方式和执行次序是: i. 加载内核 ii. 执行 init 程序 iii. /etc/rc.d/rc.sysinit # 由 init 执行的第一个脚本 iv. /etc/rc.d/rc $RUNLEVEL # $RUNLEVEL 为缺省的运行模式 v. /etc/rc.d/rc.local vi. /sbin/mingetty # 等待用户登录 init 在等待/etc/rc.d/rc 执行完毕之后(因为在 /etc/i
5、nittab 中/etc/rc.d/rc 的 action 是 wait) ,将在指定的各个虚拟终端上运行 /sbin/mingetty,等待用户的登 录。 至此,Linux 的启动结束。 5 2.2.1 Linux 的引导过程 系统启动之后,在进入 init.d 之前,我们先来看看系统都做了什么工作. 我们从比较高的角度去看开始引导的整个过程,比较清晰明了。系统加电之后, 首先进行的硬件自检,然后是 bootloader 对系统的初始化,加载内核。内核被 加载到内存中之后,就开始执行了。一旦内核启动运行,对硬件的检测就会决 定需要对哪些设备驱动程序进行初始化。从这里开始,内核就能够挂装根文件
6、 系统(这个过程类似于 Windows 识别并存取 C 盘的过程) 。内核挂装了根文件 系统,并已初始化所有的设备驱动程序和数据结构等之后,就通过启动一个叫 init 的用户级程序,完成引导进程。 2.2.2 运行级别(run level) init 进程是系统启动之后的第一个用户进程,所以它的 pid(进程编号)始终为 1。init 进程上来首先做的事是去读取/etc/目录下 inittab 文件中 initdefault id 值, 这个值称为运行级别(run-level)。它决定了系统启动之后运行于什么级别。运行 级别决定了系统启动的绝大部分行为和目的。这个级别从 0 到 6 ,具有不同
7、的 功能。不同的运行级定义如下: # 0 - 停机(千万别把 initdefault 设置为 0,否则系统永远无法启动) # 1 - 单用户模式 # 2 - 多用户,没有 NFS # 3 - 完全多用户模式(标准的运行级) # 4 系统保留的 # 5 - X11 (x window) # 6 - 重新启动 (千万不要把 initdefault 设置为 6,否则将一直在重启) 2.2.3 /etc/rc.d/与/etc/rc.d/init.d 的关系 写到这里,应该差不多要进入 init.d 了,可是我觉得单写/etc/rc.d/init.d 的话 不一定能说得清楚明白,就拿它跟/etc/rc.
8、d 这个它上一级的目录一起来讨论,可 能比较合适一些,因为他们之间有着千丝万缕的关系。 在这里先解释一下 init.d 里面放的都是什么东西。这个目录存放的是一些脚 本,一般是 linux 以 rpm 包安装时设定的一些服务的启动脚本。系统在安装时 装了好多 rpm 包,这里面就有很多对应的脚本。执行这些脚本可以用来启动, 停止,重启这些服务。 前面说到,/etc/rc.d/init.d 这个目录下的脚本就类似与 windows 中的注册表, 在系统启动的时候执行。程序运行到这里(init 进程读取了运行级别),相信从命 名的角度大家也能猜到该运行/etc/rc.d/init.d 里面的脚本了
9、,不然它为什么也叫 6 init(.d)呢是吧。没错,是该运行 init.d 里的脚本了,但是并不是直接运行,而是 有选择的因为系统并不需要启动所有的服务。 那么,系统是如何选择哪些需要启动哪些不要呢?这时刚才说的运行级别 就起作用了。在决定了系统启动的 run level 之后, /etc/rc.d/rc 这个脚本先执行。 在 RH9 和 FC7 的源码中它都是一上来就 check_runlevel()(虽然实现的代码不 一样,也大同小异) ,知道了运行级别之后,对于每一个运行级别,在 rc.d 下都 有一个子目录分别是 rc0.d,rc1.d rc6.d。每个目录下都是到 init.d 目
10、录的一 部分脚本一些链接。每个级别要执行哪些服务就在相对应的目录下,比如级别 5 要启动的服务就都放在 rc5.d 下,但是放在这个 rc5.d 下的都是一些链接文件, 链接到 init.d 中相对应的文件,真正运行的是 init.d 里的脚本。 到这里,估计大家可能都比较清楚了,我开始也以为是这样的。可是后来 我仔细看过和比较这些链接文件和 init.d 里真正被执行的脚本的文件名之后,一 直有几个问题没弄明白。借着写这个文章的机会,我做了一些功课,总算是大 概解开了那些疑惑。 1、这些链接文件前面为什么会带一个 Kxx 或者 Sxx 呢? 是这样的,带 K 的表示停止(Kill)一个服务,
11、S 表示开启(Start)的意思,凡是 以 Kxx 开头的,都以 stop 为参数来调用;凡是以 Sxx 开头的,都以 start 为参 数来调用。调用的顺序按 xx 从小到大来执行。例如,假设缺省的运行模式是 3,/etc/rc.d/rc 就会按上述方式调用/etc/rc.d/rc3.d/下的脚本。 2、K 和 S 后面带的数字呢?干什么用的 这个我开始的时候还以为是排列起来好看或者数数用呢。后来发现不是的。 它的作用是用来排序,就是决定这些脚本执行的顺序,数值小的先执行,数值 大的后执行。很多时候这些执行顺序是很重要的,比如要启动 Apache 服务,就 必须先配置网络接口,不然一个没有
12、IP 的机子来启动 http 服务那岂不是很搞笑。 。 。 3、无意中我发现同一个服务带 S 的和带 K 的链接到 init.d 之后是同一个脚 本。我就纳闷了,为什么会是执行同一个脚本呢? 这个时候真是 S 和 K 的妙用了,原来 S 和 K 并不止是用来看起来分的清楚 而已。S 给和 K 还分别给 init.d 下面的脚本传递了 start 和 stop 的参数。哦,是 这样的( 焕然大悟的样子,呵呵)!这时我才想起来原来曾经无数用过的 /etc/rc.d/init.d/network restart 命令。原来传 S 时相当于执行了/etc/rc.d/init.d/xxx start 这
13、条命令,当然 K 就相当于 /etc/rc.d/init.d/xxx stop 了. 7 3. /init/main.c 中 init()函数 init()函数的功能可分为 4 个部分:安装根文件系统; 显示系统信息; 运行系统初始资源配置文件 rc 中的命令;执行用户登录 shell 程序。 代码首先调用系统调用 setup(),用来收集硬盘设备分区表信息并安装根文 件系统。在安装根文件系统之前,系统会先判断是否需要先建立虚拟盘若编 译内核时设置了虚拟盘的人小,并在前面内核初始化过程中已经开辟了一块内 存用作虛拟盘,则内核就会首先尝试把根文件系统加载到内存的虚拟盘区中 然后 init()打开
14、一个终端设备 tty0,并复制其文件描述符以产生标准输入 stdin、标准输出 stdout 和错误输出 stderr 设备。内核随后利用这些描述符在终 端上显示一些系统信息,例如高速缓冲区中缓冲块总数、主内存区空闲内存总 字节数等。 接着 init()又新建了一个进程(进程 2),并在其中为建立用户交互使用环境而 执行一些初始配置操作,即在用户可以使用 shell 命令行环境之前,内核调用 /bin/sh 程序运行了配置文件/etc/rc 中设置的命令。 rc 文件的作用与 DOS 系统根 目录上的 AUTOEXEC.BAT 文件类似。这段代码首先通过关闭文件描述符 0, 并立刻打开文件/e
15、tc/rc,从而把标准输入 stdin 定向到/etc/rc 文件上。这样,所 有的标准输入数据都将从该文件中读取。然后内核以非交互形式执行/bin/sh, 从而实现执行/etc/rc 文件中的命令。当该文件中的命令执行完毕后,/bin/sh 就 会立刻退出。因此进程 2 也就随之结束。 init()函数的最后一部份用于在新建进程中为用户建立一个新的会话,并运 行用户登录 shell 程序/bin.sh在系统执行进程 2 中的程序时,父进程(init 进程) 一直等待着它的结束。随着进程 2 的退出,父进程就进入到一个无限循环中。 在该循环中,父进程会再次生成一个新进程,然后在该进程中创建一个
16、新的会 话。并以登录 shell 方式再次执行程序/bin/sh,以创建用户交互 shell 环境。然后 父进程继续等待该于进程。登录 shell 虽然与前而的非交互式 shell 是同一个程 序/bin/sh,但是所使用的命令行参数(argv)不同。登录 shell 的第 0 个命令行参 数的第 1 个字符一定是一个减号-。这个特定的标志会在/bin/sh 执行时通知它 这不是一次普通的运行,而是作为登录 shell 运行/bin/sh 的。从这时开始,用户 就可以正常使用 Linux 命令行环境了,而父进程随之又进入等待状态此后若 用户在命令行上执行了 exit 或 logout 命令,那
17、么在显示一条当前登录 shell 退出 的信息后,系统就会在这个无限循环中再次重复以上创建登录 shell 进程的过程。 以下是 init/main.c 中的关于 init()函数的源代码: 8 void init(void) int pid,i; setup(void *) sprintf(term, “TERM=con%dx%d“, ORIG_VIDEO_COLS, ORIG_VIDEO_LINES); (void) open(“/dev/tty1“,O_RDWR,0); (void) dup(0); (void) dup(0); execve(“/etc/init“,argv_init,
18、envp_init); execve(“/bin/init“,argv_init,envp_init); execve(“/sbin/init“,argv_init,envp_init); /* if this fails, fall through to original stuff */ if (!(pid=fork() close(0); if (open(“/etc/rc“,O_RDONLY,0) _exit(1); execve(“/bin/sh“,argv_rc,envp_rc); _exit(2); if (pid0) while (pid != wait( while (1)
19、if (pid = fork() (reserved) 11 0.000000 last_pfn = 0x40000 max_arch_pfn = 0x100000 0.000000 MTRR default type: uncachable 0.000000 MTRR fixed ranges enabled: 0.000000 00000-9FFFF write-back 0.000000 A0000-BFFFF uncachable 0.000000 C0000-CBFFF write-protect 0.000000 CC000-EFFFF uncachable 0.000000 F0
20、000-FFFFF write-protect 0.000000 MTRR variable ranges enabled: 0.000000 0 base 0000000000 mask 00C0000000 write-back 0.000000 1 disabled 0.000000 2 disabled 0.000000 3 disabled 0.000000 4 disabled 0.000000 5 disabled 0.000000 6 disabled 0.000000 7 disabled 0.000000 PAT not supported by CPU. 0.000000
21、 - cut here - 0.000000 WARNING: at /build/buildd/linux- 2.6.32/arch/x86/kernel/cpu/mtrr/generic.c:467 generic_get_mtrr+0xeb/0x100() 0.000000 Hardware name: VMware Virtual Platform 0.000000 mtrr: your BIOS has set up an incorrect mask, fixing it up. 0.000000 Modules linked in: 0.000000 Pid: 0, comm:
22、swapper Not tainted 2.6.32-22-generic #36-Ubuntu 0.000000 Call Trace: 0.000000 warn_slowpath_common+0x72/0xa0 0.000000 ? generic_get_mtrr+0xeb/0x100 0.000000 ? generic_get_mtrr+0xeb/0x100 0.000000 warn_slowpath_fmt+0x2b/0x30 0.000000 generic_get_mtrr+0xeb/0x100 0.000000 mtrr_trim_uncached_memory+0x7
23、6/0x32e 0.000000 ? native_write_cr4+0x8/0x10 0.000000 ? get_mtrr_state+0x102/0x10a 12 0.000000 ? mtrr_bp_init+0x253/0x271 0.000000 setup_arch+0x41e/0x69f 0.000000 ? printk+0x1d/0x23 0.000000 ? default_spin_lock_flags+0x9/0x10 0.000000 start_kernel+0xc3/0x357 0.000000 i386_start_kernel+0xaa/0xb1 0.00
24、0000 - end trace a7919e7f17c0a725 - 0.000000 Scanning 0 areas for low memory corruption 0.000000 modified physical RAM map: 0.000000 modified: 0000000000000000 - 0000000000010000 (reserved) 0.000000 modified: 0000000000010000 - 000000000009f800 (usable) 0.000000 modified: 000000000009f800 - 00000000
25、000a0000 (reserved) 0.000000 modified: 00000000000ca000 - 00000000000cc000 (reserved) 0.000000 modified: 00000000000dc000 - 00000000000e4000 (reserved) 0.000000 modified: 00000000000e8000 - 0000000000100000 (reserved) 0.000000 modified: 0000000000100000 - 000000003fef0000 (usable) 0.000000 modified:
26、 000000003fef0000 - 000000003feff000 (ACPI data) 0.000000 modified: 000000003feff000 - 000000003ff00000 (ACPI NVS) 0.000000 modified: 000000003ff00000 - 0000000040000000 (usable) 0.000000 modified: 00000000e0000000 - 00000000f0000000 (reserved) 0.000000 modified: 00000000fec00000 - 00000000fec10000
27、(reserved) 0.000000 modified: 00000000fee00000 - 00000000fee01000 (reserved) 0.000000 modified: 00000000fffe0000 - 0000000100000000 (reserved) 0.000000 initial memory mapped : 0 - 00c00000 0.000000 init_memory_mapping: 0000000000000000-00000000377fe000 0.000000 Using x86 segment limits to approximat
28、e NX protection 0.000000 0000000000 - 0000400000 page 4k 0.000000 0000400000 - 0037400000 page 2M 0.000000 0037400000 - 00377fe000 page 4k 0.000000 kernel direct mapping tables up to 377fe000 10000-15000 0.000000 RAMDISK: 2f7dc000 - 2ff73ed6 0.000000 ACPI: RSDP 000f6940 00024 (v02 PTLTD ) 0.000000 A
29、CPI: XSDT 3fef081b 0004C (v01 INTEL 440BX 06040000 VMW 01324272) 13 0.000000 ACPI: FACP 3fefee98 000F4 (v04 INTEL 440BX 06040000 PTL 000F4240) 0.000000 ACPI: DSDT 3fef09e1 0E4B7 (v01 PTLTD Custom 06040000 MSFT 03000001) 0.000000 ACPI: FACS 3fefffc0 00040 0.000000 ACPI: BOOT 3fef09b9 00028 (v01 PTLTD
30、 $SBFTBL$ 06040000 LTP 00000001) 0.000000 ACPI: APIC 3fef095b 0005E (v01 PTLTD ? APIC 06040000 LTP 00000000) 0.000000 ACPI: MCFG 3fef091f 0003C (v01 PTLTD $PCITBL$ 06040000 LTP 00000001) 0.000000 ACPI: SRAT 3fef089f 00080 (v02 VMWARE MEMPLUG 06040000 VMW 00000001) 0.000000 ACPI: Local APIC address 0
31、xfee00000 0.000000 136MB HIGHMEM available. 0.000000 887MB LOWMEM available. 0.000000 mapped low ram: 0 - 377fe000 0.000000 low ram: 0 - 377fe000 0.000000 node 0 low ram: 00000000 - 377fe000 0.000000 node 0 bootmap 00011000 - 00017f00 0.000000 (9 early reservations) = bootmem 0000000000 - 00377fe000
32、 0.000000 #0 0000000000 - 0000001000 BIOS data page = 0000000000 - 0000001000 0.000000 #1 0000001000 - 0000002000 EX TRAMPOLINE = 0000001000 - 0000002000 0.000000 #2 0000006000 - 0000007000 TRAMPOLINE = 0000006000 - 0000007000 0.000000 #3 0000100000 - 00008d9e98 TEXT DATA BSS = 0000100000 - 00008d9e
33、98 0.000000 #4 002f7dc000 - 002ff73ed6 RAMDISK = 002f7dc000 - 002ff73ed6 0.000000 #5 000009f800 - 0000100000 BIOS reserved = 000009f800 - 0000100000 0.000000 #6 00008da000 - 00008dd1c0 BRK = 14 00008da000 - 00008dd1c0 0.000000 #7 0000010000 - 0000011000 PGTABLE = 0000010000 - 0000011000 0.000000 #8
34、0000011000 - 0000018000 BOOTMAP = 0000011000 - 0000018000 0.000000 found SMP MP-table at c00f69b0 f69b0 0.000000 Zone PFN ranges: 0.000000 DMA 0x00000010 - 0x00001000 0.000000 Normal 0x00001000 - 0x000377fe 0.000000 HighMem 0x000377fe - 0x00040000 0.000000 Movable zone start PFN for each node 0.0000
35、00 early_node_map3 active PFN ranges 0.000000 0: 0x00000010 - 0x0000009f 0.000000 0: 0x00000100 - 0x0003fef0 0.000000 0: 0x0003ff00 - 0x00040000 0.000000 On node 0 totalpages: 262015 0.000000 free_area_init_node: node 0, pgdat c0798720, node_mem_map c1001200 0.000000 DMA zone: 32 pages used for memm
36、ap 0.000000 DMA zone: 0 pages reserved 0.000000 DMA zone: 3951 pages, LIFO batch:0 0.000000 Normal zone: 1744 pages used for memmap 0.000000 Normal zone: 221486 pages, LIFO batch:31 0.000000 HighMem zone: 273 pages used for memmap 0.000000 HighMem zone: 34529 pages, LIFO batch:7 0.000000 Using APIC
37、driver default 0.000000 ACPI: PM-Timer IO Port: 0x1008 0.000000 ACPI: Local APIC address 0xfee00000 0.000000 ACPI: LAPIC (acpi_id0x00 lapic_id0x00 enabled) 0.000000 ACPI: LAPIC (acpi_id0x01 lapic_id0x01 enabled) 0.000000 ACPI: LAPIC_NMI (acpi_id0x00 high edge lint0x1) 0.000000 ACPI: LAPIC_NMI (acpi_
38、id0x01 high edge lint0x1) 0.000000 ACPI: IOAPIC (id0x02 address0xfec00000 gsi_base0) 0.000000 IOAPIC0: apic_id 2, version 17, address 0xfec00000, GSI 0-23 15 0.000000 ACPI: INT_SRC_OVR (bus 0 bus_irq 0 global_irq 2 high edge) 0.000000 ACPI: IRQ0 used by override. 0.000000 ACPI: IRQ2 used by override
39、. 0.000000 ACPI: IRQ9 used by override. 0.000000 Using ACPI (MADT) for SMP configuration information 0.000000 SMP: Allowing 2 CPUs, 0 hotplug CPUs 0.000000 nr_irqs_gsi: 24 0.000000 PM: Registered nosave memory: 000000000009f000 - 00000000000a0000 0.000000 PM: Registered nosave memory: 00000000000a00
40、00 - 00000000000ca000 0.000000 PM: Registered nosave memory: 00000000000ca000 - 00000000000cc000 0.000000 PM: Registered nosave memory: 00000000000cc000 - 00000000000dc000 0.000000 PM: Registered nosave memory: 00000000000dc000 - 00000000000e4000 0.000000 PM: Registered nosave memory: 00000000000e40
41、00 - 00000000000e8000 0.000000 PM: Registered nosave memory: 00000000000e8000 - 0000000000100000 0.000000 Allocating PCI resources starting at 40000000 (gap: 40000000:a0000000) 0.000000 Booting paravirtualized kernel on bare hardware 0.000000 NR_CPUS:8 nr_cpumask_bits:8 nr_cpu_ids:2 nr_node_ids:1 0.
42、000000 PERCPU: Embedded 14 pages/cpu c1c00000 s36024 r0 d21320 u2097152 0.000000 pcpu-alloc: s36024 r0 d21320 u2097152 alloc=1*4194304 0.000000 pcpu-alloc: 0 0 1 0.000000 Built 1 zonelists in Zone order, mobility grouping on. Total pages: 259966 0.000000 Kernel command line: BOOT_IMAGE=/boot/vmlinuz
43、-2.6.32-22- generic root=UUID=1f9d6cfe-dee5-448e-a89c-295e30fda028 ro quiet splash 0.000000 PID hash table entries: 4096 (order: 2, 16384 bytes) 16 0.000000 Dentry cache hash table entries: 131072 (order: 7, 524288 bytes) 0.000000 Inode-cache hash table entries: 65536 (order: 6, 262144 bytes) 0.0000
44、00 Enabling fast FPU save and restore. done. 0.000000 Enabling unmasked SIMD FPU exception support. done. 0.000000 Initializing CPU#0 0.000000 allocated 5242560 bytes of page_cgroup 0.000000 please try cgroup_disable=memory option if you dont want memory cgroups 0.000000 Initializing HighMem for nod
45、e 0 (000377fe:00040000) 0.000000 Memory: 1017304k/1048576k available (4673k kernel code, 30096k reserved, 2121k data, 656k init, 139208k highmem) 0.000000 virtual kernel memory layout: 0.000000 fixmap : 0xfff1d000 - 0xfffff000 ( 904 kB) 0.000000 pkmap : 0xff800000 - 0xffc00000 (4096 kB) 0.000000 vma
46、lloc : 0xf7ffe000 - 0xff7fe000 ( 120 MB) 0.000000 lowmem : 0xc0000000 - 0xf77fe000 ( 887 MB) 0.000000 .init : 0xc07a3000 - 0xc0847000 ( 656 kB) 0.000000 .data : 0xc0590663 - 0xc07a2e48 (2121 kB) 0.000000 .text : 0xc0100000 - 0xc0590663 (4673 kB) 0.000000 Checking if this processor honours the WP bit even in supervisor mode.Ok. 0.000000 SLUB: Genslabs=13, HWalign=64, Order=0-3, MinObjects=0, CPUs=2, Nodes=1 0.000000 Hierarchical RCU implementation. 0.000000 NR_IRQS:2304 nr_irqs:424 0.000000 Extended CMOS year: 2000 0.000000 Console: colour VGA+