1. 功能描述

被编译成目标文件后会与内核其他程序一起被链接成system模块,位于system模块的最前面开始部分。system模块将被放在磁盘上setup模块之后开始的扇区中,即从磁盘上第6个扇区开始放置。一般Linux 0.12内核的system模块大约120KB左右,大约240个扇区

从这里开始,内核完全在保护模式运行。head.s采用AT&T语法格式,并需要使用GNU的gas和gld编译连接,赋值是从左到右。

这段程序实际处于内存绝对地址0开始地方。程序功能比较单一。首先加载各个数据段寄存器,重新设置IDT,共256项,并使所有表项指向一个只报错误的哑中断子程序ignore_int。格式如下。

4. head.s程序

中断描述符中段选择符是0x0008(这个会指向GDT或LDT。1000,索引是1,刚好是setup.S设置的GDT中的第1个描述符,是代码段描述符索引位置),表示该哑中断处理程序在内核代码(第1个描述符中的基地址是0)中偏移值(在中断描述符中!!!)被设置为ignore_init中断处理程序在head.s程序中的偏移值。由于head.s被移动到内存地址0开始处,因此该偏移值也就是中断处理程序在内核代码段中的偏移值。由于内核代码段一直存在内存中,且特权级为0,即P=1,DPL=00。因此中断门描述符的字节5和字节4应该是0x8E00。

设置好IDT后,又重新设置了GDT。新设的GDT表与原来的setup.s除了在段限长上有些区别(原8MB,现16MB),其他完全一样。当然可以在setup.s就把GDT段限长直接设置为16MB,然后直接把原GDT移动到合适内存为止。之前GDT处于内存0x902XX处。这个地方将在内核初始化后用作内存高速缓冲区的一部分。

接着使用物理地址0与1MB开始处字节比较,检测A20地址是否已开启。若没开,则访问高于1MB物理内存地址时CPU实际只会循环访问(IP MOD 1MB)地址处内容,即与访问从0地址开始对应字节的内容都相同。若发现没有开启,进入死循环。然后测试PC是否有数学协处理器(80287、80387等),并在控制寄存器CR0设置相应标志位。

接着设置分页处理机制,将页目录表放在绝对物理地址0开始处(会覆盖),然后后面放可寻址16MB的4个页表,并分别设置表项。页目录表项和页表项结构见其他资料。

每个表项都被设为0x07(P=1,U/S=1,R/W=1),表示页存在、用户可读写。

这样设置内核页表属性因为:CPU的分段和分页都有保护方法。分页机制中页目录表和页表项中设置的保护标志(U/S、R/W)需要和段描述符中的特权级(PL)一起组合使用。但段描述符中的PL起主要作用。CPU会首先检查段保护,再检查页保护。若CPU<3,说明CPU正以超级用户(Supervisor)身份运行。此时可以访问所有页面并随意内存读写。CPL=3,说明以用户(user)身份运行,只能访问User的页面(U/S=1)可以访问,并且只有标记为可读写的页面(W/R=1)是可写的。而属于超级用户的页面(U/S=0)既不可写,也不可读。

最后,head.s利用返回指令将预先设置在堆栈中的init/main.c程序入口地址弹出,运行main()程序。

2. 代码注释

3. 其他信息

3.1 程序执行结束的内存映像

执行后,正式完成了内存页目录和页表的设置,并重新设置了内核实际使用的IDT和GDT。另外,为软盘驱动开辟1KB缓冲区。此时sysetm模块在内存中的详细映像如图

4. head.s程序

3.2 Intel 32位保护运行机制

3.3 前导符(伪指令)align

相关文章:

  • 2021-07-02
  • 2022-01-18
  • 2021-11-05
  • 2022-01-05
  • 2021-06-27
  • 2021-05-05
  • 2021-12-26
  • 2021-10-04
猜你喜欢
  • 2021-04-10
  • 2021-10-20
  • 2021-05-17
  • 2022-01-20
  • 2021-08-25
  • 2021-10-12
  • 2022-12-23
相关资源
相似解决方案