导航:首页 > 操作系统 > linux启动原理

linux启动原理

发布时间:2023-06-12 07:56:01

linux进程管理及作业控制的启动进程

键入需要运行的程序的程序名,执行一个程序,其实也就是启动了一个进程。在Linux系统中每个进程都具有一个进程号,用于系统识别和调度进程。启动一个进程有两个主要途径:手工启动和调度启动,后者是事先进行设置,根据用户要求自行启动。 由用户输入命令,直接启动一个进程便是手工启动进程。但手工启动进程又可以分为很多种,根据启动的进程类型不同、性质不同,实际结果也不一样,下面分别介绍。
1. 前台启动
这或许是手工启动一个进程的最常用的方式。一般地,用户键入一个命令“ls –l”,这就已经启动了一个进程,而且是一个前台的进程。这时候系统其实已经处于一个多进程状态。或许有些用户会疑惑:我只启动了一个进程而已。但实际上有许多运行在后台的、系统启动时就已经自动启动的进程正在悄悄运行着。还有的用户在键入“ls –l”命令以后赶紧使用“ps –x”查看,却没有看到ls进程,也觉得很奇怪。其实这是因为ls这个进程结束太快,使用ps查看时该进程已经执行结束了。如果启动一个比较耗时的进程:
find / -name fox.jpg
然后再把该进程挂起,使用ps查看,就会看到一个find进程在里面。
2. 后台启动
直接从后台手工启动一个进程用得比较少一些,除非是该进程甚为耗时,且用户也不急着需要结果的时候。假设用户要启动一个需要长时间运行的格式化文本文件的进程。为了不使整个shell在格式化过程中都处于“瘫痪”状态,从后台启动这个进程是明智的选择。
[例1]
$ troff –me notes > note_form &
[1] 4513
$
由上例可见,从后台启动进程其实就是在命令结尾加上一个&号。键入命令以后,出现一个数字,这个数字就是该进程的编号,也称为PID,然后就出现了提示符。用户可以继续其他工作。
上面介绍了前、后台启动的两种情况。实际上这两种启动方式有个共同的特点,就是新进程都是由当前shell这个进程产生的。也就是说,是shell创建了新进程,于是就称这种关系为进程间的父子关系。这里shell是父进程,而新进程是子进程。一个父进程可以有多个子进程,一般地,子进程结束后才能继续父进程;当然如果是从后台启动,那就不用等待子进程结束了。
一种比较特殊的情况是在使用管道符的时候。例如:
nroff -man ps.1|grep kill|more
这时候实际上是同时启动了三个进程。请注意是同时启动的,所有放在管道两边的进程都将被同时启动,它们都是当前shell的子程序,互相之间可以称为兄弟进程。
以上介绍的是手工启动进程的一些内容,作为一名系统管理员,很多时候都需要把事情安排好以后让其自动运行。因为管理员不是机器,也有离开的时候,所以有些必须要做的工作而恰好管理员不能亲自操作,这时候就需要使用调度启动进程了。 有时候需要对系统进行一些比较费时而且占用资源的维护工作,这些工作适合在深夜进行,这时候用户就可以事先进行调度安排,指定任务运行的时间或者场合,到时候系统会自动完成这一切工作。
要使用自动启动进程的功能,就需要掌握以下几个启动命令。
at命令
用户使用at命令在指定时刻执行指定的命令序列。也就是说,该命令至少需要指定一个命令、一个执行时间才可以正常运行。at命令可以只指定时间,也可以时间和日期一起指定。需要注意的是,指定时间有个系统判别问题。比如说:用户现在指定了一个执行时间:凌晨3:20,而发出at命令的时间是头天晚上的20:00,那么究竟是在哪一天执行该命令呢?如果用户在3:20以前仍然在工作,那么该命令将在这个时候完成;如果用户3:20以前就退出了工作状态,那么该命令将在第二天凌晨才得到执行。下面是at命令的语法格式:
at [-V] [-q 队列] [-f 文件名] [-mldbv] 时间
at -c 作业 [作业...]
at允许使用一套相当复杂的指定时间的方法,实际上是将POSIX.2标准扩展了。它可以接受在当天的hh:mm(小时:分钟)式的时间指定。如果该时间已经过去,那么就放在第二天执行。当然也可以使用midnight(深夜),noon(中午),teatime(饮茶时间,一般是下午4点)等比较模糊的词语来指定时间。用户还可以采用12小时计时制,即在时间后面加上AM(上午)或者PM(下午)来说明是上午还是下午。
也可以指定命令执行的具体日期,指定格式为month day(月 日)或者mm/dd/yy(月/日/年)或者dd.mm.yy(日.月.年)。指定的日期必须跟在指定时间的后面。
上面介绍的都是绝对计时法,其实还可以使用相对计时法,这对于安排不久就要执行的命令是很有好处的。指定格式为:now + count time-units ,now就是当前时间,time-units是时间单位,这里可以是 minutes(分钟)、hours(小时)、days(天)、weeks(星期)。count是时间的数量,究竟是几天,还是几小时,等等。
还有一种计时方法就是直接使用today(今天)、tomorrow(明天)来指定完成命令的时间。下面通过一些例子来说明具体用法。
[例2] 指定在今天下午5:30执行某命令。假设现在时间是中午12:30,1999年2月24日,其命令格式如下:
at 5:30pm
at 17:30
at 17:30 today
at now + 5 hours
at now + 300 minutes
at 17:30 24.2.99
at 17:30 2/24/99
at 17:30 Feb 24
以上这些命令表达的意义是完全一样的,所以在安排时间的时候完全可以根据个人喜好和具体情况自由选择。一般采用绝对时间的24小时计时法可以避免由于用户自己的疏忽造成计时错误的情况发生,例如上例可以写成:
at 17:30 2/24/99
这样非常清楚,而且别人也看得懂。
对于at命令来说,需要定时执行的命令是从标准输入或者使用-f选项指定的文件中读取并执行的。如果at命令是从一个使用su命令切换到用户shell中执行的,那么当前用户被认为是执行用户,所有的错误和输出结果都会送给这个用户。但是如果有邮件送出的话,收到邮件的将是原来的用户,也就是登录时shell的所有者。
[例3]
$ at -f work 4pm + 3 days
在三天后下午4点执行文件work中的作业。
$ at -f work 10am Jul 31
在7月31日上午10点执行文件work中的作业。
在任何情况下,超级用户都可以使用这个命令。对于其他用户来说,是否可以使用就取决于两个文件:/etc/at.allow和/etc/at.deny。如果/etc/at.allow文件存在的话,那么只有在其中列出的用户才可以使用at命令;如果该文件不存在,那么将检查/etc/at.deny文件是否存在,在这个文件中列出的用户均不能使用该命令。如果两个文件都不存在,那么只有超级用户可以使用该命令;空的/etc/at.deny文件意味着所有的用户都可以使用该命令,这也是默认状态。
下面对命令中的参数进行说明。
-V 将标准版本号打印到标准错误中。
-q queue 使用指定的队列。队列名称是由单个字母组成,合法的队列名可以由a-z或者A-Z。a队列是at命令的默认队列。
-m 作业结束后发送邮件给执行at命令的用户。
-f file 使用该选项将使命令从指定的file读取,而不是从标准输入读取。
-l atq命令的一个别名。该命令用于查看安排的作业序列,它将列出用户排在队列中的作业,如果是超级用户,则列出队列中的所有工作。
命令的语法格式如下:
atq [-V] [-q 队列] [-v]
-d atrm 命令的一个别名。该命令用于删除指定要执行的命令序列,语法格式如下:
atrm [-V] 作业 [作业...]
-c 将命令行上所列的作业送到标准输出。
[例4] 找出系统中所有以txt为后缀名的文件,并且进行打印。打印结束后给用户foxy发出邮件通知取件。指定时间为十二月二十五日凌晨两点。
首先键入:
$ at 2:00 12/25/99
然后系统出现at>提示符,等待用户输入进一步的信息,也就是需要执行的命令序列:
at> find / -name “*.txt”|lpr
at> echo “foxy:All texts have been printed.You can take them over.Good day!River” |mail -s ”job done” foxy
输入完每一行指令然后回车,所有指令序列输入完毕后,使用组合键结束at命令的输入。这时候屏幕将出现如下信息:
warning:command will be executed using /bin/sh.
job 1 at 1999-12-25 02:00
提醒用户将使用哪个shell来执行该命令序列。 实际上如果命令序列较长或者经常被执行的时候,一般都采用将该序列写到一个文件中,然后将文件作为at命令的输入来处理。这样不容易出错。
例5] 上面的例子可以修改如下:
将命令序列写入到文件/tmp/printjob,语句为:
$ at -f /tmp/printjob 2:00 12/25/99
这样一来,at命令将使用文件中的命令序列,屏幕显示如下:
Warning:command will be executed using /bin/sh.
job 2 at 1999-12-25 02:00
当然也可以采用以下命令:
$ at< /tmp/printjob 2:00 12/25/99
来完成同样的任务。也就是使用输入重定向的办法将文件定向为命令输入。
batch命令
batch 用低优先级运行作业,该命令几乎和at命令的功能完全相同,唯一的区别在于,at命令是在指定时间,很精确的时刻执行指定命令;而batch却是在系统负载较低,资源比较空闲的时候执行命令。该命令适合于执行占用资源较多的命令。
batch命令的语法格式也和at命令十分相似,即
batch [-V] [-q 队列] [-f 文件名] [-mv] [时间]
具体的参数解释请参考at命令。一般地说,不用为batch命令指定时间参数,因为batch本身的特点就是由系统决定执行任务的时间,如果用户再指定一个时间,就失去了本来的意义。
[例6] 使用例4,键入:
$ batch
at> find / -name *.txt|lpr
at> echo “foxy:All texts have been printed.You can take them over.Good day!River” |mail -s ”job done” foxy
现在这个命令就会在合适的时间进行了,进行完后会发回一个信息。
仍然使用组合键来结束命令输入。而且batch和at命令都将自动转入后台,所以启动的时候也不需要加上&符号。
cron命令
前面介绍的两条命令都会在一定时间内完成一定任务,但是要注意它们都只能执行一次。也就是说,当指定了运行命令后,系统在指定时间完成任务,一切就结束了。但是在很多时候需要不断重复一些命令,比如:某公司每周一自动向员工报告头一周公司的活动情况,这时候就需要使用cron命令来完成任务了。
实际上,cron命令是不应该手工启动的。cron命令在系统启动时就由一个shell脚本自动启动,进入后台(所以不需要使用&符号)。一般的用户没有运行该命令的权限,虽然超级用户可以手工启动cron,不过还是建议将其放到shell脚本中由系统自行启动。
首先cron命令会搜索/var/spool/cron目录,寻找以/etc/passwd文件中的用户名命名的crontab文件,被找到的这种文件将载入内存。例如一个用户名为foxy的用户,它所对应的crontab文件就应该是/var/spool/cron/foxy。也就是说,以该用户命名的crontab文件存放在/var/spool/cron目录下面。cron命令还将搜索/etc/crontab文件,这个文件是用不同的格式写成的。
cron启动以后,它将首先检查是否有用户设置了crontab文件,如果没有就转入“休眠”状态,释放系统资源。所以该后台进程占用资源极少。它每分钟“醒”过来一次,查看当前是否有需要运行的命令。命令执行结束后,任何输出都将作为邮件发送给crontab的所有者,或者是/etc/crontab文件中MAILTO环境变量中指定的用户。
上面简单介绍了一些cron的工作原理,但是cron命令的执行不需要用户干涉;需要用户修改的是crontab中要执行的命令序列,所以下面介绍crontab命令。
crontab命令
crontab命令用于安装、删除或者列出用于驱动cron后台进程的表格。也就是说,用户把需要执行的命令序列放到crontab文件中以获得执行。每个用户都可以有自己的crontab文件。下面就来看看如何创建一个crontab文件。
在/var/spool/cron下的crontab文件不可以直接创建或者直接修改。crontab文件是通过crontab命令得到的。现在假设有个用户名为foxy,需要创建自己的一个crontab文件。首先可以使用任何文本编辑器建立一个新文件,然后向其中写入需要运行的命令和要定期执行的时间。
然后存盘退出。假设该文件为/tmp/test.cron。再后就是使用crontab命令来安装这个文件,使之成为该用户的crontab文件。键入:
crontab test.cron
这样一个crontab 文件就建立好了。可以转到/var/spool/cron目录下面查看,发现多了一个foxy文件。这个文件就是所需的crontab 文件。用more命令查看该文件的内容可以发现文件头有三行信息:
#DO NOT EDIT THIS FILE -edit the master and reinstall.
#(test.cron installed on Mon Feb 22 14:20:20 1999)
#(cron version --$Id:crontab.c,v 2.13 1994/01/17 03:20:37 vivie Exp $)
大概意思是:
#切勿编辑此文件——如果需要改变请编辑源文件然后重新安装。
#test.cron文件安装时间:14:20:20 02/22/1999
如果需要改变其中的命令内容时,还是需要重新编辑原来的文件,然后再使用crontab命令安装。
可以使用crontab命令的用户是有限制的。如果/etc/cron.allow文件存在,那么只有其中列出的用户才能使用该命令;如果该文件不存在但cron.deny文件存在,那么只有未列在该文件中的用户才能使用crontab命令;如果两个文件都不存在,那就取决于一些参数的设置,可能是只允许超级用户使用该命令,也可能是所有用户都可以使用该命令。
crontab命令的语法格式如下:
crontab [-u user] file
crontab [-u user]{-l|-r|-e}
第一种格式用于安装一个新的crontab 文件,安装来源就是file所指的文件,如果使用“-”符号作为文件名,那就意味着使用标准输入作为安装来源。
-u 如果使用该选项,也就是指定了是哪个具体用户的crontab 文件将被修改。如果不指定该选项,crontab 将默认是操作者本人的crontab ,也就是执行该crontab 命令的用户的crontab 文件将被修改。但是请注意,如果使用了su命令再使用crontab 命令很可能就会出现混乱的情况。所以如果是使用了su命令,最好使用-u选项来指定究竟是哪个用户的crontab文件。
-l 在标准输出上显示当前的crontab。
-r 删除当前的crontab文件。
-e 使用VISUAL或者EDITOR环境变量所指的编辑器编辑当前的crontab文件。当结束编辑离开时,编辑后的文件将自动安装。
[例7]
# crontab -l #列出用户目前的crontab。
10 6 * * * date
0 */2 * * * date
0 23-7/2,8 * * * date
#
在crontab文件中如何输入需要执行的命令和时间。该文件中每行都包括六个域,其中前五个域是指定命令被执行的时间,最后一个域是要被执行的命令。每个域之间使用空格或者制表符分隔。格式如下:
minute hour day-of-month month-of-year day-of-week commands
第一项是分钟,第二项是小时,第三项是一个月的第几天,第四项是一年的第几个月,第五项是一周的星期几,第六项是要执行的命令。这些项都不能为空,必须填入。如果用户不需要指定其中的几项,那么可以使用*代替。因为*是统配符,可以代替任何字符,所以就可以认为是任何时间,也就是该项被忽略了。在表4-1中给出了每项的合法范围。
表4-1指定时间的合法范围
时间
合法值
minute 00-59
hour 00-23,其中00点就是晚上12点
day-of-month
01-31
month-of-year
01-12
day-of-week
0-6,其中周日是0
这样用户就可以往crontab 文件中写入无限多的行以完成无限多的命令。命令域中可以写入所有可以在命令行写入的命令和符号,其他所有时间域都支持列举,也就是域中可以写入很多的时间值,只要满足这些时间值中的任何一个都执行命令,每两个时间值中间使用逗号分隔。
[例8]
5,15,25,35,45,55 16,17,18 * * * command
这就是表示任意天任意月,其实就是每天的下午4点、5点、6点的5 min、15 min、25 min、35 min、45 min、55 min时执行命令。
[例9]
在每周一,三,五的下午3:00系统进入维护状态,重新启动系统。那么在crontab 文件中就应该写入如下字段:
00 15 * * 1,3,5 shutdown -r +5
然后将该文件存盘为foxy.cron,再键入crontab foxy.cron安装该文件。
[例10]
每小时的10分,40分执行用户目录下的innd/bbslin这个指令:
10,40 * * * * innd/bbslink
[例11]
每小时的1分执行用户目录下的bin/account这个指令:
1 * * * * bin/account
[例12]
每天早晨三点二十分执行用户目录下如下所示的两个指令(每个指令以;分隔):
20 3 * * * (/bin/rm -f expire.ls logins.bad;bin/expire>expire.1st)
[例13]
每年的一月和四月,4号到9号的3点12分和3点55分执行/bin/rm -f expire.1st这个指令,并把结果添加在mm.txt这个文件之后(mm.txt文件位于用户自己的目录位置)。
12,55 3 4-9 1,4 * /bin/rm -f expire.1st>> m.txt
[例14]
我们来看一个超级用户的crontab文件:
#Run the ‘atrun’ program every minutes
#This runs anything that’s e to run from ‘at’.See man ‘at’ or ‘atrun’. 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /usr/lib/atrun
40 7 * * * updatedb
8,10,22,30,39,46,54,58 * * * * /bin/sync
进程的挂起及恢复命令bg、fg
作业控制允许将进程挂起并可以在需要时恢复进程的运行,被挂起的作业恢复后将从中止处开始继续运行。只要在键盘上按,即可挂起当前的前台作业。
[例15]
$ cat >
< ctrl+z>
text.file [1] + stopped cat > text.file
$ jobs [1]+ stopped cat >text.file
在键盘上按后,将挂起当前执行的命令cat。使用jobs命令可以显示shell的作业清单,包括具体的作业、作业号以及作业当前所处的状态。
恢复进程执行时,有两种选择:用fg命令将挂起的作业放回到前台执行;用bg命令将挂起的作业放到后台执行。
[例16]
用户正在使用Emacs,突然需要查看系统进程情况。就首先使用组合键将Emacs进程挂起,然后使用bg命令将其在后台启动,这样就得到了前台的操作控制权,接着键入“ps –x”查看进程情况。查看完毕后,使用fg命令将Emacs带回前台运行即可。其命令格式为:
< ctrl+z>
$ bg emacs
$ ps –x
$ fg emacs
默认情况下,fg和bg命令对最近停止的作业进行操作。如果希望恢复其他作业的运行,可以在命令中指定要恢复作业的作业号来恢复该作业。例如:
$ fg 1
cat > text.file
灵活使用上述命令,将给自己带来很大的方便。

