Chinaunix首页 | 论坛 | 博客
  • 博客访问: 235698
  • 博文数量: 59
  • 博客积分: 4010
  • 博客等级: 上校
  • 技术积分: 900
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-30 20:21
文章分类

全部博文(59)

文章存档

2011年(1)

2009年(58)

我的朋友

分类: LINUX

2009-04-01 17:11:35

以下内容摘自:

Linux 开机程序之研讨 
CCCA 资工86 许景华 


各位是否曾经对电脑整个开机的流程感到好奇呢 这一次 我们所要讨论的 
主题 就是 Linux 从开机的一瞬间到 login 为止 到底发生了什么事情 


想必各位都知道 在刚开机时 由于 80x86 的特性 CS Code Segment 
这个寄存器中全部都放着 而 IP Instruction Pointer 这个寄存器 
中全部都放着 换句话说 CS=FFFF 而 IP=0000 此时 CPU 就依据 
CS 及 IP 的值 到 FFFF0H 去执行那个地方所放的指令 这时候 由于 
FFFF0H 已经到了高位址的顶端 所以 FFFF0H 这个地方 总是会放一个 
JMP 指令 跳到比较低的位址 接著 ROM BIOS 就会作一些检查的动作 
像内存 键盘 等...... 并在我们俗称的 UMB Upper Memory Block 
之中扫描 看看是否有合法的 ROM 存在 比如 SCSI 卡上的 ROM 
假如有 就到里面去执行一些东西 执行完之后再继续刚才的行程 到了 
最后 读取硬盘上的第一个 sector 在这里 我假设各位由硬盘启动 
因此 就硬盘的构造而言 它的第一个 sector 称为 MBR Master Boot 
Record 因为一个 sector 是 512 bytes 而 MBR 这 512 bytes 可分 
为两个部份 第一个部份为 Pre-Boot 区 占了 446 bytes 第二部份 
是 Partition Table 占了 66 bytes Pre-Boot 区的作用之一 就是 
去看看那个 Partition 被标成 Active 然後去读那个 Partition 的 Boot 
区 


在 Linux 的启动方面 一般人最常把 LILO 放在 MBR 或 Superblock 
假如你把 LILO 放在 MBR 那很明显的 当读取到 MBR 的时候 LILO 
就被执行 此时 你的屏幕上会出现 boot: 接着 就进行 Load Kernel 
的动作 在另一方面来说 假如你把 LILO 安装在 Superblock 通常你 
还会有一个管理开机的程序 也许是放在 MBR 像 OSBS 或者是放在一 
个单独的 Partition 像 OS/2 的 Boot Manager 再由这个管理开机 
的程式去读取 LILO 进而做 Load Kernel 的动作 


好了 到了目前为止 我们已经讲到 Load Kernel 的动作 Kernel 被 
load 到 memory 中之后 接着进行一连串 probe 周边的动作 像串口 
并口 软盘 声卡 硬盘 光驱 等 ...... 接着 mount root 
partition 在这之后 kernel 会起动 init 这个 process init 这 
个 process 的 PID 为 它是所有 process 的祖先 


接下来呢 系统就开始执行 /rc.d/rc.S 在这里 我们暂时打住 
先对大概的 initialization script 执行的顺序作一个浏览 请看下面 
的流程 


init[1] 
rc.S begin <--- 目前我们已经讲到这里 
rc.serial begin 
rc.serial end 
rc.S end 
init[1] enter runlevel 
rc.M begin 
rc.inet1 begin 
rc.inet1 end 
rc.inet2 begin 
rc.inet2 end 
rc.font begin 
rc.font end 
rc.local begin 
rc.local end 
rc.M end 
login 


