简析linux内核的内核执行流程图

合集下载

linux思维导图期末知识点总结

linux思维导图期末知识点总结

linux思维导图期末知识点总结环境:虚拟机/云服务器许多程序需要开机启动,它们在win叫服务,在linux叫守护进程,init进去运行开机启动的程序。

正常情况下,很少遇到关机情况。

正确关机流程:sync > shutdown > reboot > halt区别于重启系统和关闭系统,都要运行sync,把内存中的数据写到磁盘中关机命令:shutdown –h now halt poweroff 和 init 0重启系统的命令:shutdown –r now reboot init 6内核版本cat /etc/issue系统版本cat /proc/version1、yum源进行备份进入到yum源的配置文件中执行命令如下:cd /etc/yum.repos.d将yum源进行备份:mv Centos-Base.repo Centos-Base.repo.bak2、获取阿里的yum源配置文件执行命令:wget -O Centos-Base.repo3、对yum源生成缓存执行命令:yum makecache4、更新yum源执行命令:yum -y install update执行完成之后就可以使用yum源了,到此yum源就更换成功了。

在 Linux 或 Unix 操作系统中,所有的文件和目录都被组织成以一个根节点开始的倒置的树状结构。

文件系统的最顶层是由根目录开始的,系统使用 / 来表示根目录。

在根目录之下的既可以是目录,也可以是文件,而每一个目录中又可以包含子目录文件。

如此反复就可以构成一个庞大的文件系统。

/boot:存放的启动Linux 时使用的内核文件,包括连接文件以及镜像文件。

/etc:存放所有的系统需要的配置文件和子目录列表,更改目录下的文件可能会导致系统不能启动。

/lib:存放基本代码库(比如c++库),其作用类似于Windows里的DLL文件。

几乎所有的应用程序都需要用到这些共享库。

Linuxreboot全过程

Linuxreboot全过程

Linuxreboot全过程⼀、版本说明嵌⼊式Linux 下⾯的reboot命令看似简单,但出问题时定位起来发现别有洞天。

下⾯就按在shell下执⾏reboot命令之后程序的执⾏过程进⾏解析。

Busybox:1.23.2 ——制作跟⽂件系统,/sbin/reboot程序的由来Libc:2.6.1 ——标准C库Linux kernel:2.6.35 ——内核版本⼆、流程简介如图所⽰是reboot的简要流程图。

普通的reboot是通过busybox为⼊⼝,进⼊halt_main函数,然后给init进程发送SIGTERM信号,init进程接收到信号后给其他进程发送终⽌信号,最后调⽤C库函数reboot,reboot通过系统调⽤sys_reboot进⼊内核,内核将整个系统重启。

其中在shell中执⾏reboot –f则通过halt_main直接调⽤C函数reboot,不经过init进程。

三、代码详解1.reboot命令端执⾏reboot命令,busybox检查当前命令为reboot,进⼊函数halt_main,reboot,halt和poweroff都会进⼊这个函数,不同的命令发送的信号和执⾏的操作不同。

现只分析reboot的情况。