⑵ Linux系统开机时启动内核步骤是什么

实模式,并开始执行位于地址0xFFFF0处
的代码,也就是ROM-BIOS起始位置的代码。BIOS先进行一系列的系统自检,然后初始化位
于地址0的中断向量表。最后BIOS将启动盘的第一个扇区装入到0x7C00,并开始执行此处
的代码。这就是对内核初始化过程的一个最简单的描述。
最初,linux核心的最开始部分是用8086汇编语言编写的。当开始运行时,核心将自
己装入到绝对地址0x90000,再将其后的2k字节装入到地址0x90200处,最后将核心的其余
部分装入到0x10000。
当系统装入时,会显示Loading...信息。装入完成后,控制转向另一个实模式下的汇
编语言代码boot/Setup.S。Setup部分首先设置一些系统的硬件设备,然后将核心从
0x10000处移至0x1000处。这时系统转入保护模式,开始执行位于0x1000处的代码。
接下来是内核的解压缩。0x1000处的代码来自于文件Boot/head.S,它用来初始化寄
存器和调用decompress_kernel( )程序。decompress_kernel( )程序由Boot/inflate.c,
Boot/unzip.c和Boot../misc.c组成。解压缩后的数据被装入到了0x100000处,这也是
linux不能在内存小于2M的环境下运行的主要原因。
解压后的代码在0x1010000处开始执行,紧接着所有的32位的设置都将完成: IDT、
GDT和LDT将被装入,处理器初始化完毕,设置好内存页面,最终调用start_kernel过程。
这大概是整个内核中最为复杂的部分。
[系统开始运行]
linux kernel 最早的C代码从汇编标记startup_32开始执行
startup_32:
start_kernel
lock_kernel
trap_init
init_IRQ
sched_init
softirq_init
time_init
console_init
#ifdef CONFIG_MODULES
init_moles
#endif
kmem_cache_init
sti
calibrate_delay
mem_init
kmem_cache_sizes_init
pgtable_cache_init
fork_init
proc_caches_init
vfs_caches_init
buffer_init
page_cache_init
signals_init
#ifdef CONFIG_PROC_FS
proc_root_init
#endif
#if defined(CONFIG_SYSVIPC)
ipc_init
#endif
check_bugs
smp_init
rest_init
kernel_thread
unlock_kernel
cpu_idle
・startup_32 [arch/i386/kernel/head.S]
・start_kernel [init/main.c]
・lock_kernel [include/asm/smplock.h]
・trap_init [arch/i386/kernel/traps.c]
・init_IRQ [arch/i386/kernel/i8259.c]
・sched_init [kernel/sched.c]
・softirq_init [kernel/softirq.c]
・time_init [arch/i386/kernel/time.c]
・console_init [drivers/char/tty_io.c]
・init_moles [kernel/mole.c]
・kmem_cache_init [mm/slab.c]
・sti [include/asm/system.h]
・calibrate_delay [init/main.c]
・mem_init [arch/i386/mm/init.c]
・kmem_cache_sizes_init [mm/slab.c]
・pgtable_cache_init [arch/i386/mm/init.c]
・fork_init [kernel/fork.c]
・proc_caches_init
・vfs_caches_init [fs/dcache.c]
・buffer_init [fs/buffer.c]
・page_cache_init [mm/filemap.c]
・signals_init [kernel/signal.c]
・proc_root_init [fs/proc/root.c]
・ipc_init [ipc/util.c]
・check_bugs [include/asm/bugs.h]
・smp_init [init/main.c]
・rest_init
・kernel_thread [arch/i386/kernel/process.c]
・unlock_kernel [include/asm/smplock.h]
・cpu_idle [arch/i386/kernel/process.c]
start_kernel( )程序用于初始化系统内核的各个部分,包括:
*设置内存边界,调用paging_init( )初始化内存页面。
*初始化陷阱,中断通道和调度。
*对命令行进行语法分析。
*初始化设备驱动程序和磁盘缓冲区。
*校对延迟循环。
最后的function'rest_init' 作了以下工作:
・开辟内核线程'init'
・调用unlock_kernel
・建立内核运行的cpu_idle环, 如果没有调度,就一直死循环
实际上start_kernel永远不能终止.它会无穷地循环执行cpu_idle.
最后,系统核心转向move_to_user_mode( ),以便创建初始化进程(init)。此后,进程0开始进入无限循环。
初始化进程开始执行/etc/init、/bin/init 或/sbin /init中的一个之后,系统内核就不再对程序进行直接控制了。之后系统内核的作用主要是给进程提供系统调用,以及提供异步中断事件的处理。多任务机制已经建立起来,并开始处理多个用户的登录和fork( )创建的进程。
[init]
init是第一个进程,或者说内核线程
init
lock_kernel
do_basic_setup
mtrr_init
sysctl_init
pci_init
sock_init
start_context_thread
do_init_calls
(*call())-> kswapd_init
prepare_namespace
free_initmem
unlock_kernel
execve
[目录]
--------------------------------------------------------------------------------
启动步骤
系统引导:
涉及的文件
./arch/$ARCH/boot/bootsect.s
./arch/$ARCH/boot/setup.s
bootsect.S
这个程序是linux kernel的第一个程序,包括了linux自己的bootstrap程序,
但是在说明这个程序前,必须先说明一般IBM PC开机时的动作(此处的开机是指
"打开PC的电源"):
一般PC在电源一开时,是由内存中地址FFFF:0000开始执行(这个地址一定
在ROM BIOS中,ROM BIOS一般是在FEOOOh到FFFFFh中),而此处的内容则是一个
jump指令,jump到另一个位于ROM BIOS中的位置,开始执行一系列的动作,包
括了检查RAM,keyboard,显示器,软硬磁盘等等,这些动作是由系统测试代码
(system test code)来执行的,随着制作BIOS厂商的不同而会有些许差异,但都
是大同小异,读者可自行观察自家机器开机时,萤幕上所显示的检查讯息。
紧接着系统测试码之后,控制权会转移给ROM中的启动程序
(ROM bootstrap routine),这个程序会将磁盘上的第零轨第零扇区读入
内存中(这就是一般所谓的boot sector,如果你曾接触过电脑病
毒,就大概听过它的大名),至于被读到内存的哪里呢? --绝对
位置07C0:0000(即07C00h处),这是IBM系列PC的特性。而位在linux开机
磁盘的boot sector上的正是linux的bootsect程序,也就是说,bootsect是
第一个被读入内存中并执行的程序。现在,我们可以开始来
看看到底bootsect做了什么。
第一步
首先,bootsect将它"自己"从被ROM BIOS载入的绝对地址0x7C00处搬到
0x90000处,然后利用一个jmpi(jump indirectly)的指令,跳到新位置的
jmpi的下一行去执行,
第二步
接着,将其他segment registers包括DS,ES,SS都指向0x9000这个位置,
与CS看齐。另外将SP及DX指向一任意位移地址( offset ),这个地址等一下
会用来存放磁盘参数表(disk para- meter table )
第三步
接着利用BIOS中断服务int 13h的第0号功能,重置磁盘控制器,使得刚才
的设定发挥功能。
第四步
完成重置磁盘控制器之后,bootsect就从磁盘上读入紧邻着bootsect的setup
程序,也就是setup.S,此读入动作是利用BIOS中断服务int 13h的第2号功能。
setup的image将会读入至程序所指定的内存绝对地址0x90200处,也就是在内存
中紧邻着bootsect 所在的位置。待setup的image读入内存后,利用BIOS中断服
务int 13h的第8号功能读取目前磁盘的参数。
第五步
再来,就要读入真正linux的kernel了,也就是你可以在linux的根目录下看
到的"vmlinuz" 。在读入前,将会先呼叫BIOS中断服务int 10h 的第3号功能,
读取游标位置,之后再呼叫BIOS 中断服务int 10h的第13h号功能,在萤幕上输
出字串"Loading",这个字串在boot linux时都会首先被看到,相信大家应该觉
得很眼熟吧。
第六步
接下来做的事是检查root device,之后就仿照一开始的方法,利用indirect
jump 跳至刚刚已读入的setup部份
第七步
setup.S完成在实模式下版本检查,并将硬盘,鼠标,内存参数写入到 INITSEG
中,并负责进入保护模式。
第八步
操作系统的初始化。