上面的流程清楚的指出 在 rc.S 这个 shell script 中 会去执行 rc.serial 
接着再执行 rc.M rc.M 中又包含了 rc.inet1 rc.inet2 rc.font rc.local 
最后执行 login 在下面的内容中 将为各位介绍这几个 shell script 
从下面开始 凡是每一列之前有一个 的 为原来 shell script 中的注释 
有两个 的 为笔者加上的注释 当然啦 没有任何 的为 shell script 
的内容 而对命令或内容的解释 一律都写在命令或内容的前面 
首先由 rc.S 开始 


***************************** rc.S ********************************** 


#!/bin/sh 

/etc/rc 

These commands are executed at boot time by init(8). 
User customization should go in /etc/rc.local. 


echo '======== rc.S is running System Initializing Now !!! ========' 
PATH=/sbin:/usr/sbin:/bin:/usr/bin 


## 打开所有 swap 下面 /sbin/swapon -a 的意思是 使得 /etc/fstab 中被记录 
## 成 swap 的 device 全部启动 


/sbin/swapon -a 



## 喔 下面这个指令 update 就很重要了 它负责每隔一段固定的时间 就将 
## buffer 中的资料 利用 sync 写回磁盘上 并将 superblock 做 update 
## 的动作 使用 ps 这个指令看看有那些 process 就可看到 update 还有一个 
## bdflush 这两个 process 都是必然要存在的 可不要随便砍掉 要不然 
## 万一系统 crash 了 那磁盘里面的资料就不是最新的了 ...... 


/sbin/update 



## 利用 echo -n >;>; 制造一个文件 并用 rm -f 这个档案来测试 root partition 
## 是不是 read-only 或者是可读写 


READWRITE=no 
if echo -n >;>; "Testing filesystem status"; then 
rm -f "Testing filesystem status" 
READWRITE=yes 
fi 



## 假如 root partition 是 read-only 就作 fsck 的动作 假如不是 read-only 
## 而是 read-write 的话 就做下面 else 之后的动作 


if $READWRITE yes ]; then 
## 利用 fsck 做检查及修复文件系统的工作 后面接的两个参数 -A -a 
## -A 的意思是 fsck 会依据 /etc/fstab 中的记录 去检查所有的文件 
## 系统 而 -a 就是 auto 的意思 当 fsck 有修复的动作时 它不会问 
## 你问题 而直接修复 


/sbin/fsck -A -a 



## 假如 fsck 有 error $? -gt 括号里面的意思是 若上个命令的 
## 传回值大于 而上个命令就是 fsck 让我们看看 fsck 的传回值 
## No errors 
## File system errors corrected 
## File system errors corrected, system should 
## be rebooted if file system was mounted 
## File system errors left uncorrected 
## Operational error 
## 16 Usage or syntax error 
## 128 Shared library error 
## 很明显的 若有任何错误产生的话 那 fsck 的传回值都大于 其实 
## 就我的观点认为 应该写成 if $? -ge 比较好 既然有错呢 系统 
## 应该就要跳至单用户模式 在单用户模式中主要就是 /etc/rc.d/rc.K 
## 中的两件事 关掉 swap 及 卸下所有的文件系统 而最后重新 login 
## 一般正常的情况下 if 下面这一大段是不会执行的 而会跳至下面 
## 标有 ************************* Normal ************************* 处 


if $? -gt then 
echo 
echo 
echo "**************************************" 
echo "fsck returned error code REBOOT NOW!" 
echo "**************************************" 
echo 
echo 
/bin/login 
fi 


## ****************************** Normal ************************** 
## 当 fsck 检查没有错误之后 就把 root partition 重新 mount 上来 
## 下面指令的参数有三个 -w 代表mount 成可读写 -n 代表把一个 file- 
## system mount 上来 但不会把记录写到 /etc/mtab 中 在上次对 /etc/mtab 
## 介绍时有提到 当我们使用 mount 这个指令把一个 filesystem mount 上来 
## 的时候 /etc/mtab 就会记录 利用 -n 这个 option 可使得做 mount 的动 
## 作 却不会记录 -o 后面可以接许多的选项 在这里 我们给它的选项是 
## remount remount 的意思是 重新 mount 一个已经被 mount 的 filesystem 
## 这个选项通常被用来改变该 filesystem 的读写标志 ,尤其是把 filesystem 
## 从 read-only 的状态 改变成 read-write 的状态 


