湘潭大学Linux内核分析知识点.docx

上传人:b****6 文档编号:5867870 上传时间:2023-01-01 格式:DOCX 页数:15 大小:123.73KB
下载 相关 举报
湘潭大学Linux内核分析知识点.docx_第1页
第1页 / 共15页
湘潭大学Linux内核分析知识点.docx_第2页
第2页 / 共15页
湘潭大学Linux内核分析知识点.docx_第3页
第3页 / 共15页
湘潭大学Linux内核分析知识点.docx_第4页
第4页 / 共15页
湘潭大学Linux内核分析知识点.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

湘潭大学Linux内核分析知识点.docx

《湘潭大学Linux内核分析知识点.docx》由会员分享,可在线阅读,更多相关《湘潭大学Linux内核分析知识点.docx(15页珍藏版)》请在冰豆网上搜索。

湘潭大学Linux内核分析知识点.docx

湘潭大学Linux内核分析知识点

第一章

1.Linux诞生于1991年10月25日。

2.Linux诞生和发展不可缺少的五个支柱:

1、UNIX最初的开放源代码版本为Linux提供了基本原理和算法。

2、RichardStallman的GNU计划为Linux系统提供了丰富且免费的各种实用工具。

3、POSIX标准的出现为Linux提供了实现与标准兼容系统的参考指南。

4、Tanenbaum的MINIX操作系统为Linux的诞生起到了不可忽略的参考作用。

5、互联网是Linux成长和壮大的必要环境。

第二章

1.操作系统主要有4部分组成:

硬件、操作系统内核、操作系统服务和用户应用程序。

2.操作系统内核的结构模式主要可分为整体式的单内核模式和层次式的微内核模式。

3.单内核的主要优点:

内核代码结构紧凑、执行速度快,不足之处:

层次结构性不强。

4.单内核模式可分为三层:

调用服务的逐层序层、执行系统调用的服务层和支持系统调用的底层函数。

5.Linux内核主要由5个模块构成:

进程调度模块、内存管理模块、文件系统模块、进程间通信模块和网络接口模块。

6.Makefile的三部分:

目标、先决条件和命令。

7.内核映像文件(Image)的三部分:

bootsect、setup、system。

通过build工具连接而成。

第三章

1.引导扇区是磁盘的第一个扇区(0磁头,0磁道,1扇区),自举程序(引导程序)的大小为512B,最后两个字节必须为0xaa55。

2.movw指令:

从ds:

si移动一个字到es:

di,然后根据标志寄存器中direct标志位,把si和di分别加2(d=0)或减2(d=1)。

Rep指令:

重复执行后面的命令,重复次数放在cx寄存器中,每执行一次后面的命令则把cx中的值减1,直到cx为0。

3.限制

(1)13中断一次只能读同一磁道上的扇区

(2)实模式下内存段大小不能超过64K

解决方法:

(1)一次读一个扇区,读完后如果内存段满了则调整到下一个内存段。

太慢!

(2)在读之前取磁道上剩余扇区大小和内存段剩余大小中的最小值M,读M/512个扇区。

4.磁盘读取规则:

当0磁头的某个磁道读完,下一次就读1磁头的相同磁道;当1磁头的某个磁道读完,下一次就读0磁头的下一个磁道。

5.Setup.s程序的功能:

1、1-106行:

获取并保存系统参数。

从0x90000内存块开始

2、113-126行:

移动system。

从0x10000到0x00000

3、130-193行:

进入保护模式。

6.保护模式下的两种内存管理机制:

分页和分段。

三种不同的地址:

1、逻辑地址:

包含在机器语言指令中的地址,由一个段:

段内偏移组成。

2、线性地址:

逻辑地址到物理地址变换间的中间层。

3、物理地址:

内存单元的地址。

7.分段:

保护模式下把内存分为多个段,每个段用一个描述符(数据结构)用来描述它的属性,包括段的开始地址、段长度、类型、访问权限等。