⑶ Linux服务开机自启动三种方式,你觉得哪种最优雅

很多时候,我们需要将一些服务在Linux系统启动时即自动运行,省得每次都要去手动启动一遍,如Redis, MySQL, Nginx等。本文对CentOS与Ubuntu下开机自启动的配置方法进行整理,供参考查阅。

rc.local是CentOS以前版本的方式,在CentOS7中仍然以兼容的形式存在,虽仍可用,但不推荐(推荐使用systemd service)。

1、编写需要开机自启动的脚本,并添加执行权限

作为测试,上述脚本打印一个时间到/tmp/test.log文件中

2、在/etc/rc.d/rc.local配置文件中添加脚本运行命令(使用绝对路径)

3、添加/etc/rc.d/rc.local文件的执行权限

在centos7中,/etc/rc.d/滚毁岩rc.local没有执行权限,需要手动授权

以上三步,即可使/root/test_rclocal.sh >/dev/null 2>/dev/null 命令在服务器系统启动时自动运行。

1、编写需要开机自启动的测试脚本,并添加执行权限

2、在/etc/rc.d/init.d/目录下添加一个可执行脚本testchkconfig

上述testchkconfig脚本的头部必须遵循一定的格式 # chkconfig: 2345 90 10, 其中2345指定服务在哪些执行等级中开启或关闭,90表示启动的优先级(0-100,越大优先级越低),10表示关闭的优先级。执行等级包括

