linux内核启动总结,《Linux0.11内核完全注释》读书笔记之内核启动方式总结

Linux0.11启动方式

BIOS启动

当PC电源打开后,80X86结构的CPU将自动进入实模式,并从0xFFFF0开始自动执行程序,

这通常是ROM-BIOS中的地址。PC机的BIOS将执行某些系统检测,并在物理地址0处开始初

始化中断向量。此后将可启动设备的第一个扇区读入内存绝对地址0x7C00处,并跳转到这

个地方。

bootsect.s/setup.s

bootsect.s

Linux最前面的部分是boot/bootsect.s,它将由BIOS读入到内存绝对地址0x7C00处,

当它被执行时就会把自己移动到内存绝对地址0x90000(576KB)处,并把启动设备后

2KB字节代码boot/setup.s读入到内存0x90200处,而内核其他部分(system模块)

则被读入到内存地址0x10000(64KB)开始处,因此从机器家电开始的执行顺序如下图。

A152750797-117798.png_small.png

setup.s

在系统加载期间将显示信息“Loading…”。然后控制权将传递给boot/setup.s,这是

另一个实模式汇编语言程序。

A152753032-117798.png_small.png

启动部分识别主机的某些特性,如果需要会要求用书为控制台选择显示模式。然后将整

个系统从地址0x10000移至0x0000处,读取并为system模块保留系统参数,之后进入

保护模式并跳转至系统余下部分(0x0000处)。

system模块加载

head.s

head.s位于system模块头部。从这里开始,内核完全是在保护模式下运行。这个程序功

能比较单一。首先是加载各个数据段寄存器,重设中断描述符表idt,使各表项执行一个

只报错误的哑中断子程序ignore_int。然后重设gdt,检测A20地址线是否已真的开启,

如果没开启进入死循环。检测数学协处理器。

设置分页处理机制,将页目录表放在绝对物理地址0开始处(本程序会被覆盖)。最后,

head.s利用返回指令将预先放在堆栈中的/init/main.c程序的入口地址弹出,去运行

main()程序。

main.c

main.c程序首先利用前面setup.s程序取得的系统参数设置系统的根文件设备号以及一

些内存全局变量。

A152755282-117798.png_small.png

初始化基本环境

内核先进行所有方面的硬件初始化。包括陷阱门、块设备、字符设备和tty,包括人工设置

第一个任务(task 0)。待所有初始化完成后设置中断允许标志开启中断,并“手动”切换

到任务0中运行。

A152757454-117798.png_small.png

task 0启动(idle进程)

直接fork()创建task 1,由于是内核创建的进程无法使用copy-on-write,又和内核

和之后新建的task 1共用堆栈,因此不能使用堆栈破坏其他程序运行,所以使用了内

联函数fork()和pause()。创建完task 1后就开始pause()死循环。

task 1启动(init进程)

注意: init进程由用户态进程idle进程创建,因此可以使用copy-on-write,

所以能使用堆栈

在main()中已经进行了系统初始化,包括内存管理、各种硬件设备和驱动程序。init()

函数运行在任务0第一次创建的子进程(任务1)中。它首先对第一个将要执行的程序

(shell)的环境进行初始化,然后以非交互式shell方式加载该程序并执行之(见下方

task 2启动),并等待task 2结束。

init进程在task 2结束后再次创建新的shell进程,这次是作为登录shell运行/bin/sh

的。之后一直等待创建的子进程结束返回,对于所创建的子进程将关闭所有以前还遗留的

句柄(stdin, stdout, stderr),新创建一个会话并设置进程组号,然后重新打开

/dev/tty0作为stdin,并复制成stdout和stderr。再次执行/bin/sh。

wait()的另一个功能是处理孤儿进程。如果一个进程的父进程先终止了,那么这个进程

的父进程就会被设置为这里的init进程,并由init进程负责释放一个已经终止进程的任

务数据结构等资源。

task 2启动(/bin/sh)