echo "Remounting root device with read-write enabled." 
/sbin/mount -w -n -o remount 



## 在前面的情况中 都是 root partition 为 read-only 的状态下 所做的一些 
## 工作 到了最后一个指令 /sbin/mount -w -n -o remount 才把 root 
## partition mount 成 read-write 各位有没有看到前面那行 
## if $READWRITE yes ]; then ..... 下面这个 else 就是与这个 if 对应 
## 也就是说 前面那个 if 的区块中 所作的工作都是在 root partition 为 
## read-only 的条件成立下所作的事 那很明显的 下面这个 else 就是 root 
## partition 为 read-write 的条件下所作的工作 假如你的 root partition 
## 为 read-writeable 的话 那么系统就会显示下面的信息 cat << EOF 所作的 
## 事 就是把 EOF 之前的信息全部显示在屏幕上 
## 我想 下面的信息写得很明显了 它说 你的 root partition 被 mount 成 
## read-write 没有办法检查 要使检查的动作能够顺利的进行 你必须把 
## root partition mount 成 read-only 那要怎么做呢 很容易 只要利用 
## rdev -R 就可以了 ...... 


else 
cat << EOF 


*** Root partition has already been mounted read-write. Cannot check! 
For filesystem checking to work properly, your system must initially mount 
the root partition as read only. Please modify your kernel with 'rdev' so 
that 
it does this. If you're booting with LILO, type: 
rdev -R /vmlinuz 
(^^^^^^^^ ... or whatever your kernel name is.) 


If you boot from kernel on floppy disk, put it in the drive and type: 
rdev -R /dev/fd0 


This will fix the problem *AND* eliminate this annoying message. :^) 


EOF 



## 下面这个指令没什么好说的 就是暂停 10 秒钟 让 user 能够有充足的 
## 时间看完上面的信息 


sleep 10 
fi 



## 删除 /etc/mtab /etc/nologin /etc/utmp 


/bin/rm -f /etc/mtab* /etc/nologin /etc/utmp 



## 制造 /etc/utmp 这是一个很典型制造空文件的写法 /dev/null 这个 node 
## 蛮有趣的 在某一方面来说 它有点像是一个 黑洞 怎么说呢 
## 各位可以试试看下面的指令 ls >;>; /dev/null 当你使用这个指令之后会 
## 发生什么事呢 什么也没发生 而且 ls 的输出就好像被丢到黑洞里 无 
## 影无踪了 那也许你会想 那这有什么用 我的回答是 的确没有什么 
## 很大的用处 但当你想抑制输出的信息时 你就会用得到了 


cat /dev/null >;>; /etc/utmp 



## 依据 fstab filesystem table 中的描述 自动的挂上文件系统 
## 但此时因为 TCP/IP 还没有设定 故不用 NFS 


echo 'Mount Filesystem !!!' 
/sbin/mount -avt nonfs 



## 设定系统的时钟 下面这几行所做的事就是 看看 /sbin/clock 这个文件是 
## 不是可执行的 假如可以执行 就把 CMOS 中的时间设定为系统的时间 


if -x /sbin/clock ]; then 
echo 'Set System Clock' 
/sbin/clock -s 
fi 



## 下面的四行若没有 mark 则每次开机 issue 及 motd 都会被改变 这应该 
## 可算是 FAQ 级的问题了 ...... 因为我有自己设计的 issue 及 motd 所以 
## 下面的四行前面都有 被注释掉 
## 假如你要有自己的设定 下面一定都要 mark 起来 


#echo >; /etc/issue 
#echo Welcome to Linux /bin/uname -a /bin/cut -d\ -f3. >;>; /etc/issue 
#echo >;>; /etc/issue 
#echo "/bin/uname -a /bin/cut -d\ -f1,3. (Posix)." >; /etc/motd 