段描述符由8个字节组成。

8.两位RPL(RequestorPrivilegeLevel)指定了进程的特权级别,RPL<=DPL才能访问成功。

9.分段的实现:

(1)给定一个逻辑地址

(2)检查段选择子中的TI标志,决定段描述符是保存在哪个描述符表中,并到相应的寄存器中取得描述符表的基地址(3)把索引字段的值乘以8(段描述符的大小),加上描述符表的基地址,从而得到段描述符(4)用段描述符中段的基地址加上逻辑地址中的偏移量,得到了线性地址

10.特权级别:

数字越小,级别越高。

高级别特权可以访问低级别特权。

Linux用了两个级别:

0级内核态,3级用户态。

11.段机制有CPU自动实现,我们要做的事:

(1)定义好描述附表。

(2)把描述符的基地址装入gdtr或idtr。

(3)使用正确的段选择子。

12.Head.s程序的功能:

1、设置数据段段选择子和堆栈

2、设置中断描述符表

3、设置全局描述符表

4、设置页表,启动分页并调用内核启动函数main

13.保护模式下内存寻址的总结:

1.在程序中使用虚拟地址段选择子:

段内偏移

2.用段选择子作为索引,查找全局描述符表(基地址在gdtr中),得到段的基地址

3.用段的基地址+段内偏移得到线性地址

4.用线性地址的高10位作为索引,查找页目录表(基地址在CR3中),得到页表的基地址

5.用线性地址的次高10位作为索引,到上1步得到的页表中查找,得到页框的基地址

6.用页框的基地址+线性地址后12位得到物理地址

14.分页机制有CPU自动实现,我们要做的事:

(1)定义好页目录表和页表。

(2)设置页目录表和页表。

(3)把页目录表的基地址装入CR3中。

(4)启动分页。

15.

(1)在分段时有x=seg(x)即虚拟地址=线性地址

(2)在分页时有x=pg(x)即线性地址=物理地址(3)总体看有x=pg(seg(x))即虚拟地址=线性地址=物理地址

第四章

1.main_memory_start最小值可能是1MB,memory_end最大值可能是16MB,buffer_memory_end是缓冲区的结束标志。

2.mem_init(main_memory_start,memory_end)初始化内存模块。

Move_to_user_mode()创建进程0。

3.#defineEXT_MEM_K(*(unsignedshort*)0x90002)

#defineDRIVE_INFO(*(structdrive_info*)0x90080)

#defineORIG_ROOT_DEV(*(unsignedshort*)0x901FC)

此三个定义是读取系统参数。

4.staticvoidtime_init(void)函数的作用:

1、读CMOS的时钟值。

2、把用BCD码表示的时间转换为十进制。

3、计算从1970年1月1号0点到现在为止经过的秒数(kernel_mktime)。

5.fork系统调用:

两个进程有相同的数据段内容、堆栈段内容和代码段内容。

在父进程中,fork调用返回的是子进程的进程id在子进程中,fork调用返回的是0.

6.execve系统调用:

(1)fork调用后两个进程有相同的数据段内容,堆栈段内容和代码段内容。

(2)子进程调用execve后,子进程装入另外一个程序,两个进程的数据段内容、堆栈段内容和代码段内容都不同了。

第五章

1.中断管理的概念:

改变处理器正常执行顺序的事件。

中断来源:

硬件:

时钟、键盘、硬盘等。

软件:

异常:

CPU检测到的错误。

系统调用:

进程向OS发出的请求。

2.中断向量:

保护模式支持256个中断,每个中断用一个0到255的整数来标识,把这个整数称为中断向量。

0到31对应异常。

32到47对应硬件中断。

48到255预留,Linux使用了0x80作为系统调用。

3._set_gate(gate_addr,type,dpl,addr)作用:

用来设置中断描述符。

其中gate_addr:

描述符的地址。

type:

描述符的类型。

dpl:

使用描述符的最低权限。

addr:

中断处理函数的地址。