代码如下1.int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;2.int halt_main(int argc UNUSED_PARAM, char **argv)3.{4.static const int magic[] = {RB_HALT_SYSTEM,6.RB_POWER_OFF,7.RB_AUTOBOOT8.};9.static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM };10.11.int delay = 0;12.int which, flags, rc;13.14./* Figure out which applet we're running */15.for (which = 0; "hpr"[which] != applet_name[0]; which++)16.continue;17.18./* Parse and handle arguments */19.opt_complementary = "d+"; /* -d N */20./* We support -w even if !ENABLE_FEATURE_WTMP,21.* in order to not break scripts.22.* -i (shut down network interfaces) is ignored.23.*/24.flags = getopt32(argv, "d:nfwi", &delay);25.26.sleep(delay);27.28.write_wtmp();29.30.if (flags & 8) /* -w */31.return EXIT_SUCCESS;32.33.if (!(flags & 2)) /* no -n */34.sync();35.36./* Perform action. */37.rc = 1;38.if (!(flags & 4)) { /* no -f *///TODO: I tend to think that signalling linuxrc is wrong 40.// pity original author didn't comment on it...41.if (ENABLE_FEATURE_INITRD) {42./* talk to linuxrc */43./* bbox init/linuxrc assumed */44.pid_t *pidlist = find_pid_by_name("linuxrc");45.if (pidlist[0] > 0)46.rc = kill(pidlist[0], signals[which]);47.if (ENABLE_FEATURE_CLEAN_UP)48.free(pidlist);49.}50.if (rc) {51./* talk to init */52.if (!ENABLE_FEATURE_CALL_TELINIT) {53./* bbox init assumed */54.rc = kill(1, signals[which]);55.} else {56./* SysV style init assumed */57./* runlevels:58.* 0 == shutdown59.* 6 == reboot */60.execlp(CONFIG_TELINIT_PATH,61.CONFIG_TELINIT_PATH,62.which == 2 ? "6" : "0",63.(char *)NULL64.);65.bb_perror_msg_and_die("can't execute '%s'",66.CONFIG_TELINIT_PATH);67.}68.}69.} else {70.rc = reboot(magic[which]);71.}72.if (rc)74.bb_perror_nomsg_and_die();75.return rc;76.}该函数判断reboot是否带了 -f 参数,如果带了,直接调⽤reboot调⽤C函数库如果没带,则通过kill(1, signals[which]);给init进程发送SIGTERM信号。

linux elf执行流程

linux elf执行流程

linux elf执行流程Linux ELF 执行流程ELF(Executable and Linkable Format)是Linux系统中可执行文件的一种格式。

在Linux下,当我们执行一个可执行文件时,操作系统会按照一定的流程解析和执行该文件。

本文将介绍Linux ELF 的执行流程。

1. ELF文件格式ELF文件由多个段(section)组成,每个段都有特定的作用。

常见的段包括.text段(包含程序的指令)、.data段(包含程序的全局变量和静态变量)、.bss段(包含未初始化的全局变量和静态变量)等。

2. 加载可执行文件当用户在终端输入可执行文件名并按下回车键时,操作系统会通过解析文件头判断该文件是否为有效的ELF文件。

如果是有效的ELF 文件,操作系统会为该进程分配一块内存空间,并将ELF文件中的各个段加载到相应的内存地址上。

3. 解析程序入口操作系统会根据ELF文件中的程序入口地址(Entry Point)来确定程序的入口点。

程序入口地址通常位于.text段的起始位置。

操作系统将程序计数器(PC)设置为程序入口地址,从而开始执行程序。

4. 执行程序指令程序从程序入口地址开始执行,按照顺序执行.text段中的指令。

每条指令都会被解码和执行,直到程序结束或者遇到跳转指令。

5. 解析跳转指令在程序执行过程中,可能会遇到跳转指令(如条件跳转、无条件跳转、函数调用等)。

当遇到跳转指令时,操作系统会根据指令中的目标地址重新设置程序计数器,从而改变程序的执行流程。

6. 处理函数调用当程序执行到函数调用指令时,操作系统会将函数的返回地址和参数等信息保存到栈中,并跳转到函数的入口地址执行。

函数执行完毕后,操作系统会从栈中恢复返回地址,继续执行函数调用指令后面的指令。

7. 处理系统调用程序中可能会包含系统调用指令,用于请求操作系统提供各种服务。

当遇到系统调用指令时,操作系统会切换到内核态,执行相应的系统调用处理程序,并返回结果给用户程序。

Linux设备驱动程序原理及框架-内核模块入门篇

Linux设备驱动程序原理及框架-内核模块入门篇

Linux设备驱动程序原理及框架-内核模块入门篇内核模块介绍应用层加载模块操作过程内核如何支持可安装模块内核提供的接口及作用模块实例内核模块内核模块介绍Linux采用的是整体式的内核结构,这种结构采用的是整体式的内核结构,采用的是整体式的内核结构的内核一般不能动态的增加新的功能。

为此,的内核一般不能动态的增加新的功能。

为此,Linux提供了一种全新的机制,叫(可安装) 提供了一种全新的机制,可安装) 提供了一种全新的机制模块” )。