## 接下来 将执行 rc.serial 顾名思义 rc.serial 是作串口设定的工作 
## 在 rc.serial 中 内容虽然也是很简单 但并不像 rc.S 那样直接 换句话 
## 说 读者至少要 稍微 懂一点 shell programming 所以说呢 假如 
## 还不会 shell programming 的读者呢 都应该赶快去找一本书来看一下 在 
## 这篇文章的结尾 我会提出一些书单 各位可以去找找这几本书 ...... 


/bin/sh /etc/rc.d/rc.serial 
echo '================= rc.S is finish NOW !!! =========================' 




到了这里 rc.S 的最後一步 是去执行 rc.serial 大家可以看一看 
/rc.d/rc.serial 好像很长的样子 但实际上呢 各位必然发现到了 这个 
shell script 大部份指令的前面都有一个 '#' 号 这代表着 这些指令完全 
不会被执行 所以呢 真正有用的只不过寥寥十几行吧 在另一方面来说 
假如你是用网卡连上网络 那 rc.serial 对你并没有什么大用处 



**************************** rc.serial ****************************** 


#!/bin/sh 

/etc/rc.serial 
Initializes the serial ports on your system 

Version 2.01 


echo '======================= rc.serial is begin !!! =====================' 
cd /dev 


## 下面三行中的前两行是设定一些变量 由于在这个 shell script 中 需要 
## 用到 /bin/setserial -b 这个指令 或是需要用到所有以 cua 开头的 node 
## 的次数太多了 因此 把它们设定为一个变量 是一个不错的方法 尤其 
## PORTS=`echo cua? cua??` 这是一个聪明的写法 那为什么不写成 PORT= 
## `echo cua*` 呢 各位可以在 /dev 下分别使用这两个指令 观察输出到底 
## 有什么不同 ...... 


SETSERIAL="/bin/setserial -b" 
PORTS=`echo cua? cua??` 
echo -n "Configuring serial ports...." 



## 下面这行 没有学过 shell programming 的人很可能会看不懂 不过没有 
## 关系 这行中的 ${SETSERIAL} 会被换成 /bin/setserial -b 而 ${PORTS} 
## 会被换成 cua0 cua1 cua2 ....... cua31 所以整句翻译就是 
## /bin/setserial -b -W cua0 cua1 cua2 cua3 cua4 cua5 cua6 ...... cua31 
## 那这行指令到底在做什么呢 其实只是在做中断侦测的工作 


${SETSERIAL} -W ${PORTS} 



## 各位看到下面原来的注释了吧 当你有一些特殊的卡时 你可以把相对应部 
## 份前面的 '#' 去掉 以便能做自动设定的工作 其实呢 这种情况实在 
## 不多 大部份人的设备都差不了多少 说到关于串口 差异就更少了 

AUTOMATIC CONFIGURATION 

Uncomment the appropriate lines below to enable auto-configuration 
of particular board. Or comment them out to disable them.... 




## 好了 这下我们又多了一个变量 AUTO_IRQ 这在下面会用到 


AUTO_IRQ=auto_irq 



## 下面几行非常整齐 它们可以分别被换成 
## /bin/setserial -b /dev/cua? auto_irq skip_test autoconfig 
## setserial 说穿了也没什么 这个指令可以让你对 serial port 做设定及回报 
## 的动作 像 IRQ I/O port 啦等等的事情 一般的情况下 大家的电脑中 
## 通常只有 COM1-COM4 但假如你想增加新的 port 那 setserial 就派上用 
## 场了 


These are the standard COM1 through COM4 devices 

If you have an internal modeme with Rockwell Chipset, add "skip_test" 
to the /dev/cua3 line below. (It's not added by default because it will 
screw up people with 8514 displays). 

