新闻  |   论坛  |   博客  |   在线研讨会
linux内核学习
wangderfvl | 2010-06-30 13:44:23    阅读:62482   发布文章

原文地址:linux内核学习笔记作者:伊人何处
来源:(http://blog.sina.com.cn/s/blog_4bc179a80100hf1g.html) - [转载]linux内核学习笔记_雪后DE阳光_新浪博客

1.
对于形如#define __LIBRARY__
后面没有任何东西,用处何在???
观察文件include/unistd.h便可以看到#ifdef __LIBRARY__

2.
fork()函数产生新进程
新进程也应当是从当前地方fork()之后开始执行。

3.
c语言外部变量与外部函数

4.
系统调用,嵌入式汇编,内联函数,c语言汇编相互调用,

5.汇编语言中的标号的下划线?

变量定义是混合编程的基本问题。C程序与汇编程序定义的变量相互之间可以进行访问。在汇编程序中定义时,需要在变量前加下划线“_”,然后再用.global定义为全局变量。在C程序中则需要说明为extern变量。
C语言中常用的数组与指针也可以很方便地在汇编程序中定义并互相访问。如例,在汇编语言中用.usect定义占用6*32个字的全局变量_AC_RSLT,在C程序中被说明成一个6*32的16位无符号数的二位数组。当然,在汇编程序中,数据的存放格式需要满足C对二维数组数据存放格式的要求。即在存储器中,从低地址到高地址,二维数组的内容从第一行起各行依次放入存储器中。实际上,这个数组定义也可以看作是指针定义。
汇编程序:
_AC_RSLT .usect “ADDATA”, (6*32)
.global  _AC_RSLT
C程序:
extern INT16U  AC_RSLT[6][32];
( extern  INT16U  *AC_RSLT; )

6.
调度实现原理
再系统状态中,进行schedule()函数的调用

7.
每个程序都具有内核堆栈段和用户堆栈段

8.
boot程序无法直接将程序直接挪到地址0处,原因是一开始数据从启动盘上移动到内存中依靠的是bios的中断处理程序。而其中断向量表即存放在地址0处。

9.如何从内核态将控制权交给用户态进程?
模拟中断返回动作,使用iret指令。

10.观察一个最简单的操作系统。
首先bios负责将内核的开始部分装入内存,然后boot负责装入其他部分,再是模式下完成一些初始化,然后跳到程序开始出运行,设置中断处理程序,设置描述符表,描述符表的内容保存有任务的tss属性,即任务的代码位置等。
进入第一个进程,通过时钟中断完成切换。

操作系统制作过程可以如下:
编写一个操作系统,将可执行代码放置在启动盘的第一扇区内。
重新启动电脑,进行BIOS的界面设置,并且把软盘设为第一个启动的设备。然后插入软盘,电脑从软盘上启动。

11.
seg cs ! 表示下一条语句操作 在CS段寄存器所指的段中

12.内核映像读取时的64k单位相关。
读取映像文件得时候是以64k为单位的,但是不是意味着内核的image从硬盘读到内存是不连续存放的,首先因为一个硬盘块大小是512字节,刚好是64k的因数。其次内核的bootsect读取得时候,是要判断是否快到64k,如果超过了,就计算还可以读取多少块,然后再进行读取。

13.linux内存中页表与页目录项与内核内码的存放关系??是否造成冲突,还是进行了覆盖或开始就是分离的?
本身head.s中的gdt,ldt等数据结构也是system映像的内容。
可以参见 《linux内核完全注释>>P33页

linux进行中断处理的函数如何体现从用户态到内核态的转换的?哪个函数实现了此项功能?/
int指令将触发导致切换(关于中断服务程序地址的转换应该由硬件或者bios实现):伴随如下动作

谁改变了代码段,数据段,堆栈段,使它们指向了内核态?
由于运行级别发生变化,会从TR指向的TSS内容里的内核堆栈进行切换。记得曾经看到关于各个段寄存器的影子寄存器的内容变化条件为:
iret指令与ret。
int与iret执行了相反的动作
在执行INT指令时,实际完成了以下几条操作:
(1)由于INT指令发生了不同优先级之间的控制转移,所以首先从TSS(任务状态段)中获取高优先级的核心堆栈信息(SS和ESP);
(2)把低优先级堆栈信息(SS和ESP)保留到高优先级堆栈(即核心栈)中;
(3) 把EFLAGS,外层CS,EIP推入高优先级堆栈(核心栈)中。
(4) 通过IDT加载CS,EIP(控制转移至中断处理函数)
然后就进入了中断0x80的处理函数system_call了

 

14.asm.s文件中的中断处理程序no_error_code:中
push $0
lea 44(%esp),%edx的作用?
中断处理函数的参数。

15.分页是从0x100000开始的,那末内核运行的时候有没有使用分页机制?
head.s中p198行,已经有设置分页的代码,将内核的4个页表放入了页目录同时将4个页表的内容进行了填写,最后设置了页目录基址寄存器CR3,然后修改CR1使PG标志为1,启动分页机制。

16.系统调用的参数传递方式,如何setuid(int uid)->_syscall_->setuid(int uid)传到相应的c处理函数?类似的中断处理c函数是如何获得其参数的?

观察kenel/asm.s文件,可以看到两个个入栈操作,但是中断处理的c函数都是有两个相同的参数。
至于系统调用还需要其他方法。
具体应该如下:
_system_call:
 cmpl $nr_system_calls-1,%eax
 ja bad_sys_call
 push %ds
 push %es
 push %fs
 pushl %edx
 pushl %ecx  # push %ebx,%ecx,%edx as parameters
 pushl %ebx  # to the system call
 movl $0x10,%edx  # set up ds,es to kernel space
 mov %dx,%ds
 mov %dx,%es
 movl $0x17,%edx  # fs points to local data space
 mov %dx,%fs
 call _sys_call_table(,%eax,4)

17.kenel/sched.c里面的showtask函数中的((char*)(p+1))[i]表示的是哪个地址的数据?

p+1不是对于指针数量上加一,而是表示从当前的位置跳过当前指针指向类型长度的空间,对于win32的int为4byte;
另外内核堆栈是从页末尾开始使用的,所以这样的计算空闲堆栈区是正确的。
指针数组的定义形式为:int *p[10];

18.kenel/sched.c中为什莫说把软盘驱动的程序放在这里便于使用时钟?
如何监视各个进程的运行时间的,在何处完成了counter值得修改?哪个中断处理了系统定时处理?

do_timer调用了schedule;
同时可以看到该程序中,对于内核态的时候不执行do_timer
同时在 schedinit()中,set_intr_gate(0x20,&timer_interrupt);
timer_interrupt位于sytemcall.s中


19.knenl/signal.c信号处理机制如何产生信号,如何保存信号,如何通知其他程序信号的发生?

信号事件的发生有两个来源
:一个是硬件的原因(比如我们按下了键盘),一个是软件的原因(比如我们使用系统函数或
者是命令发出信号). 最常用的四个发出信号的系统函数是kill, raise, alarm和setit
imer函数. setitimer函数我们在计时器的使用 那一章再学习.

本程序通过修改其它程序的信号数据结构(该数据结构保存,但是其他程序如何知道本身数据的变化?

信号接收者在进行系统调用完成的时候会进行信号处理。详见:kenel/system_call.s,line 119

是否所有的程序都会进行系统调用?如果进程无系统调用如何处理信号?系统调用发生的时间?

程序运行在内核态,比如如果发生时钟中断,就会调用schedule();实际情况也是如此
可以参考kenel/system_call.s中关于时钟中断timer_interrupt的中断处理程序,可以发现它最终也是要jmp ret_from_sys_call;也就是说也要执行signal处理程序部分。

20.sigaction如何实现多信号的保存?

在include/linux/sched.h中的task_struct结构中的变量sigaction[32]保存了所有信号的数据结构;INIT_TASK变包含了对32个信号初始化。
signa变量既是所有32个信号的位图

sig_action()比传统信号处理 signal()到底有何优点?

21.如何进行硬盘读写?

当程序需要读写的时候,首先向缓冲区管理程序发出申请,如果缓冲区已经有了,就直接对缓冲区头指针返回给程序并唤醒该程序进程。否则就要调用ll_rw_block().

对于请求列表如何,保证所有的请求都被处理?
ll_rw_block()采用make_request();然后make_request()中会调用add_request()将请求添加到请求队列里面;add_request()中调用了do_hd_request();do_hd_request()会调用hd_out()给控制器发送读写命令;当完成时中断处理程序即read_intr()和write_intr(),而这两个程序会再一次调用do_hd_request(),保证所有的请求都可以得到处理。参照P202页

22.主设备号,为何叫做主?
根据种类分的,每个种类又有不同的个数,具有子或从设备号。

23.linux/kenel/blk_dev/blk.h被include的时候,可以发现会根据MAJAR_NR进行define
所以include blk.h之前都会有define MAJAR_NR这句

24.对于一个正在读取的request如何插入其他的?如何保证current指针不被乱改?

ll_rw_block(),只有在request对列为空的时候才进行处理request,否则只进行插入操作。

25.电梯算法为何只是进行了一次比较,如何保证有序性?

因为所有的插入都是进行了同样的比较,所以保证了,插入之前的所有request都是顺序存放的。

26.linux重要思想及概念

硬件操作请求对列
程序自拷贝,系统boot
进程调度器
系统调用
向量表
特权级

27.从最最简单的操作系统0.01开始入门,理解一个操作系统
早期的linux如何实现开发,程序安装,程序执行的?a.out文件

28.将一个网络的client程序封装成系统调用,然后加入到内核代码中
编译内核生成内核image文件,然后安装内核?????????????
将可执行文件进行格式转换。

29.linux内核的缺页异常到底是硬件触发还是软件触发的?内核中某个进程的物理页大小的分配根据是什么?交换是否指本进程内部的交换,还是整个系统层次的页交换?

缺页中断是由cpu发出的。

30.文件系统本身相关的操作程序是由操作系统包含的还是文件系统包含的?

31.对于linux虚拟内存管理的理解,以及cs+eip;pc;段选择符;段描述符;GDT;LDT;页目录;页表等概念的关系。

linux虚拟内存管理:程序写的时候采用的是虚拟地址或者称逻辑地址,用cs+EIP表示;

虚拟地址-〉线形地址-〉物理地址

程序执行时首先得到cs+eip;
然后cs存放的是段选择符;
根据段选择符需要根据LDT,GDT保存的段描述符首地址查找段描述符,然后将其加载到影子寄存器,里面包含了段基地址和段限长和权限信息,根据这些信息求出线形地址;
然后线性地址根据分页原理,首先找到页目录,然后页表,然后偏移,求得物理地址。

指令存放在IR(指令寄存器)里面,cs+eip,默认下eip应当是自增的,只有发生转移的时候才可能修改它们的值。

对于linux来说,线形地址是有所有进程占有的,第i个进程占用n*64m开始的地方


如何保证GDT的全局共享和LDT的局部独立?究竟是如何引用它们的,以及那些代码体现了内核是被共享的?

switch操作的切换,是否使用跳转实现的?

如何保证相同虚拟地址不被转换到同一物理地址,或者是否允许程序具有相同虚拟地址?所谓的虚拟地址是何时获得的,编译还是运行时分配的?

分页是操作系统支持的还是硬件支持的?硬件提供的支持体现在何处?

分页应当是硬件提供支持的,在控制寄存器里有一位来标识是否开启分页管理机制,MMU便是要提供分页机制的支持。
但是为了进行分页,操作系统也是需要进行相关的内存管理支持的,


32.Uboot如何实现自动更新?自己覆盖自己?
其实Uboot执行时是需要从永久性存储器(如:flash)中加载读取到内存中的。
而如果我们仅仅采用数据复制到内存的方式,只能在供电的状况下存在。

如果要实现其更新功能,本质上就是将新版的Uboot复制到flash中,而不是内存中,而执行中的Uboot是在内存中的,所以不是自覆盖的方式。

33.进程在建立页表的时候,是否将所有的页表都分配空间?当发生缺页中断的时候,如何找到页面在硬盘上的地址?

 

34.Linux0.11中的内存管理有何特点?linux0.99之后采用了什么新的方法?

Linux0.11中为了方便内存管理,采取了简化措施,所有的进程共用一个页目录这就意味着,他们共用同一个线形地址空间。必须保证线性地址空间不能重叠,linux0.11采用了如下方法避免重叠。

给进程分配线性地址的时候,采用如下方式:64M+NR*64M。NR代表任务号。

Linux0.99之后,对内存地址空间使用发生了变化。每个进程都可以使用4GB的虚拟地址空间。
而且绕过了段式存储,即所有进程都指向相同的GDT中的代码段和数据段描述符。已经基本不使用LDT。而所有的代码段,数据段指向相同的基地址0x00000000。

同时逻辑上采用了三级映射,而386则是物理上的两极映射。通过设置pmd的位数为1,绕过了中间的那一级映射。

从以上我们可以发现如何保证相同的线性地址影射到不同的物理地址的方法
1.进程使用不同的页目录表。
2.进程使用不同的段描述符,使段基地址不同。

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客