3、加入开机启动服务列表

使用 chkconfig --list 可查看当前加入开机自启动的服务列表,但如Note部分所述,该命令只显示SysV服务,不包含原生的systemd服务,查看systemd服务可使用systemctl list-unit-files命令。

以上三步,即可使/root/test_chkconfig.sh >/dev/null 2>/dev/null 命令在服务器系统启动时自动运行。

chkconfig的其它命令参考

CentOS7的余滚systemd服务脚本存放在:/usr/lib/systemd/system(系统级)/usr/lib/systemd/user(用户级)下,以.service结尾。这里以nginx为例

1、在/usr/lib/systemd/system目录大御下创建nginx.service文件

其中Service部分的Type包括如下几种类型:

2、 开启开机自启动

以上两步,就将nginx服务配置成了在操作系统启动时自动启动。

其它命令参考

从字面看是PID文件不可读,查看/var/run/nginx.pid,该文件也确实不存在,查看nginx.conf配置文件,发现是pid /var/run/nginx.pid;这行配置被注释掉了, 如果不指定pid文件位置,nginx默认会把pid文件保存在logs目录中。所以出现systemd启动服务时找不到pid文件而报错,将nginx.conf中的pid配置注释去掉,重启nginx.service即可。

在Ubuntu18.04中,主要也是以systemd服务来实现开机自启动,systemd默认读取/etc/systemd/system/下的配置文件,该目录下的一些文件会链接到/lib/systemd/system/下的文件。

