Linux·内核源码简单分析

目录

系统总体流程:

各个目录的阅读总结:

(一) boot

(二)内核初始化init

(三)kernel:

(四)mm内存管理

         (五)文件系统模块fs:


 

系统总体流程:

系统从boot开始动作,把内核从启动盘装到正确的位置,进行一些基本的初始化,如检测内存,保护模式相关,建立页目录和内存页表,GDT表,IDT表。然后进入main进行初始化设置,main完成系统各个模块要用到的所有数据结构和外部设备的初始化。使得系统可以正常的工作。然后才进入用户模式。执行第一个fork生成进程1执行init,运行shell,接受并执行用户命令.

这里整个系统建立起来了,OS就处于被动状态,靠中断和系统调用来完成每一项服务。

各个目录的阅读总结:

() boot

1bootsect.s 

bootsect.s编译结果生成一个512BYTE(一个扇区)镜像。这个扇区的最后一个字是0xAA55,倒数第二个字是root_dev变量,值为ROOT_DEV(306),即根文件系统所在的设备号。这段代码必须写入到启动盘的启动扇区,也就第一个物理扇区上。这样机器启动后,BIOS自动把它加载到7C00H处并跳到那里开始执行。bootsect将自己移动到90000H(576K)处,并跳至那里相应位置执行。然后利用BIOS中断将setup直接加载到自己的后面(90200h)(576.5K处),并将system加载到地址10000h处。 跳到setup中执行。

2setup.s

利用BIOS中断把系统参数如显卡,硬盘参数保存到内存90000开始的位置,即覆盖原bootsect所在的内存位置。再把整个system 模块移动到00000 位置。加载GDTRIDTR,这里的GDT表是临时的,保存了两个描述符,即内核代码、内核数据段描述符,其段基地址为0。而加载IDT除了进入保护模式需要加载IDTR之外,没有任何意义。开启A20 地址线开启扩展内存。重新设置8259中断码0x20~0x2f。进入保护模式(PE1)跳转到system模块中的head.s(0)执行。Bootsect.ssetup.s执行时内存变化情况。

 

3head.s

4KB的代码将被页目录覆盖掉。这些代码执行的操作包括:设置系统堆栈为_stack_start。重新设置GDTRIDTRgdtidt表都定义在head.s的末端,长度均为256(2KBYTE)。第2个页面到第5个页面是系统的4张页表。最后一个页表后面的代码执行分页操作,即填充的4个页目录和4张页表的内容,实现对等映射,即物理地址=线性地址。每个页表项属性为存在并且用户可读写。设置好后置CR3页目录地址即0。启动分页标志,CR0PG标志置1。跳到main函数中执行。

跳到main之前,内存布局如下:从016M

                    页目录4K(0x0开始)

                    页表1 4K

                    页表2 4K

                    页表3 4K

                    页表4 4K

                     软盘缓冲区1K

                     head.s后半部分代码

                     IDT2K

                     GDT2K

                     main.o代码部分

                  内核其余部分(大约到512Kend值为结束地址)

                  setup保存的系统参数(90000H~900200)这个区间还保存着root_dev.

                  BIOS(640K-1M)

                     主内存区(1M-16M)

 

现在初始化好了内核工作依赖的主要的数据结构是GDTIDT表,还有页表。

()内核初始化init

main.c将进行进一步初始化工作。主要方面:分配主内存功能,IDT表各中断描述符重新设定,对内核其它模块如mm,fs进行初始化,然后移到用户模式下生成进程1执行init,常驻进程0死循环执行pause。进程init加载根文件系统,设置终端标准IO,创建进程2/etc/rc为标准输入文件执行shell.完成rc文件中的命令。

init等进程2退出,进入死循环:创建子进程,建立新会话,设置标准IO终端,以登录方式执行shell.

至此系统动作起来了。

 

所以整个系统的建立起来后除了两个死循环的进程idleinit,其它的动作都是由用户在shell下执行命令,产生系统调用来工作的。

通过执行move_to_usermdoe()idleinit进程都属于用户态下的进程。而内核则完全是中断驱动的。也就是说只有通过中断才能进入系统,如时钟和系统调用等。

 

所以问题的重点就在于内核各部分数据结构的建立、初始化、操作是怎样进行的。这些初始化流程涉及到内核各个模块全部重要的数据结构。

现在从main执行的一系列初始化代码来浅窥一下:

1.根据内存的大小,设置高速缓冲的末端。16M内存把高速缓冲末端设为4M。缓冲末端到主存末端为主内存区。

2.mem_init(main_memory_start,memory_end);主内存区初始化

 设置高端内存HIGH_MEMORY=memory_end,

 设置内存映射字节图mem_map [ PAGING_PAGES ],将不可用的全部置为USED,可用的置为0mem_map数组是系统mm模块核心数据结构,记载了每个内存页使用计数。

3.trap_init().硬件中断向量表设置。

  向IDT中填充各个中断描述符,使其指向对应的中断处理程序。对于错误,基本是结束当前进程。其他如外设中断都是各个模块初始化的时候向IDT表中相应项进行设置。

4.blk_dev_init();     // 块设备初始化。

       初始化请求数组request[],将所有请求项置为空闲项(dev = -1)

5.chr_dev_init();    // 字符设备初始化。尚为空操作。

6.tty_init();            // tty 初始化。                    

       /// tty 终端初始化函数。                                                 

       // 初始化串口终端和控制台终端。                                          

       void tty_init (void)                                                     

       { 

              rs_init ();                   // 初始化串行中断程序和串行接口2(serial.c, 37)   

              con_init ();            

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无用程序员~

家里还有病重的爷爷奶奶🙏🙏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值