利用这个机制“模块”(module)。

利用这个机制,可以)。

利用这个机制,根据需要,根据需要,在不必对内核重新编译链接的条件将可安装模块动态的插入运行中的内核,下,将可安装模块动态的插入运行中的内核,成为内核的一个有机组成部分;成为内核的一个有机组成部分;或者从内核移走已经安装的模块。

正是这种机制,走已经安装的模块。

正是这种机制,使得内核的内存映像保持最小,的内存映像保持最小,但却具有很大的灵活性和可扩充性。

和可扩充性。

内核模块内核模块介绍可安装模块是可以在系统运行时动态地安装和卸载的内核软件。

严格来说,卸载的内核软件。

严格来说,这种软件的作用并不限于设备驱动,并不限于设备驱动,例如有些文件系统就是以可安装模块的形式实现的。

但是,另一方面,可安装模块的形式实现的。

但是,另一方面,它主要用来实现设备驱动程序或者与设备驱动密切相关的部分(如文件系统等)。

密切相关的部分(如文件系统等)。

课程内容内核模块介绍应用层加载模块操作过程内核如何支持可安装模块内核提供的接口及作用模块实例内核模块应用层加载模块操作过程内核引导的过程中,会识别出所有已经安装的硬件设备,内核引导的过程中,会识别出所有已经安装的硬件设备,并且创建好该系统中的硬件设备的列表树:文件系统。

且创建好该系统中的硬件设备的列表树:/sys 文件系统。

(udev 服务就是通过读取该文件系统内容来创建必要的设备文件的。

)。

Linux系统调用详细全过程

Linux系统调用详细全过程
方法分配和释放内存。
6
系统命令、内核函数
系统调用与系统命令

系统命令相对API来说,更高一层。每个系统命令
都是一个执行程序,如ls命令等。这些命令的实现
调用了系统调用。
系统调用与内核函数


系统调用是用户进入内核的接口层,它本身并非内
核函数,但是它由内核函数实现。
进入内核后,不同的系统调用会找到各自对应的内
常,CPU便被切换到内核态执行内核函
数,转到了系统调用处理程序的入口:
system_call()。
int $0x80指令将用户态的执行模式转变为内
核态,并将控制权交给系统调用过程的起点
system_call()处理函数。
4
system_call()函数
system_cal()检查系统调用号,该号码告诉内核
SYMBOL_NAME(sys_exit)
.long
.longSYMBOL_NAME(sys_read)
SYMBOL_NAME(sys_fork)
.long
.longSYMBOL_NAME(sys_write)
SYMBOL_NAME(sys_read)
.long
.longSYMBOL_NAME(sys_open)
SYMBOL_NAME(sys_write)
.long
.long
…… SYMBOL_NAME(sys_open)
……
……
……
.long
SYMBOL_NAME(sys_getuid)
.long SYMBOL_NAME(sys_getuid)
* 4
+
21
系统调用的返回
当服务例程结束时,system_call( ) 从eax

嵌入式linux系统分析及snmpd移植

嵌入式linux系统分析及snmpd移植

基于Linux/Net-Snmp构建DMS系统图1显示了典型的DMS系统结构图,其中中央电脑与DMS控制器之间的通信必须是基于NTCIP的。

同时,我们也可以在现场直接通过串口来控制控制器。

图1:典型的DMS系统框架在应用层,NTCIP建议使用SNMP协议来管理网络内的不同终端。

SNMP的工作模式是基于管理工作站/代理模式的。

运行网络管理程序的主机成为管理工作站,就是NTCIP网络内的中央电脑(管理中心);运行代理程序的网络设备就是我们的代理,也就是我们这里的DMS控制器。

SNMP的数据以一种标准化的层次结构进行布置。

这种强制的组织方式使数据空间既保持了通用性又保持了可扩展性。