4.异常初始化:

trap.c中的trap_init()函数负责再次初始化中断描述符表,该函数在main

函数中被调用。

5.中断初始化:

在traps.c中的trap_init()函数的最后设置了并口(0x27)的中断描述符。

在sche.c中的sched_init函数的最后设置了时钟中断(0x20)的中断描述符。

6.系统调用初始化:

在sche.c中的sched_init函数的最后设置了系统调用(0x80)的中断描述符。

7.中断处理:

异常和中断发生时,进程肯呢个在用户态也可能在内核态。

系统调用肯定在发生在用户态。

(1)当发生中断时,如果当前进程运行在内核态,CPU会将EFLAGS、CS和EIP寄存器中的内容压入堆栈。

(2)当发生中断时,如果当前进程运行在用户态,CPU除了会将EFLAGS、CS和EIP寄存器中的内容压入堆栈外,还会把进程在用户态时使用的SS和ESP寄存器的内容压入堆栈。

(3)处理中断总是在内核态。

8.异常处理:

异常发生时,可能带有出错码。

如果有,则该出错码也会被CPU压入堆栈。

9.异常处理流程:

10.系统调用的输入:

(1)把子功能号放入eax中。

(2)如果还有其它参数(最多3个),则第1、第2和第3个参数分别放入寄存器ebx、ecx和edx中。

系统调用的返回值保存在eax中。

11.系统调用的数据结构:

函数指针数组sys_call_table[]

12.处理流程:

以子功能号作为索引查找sys_call_table,找到处理该功能的C语言函数,然后调用该函数。

13.进程的概念:

进程是程序的一次执行,是由代码段、数据段和堆栈段组成动态的实体。

在Linux中,把进程又称为任务。

进程是系统资源分配的基本单位,也是使用CPU运行的基本调度单位。

14.进程描述符:

为了管理进程,操作系统需要清楚地知道每个进程的属性,Linux用一个称为进程描述符(task_struct)的数据结构来描述。

15.进程描述符(状态,线性地址分布(代码,数据,bbs,用户态堆栈,环境参数),任务状态段(TSS)是保存任务的所有信息的内存段,共104B,1、寄存器保存区域。

2、内层堆栈指针区域。

3、地址映射寄存器区域。

4、其它字段。

局部描述符表)

16.TSS的段描述符在GDT中,当前进程的TSS的段选择子被保存在TR寄存器中。

17.任务切换过程:

首先,CPU中各寄存器的当前值被自动保存到TR所指定的TSS中(当前任务的TSS中)然后,下一任务的TSS的选择子被装入TR,最后,从TR所指定的TSS中取出各寄存器的值送到处理器的各寄存器中。

由此可见,通过在TSS中保存任务现场各寄存器状态的完整影响,实现任务的切换。

18.局部描述符表(LDT)包含任务私有内存段的描述符(也是一个内存段),LDT的端描述符在GDT中,当前进程的LDT端选择子在ldtr中。

Linux中LDT包含3个描述符,其中:

第0个没用,第1个描述的是代码段,该段的段选择子时0xf(1111),第2个描述的是数据段,该段的段选择子是0x17(10111)。

19.Linux内核堆栈:

Intel平台上进程在不同的特权级别下使用不同的堆栈。

在Linux中为进程在内核态建立的堆栈与进程描述符公用一块4K的内存块。

20.进程0:

进程0是一个特殊的进程,它是所有其他进程的祖先进程,位于进程树的根节点出。

多以其他的进程都是fork通过系统调用,复制进程0或者其后代进程产生的。

但是进程0却不是通过fork产生的。

21.创建进程0的步骤:

1、申请一个进程描述符与进程内核堆栈的共用体。

2、把进程描述符的地址放在task数组的第0项。

3、在GDT中设置进程0的甜丝丝段描述符和ldt段描述符(sched_init函数)。

4、把进程0甜丝丝段描述符的选择子和ldt段描述的选择子装载到tr寄存器和ldtr寄存器中。