因此可以在/etc/systemd/system/目录下面创建一个自启动服务配置,以内网穿透服务frp客户端为例,如

各配置项与CentOS类似。然后将服务器加到自启动列表中并启动服务

其它更多systemctl命令与CentOS类似。

也可以使用/lib/systemd/system/rc-local.service来执行一些开机需要执行的脚本,该文件内容为

从Description看它是为了兼容之前版本的/etc/rc.local的,该服务启动命名就是/etc/rc.local start,将该文件链接到/etc/systemd/system下

创建/etc/rc.local文件,并赋予可执行权限

作者:半路雨歌
链接:https://juejin.cn/post/6844904104515338248

⑷ Linux驱动程序的工作原理

由于你的问题太长我只好转载别人的手打的太累不好意思~~~
Linux是Unix***作系统的一种变种,在Linux下编写驱动程序的原理和

思想完全类似于其他的Unix系统,但它dos或window环境下的驱动程序有很大的

区别.在Linux环境下设计驱动程序,思想简洁,***作方便,功芤端口芮看?但是

支持函数少,只能依赖kernel中的函数,有些常用的***作要自己来编写,而且调

试也不方便.本人这几周来为实验室自行研制的一块多媒体卡编制了驱动程序,

获得了一些经验,愿与Linux fans共享,有不当之处,请予指正.

以下的一些文字主要来源于khg,johnsonm的Write linux device driver,

Brennan's Guide to Inline Assembly,The Linux A-Z,还有清华BBS上的有关

device driver的一些资料. 这些资料有的已经过时,有的还有一些错误,我依

据自己的试验结果进行了修正.

一. Linux device driver 的概念

系统调用是***作系统内核和应用程序之间的接口,设备驱动程序是***作系统

内核和机器硬件之间的接口.设备驱动程序为应用程序屏蔽了硬件的细节,这样

在应用程序看来,硬件设备只是一个设备文件, 应用程序可以象***作普通文件

一样对硬件设备进行***作.设备驱动程序是内核的一部分,它完成以下的功能:

1.对设备初始化和释放.

2.把数据从内核传送到硬件和从硬件读取数据.

3.读取应用程序传送给设备文件的数据和回送应用程序请求的数据.

4.检测和处理设备出现的错误.

在Linux***作系统下有两类主要的设备文件类型,一种是字符设备,另一种是

块设备.字符设备和块设备的主要区别是:在对字符设备发出读/写请求时,实际

的硬件I/O一般就紧接着发生了,块设备则不然,它利用一块系统内存作缓冲区,

当用户进程对设备请求能满足用户的要求,就返回请求的数据,如果不能,就调用请求函数来进行实际

的I/O***作.块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间

来等待.

已经提到,用户进程是通过设备文件来与实际的硬件打交道.每个设备文件都

都有其文件属性(c/b),表示是字符设备还蔤强樯璞?另外每个文件都有两个设

备号,第一个是主设备号,标识驱动程序,第二个是从设备号,标识使用同一个

设备驱动程序的不同的硬件设备,比如有两个软盘,就可以用从设备号来区分

他们.设备文件的的主设备号必须与设备驱动程序在登记时申请的主设备号

一致,否则用户进程将无法访问到驱动程序.

最后必须提到的是,在用户进程调用驱动程序时,系统进入核心态,这时不再是

抢先式调度.也就是说,系统必须在你的驱动程序的子函数返回后才能进行其他

的工作.如果你的驱动程序陷入死循环,不幸的是你只有重新启动机器了,然后就

是漫长的fsck.//hehe

(请看下节,实例剖析)

读/写时,它首先察看缓冲区的内容,如果缓冲区的数据

如何编写Linux***作系统下的设备驱动程序

Roy G

二.实例剖析

我们来写一个最简单的字符设备驱动程序.虽然它什么也不做,但是通过它

