其他
第二部分完结撒花!大战前期的初始化工作
第二部分所讲的代码,就和第二部分的目录一样规整,一个 init 方法对应一个章节,简单粗暴。
void main(void) {
...
mem_init(main_memory_start,memory_end);
trap_init();
blk_dev_init();
chr_dev_init();
tty_init();
time_init();
sched_init();
buffer_init(buffer_memory_end);
hd_init();
floppy_init();
sti();
move_to_user_mode();
if (!fork()) {init();}
for(;;) pause();
}
如果坚持到这里了,先给自己鼓鼓掌!这个过程,你可能觉得无聊,因为全是各种数据结构、中断、外设的初始化工作,后面将会怎么用它们,并没有展开讲解。 但你也可能觉得兴奋,因为后面操作系统的全部工作,都是围绕着这几个初始化了的结构展开的,而它们却都是那么的好理解。 其实我是蛮喜欢这个过程的,比如我看电影,其实我对高潮部分并不是很感兴趣,我就喜欢看一场大战或者一场阴谋前各部门的准备工作,看着它们为了后面一个完美的计划,所做的前期筹备,是一种享受,你懂的! 所以今天特地花一章的功夫,把之前的初始化工作梳理一遍,之前没仔细看的同学,这章是个重新开始的机会!
------- 开始 -------
电脑开机后,首先由 BIOS 将操作系统程序加载到内存,之后在进入 main 函数前,我们用汇编语言(boot 包下的三个汇编文件)做了好多苦力活。
这些苦力活做好后,内存布局变成了这个样子。
-------- 进入 main 函数后 ---------
进入 main 函数后,首先进行了内存划分,其实就是设置几个边界值,将内核程序、缓冲区、主内存三个部分划分开界限。这就是 第12回 | 管理内存前先划分出三个边界值 所做的事情。
再往后,通过 trap_init 函数把中断描述符表的一些默认中断都设置好了,随后再由各个模块设置它们自己需要的个性化的中断(比如硬盘中断、时钟中断、键盘中断等)。这是 第14回 | 中断初始化 trap_init 的内容。
这就是进程调度的简单流程,也是后面要讲的一个非常精彩的环节。 最后最后,一个简单的硬盘初始化 hd_init,为我们开启了硬盘中断,并设置了硬盘中断处理函数,此时我们便可以真正通过硬盘的端口与其进行读写交互了。这是 第20回 | 硬盘初始化 hd_init 的内容。 把之前几个模块设置的中断放一块,此时的中断表我们看一下。
中断号 | 中断处理函数 |
---|---|
0 ~ 0x10 | trap_init 里设置的一堆 |
0x20 | timer_interrupt |
0x21 | keyboard_interrupt |
0x2E | hd_interrupt |
0x80 | system_call |
这里我又提了一嘴,操作系统本质上就是个中断驱动的死循环,这个后面你会慢慢体会到。
而我们再往下看一行 main 方法。
#define sti() __asm__ ("sti"::)
void main(void) {
...
sti();
...
}
是一个 sti 汇编指令,意思是打开中断。其本质上是将 eflags 寄存器里的中断允许标志位 IF 位置 1。(由于已经是 32 位保护模式了,所以我把寄存器也都偷偷换成了 32 位的名字)这就代表着,操作系统具有了控制台交互能力,硬盘读写能力,进程调度能力,以及响应用户进程的系统调用请求! 至此,全部初始化工作,就结束了!这里有几个初始化函数没有讲,都是可以忽略的,不要担心。 一个是 chr_dev_init,因为这个函数里面本身就是空的,什么也没做。
------- 关于本系列 -------
本系列的开篇词看这
本系列的扩展资料看这(也可点击阅读原文),这里有很多有趣的资料、答疑、互动参与项目,持续更新中,希望有你的参与。
https://github.com/sunym1993/flash-linux0.11-talk
本系列全局视角
最后,祝大家都能追更到系列结束,只要你敢持续追更,并且把每一回的内容搞懂,我就敢让你在系列结束后说一句,我对 Linux 0.11 很熟悉。
另外,本系列完全免费,希望大家能多多传播给同样喜欢的人,同时给我的 GitHub 项目点个 star,就在阅读原文处,这些就足够让我坚持写下去了!我们下回见。