命名的层次结构由MIB(管理信息库)组成,它是描述通过SNMP可访问的数据的结构化文本文件。

MIB包含了对特定数据变量的说明,数据变量用被称作对象标识符(OID)的名字来引用。

但是MIB只是一个给管理数据命名的约定。

SNMP名字空间和设备实际状态之间的映射关系必须由代理端代码支持才有用(包括代理的扩展开发和代理的应用程序开发)。

一、Net-Snmp在网络设备上我们使用的是基于Linux的net-snmp。

net-snmp除了提供用于响应管理站的代理程序snmpd外,还提供了一些命令行工具和一个可用于开发支持SNMP的应用程序的库组成。

在linux下通过命令行可以很方便的调用这些工具,在我们进行代理端的扩展开发时,可以使用它们来进行测试。

而开发下位机应用程序时,使用的就是该库提供的API。

下面的工作主要是在PC-Linux上完成的,在后续的工作中会逐渐的把它移植到嵌入式的开发板上。

安装完Net-Snmp后,我们需要修改代理的配置文件snmpd.conf,图2是修改前和修改后的对比。

首先ip地址的修改是指明snmpd支持的主机(即可以访问本代理的主机);把MyROGroup改成MyRWGroup,这样代理就支持了管理站对自己的写(set)操作。

深入linu内核x进程管理和调度

深入linu内核x进程管理和调度

第2 章进程管理和调度2.1 进程优先级1、硬实时进程有严格的时间限制——系统必须保证不会超过某一时间范围。

2、软实时进程是硬实时进程的一种软化形式。

3、多数进程是没有特定时间约束的普通进程,可以根据重要性来分配优先级。

2.2 进程的生命期1、僵尸状态:资源已经释放,但是PCB表里还有对应的表项。

2、抢占式多任务处理(1)从用户状态切换到核心态有两种方式:系统调用、中断。

(2)判断如下进程可以被抢断:⏹普通进程总是可能被抢占,甚至有由其他进程抢占。

⏹系统处于核心态并正在处理系统调用,那么系统中的其他进程是无法夺取其CPU时间的。

⏹中断可以暂停处于用户状态和核心态的进程。

2.3 进程表示1、state指定进程的当前状态,可用以下值:⏹TASK_RUNNING——进程处于可运行。

⏹TASK_INTERRUPTIBLE——等待某事件或资源而睡眠的进程。

⏹TASK_STOPPED——进程停止运行。

..............2、Linux提供资源限制机制,该机制利用了task_struct中的rlim数组。

其中包括软限制(当前的资源限制),硬限制(该限制的最大容许值)。

2.3.1 进程类型典型的UNIX的进程包括:由二进制代码组成的应用程序、单线程、分配给应用程序的一组资源。

新进程是使用fork和exec系统调用产生的。

2.3.2 命名空间1、概念⏹只使用一个内核在一台物理计算机上运行,所有的全局资源都通过命名空间抽象起来。

这使得一组进程放置到容器中,各个容器彼此分离。

⏹新的命名空间可以用下面两种方法创建:(1)在用fork或clone系统调用创建新进程时,有特定的选项可以控制是与父进程共享命名空间,还是建立新的命名空间。

(2)unshare系统调用将进程的某些部分从父进程分离,其中也包括命名空间。

2、实现⏹命名空间的实现包括两个方面:每个子系统的命名空间结构,将此前所有的全局组件包装到命名空间中;⏹将给定进程关联到所属各个命名空间的机制。

Linux内核的cpufreq(变频)机制

Linux内核的cpufreq(变频)机制

Linux内核的cpufreq(变频)机制linux低功耗研究也有一段时间了,基本把低功耗的实现方式想清楚了(主要分成机制和策略),这段时间的工作主要在机制上。

暂时想实现的主要的机制有:cpu级,设备驱动级,系统平台级。

管理颗粒度不断递增,形成三驾马车齐驱的形势。

cpu级:主要实现比较容易的在系统处于目标在于频繁发生、更高粒度的电源状态改变,主要的实现方式为idle,包括今天的主要想讲的动态主频。