可以了解Linux的设备驱动程序的工作原理.把下面的C代码输入机器,你就会

获得一个真正的设备驱动程序.不过我的kernel是2.0.34,在低版本的kernel

上可能会出现问题,我还没测试过.//xixi

#define __NO_VERSION__

#include

#include

char kernel_version [] = UTS_RELEASE;

这一段定义了一些版本信息,虽然用处不是很大,但也必不可少.Johnsonm说所

有的驱动程序的开头都要包含,但我看倒是未必.

由于用户进程是通过设备文件同硬件打交道,对设备文件的***作方式不外乎就

是一些系统调用,如 open,read,write,close...., 注意,不是fopen, fread.,

但是如何把系统调用和驱动程序关联起来呢?这需要了解一个非常关键的数据

结构:

struct file_operations {

int (*seek) (struct inode * ,struct file *, off_t ,int);

int (*read) (struct inode * ,struct file *, char ,int);

int (*write) (struct inode * ,struct file *, off_t ,int);

int (*readdir) (struct inode * ,struct file *, struct dirent * ,int);

int (*select) (struct inode * ,struct file *, int ,select_table *);

int (*ioctl) (struct inode * ,struct file *, unsined int ,unsigned long

int (*mmap) (struct inode * ,struct file *, struct vm_area_struct *);

int (*open) (struct inode * ,struct file *);

int (*release) (struct inode * ,struct file *);

int (*fsync) (struct inode * ,struct file *);

int (*fasync) (struct inode * ,struct file *,int);

int (*check_media_change) (struct inode * ,struct file *);

int (*revalidate) (dev_t dev);

}

这个结构的每一个成员的名字都对应着一个系统调用.用户进程利用系统调用

在对设备文件进行诸如read/write***作时,系统调用通过设备文件的主设备号

找到相应的设备驱动程序,然后读取这个数据结构相应的函数指针,接着把控制

权交给该函数.这是linux的设备驱动程序工作的基本原理.既然是这样,则编写

设备驱动程序的主要工作就是编写子函数,并填充file_operations的各个域.

相当简单,不是吗?

下面就开始写子程序.

#include

#include

#include

#include

#include

unsigned int test_major = 0;

static int read_test(struct inode *node,struct file *file,

char *buf,int count)

{

int left;

if (verify_area(VERIFY_WRITE,buf,count) == -EFAULT )

return -EFAULT;

for(left = count left > 0 left--)

{

__put_user(1,buf,1);

buf++;

}

return count;

}

这个函数是为read调用准备的.当调用read时,read_test()被调用,它把用户的

缓冲区全部写1.

buf 是read调用的一个参数.它是用户进程空间的一个地址.但是在read_test

被调用时,系统进入核心态.所以不能使用buf这个地址,必须用__put_user(),

这是kernel提供的一个函数,用于向用户传送数据.另外还有很多类似功能的

函数.请参考.在向用户空间拷贝数据之前,必须验证buf是否可用.

这就用到函数verify_area.

static int write_tibet(struct inode *inode,struct file *file,

const char *buf,int count)

{

return count;

}

static int open_tibet(struct inode *inode,struct file *file )

{

MOD_INC_USE_COUNT;

return 0;

} static void release_tibet(struct inode *inode,struct file *file )

{

MOD_DEC_USE_COUNT;

}

这几个函数都是空***作.实际调用发生时什么也不做,他们仅仅为下面的结构

提供函数指针。

struct file_operations test_fops = {

NULL,

read_test,

write_test,

NULL, /* test_readdir */

NULL,

NULL, /* test_ioctl */

NULL, /* test_mmap */

open_test,

release_test, NULL, /* test_fsync */

NULL, /* test_fasync */

/* nothing more, fill with NULLs */

};

设备驱动程序的主体可以说是写好了。现在要把驱动程序嵌入内核。驱动程序

可以按照两种方式编译。一种是编译进kernel,另一种是编译成模块(moles),

如果编译进内核的话,会增加内核的大小,还要改动内核的源文件,而且不能

动态的卸载,不利于调试,所以推荐使用模块方式。

int init_mole(void)

{

int result;

result = register_chrdev(0, "test", &test_fops);

if (result < 0) {

printk(KERN_INFO "test: can't get major number ");

return result;

}

if (test_major == 0) test_major = result; /* dynamic */

return 0;

}

在用insmod命令将编译好的模块调入内存时,init_mole 函数被调用。在

这里,init_mole只做了一件事,就是向系统的字符设备表登记了一个字符

设备。register_chrdev需要三个参数,参数一是希望获得的设备号,如果是

零的话,系统将选择一个没有被占用的设备号返回。参数二是设备文件名,

参数三用来登记驱动程序实际执行***作的函数的指针。

如果登记成功,返回设备的主设备号,不成功,返回一个负值。

void cleanup_mole(void)

{

unregister_chrdev(test_major, "test");

}

在用rmmod卸载模块时,cleanup_mole函数被调用,它释放字符设备test

在系统字符设备表中占有的表项。

一个极其简单的字符设备可以说写好了,文件名就叫test.c吧。

下面编译

$ gcc -O2 -DMODULE -D__KERNEL__ -c test.c

得到文件test.o就是一个设备驱动程序。

如果设备驱动程序有多个文件,把每个文件按上面的命令行编译,然后

ld -r file1.o file2.o -o molename.

驱动程序已经编译好了,现在把它安装到系统中去。

$ insmod -f test.o

如果安装成功,在/proc/devices文件中就可以看到设备test,

并可以看到它的主设备号,。

要卸载的话,运行

$ rmmod test

下一步要创建设备文件。

mknod /dev/test c major minor

c 是指字符设备,major是主设备号,就是在/proc/devices里看到的。

用shell命令

$ cat /proc/devices | awk "\$2=="test" {print \$1}"

就可以获得主设备号,可以把上面的命令行加入你的shell script中去。

minor是从设备号,设置成0就可以了。

我们现在可以通过设备文件来访问我们的驱动程序。写一个小小的测试程序。

#include

#include

#include

#include

main()

{

int testdev;

int i;

char buf[10];

testdev = open("/dev/test",O_RDWR);

if ( testdev == -1 )

{

printf("Cann't open file ");

exit(0);

}

read(testdev,buf,10);

for (i = 0; i < 10;i++)

printf("%d ",buf);

close(testdev);

}

编译运行,看看是不是打印出全1 ?

以上只是一个简单的演示。真正实用的驱动程序要复杂的多,要处理如中断,

DMA,I/O port等问题。这些才是真正的难点。请看下节,实际情况的处理。

如何编写Linux***作系统下的设备驱动程序

Roy G

三 设备驱动程序中的一些具体问题。

1. I/O Port.

和硬件打交道离不开I/O Port,老的ISA设备经常是占用实际的I/O端口,

在linux下,***作系统没有对I/O口屏蔽,也就是说,任何驱动程序都可以

对任意的I/O口***作,这样就很容易引起混乱。每个驱动程序应该自己避免

误用端口。

有两个重要的kernel函数可以保证驱动程序做到这一点。

1)check_region(int io_port, int off_set)