注意:

sched_init函数运行完之后,进程0还是运行在内核态。

进程0此时使用的堆栈还是在head.s中设置的堆栈user_stack。

22.利用模拟中断返回的方法把进程0从内核态切换到用户态。

23.进程0的总结:

(1)move_to_user_mode()之后进程0运行在了用户态,但是请注意,这是进程0的堆栈仍然是user_stack。

也就是说进程0的用户态堆栈和系统堆栈是共享的,都是user_stack。

在move_to_user_mode()前,user_stack当做系统堆栈使用,在之后,变成了进程0的用户堆栈。

(2)进程0的内核态堆栈和其他进程的内核态堆栈一样,都在进程控制块task_struct所在页的高端。

23.intfind_empty_process(void)定义在fork.c中作用:

寻找task数组中的空位。

返回:

如果找到则返回空位索引,否则返回错误。

在Linux中,所有现存的进程的进程号不能相同。

24.intcopy_process(intnr,longebp,longedi,longesi,longgs,longnone,longebx,longecx,longedx,longfs,longes,longds,longeip,longcs,longefiags,longesp,longss)作用:

拷贝当前进程的描述符到子进程描述符中。

返回:

子进程的进程号。

25.intcopy_mem(intnr,structtask_struct*p)作用:

修改子进程的死有段的基地址,并拷贝当前进程的也目录项和页表。

参数:

nr——子进程在task数组中的索引,p——子进程描述符的指针。

返回:

0表示无错,小于0表示有错。

26.线性地址的分布:

4G的线性地址给64个进程使用,每个进程占64M的线性地址。

Task数组中的第n个进程占用线性地址是n*64M——(n+1)*64M。

task数组中的第n个进程的所有段的基地址设为n*64M。

27.任务切换的步骤:

1、从指令JMP的操作数种获取新任务的TSS段选择子。

2、检查新任务的TSS描述符是否存在。

3、在当前任务的TSS中保存当前任务的状态。

4、为TR装载新任务TSS所需要的段选择子,从新任务的TSS中装载新任务的状态到处理器中。

5、开始执行新任务。

28.voidschedule()作用:

选择一个任务并与当前任务进行切换。

29.调用schedule。

(1)时钟中断发生时:

进程处于用户态被动放弃CPU(被抢夺),进程的状态仍然是可运行状态。

(2)系统调用返回时:

进程处于内核态被动放弃CPU(被抢夺),进程的状态仍然是可运行的状态。

(3)睡眠函数内:

进程处于内核态主动放弃CPU,进程的状态是不可运行状态。

30.时钟中断:

Linux设置时钟中断频率为10毫秒,每次中断时调用timer_interrupt,定义在system_call.s中。

31.进程睡眠:

当进程请求的资源无效时,进程将会进入睡眠状态,知道资源有效时。

每个资源上都会有一个等待队列,在该队列上排队的就是为等待此资源而进入睡眠状态的进程。

32.进程可以以两种状态进入睡眠:

不可中断睡眠(sleep_on),可中断睡眠(interruptible_sleep_on)。

33.voidsleep_on(structtask_struct**p)作用:

把任务设置为不可中断睡眠,并把任务挂在某个等待队列上。

参数p——等待队列的头指针。

当资源有效时,在该资源等待队列上的进程全部都被唤醒。

有可能还会发生资源冲突。

常见的使用方法是while(资源无效)sleep_on(资源等待队列头指针的指针)。

34.voidinterruptible_sleep_on(strcttask_struct**p)作用:

把任务设置为可中断睡眠,并把任务挂在某个等待队列上。

参数:

p——指向等待队列的头指针的指针。

当资源有效时或是任一进程有信号时,在该资源等待队列上的进程全部都被唤醒。

有可能还会发生资源冲突或没有信号而被唤醒。

常见的使用方法是:

while(资源无效&&没有信号)interruptible_sleep_on(资源等待队列头指针的指针)。

