linux 0.11 head.s文件

经过setup初始化后,控制流转移到该文件起始位置,进入该文件需要留意一点就是此时已经切换到分段模式,因此这里的寻址的段寄存器的意义变为了分段状态下的段,也就是段选择符;因此一开始的段寄存器设置0x10段,该段就是GDT表中的第一个段,该段段基址为0x0,段长为8M(setup中设置),

然后指向一个临时栈区,stack_start,该栈区占据空间1页,4096 Byte空间,这里聊一下栈区和函数调用关系,函数调用过程中函数接口参数和函数中定义变量所占据空间都是使用的是栈区空间,在call的时候还会将调用函数位置之后的eip入栈用以函数返回时的eip执行位置;

首先设置了IDT中断描述符表,即setup_idt子程序,该子程序中有个量,就是_idt,在gcc 1.4版本中,C程序汇编后的汇编文件会在对应的C语言标识符前加个'_',然后在中断描述符表中进行初始化,将中断标识符表中的每个中断门设置为ignore_int程序调用,中断描述符表共是256个中断门,中断描述符表空间就在head.s文件中的_idt标号位置;最后加载了idt描述符表到IDTR中;

接着设置了GDT全局描述符表,即setup_gdt子程序,该子程序就是加载了一下GDTR,一共也是256个GDT描述符空间,与前面setup设置的内核GDT描述符区别就在于该内核GDT描述符的段长为16M,段基址的不变的,因此system程序可以继续向下执行;

设置完毕后,由于段寄存器在保护模式下会将段描述符缓冲起来,因此重新加载一下,更新对应的段描述符;在setup中设置了A20地址线以允许访问1M以上空间,这里又进行了一次确认;然后进行跳转,这里之所以进行跳转是因为Linux 0.11布局中,0x0000到0x5000这段空间上,为页目录和4张页表的占据空间位置以供内核使用;一页可以映射4K空间,一张页表可以管理4M空间,因此内核可以访问到全部的16M空间;

setup_paging先进行初始化,将页目录和页表对应的20K空间清零,而后设置页目录的前4个页目录项分别为pg0,pg1,pg2和pg3,每个页目录项占据4 byte空间,其中后12bit是不使用的,作为页表属性进行使用,只有前面的20bit数据用于描述页表所在页地址;初始化完毕页目录项后,就对4张页表进行初始化,使其可以遍历整个操作系统要管理的内存16M,之后开启分页管理,此后内存寻址的分段地址转换出来的地址就是一个线性地址,他需要进行页表转换才会映射到物理地址。

最后,基于函数调动机制,使用ret跳转到init.c程序中执行main函数;当然,如果此时main函数如果再次ret,那么就跳转L6进入死循环。

posted @   呵哈呵  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示