这个函数察看系统的I/O表,看是否有别的驱动程序占用某一段I/O口。

参数1:io端口的基地址,

参数2:io端口占用的范围。

返回值:0 没有占用, 非0,已经被占用。

2)request_region(int io_port, int off_set,char *devname)

如果这段I/O端口没有被占用,在我们的驱动程序中就可以使用它。在使用

之前,必须向系统登记,以防止被其他程序占用。登记后,在/proc/ioports

文件中可以看到你登记的io口。

参数1:io端口的基地址。

参数2:io端口占用的范围。

参数3:使用这段io地址的设备名。

在对I/O口登记后,就可以放心地用inb(), outb()之类的函来访问了。

在一些pci设备中,I/O端口被映射到一段内存中去,要访问这些端口就相当

于访问一段内存。经常性的,我们要获得一块内存的物理地址。在dos环境下,

(之所以不说是dos***作系统是因为我认为DOS根本就不是一个***作系统,它实

在是太简单,太不安全了)只要用段:偏移就可以了。在window95中,95ddk

提供了一个vmm 调用 _MapLinearToPhys,用以把线性地址转化为物理地址。但

在Linux中是怎样做的呢?

2 内存***作

在设备驱动程序中动态开辟内存,不是用malloc,而是kmalloc,或者用

get_free_pages直接申请页。释放内存用的是kfree,或free_pages. 请注意,

kmalloc等函数返回的是物理地址!而malloc等返回的是线性地址!关于

kmalloc返回的是物理地址这一点本人有点不太明白:既然从线性地址到物理

地址的转换是由386cpu硬件完成的,那样汇编指令的***作数应该是线性地址,

驱动程序同样也不能直接使用物理地址而是线性地址。但是事实上kmalloc

返回的确实是物理地址,而且也可以直接通过它访问实际的RAM,我想这样可

以由两种解释,一种是在核心态禁止分页,但是这好像不太现实;另一种是

linux的页目录和页表项设计得正好使得物理地址等同于线性地址。我的想法

不知对不对,还请高手指教。

言归正传,要注意kmalloc最大只能开辟128k-16,16个字节是被页描述符

结构占用了。kmalloc用法参见khg.

内存映射的I/O口,寄存器或者是硬件设备的RAM(如显存)一般占用F0000000

以上的地址空间。在驱动程序中不能直接访问,要通过kernel函数vremap获得

重新映射以后的地址。

另外,很多硬件需要一块比较大的连续内存用作DMA传送。这块内存需要一直

驻留在内存,不能被交换到文件中去。但是kmalloc最多只能开辟128k的内存。

这可以通过牺牲一些系统内存的方法来解决。

具体做法是:比如说你的机器由32M的内存,在lilo.conf的启动参数中加上

mem=30M,这样linux就认为你的机器只有30M的内存,剩下的2M内存在vremap

之后就可以为DMA所用了。

请记住,用vremap映射后的内存,不用时应用unremap释放,否则会浪费页表。

3 中断处理

同处理I/O端口一样,要使用一个中断,必须先向系统登记。

int request_irq(unsigned int irq ,

void(*handle)(int,void *,struct pt_regs *),

unsigned int long flags,

const char *device);

irq: 是要申请的中断。

handle:中断处理函数指针。

flags:SA_INTERRUPT 请求一个快速中断,0 正常中断。

device:设备名。

如果登记成功,返回0,这时在/proc/interrupts文件中可以看你请求的

中断。

4一些常见的问题。

对硬件***作,有时时序很重要。但是如果用C语言写一些低级的硬件***作

的话,gcc往往会对你的程序进行优化,这样时序就错掉了。如果用汇编写呢,

gcc同样会对汇编代码进行优化,除非你用volatile关键字修饰。最保险的

办法是禁止优化。这当然只能对一部分你自己编写的代码。如果对所有的代码

都不优化,你会发现驱动程序根本无法装载。这是因为在编译驱动程序时要

用到gcc的一些扩展特性,而这些扩展特性必须在加了优化选项之后才能体现

出来。

关于kernel的调试工具,我现在还没有发现有合适的。有谁知道请告诉我,

不胜感激。我一直都在printk打印调试信息,倒也还凑合。

关于设备驱动程序还有很多内容,如等待/唤醒机制,块设备的编写等。

我还不是很明白,不敢乱说。

⑸ 安装linux系统实验原理

1) 启动vmware虚拟机
2) 单击“文件—>新建?虚拟机”,出现“安装虚拟机向导”对话框,单击“下一步”,选“典型”;
3)“客户机操作系统”选择安装linux,版本选“redhat linux”,单击“下一步”;
4) 在“虚拟机名称”处:输入“linux”, 创建指定位置(不要选择在c盘)的磁盘映像文件linux.vmx单击“下一步”,出现“网络连接” 设置界面,选择“使用桥接网络” 单击下一步;
5) 磁盘容量为8g, 单击“完成”;
6)编辑虚拟机设置:
双击设备栏“cd-rom”,选择“使用iso镜像”;指定镜像文件路径,例如: d:\redhatlinux_isofiles\redhatlinux9_i386_disc1.iso ;
floppy设备栏取消“打开电源时连接“
7) 配置步骤完成,启动系统。

⑹ linux 管道原理

Linux原理的学习,我打算由浅入深,从上之下,也就是先了解个大概再逐个深入。先了解一下Linux的进程先。

一、Linux进程上下文

Linux进程上下文,我理解就是进程组成元素的集合。包括进程描述符tast_struct,正文段,数据段,栈,寄存器内容,页表等。

1)tast_struct

它是一种数据结构,存储着进程的描述信息,例如pid,uid,状态,信号项,打开文件表等。是进程管理和调度的重要依据。

2)用户栈和核心栈

顾名思义,用户栈是进程运行在用户态使用的栈,含有用户态执行时候函数调用的参数,局部变量等;核心栈是该进程运行在核心态下用的栈,保存调用系统函数所用的参数和调用序列。这两个栈的指针都保存在tast_struct结构中。

3)寄存器

保存程序计数器,状态字,通用寄存器,栈指针。

4)页表

线性地址到物理地址的映射

5)正文段,数据段。

二、Linux进程的状态

Linux中进程共有5个状态:就绪,可中断睡眠,不可中断睡眠,暂停,僵死。也就是说,linux不区分就绪和运行,它们统一叫做就绪态。进程所处的状态记录在tast_struct中。

三、进程的控制

1)进程树的形成