35.进程终止:

进程终止时,要释放它占用的所有资源,包括:

1、进程描述符和内核对战占用空间。

2、task数组中的一项。

3、GDT中的LDT何TSS描述符。

4、页表和页目录占用的物理页面。

5、代码和数据占用的物理页面。

6、打开的文件。

36.进程资源的释放:

GDT中的两项不用特意清楚,以后别的进程要用时直接覆盖上去就了。

因此,进程要结束就要做好如下几件事情:

1、释放所有物理页面。

2、关闭所有打开的文件。

37.进程终止的问题:

通常父进程在子进程终止后,需要查询子进程的终止状态,该状态保存在子进程的进程描述符中。

如果,子进程终止时释放了进程描述符,则无法查询终止状态。

由父进程负责回收子进程的进程描述符。

但是如果父进程在子进程之前终止,谁来负责回收子进程的进程描述符?

进程在终止时,把所有未终止的子进程过继给进程1。

由进程1负责接收这些子进程终止信号,并回收子进程的进程描述符。

38.intsys_exit(interror_code)作用:

释放进程占用的物理内存并关闭进程打开的文件。

参数:

error_code退出码。

返回:

无意义。

39.intsys_waitpid(pid_tpid,unsignedlong*stat_addr,intoptions)作用:

如果任意一个符合pid条件的子进程僵死,则释放子进程占用的进程描述符;如果所有符合pid条件的子进程都不处于僵死状态,则按照potion选项或者等待或立即返回。

参数:

pidpid>0等待进程号为pid的子进程。

pid=0等待进程组号等于当前进程组号的任何一个子进程。

Pid=-1等待任何一个子进程。

pid<-1等待进程组号等于-pid的任何一个子进程。

Stat_addr:

存放子进程的退出码。

Options:

options中WNOHANG置位:

表示如果没有满足pid标识的子进程是僵死状态,则当前进程马上返回;否则当前进程挂起。

返回:

正常返回子进程的pid,出错返回负数。

40.信号提供了一种进程间通讯的方式,这种机制是异步的。

Linux支持32个信号,每个信号用一个整数数值来标识。

41.信号处理数据结构:

longsignal:

对应32个信号,向进程发送信号就是把signal中信号对应的那一位置1。

longblocked:

对应32个信号,如果某个信号对应的那一位置1,表示该信号被屏蔽。

Signal&~blocked表示进程中未被屏蔽的信号。