设备驱动级:主要实现对单个设备驱动的管理(suspend,resume等),通过系统监测将闲置的设备,通过从用户态对sys文件目录动态进行单个驱动设备的管理,置于省电模式。

系统平台级:目标在于管理较大的、非常见的重大电源状态改变,用于减少产品设备在长时间的空闲之后,减少电源消耗。

主要实现方式是依托linux内核所支持的apm技术,实现整个系统的睡眠/恢复(sleep)这几个层次其实并不是相互独立的,都是相互交叉的,比如系统平台级的睡眠不可避免会涉及到cpu的sleep模式和设备驱动的挂起,而动态主频的实现除了cpu本身的支持也需要外围驱动随着主频变化做出相应的适应活动。

因此这里的分级只是一种粗范围的,逻辑上的分层。

前段时间还调研了一下IBM和Monta Vista搞得那套DPM(Dynamic Power Management)机制,看了不少论文和观点,总的感觉就是太过复杂而且也不是很实用,感觉噱头大过实际功效,(因此这套机制始终还不能进入内核的mainline),言归正传,还是重点讲述下cpufreq技术。

一、为什么要cpufreq?关于要不要实现cpufreq技术,我也纠结过,一个原因是:当时对内核如何提供这么一套动态变频的机制还不了解,只觉得应该非常麻烦,因为涉及到外围驱动的参数更新,另外一个原因是:在SEP4020这种体量的处理器上跑linux,即使运行在最高频率时的处理能力可能也不是很富余,我再给它降频还有没有意义?挣扎之后还是觉得要实现它,我也给自己列了这么几条原因:1. 虽然cpu在板级中已不是主要的耗电源,但是仍然占着举足轻重的位置,功耗机制到最后就是几毫安几毫安的扣了,降频肯定能在一定程序上节约功耗那我为什么不采用?2. 细化功耗管理的颗粒度,为应用程序提供更多的功耗节省机制3. 对普通的应用,系统可以运行在维持平台运作的最低频率,在有处理任务时,变频机制会自动切换到合适的高主频,并且在任务结束时重回省电的低主频,这样就解决了我之前的第二个疑惑。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

简析linux核的执行流程----从bootsect.s到main.c(核版本0.11)Linux启动的第一阶段(从开机到main.c)3个任务:A、启动BIOS,准备实模式下的中断向量表和中断服务程序。

B、从启动盘加载操作系统程序到存。

C、为执行32的main函数做过渡准备。

存变化如下:①、0xFE000到0xFFFFF是BIOS启动块,其中上电后第一条指令在0xFFFF0。

②、而后0x00000到0x003FF总共1KB存放中断向量表,而接下去的地址到0x004FF共256B存放BIOS数据,从0x0E05B 开始的约8KB的存中存放中断服务程序。

③、利用BIOS中断0x19h把硬盘的第一扇区bootsect.s的代码加载到存中,即0x07c00处,后转到该处执行。

④、将bootsect.s的代码复制到0x90000处。

⑤、利用中断0x13h将setup.s程序加载到存0x90200处。

⑥、再将剩余的约240个扇区的容加载到0x10000~0x2EFFF 处。

⑦、开始转到setup.s处执行,第一件事就利用BIOS提供的中断服务程序从设备上获取核运行的所需系统数据并存在0x90000的地址处,这时将原来bootsect.s的代码覆盖得只剩2Byte的空间。

⑧、关中断并将系统代码复制到0x00000处,将原来放在这里的中断向量表与BIOS数据区覆盖掉,地址围是0x00000~0x1EFFF。

同时制作两表与两寄存器。

⑨开地址线A20,寻址空间达到4GB,后对8259重新编程,改变中断号。