计算机启动后,BIOS从磁盘引导扇区加载系统引导程序,它将Linux系统装入内存,并跳到内核处执行,Linux内核就执行初始化工作:初始化硬件、初始化内部数据结构、建立进程0。进程0创建进程1,进程1是以后所有创建的进程的祖先,它负责初始化所有的用户进程。进程1创建shell进程,shell进程显示提示符,等待命令的输入。

2)进程的创建

任何一个用户进程的创建都是由现有的一个进程完成的,进程的创建要经过fork和exec两个过程。Fork是为新进程分配相应的数据结构,并将父进程的相应上下文信息复制过来。Exec是将可执行文件的正文和数据转入内存覆盖它原来的(从父进程复制过来的),并开始执行正文段。

3)进程的终止

系统调用exit()就可自我终结,exit释放除了tast_struct以外的所有上下文,父进程收到子进程终结的消息后,释放子进程的tast_struct。

4)进程的调度

进程的调度是由schele()完成的,一种情况是,当处理机从核心态向用户态转换之前,它会检查调度标志是否为1,如果是1,则运行schele(),执行进程的调度。另一种情况是进程自动放弃处理机,时候进行进程调度。

进程的调度过程分为两步,首先利用相关策略选择要执行的进程,然后进行上下文的切换。

四、进程的通信

进程的通信策略主要有,消息,管道,消息队列,共享存储区和信号量。

1)信息

消息机制主要是用来传递进程间的软中断信号,通知对方发生了异步事件。发送进程将信号(约定好的符号)发送到目标进程的tast_struct中的信号项,接收进程看到有消息后就调用相应的处理程序,注意,处理程序必须到进程执行时候才能执行,不能立即响应。

2)管道

我理解就是两个进程使用告诉缓冲区中的一个队列(每两个进程一个),发送进程将数据发送到管道入口,接收进程从管道出口读数据。

3) 消息队列

消息队列是操作系统维护的一个个消息链表,发送进程根据消息标识符将消息添加到制定队列中,接收进程从中读取消息。

4)共享存储区

在内存中开辟一个区域,是个进程共享的,也就是说进程可以把它附加到自己的地址空间中,对此区域中的数据进行操作。

5)信号量

控制进程的同步。

⑺ Linux系统启动的大致过程

Linux系统启动的大致过程

Linux操作系统是基于UNIX操作系统发展而来的一种克隆系统,它诞生于1991 年的 [Linux桌面] 10 月5 日。下面我准备了关于Linux系统启动的大致过程,提供给大家参考!

第一阶段:BIOS启动引导阶段;

在该过程中实现硬件的.初始化以及查找启动介质;

从MBR中装载启动引导管理器(GRUB)并运行该启动引导管理

第二阶段:GRUB启动引导阶段;

装载stage1

装载stage1.5

装载stage2

读取/boot/grub.conf文件并显示启动菜单;

装载所选的kernel和initrd文件到内存中

第三阶段:内核阶段:

运行内核启动参数;

解压initrd文件并挂载initd文件系统,装载必须的驱动;

挂载根文件系统

第四阶段:Sys V init初始化阶段:

启动/sbin/init程序;

运行rc.sysinit脚本,设置系统环境,启动swap分区,检查和挂载文件系统;

读取/etc/inittab文件,运行在/et/rc.d/rc<#>.d中定庆液义的不同运行级别的服务初始化脚本;

打开字清差睁符终端1-6号控制台/打开图形显示管理的7号控制台

同时在上述过程中各阶段所需要读取的文件和操作的对象:

BIOS启动引导阶段 GRUB启答岁动引导阶段 内核阶段 /init/sysinit阶段

====================================================================================

None /boot/grub/grub.conf /boot/vmlinuz- /etc/rc.d/rc.sysinit

/boot/grub/stage1_5 /boot/initrd- /etc/inittab

/boot/grub/stage2 /etc/rc.d/rc<#>.d

/etc/rc.d/init.d/*

;

⑻ Linux( bootloader)启动操作系统过程

Linux Booting Process:
(1) BIOS
功能:执行计算机系统完整性检测;通电自检;搜索/加载/执行 boot loader程序。
一旦 boot loader 程序被探测到,并且加载到内存,BIOS会把控制权交给它。
(2) MBR
MBR位于引导盘(Bootable Disk)的第一个扇区(512B)。
通常是在 /dev/sda 或者 /dev/hda 。

注意:引导盘(bootable disk)和引导分区(bootable partition)的区别。

(3) GRUB
GRUB = Grand Unified Bootloader

如果在系统中安装有多个内核镜像,你可以选择某一个被执行。
GRUB展示了一个启动画面,等待几秒,如果你不输入任何字符,它将会按照grub配置文件的规定加载默认的内核镜像。

Grub配置文件在: /boot/grub/grub.conf
它包含了内核和initrd.img

(4) Kernal
(注意Kernal和kernel不一样)

Kernal按照grub.conf文件的规定,挂载根文件系统。
一旦kernal启动,它第一件事情就是执行:sbin/init 进程。

initrd是被kernel用做临时根文件系统,直到Kernal挂载了根文件系统。

(5) INIT(Initilization)

根据 /etc/inittab 文件决定Linux运行层级,运行级别决定了哪个初始化程序(Initial Programs)被加载到启动项。

(6) Run Level

根据你的运行级别的设定,操作系统会执行下来对应的文件夹下的程序:

Linux的7个运行级别(Run levels):

标准的Linux运行级别为3或者5,如果是3的话,系统就在多用户状态;如果是5的话,则是运行着XWindow系统。不同的运行级别有着不同的用处,也应该根据自己的不同清晰来设置。例如,如果丢失了root口令,那么可以让机器启动进入单用户模式来设置。

如果是使用S(Start)开头的程序,那么是用在启动的时候,
如果是使用K(Kill)开头的程序,那么是用在关机的时候。

阅读全文

与linux启动原理相关的资料

热点内容
加密dns列表 浏览:986
股市操练大全八册pdf 浏览:120
c传递指针到python 浏览:163
手动添加引导的命令 浏览:54
740服务器小蓝条是做什么的 浏览:523
linux文件操作命令 浏览:127
安卓手机图片文件夹加锁 浏览:781
steam提示音在哪个文件夹 浏览:339
项目开发全程实录pdf 浏览:532
单片机reset 浏览:597
pdf怎么是英文 浏览:971
旗云2压缩机保险 浏览:374
做程序员压力大吗表情包 浏览:312
pdf下拉 浏览:373
php去掉小数后面的0 浏览:954
阿里备案买什么服务器 浏览:263
网络驱动下载到哪个文件夹 浏览:483
达内程序员培训西安 浏览:507
人保送车主惠app上怎么年检 浏览:605
android手机开机密码 浏览:482