Chinaunix首页 | 论坛 | 博客
  • 博客访问: 971276
  • 博文数量: 261
  • 博客积分: 10026
  • 博客等级: 上将
  • 技术积分: 3420
  • 用 户 组: 普通用户
  • 注册时间: 2009-02-24 12:10
个人简介

https://smart888.taobao.com/ 立观智能监控

文章分类

全部博文(261)

文章存档

2011年(1)

2010年(4)

2009年(256)

我的朋友

分类: LINUX

2009-03-10 22:53:27

3.1.2 内核引导
在完成了系统引导以后, 程序跳转到Linux 内核入口startup_32 ( 在
arch/i386/kernel/head.S 文件中)。它可以分为以下几个阶段。
(1)内核引导第一部分――核心数据结构初始化
start_kernel()函数中调用了一系列核心数据结构的初始化函数,以完成kernel 本身
的设置。其中包括页表结构初始化、中断初始化、进程调度初始化、定时器初始化、内存初
始化、设备读写缓冲初始化等,这些动作有的是公共的,有的则是需要配置的才会执行的。
执行完核心数据结构的初始化后,就启动init 进程。
在源代码目录的init/main.c 文件中,可以看到start_kernel()函数主体如下(有删
减,可能会根据内核不同而有所不同,详细实现见源文件):
l 输出Linux 版本信息(printk(linux_banner))
l 设置与体系结构相关的环境(setup_arch())
l 页表结构初始化(paging_init())
l 使用"arch/alpha/kernel/entry.S"中的入口点设置系统自陷入口(trap_init())
l 使用alpha_mv 结构和entry.S 入口初始化系统IRQ(init_IRQ())
l 核心进程调度器初始化(包括初始化几个缺省的Bottom-half,sched_init())
l 时间、定时器初始化(包括读取CMOS 时钟、估测主频、初始化定时器中断等,
time_init())
l 提取并分析核心启动参数(从环境变量中读取参数,设置相应标志位等待处理,
(parse_options())
l 控制台初始化(为输出信息而先于PCI 初始化,console_init())
l 剖析器数据结构初始化(prof_buffer 和prof_len 变量)
l 核心Cache 初始化(描述Cache 信息的Cache,kmem_cache_init())
l 延迟校准(获得时钟jiffies 与CPU 主频ticks 的延迟,calibrate_delay())
l 内存初始化(设置内存上下界和页表项初始值,mem_init())
l 创建和设置内部及通用cache("slab_cache",kmem_cache_sizes_init())
l 创建uid taskcount SLAB cache("uid_cache",uidcache_init())
l 创建文件cache("files_cache",filescache_init())
l 创建目录cache("dentry_cache",dcache_init())
l 创建与虚存相关的cache("vm_area_struct","mm_struct",vma_init())
l 块设备读写缓冲区初始化( 同时创建"buffer_head"cache 用户加速访问,
ENET-DL 实用化嵌入式LINUX 计算机开发系统技术手册 第 24 页 共62 页
buffer_init())
l 创建页cache(内存页hash 表初始化,page_cache_init())
l 创建信号队列cache("signal_queue",signals_init())
l 初始化内存inode 表(inode_init())
l 创建内存文件描述符表("filp_cache",file_table_init())
l 检查体系结构漏洞(对于alpha,此函数为空,check_bugs())
l SMP 机器其余CPU(除当前引导CPU)初始化(对于没有配置SMP 的内核,此函数为空,
smp_init())
l 启动init 过程(创建第一个核心线程,调用init()函数,原执行序列调用cpu_idle()
等待调度,init())
至此start_kernel()结束,基本的核心环境已经建立起来了。
(2)内核引导第二部分――外设初始化
init()函数作为核心线程,首先锁定内核(仅对SMP(对称多处理器)机器有效),然
后调用 do_basic_setup()完成外设及其驱动程序的加载和初始化。
外设的初始化主要包括总线初始化、网络初始化、设备初始化(包括并口、字符、块设
备等)、文件系统的初始化,并加载root 文件系统。
过程如下:
l 总线初始化(比如pci_init())
l 网络初始化(初始化网络数据结构,包括sk_init()、skb_init()和proto_init()三部
分,在proto_init()中,将调用protocols 结构中包含的所有协议的初始化过程,
sock_init())
l 创建bdflush 核心线程(bdflush()过程常驻核心空间,由核心唤醒来清理被写过的内
存缓冲区,当bdflush()由kernel_thread()启动后,它将自己命名为kflushd)
l 创建kupdate 核心线程(kupdate()过程常驻核心空间,由核心按时调度执行,将内存
缓冲区中的信息更新到磁盘中,更新的内容包括超级块和inode 表)
l 设置并启动核心调页线程kswapd(为了防止kswapd 启动时将版本信息输出到其他信息
中间,核心线调用kswapd_setup()设置kswapd 运行所要求的环境,然后再创建 kswapd
核心线程)
l 创建事件管理核心线程(start_context_thread()函数启动context_thread()过程,
并重命名为keventd)
l 设备初始化( 包括并口parport_init() 、字符设备chr_dev_init() 、块设备
blk_dev_init()、SCSI 设备scsi_dev_init()、网络设备net_dev_init()、磁盘初始
化及分区检查等等,device_setup())
l 执行文件格式设置(binfmt_setup())
l 启动任何使用__initcall 标识的函数( 方便核心开发者添加启动函数,
do_initcalls())
l 文件系统初始化(filesystem_setup())
l 安装root 文件系统(mount_root())
至此do_basic_setup()函数返回init(),在释放启动内存段(free_initmem())并给
内核解锁以后,init()打开/dev/console 设备,重定向stdin、stdout 和stderr 到控制台,
最后,搜索文件系统中的init 程序(或者由init=命令行参数指定的程序),并使用 execve()
ENET-DL 实用化嵌入式LINUX 计算机开发系统技术手册 第 25 页 共62 页
系统调用加载执行init 程序。
init()函数到此结束,内核的引导部分也到此结束了,这个由start_kernel()创建的
第一个线程已经成为一个用户模式下的进程了。此时系统中存在着六个运行实体:
l start_kernel()本身所在的执行体,这其实是一个"手工"创建的线程,它在创建了
init()线程以后就进入cpu_idle()循环了,它不会在进程(线程)列表中出现
l init 线程,由start_kernel()创建,当前处于用户态,加载了init 程序
l kflushd 核心线程,由init 线程创建,在核心态运行bdflush()函数
l kupdate 核心线程,由init 线程创建,在核心态运行kupdate()函数
l kswapd 核心线程,由init 线程创建,在核心态运行kswapd()函数
l keventd 核心线程,由init 线程创建,在核心态运行context_thread()函数
对于2.4.x 版内核
这一部分的启动过程在2.4.x 内核中简化了不少,缺省的独立初始化过程只剩下网络
(sock_init())和创建事件管理核心线程,而其他所需要的初始化都使用__initcall()宏
包含在do_initcalls()函数中启动执行。
(3)init 进程和inittab 引导指令
init 进程是系统所有进程的起点,内核在完成内核引导以后,即在本线程(进程)空
间内加载init 程序,它的进程号是1。init 程序读取/etc/inittab 文件作为其行为指针,
根据initab 描述文件的内容建立相应的进程。initab 文件中描述了系统默认的运行级别,
运行rc 启动脚本,进行用户的登录合X Window 登录等工作。Initab 文件的主体部分如下:
# 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:
# System initialization.
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc 0
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
ENET-DL 实用化嵌入式LINUX 计算机开发系统技术手册 第 26 页 共62 页
# 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
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6
# Run xdm in runlevel 5
x:5:respawn:/etc/X11/prefdm –nodaemon
具体的内容在大多数的Linux书籍中有详细的介绍;开发人员也可以使用man initab命
令查看在线帮助手册,下面只作简单介绍:
inittab是以行为单位的描述性(非执行性)文本,每一个指令行都具有以下格式:
id:runlevel:action:process
其中id 为入口标识符,runlevel 为运行级别,action 为动作代号,process 为具体的
执行程序。id 一般要求4 个字符以内,对于getty 或其他login 程序项,要求id 与tty 的
编号相同,否则getty 程序将不能正常工作。runlevel 是init 所处于的运行级别的标识,
一般使用0-6 以及S 或s。0、1、6 运行级别被系统保留,0 作为shutdown 动作,1 作为重
启至单用户模式,6 为重启;S 和s 意义相同,表示单用户模式,且无需inittab 文件,因
此也不在inittab 中出现,实际上,进入单用户模式时,init 直接在控制台(/dev/console)
上运行/sbin/sulogin。在一般的系统实现中,都使用了2、3、4、5 几个级别,在Redhat
系统中,2 表示无NFS 支持的多用户模式,3 表示完全多用户模式(也是最常用的级别),4
保留给用户自定义,5 表示XDM 图形登录方式。7-9 级别也是可以使用的,传统的Unix 系
统没有定义这几个级别。runlevel 可以是并列的多个值,以匹配多个运行级别,对大多数
action 来说,仅当runlevel 与当前运行级别匹配成功才会执行。
initdefault 是一个特殊的action 值,用于标识缺省的启动级别;当init 由核心激活
以后,它将读取inittab 中的initdefault 项,取得其中的runlevel,并作为当前的运行
级别。如果没有inittab 文件,或者其中没有initdefault 项,init 将在控制台上请求输
入 runlevel。
ENET-DL 实用化嵌入式LINUX 计算机开发系统技术手册 第 27 页 共62 页
sysinit、boot、bootwait 等action 将在系统启动时无条件运行,而忽略其中的
runlevel,其余的action(不含initdefault)都与某个runlevel 相关。各个action 的定
义在inittab 的man 手册中有详细的描述。
下面是对一个initab 文件的简单说明:
id:3:initdefault:
#表示当前缺省运行级别为3--完全多任务模式;
si::sysinit:/etc/rc.d/rc.sysinit
#启动时自动执行/etc/rc.d/rc.sysinit 脚本
l3:3:wait:/etc/rc.d/rc 3
#当运行级别为3 时,以3 为参数运行/etc/rc.d/rc 脚本,init 将等待其返回
0:12345:respawn:/sbin/mingetty tty0
#在1-5 各个级别上以tty0 为参数执行/sbin/mingetty 程序,打开tty0 终端用于
#用户登录,如果进程退出则再次运行mingetty 程序
x:5:respawn:/usr/bin/X11/xdm -nodaemon
#在5 级别上运行xdm 程序,提供xdm 图形方式登录界面,并在退出时重新执行。
至此,Linux 已经完成了系统引导过程和内核引导两个过程,之后Linux 开始运行。

阅读(344) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~