⑩、转到head.s(大小是25K+184B)执行,执行该程序完后是这样的:0x00000~0x04FFF:页目录与4个页表,每一项是4KB,共20KB;0x05000~0x05400:共1KB的空间是软盘缓冲区;0x05401~0x054b8:共184B没用;0x054b9~0x05cb8:共2KB的空间存中断描述符表;0x05cb9~0x064b8:共2KB的空间存全局描述符表;之后就是main函数的代码了!第二阶段、从main.c函数到系统准备完毕阶段。

第一步:创建进程0,并让进程0具备在32位保护模式下载主机中的运算能力。

流程是:复制根设备和硬盘参数表(main.c中的102、110、111行)物理存规划格局(main.c的112行~126行,其中有rd_init函数定义在kernel/ramdisk.c中,此函数用于虚拟盘初始化;而mem_init函数是用于存管理结构初始化,定义在mem/memory.c中,该函数页面使用虚拟盘设置与初始化次数均设置成100,然后再依据主存的起始位置和终止位置将处于主存的所有页面的使用次数全部清零,系统以后把使用次数为0的页面视为空闲页面。

)存管理结构mem_map初始化异常处理类中断服务程序挂接(在main.c的127行,trap()函数定义kernel/trap.c,目的是将各种中断与中断描述符表挂接。

)初始化块设备与字符设备请求项结构(在main.c的128、129行,blk_dev_init() 定义在kernel/blk_dev/ll_rw_blk.c,chr_dev_init()定义在kernel/chr_dev/tty_io.c)将串口与显示器外设的中断服务程序挂接(在main.c的130行,tty_init()定义在kernel/chr_dev/tty_io.c)开启时间设置(在main.c的131行,time_init()定义于main.c函数76行startup_time)系统开始激活进程0(在main.c的131行,sched_init()定义在kernel/sched.c函数中,该函数实现进程相关事务设置依据时钟中断设置,系统调用服务程序挂接。

系统调用函数是对用户程序的最基本支持,利用的是进程相关事务初始化设置系统调用软中断,详细见下面讲的。

)时钟中断设置系统调用服务程序挂接初始化缓冲区管理结构(在main.c中133行,buffer_init(buffer_memory_end)定义fs/buffer.c)初始化硬、软盘(main.c中134、135行,hd_init与floppy_init 定义于kernel/blk_drv/hd.c和kernel/blk_drv/floppy.c)开中断(main.c中136行,sti())第二步:以进程0为母本创建进程1,使进程1不仅仅具备进程0所拥有的能力,而且还能以文件的形式与外设进行数据交互。

流程是:操作系统为进程0创建进程1做准备main.c中137行,move_to_user_mode()定义在include/asm/system.h,实现从核态到用户态。

进程0正式开始执行,而后执行main.c的138行的“if(!fork())”,开始创建在进程槽中为进程1申请一个空闲位置并获取进程号进程1,此时将执行unisted.h中的syscall0宏函数,得到一个编号,对于fork函数,其值是2,具体在这个程序中的第62行有定义,然后执行软中断复制进程0的信息之前,先将一些数据压栈,进入系统调用阶段,跳到核态,执行kernel/system_call.s中的代码,将一些寄存器的值压栈后,通过刚才在unisted.h中给eax赋值初步设置进程1管理结构的2偏移值在系统调用sys_call_table 中找到sys_fork函数,跳到该函数执行。

进入后首先申请一个空闲位置并获取进程号。

这同样在system_call.s函数中的sys_fork 进程0创建进程1的过程中发生时钟中断中的_find_copy_process,再跳到该函数的定义处kernel/fork.c中,后返回到sys_fork中,在从中断返回复制进程信息前,再将一些数据压栈,此时有一个寄存器的值和前面的不一样,那就是eax,此时是1,它从task[64]中得到的。

之后执行copy_process,跳到调整进程1的管理结构定义处kernel/fork.c中,设置进程1的管理结构。

假如此时发生时钟中断,系统会响应并执行kernel/system_call.s函数中的timer_interrupt定义处,先压栈后设置进程1的线性地址空间及物理页面进入kernel/sched.c的do_timer函数,别忘了此时仍在进程0执行,然后便发现时间片还没完,所以跳出,并返回到ret_from_sys_call。