Structsigaction{void(*sa_handler)(int);//信号处理函数指针sigset_tsa_mask;//在处理当前信号时需要屏蔽的信号,一般屏蔽信号Intsa_flags;//改变信号处理过程的标志void(*sa_restorer)(void);//恢复函数入口地址,用于清除用户堆栈这个函数由libc提供,用户无法自行设置}。

42.信号响应函数是void(*)(int)类型的,内核在signal.h第45行地应了两个特殊的响应函数。

#defineSIG_DFL((void(*)(int))0)#defineSIG_IGN((void(*)(int))1)

进程对于SIG_DFL的处理一般是结束进程,对于SIG_IGN一般是忽略。

在signal.h第37行由sa_glags标志值的定义#defineSA_NOCLDSTOP1//子进程处于停止态时,不处理SIGCHLD#defineSA_NOMASK0x40000000//不阻止在信号的处理程序结束后再受到该信号。

#defineSA_ONESHOT0x80000000//信号处理函数一旦被调用过,就恢复到SEG_DFL。

43.注册信号处理函数:

这一步可以省略,在省略情况下信号的处理函数是SIG_DFL。

参见进程0的定义。

进程也可以注册自己的信号处理函数。

44.信号注册系统调用:

intsys_signal(intsignum,longhandler,longrestorer)作用:

注册一个自定义信号处理函数。

参数:

signum——信号值,handler——信号处理函数指针,restorer——恢复函数。

返回:

上一次注册的处理函数指针。

Intsys_sigaction(intsignum,conststructsigaciton*action,structsigaction*oldaction)作用:

注册自定义的信号处理结构。

参数:

signum——信号值,action——自定义的sigaction指针,oldaction——用于存放上次注册的sigaction。

45.发送信号:

intsys_kill(intpid,intsig)作用:

向进程或进程组发送信号。

参数:

pid>0:

向指定进程发送信号,pid=0:

向当前进程所在组的所有进程发送信号,pid=-1:

向除进程0之外的所有进程发送信号,pid<-1:

向进程组为-pid的所有进程发送信号,sig:

信号值。

46.信号处理:

信号时一种异步通信机制,当进程收到信号后,并不马上处理。

只有等到进程系统调用返回,或者中断返回后,才处理信号。

这时程序运行到system_call.s中的ret_from_sys_call标号地址处,先检查信号位图,找到第一个允许响应的信号值,将之压入内核堆栈,然后调转到do_signal()函数。

Do_signal根据信号值调用对应的信号处理函数。

难点在于当进程注册了自定义信号处理函数时,内核怎么调用用户态的函数?

通过构造堆栈。

Voiddo_signal(…)作用:

根据信号值调用信号处理函数。

47.屏蔽信号:

intsys_ssetmask(intnewmask)作用:

为进程设置信号屏蔽位图,参数:

newmask——新的信号屏蔽位图,返回:

老的信号屏蔽位图。

48.信号处理流程:

第六章判断硬盘信息有效标志55AA

1.设备管理模块读处理过程:

1、进程向缓冲区模块提出读块(2扇区)请求。

2、缓冲区模块检查该块是否已经被缓冲。

如果已经被缓冲,则直接返回缓冲的块;否则,向设备管理模块提出读请求。

3、设备管理模块接受请求。

如果设备不忙,则向设备发送命令;否则,把请求插入到设备的请求队列中。

4、缓冲区模块挂起进程。

5、设备控制器从设备中读入数据岛自己的缓冲区,并产生中断。

6、设备中断处理程序把数据从控制器缓冲区读到内存缓冲区,然后唤醒进程。

2.设备管理模块写处理过程:

1、缓冲区模块决定要回写被缓冲的块。

如果该块是脏的,向设备管理模块提出写请求。

2、设备管理模块接受请求。

如果设备不忙,则向设备发送命令和数据;否则,把请求插入到设备的请求队列中。

3、缓冲区模块挂起进程。

4、设备控制器把数据写入到设备并产生中断。

5、设备中断处理程序唤醒进程。

3.设备号:

设备室通过主设备号和次设备号(两者构成额物理设备号)来进行区分的。

主设备号:

区分不同类型的设备。

次设备号:

区分相同类型设备中的个体。

逻辑设备号:

用于区分不同的设备,逻辑设备号=主设备号<<8+次设备号。

4.块设备结构:

每个块设备都有自己独立的请求队列。

为方便管理队列,建立了快设备结构。

Structblk_dec_struct{void(*request_fn)(void);structrequest*current_request;}

Linux支持多种块设备,为所有这些块设备结构建立了一个数组,数组下标就是设备的主设备号。

Structblk_dev_structblk_dev[NR_BLK_DEV]#defineNR_BLK_DEV7

5.voidll_rw_block(intrw,structbuffer_head*bh)作用:

完成低级读写操作,参数:

rw——读写命令,bh——缓冲区头指针。

此函数为块设备管理模块的入口函数。

6.电梯算法:

磁头朝一个方向运动来满足该方向上最近的请求。

当该方向上所有的请求都处理完之后,则反方向来处理其它请求。

例如:

磁头正在第5柱面处理请求,磁头向内运动,其后有5个请求到达,分别是第7、2、6、1、8柱面上的请求。

则处理顺序是:

567821.

一般情况下,所有请求都能获得合适的处理。

但是,在极端情况下仍然会造成饿死现象。

例如:

上例中,如果不断地有第5柱面之后的处理请求,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 自然科学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1