首次创建

由init进程创建,关闭文件描述符0(stdin),以只读方式打开/etc/rc文件,并使用execve()

函数将自身替换成/bin/sh程序,然后执行/bin/sh。由于这里sh的运行方式是非交互式的,因此

执行完rc文件中的命令后就会立即退出,进程2也随之结束。

非首次创建

以登录shell运行,交互式shell。

较新的启动方式

在前面的程序上,init()函数直接开始执行了命令解释程序(shell程序)/bin/sh,而

在实际可用的系统中却并非如此。为了能具有登录系统的功能和多人同时使用系统的能力,

通常的系统是在这里或类似地方执行系统初始化程序init.c,而此程序会根据系统/etc/

目录中配置文件的设置信息,对系统中支持的每个终端设备创建子进程,并在子进程中运

行终端初始化设置程序agettty(统称getty),gettty程序则会在终端上显示用户的登

录提示信息“login:”。当用户键入了用户名后,getty被替换成login程序。login程序验

证了用户输入口令的正确性后,最终调用shell程序,并进入shell交互工作界面。

A152759688-117798.png_small.png

init进程的主要任务是根据/etc/rc文件中设置的信息,执行其中设置的命令,然后根据

/etc/inittab文件中的信息,为每一个允许登录的终端设备使用fork()创建一个子进程,

并在每个新创建的子进程中运行getty。而init进程则调用wait(),进入等待子进程结束

状态。

每当一个子进程结束退出,就会根据返回的pid知道哪个对应终端的子进程结束了,因此

就会为相应终端设备再创建一个新的子进程。每个允许的终端设备都是中有一个对应的进

程为其等待处理。

当系统关闭时,init负责杀死所有其他进程,卸载所有的文件系统以及停止处理器的工

作,以及它配置成要做的工作。

getty程序

gettty程序主要任务是设置终端类型、属性、速度和线路规程。它打开并初始化一个tty

端口,显示提示信息,并等待用户键入用户名。该程序只能由超级用户执行。通常,若

/etc/issue文本文件存在,则getty会首先显示其中的文本信息,然后显示登录提示信

息,读取用户输入的登录名,并执行login程序。

login程序

login程序主要用于要求登录用户输入密码。根据用交输入的用户名,它从口令文件passwd

中取得对应用户的登录项,然后调用getpass()以显示“password:”提示信息,读取用户

键入的密码,然后使用加密算法对键入的密码进行加密处理,并与口令文件中该用户项中

pw_passwd字段作比较。如果登录失败,login程序会退出执行并被父进程init的wait()

接收,init会根据记录下来的信息再次创建一个子进程,并在进程中针对该终端设备再次

执行getty。

如果用户键入的密码正确,则login会把当前工作目录修改成口令文件中指定的用户起始

目录。并把对应终端的访问权限修改成用户读/写和组写,设置进程的组ID。然后利用所得

的信息初始化环境变量信息,如(HOME=)。接着显示/etc/motd(message-of-the-day)

文件中的文本信息,并检查并显示该用户是否有邮件的信息。最后login程序改变成登录

用户的用户ID并执行用户口令文件中该用户项指定的shell程序,如bash后csh等。如果

没有指定shell,则会使用默认/bin/sh。

shell程序

在登录过程中login开始执行shell时,所带参数argv[0]的第一个字符是‘-’,表示该

shell作为一个登录shell被执行。此时shell程序会根据该字符,执行某些与登录过程

相应的操作。登录shell首先从/etc/profile文件以及.profile文件(若存在)读取

命令并执行。如果在进入shell时设置了ENV环境变量或者在.profile中设置了该变量,

则shell下一步会从该变量命名的文件中读取命令并执行。因此用户应该把每次登录是

都要执行的命令放在.profile文件中,而把每次运行shell都要执行的命令放在ENV变

量指定的文件中。

如放在.profile中:

ENV=$HOME/.anyfilename;

export ENV

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值