这是继续调整进程1的管理结构在kernel/system_call.s中定义的,接着直接将刚才的压栈数据出栈,继续完成刚才创建进程1的任务,即在fork.c中继续调整进程1的管理结构,同时设置进程进程0准备切换到进程1 1的线性地址空间及物理页面,直到执行到这条语句“p->state=TASK_RUNNING;return last_pid;”,标志着系统切换到进程1执行进程1创建完成。

后跳出copy_process.c函数,返回到system_call.s,将压栈的进程1开始执行的寄存器值出栈,此时eax是1。

后中断返回,进程由从核态变为用户态,即到了unisted.h的“if(_res>=0)”这条指令中,_res的值就是eax的值,一判断成立,就返进程1开始以数据块的形式操作硬盘回该值。

最后回到了main.c的“if(!fork())”中,一判断不成立,跳出执行下一条指令“for(;;)pause();”,同理Pause函数也和fork函数一样,这里就不将找到的缓冲块与请求项挂接讲了,进入sys_pause()后将进程0置为可中断等待状态,并调用在kernel/sched.c定义的schedule()函数切换进程。

进程切换中断返回后执行了第一条语句将请求项与硬盘处理函数挂接是“if(_res>=0)”,一判断,刚存的eax值为0,返回到“if(!fork())”判断为真,执行init()函数,这在main.c定义。

进入init.c后其程序执行流程见附录,进行硬盘读盘前的工作准备各个程序执行目的正如左边写的一样。

给硬盘下达读盘命令进程1由于等待读盘操作挂起系统切换到进程0执行进程0执行过程中发生硬盘中断硬盘中断服务程序响应后,进程0继续执行再次响应硬盘中断,并唤醒进程1读盘操作完成后进程1继续执行进程1继续设置硬盘管理结构进程1获取软盘超级块,为加载根文件系统做准备进程1备份超级块数据进程1将根文件系统从软盘拷贝到虚拟盘进程1开始加载根文件系统进程1准备加载根文件系统超级块进程1继续加载根文件系统进程1准备获取根目录节点进程1加载根目录节点进程1结束加载根文件系统的过程进程1与核文件表挂接,为打开文件做准备确定打开操作的起点获取枝梢i节点---dev目录文件的i节点确定dev的目录文件i节点为枝梢节点继续返回枝梢i节点查找tty0文件的i节点将tty0设备文件的i节点,返回给sys_open系统调用分析tty0文件i节点设置文件管理结构并返回给用户进程进程复制tty0文件句柄进程1继续复制tty0文件句柄第三步:以进程1为母本创建进程2,使进程2在全面具备进程1所拥有的能力和环境的基础上,进一步具备支持”人机交互“的能力,最终实现准备阶段完成。

流程如下:进程1准备创建进程2与进程0创建进程1一样,创建进程2,复制进程1的管理结构,复制页表、页目录项等,创建进程2后即执行到init/main.c 中复制进程2的管理结构并进行调整176行与186行,分别是:if(!(pid=fork())中子进程即进程2执行,而父进程(进程1)执行186行的if(pid>0),父进程调整进程2管理结构中与文件有关的容进入wait函数,等待!进入wait函数后还做了一些动作:首先查找自己的子进程,确定是进程2后,判断进程1执行过程中发生时钟中断进程2是否处于终止状态或是僵死状态,一判断不是,就将进程1设置为可中断等待状态,继而调用schedule()函数进程1从时钟中断返回准备切换到进程2执行切换到进程2。

进入进程2后开始加载shell程序。

首先执行init/main.c中180行的“close(0);”,就是进程1查找它自己的子进程解除filp[20]与file_table[64]的第一项关系,这是从进程1继承过来的。

然后是“if(open("etc/rc",O_RDONLY,0))”,对进程2的状态进行处理其中是将进程2的管理结构指针表filp[20]的第一项与file_table[64]的第一项建立一个关于资源配置的文件,而后再执行切换到进程2执行execve函数,并映射到sys_execve系统调用。

相关文档
最新文档