${SETSERIAL} /dev/cua0 ${AUTO_IRQ} skip_test autoconfig 
${SETSERIAL} /dev/cua1 ${AUTO_IRQ} skip_test autoconfig 
${SETSERIAL} /dev/cua2 ${AUTO_IRQ} skip_test autoconfig 
${SETSERIAL} /dev/cua3 ${AUTO_IRQ} autoconfig 


These are for the first AST Fourport board (base address 0x1A0) 

${SETSERIAL} /dev/cua4 ${AUTO_IRQ} autoconfig 
${SETSERIAL} /dev/cua5 ${AUTO_IRQ} autoconfig 
${SETSERIAL} /dev/cua6 ${AUTO_IRQ} autoconfig 
${SETSERIAL} /dev/cua7 ${AUTO_IRQ} autoconfig 


These are for the second AST Fourport board (base address 0x2A0) 

${SETSERIAL} /dev/cua8 ${AUTO_IRQ} autoconfig 
${SETSERIAL} /dev/cua9 ${AUTO_IRQ} autoconfig 
${SETSERIAL} /dev/cua10 ${AUTO_IRQ} autoconfig 
${SETSERIAL} /dev/cua11 ${AUTO_IRQ} autoconfig 



## 从这里以下 我省略了一大段 因为这一大段都是支持特殊的卡 


These are the 3rd and 4th ports on the Accent Async board. 

#${SETSERIAL} /dev/cua12 ${AUTO_IRQ} autoconfig 
#${SETSERIAL} /dev/cua13 ${AUTO_IRQ} autoconfig 














## 好了 我们跳掉了一大段 直到这里 各位看到下面的注解了 
## 假如你想用手动的方法指定 IRQ I/O port 及指定 chip 的型号 
## 那你可以拿掉下面对应那行前面的 '#' 并作适当的修改 比如说 
## 你用的是比较新的 16550 或 16550A 而不是 16450 那你就可以 
## 在下面用手动的方法指定 实际上 用 autoconfig 及 autoirq 
## 的选项就可以了 没有必要用手动的方式 除非侦测不到 


############################################################### 

MANUAL CONFIGURATION 

If you want to do manual configuration of one or more of your 
serial ports, uncomment and modify the relevant lines. 

############################################################### 


These are the standard COM1 through COM4 devices 

#${SETSERIAL} /dev/cua0 uart 16450 port 0x3F8 irq 
#${SETSERIAL} /dev/cua1 uart 16450 port 0x2F8 irq 
#${SETSERIAL} /dev/cua2 uart 16450 port 0x3E8 irq 
#${SETSERIAL} /dev/cua3 uart 16450 port 0x2E8 irq 












## Ok 到此 rc.S 及 rc.serial 已经结束 因为截稿时间的关系 rc.M 
## rc.inet1 rc.inet2 rc.font rc.local 将在以后为各位介绍 


echo "done." 
${SETSERIAL} -bg ${PORTS} 


echo ====================== rc.serial is complete !!! ===================' 




关于 Shell Programming 的书单 


Title: The Unix Shell Field Guide 
Authors: Gail Anderson and Paul Anderson 
Publisher: Prentice Hall 
Edition: 1986 
ISBN: 0-13-937468-X 


这本是 C-Shell 的 Bible 想学 C-Shell 的人 可以去看这本书 



Title: Unix Shell Programming 
Authors: Stephen Kochan and Patrick Wood 
Publisher: Hayden 
Edition: 1990 
ISBN: 0-672-48448-X 


喔 这本书以 Bourne Shell 为主 内容深入浅出 读者很容易就可以了解 
这本书的内容 进而掌握 Bourne Shell 的精髓 此外 这本书也有提到 
Korn Shell 大体上来说 是一本值得看的好书 



*如何联系作者 


E-Mail Address jhhsu@csie.nctu.edu.tw 
u8217017@cc.nctu.edu.tw 


Dormitory 交通大学十舍 317R 


.. 



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