head.s会和其他c程序一起编译成内核代码,就像名字一样,他是内核的开头部分,前面setup.s程序已经完成了他的使命把内核代码加载到0开始的部分了,head就开始为内核的工作做一些初始化的工作,后面的代码则都由c来写了。
设置IDT表
内核最重要的一个功能就是处理中断了,不同的事件产生都会生成一个中断号并被cpu捕捉到,cpu根据内核设置的中断表找到对应中断号的中断处理程序,交由内核处理。所以内核就必须提前告诉cpu中断表的位置,并在中断表中设置各个中断对应的表项。
通过设置一个idtr的寄存器来让内核告诉cpu中断表位置,idtr是48位的,前16位是表限长,后32位是中断表基址。每个中断描述项如下
设置GDT表
段的内容昨天说过了,内核初始化的时候硬编码了两条记录,分别是第1和第2项,第0项规定留空不用,剩下253项先用0填充了
开启分页
linux把地址从0开始的4K地址用作页目录,紧挨着后面是4个页表,分页是把虚拟地址经过分段产生的线性地址再一次经过分页产生真正的物理地址。
分页的逻辑也很简单,32位先行地址,0-11共12位作为页偏移刚好寻址4K,中间12-21共10位作为页表项选择符,22-31共10位作为页目录选择符
使用了二级目录,原因是节省内存,如果使用一级分页,要寻址4G的物理地址,则需要4G/4M=1K页,共需要1K*4K=4M内存,什么都不干就需要吃掉4M的内存,如果使用二级页表的话,则初始化只需要一个页目录,根据需要生产二级页面,这样不会一开机就白白浪费那么多内存了。