欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Jeos

程序员文章站 2022-06-22 09:52:53
...

  Jeos 又名Je’os或我的os,特别说明:代码并非原创(目前)基本是refer的,具体地给出路径见README:https://github.com/Jeoos/Jeos.git

现在只具有boot及loader功能,简单记录和梳理下内核启动这块的东西。

Jeos

如上图,先是linux操作系统的bootsect这块,当PC加电后,80x86结构的CPU将自动进入实模式,并从地址0xFFFF0开始自启动执行程序代码,这个地址通常是ROM-BIOS中的地址。PC机的BIOS将执行某些系统的检测,并在物理地址0处初始化中断向量。此后,它将可启动设备的第一个扇区(磁盘引导扇区,512字节)读入内存绝对地址0x7c00处,并跳转到该地址处开始执行bootsect代码,而在这之前的工作都由BIOS完成。bootsect执行时会把自己移到绝对地址0x90000(也即0x9000:0x0)处,而内核的其他部分(system模块)则被读入到从地址0x10000开始处,因为当时system模块的长度不会超过0x80000字节大小(即512KB),所以它不会覆盖在0x90000处开始的bootsect和setup模块。后面setup程序将system模块移动到内存起始处(0x0),这样system模块中代码的地址也即等于实际的物理地址,便于对内核代码和数据的操作。接下来setup为了能让head在32位保护模式下运行,加载了中断描述符表寄存器(idtr)和全局描述符表寄存器(gdtr),并临时设置了相应描述表。运行到head后,会重新按照需要设置这些描述符表。关于实模式和保护模式的东西可参考之前的文章不再赘述。

现在的os,boot这块简化了但是功能更集中些有代码的迁移和实模式到保护模式的切换。loader基本没做什么,直接跳转到了0x10000就处执行。当然目前也就没必要实现和head对应的功能了。

具体的,boot.S使能保护模式,使用到CR0控制寄存器,如下
Jeos

其中PE置1代表使能保护模式,还有如PG置1使能分页后面会涉及,其它的 …

#define CR0_PE 0x0
--- ---

lgdt    gdt_ptr                 # 加载GDT
movl    %cr0,                   %eax                               | 18 /* ap start args */
orl     $CR0_PE,                %eax               
movl    %eax,                   %cr0   # 使能

同样,boot.S跳转到load.S,此时已经使能保护模式,不再是简单的段式管理。

# define SEG_KCODE = 1
ljmp    $SEG_KCODE<<3,  $0


gdt:                                                                            
  .quad   0x0000000000000000    # 第一项,默认不用                                                  
  .quad   0x00cf9a000000ffff    # 代码段描述符项                  
  .quad   0x00cf92000000ffff    # 数据段描述符项                                                  
gdt_ptr:                                                                        
  .word   . - gdt - 1                                                             
  .long   gdt          

下图分别为描述符项及选择符(selectors)的格式:
Jeos
Jeos

这时的段值就是保护模式下的段选择符了,8(0b0000 0000 0000 1000)表示特权级0、使用全局描述符表中第一项。找到 .quad 0x00cf9a000000ffff,由上图红色部分可知该项指出的基地址是0x0,又因为我们已经手动将load.S代码移到0x0处,所以偏移设置的为$0。总之,通过解析得出跳转到0x0处执行load.S。BTW,为什么不从0开始,因为对于GDT,index=0的描述符是不用的,这也是要填充对应上述的:.quad 0x0000000000000000描述符项的原因。

测试:qemu-system-i386 -hda Jeos_hd.img -m size=128M 可打印一条红线。

参考:
赵炯,linux内核完全剖析

相关标签: os

推荐阅读