0.11 源码阅读(学习)
🧼

0.11 源码阅读(学习)

 
参考文章地址
第六回 | 先解决段寄存器的历史包袱问题
本系列会以一个读小说的心态,从开机启动后的代码执行顺序,带着大家阅读和赏析 Linux 0.11 全部核心代码,了解操作系统的技术细节和设计思想。 你会跟着我一起,看着一个操作系统从啥都没有开始,一步一步最终实现它复杂又精巧的设计,读完这个系列后希望你能发出感叹,原来操作系统源码就是这破玩意。 以下是 已发布文章 的列表,详细了解本系列可以先从开篇词看起。 本系列的 GitHub 地址如下(文末阅读原文可直接跳转) https://github.com/sunym1993/flash-linux0.11-talk 书接上回,上回书咱们说到,操作系统又折腾了一下内存,之后的很长一段时间内存布局就不会变了,终于稳定下来了,目前它长这个样子。 0 地址开始处存放着操作系统的全部代码吗,也就是 system 模块,0x90000 位置处往后的几十个字节存放着一些设备的信息,方便以后使用。 是不是十分清晰? 不过别高兴得太早,清爽的内存布局,是方便后续操作系统的大显身手! 接下来就要进行真正的第一项大工程了,那就是 模式的转换,需要从现在的 16 位的 实模式转变为之后 32 位的 保护模式 。 当然,虽说是一项非常难啃的大工程,但从代码量看,却是少得可怜,所以不必太过担心。 每次讲这里都十分的麻烦,因为这是 x86 的历史包袱问题,现在的 CPU 几乎都是支持 32 位模式甚至 64 位模式了,很少有还仅仅停留在 16 位的实模式下的 CPU。所以我们要为了这个历史包袱, 写一段模式转换的代码 ,如果 Intel CPU 被重新设计而不用考虑兼容性,那么今天的代码将会减少很多甚至不复存在。 所以不用担心,听懂就听懂,听不懂就拉倒,放宽心。 我不打算直接说实模式和保护模式的区别,我们还是跟着代码慢慢品味,来。 这里仍然是
第六回 | 先解决段寄存器的历史包袱问题

整体加载图

notion image

汇编执行令

  • mov: 赋值
    • movl: mov long 四个字节,告知编译器的。
  • sub : 相减
    • sub a, a 清零操作
  • xor: 异或
    • xor a,a 清零操作
  • jmpi: 段间跳转指令
  • pushf: 标志寄存器压栈
  • popf:标志寄存器出栈
  • cld: 将寄存器DF标志位置0
  • std: 将寄存器DF标志位置1
  • rep: 重复
  • ret: 返回
  • call: 函数调用

寄存器

intel 访问内存分为:

  • 代码
    • 对应的寄存其为 代码段寄存器(cs)
  • 数据
    • 数据段寄存器(ds)
    • 栈段寄存器(ss)
白话描述:
cs:eip 表示了我们要执行哪里的代码。
ds:xxx 表示了我们要访问哪里的数据。
ss:esp 表示了我们的栈顶地址在哪里。

其它寄存器:

  • idtr: 中断描述符表 idt
  • gdtr:全局描述符表 gdt
  • TSS:任务状态段描述符
  • LDT: 局部描述符
  • CR0: 机器状态字寄存器
  • DF(Direction Flag): 方向控制位
  • esp: 栈顶地址
  • cs:eip:CPU 下一步准备执行的指令
 

描述表:

  • idt : 中断描述表,存放在idtr中。
  • gdt: 全局描述表,存放在gdtr中。

CR0:

notion image
31位:PG-分页机制标志位
30-19位: 保留位
0位:PE-保护模式开启标志位
 

CR3:

CR3含有存放页目录表页面的物理地址,因此CR3也被称为PDBR

专业名词

  • MMU:内存管理单元 (有时也叫 PMMU,分页内存管理单元)
  • IDT: Interrupt Description Table 中断描述表
  • IDTR: Interrupt Description Table Register 中断描述表寄存器
  • GDT: Global Description Table 全局描述表
  • GDTR: Global Description Table Register 全局描述表寄存器
 
代码目录
. ├── Makefile ├── boot // 引导目录 (汇编代码) │   ├── bootsect.s // 移动磁盘引导程序至内存中 │   ├── head.s │   └── setup.s // 加载硬件信息,中断描述符表,全局描述符表 gdt ├── fs │   ├── Makefile │   ├── bitmap.c │   ├── block_dev.c │   ├── buffer.c │   ├── char_dev.c │   ├── exec.c │   ├── fcntl.c │   ├── file_dev.c │   ├── file_table.c │   ├── inode.c │   ├── ioctl.c │   ├── namei.c │   ├── open.c │   ├── pipe.c │   ├── read_write.c │   ├── stat.c │   ├── super.c │   └── truncate.c ├── include │   ├── a.out.h │   ├── asm │   │   ├── io.h │   │   ├── memory.h │   │   ├── segment.h │   │   └── system.h │   ├── const.h │   ├── ctype.h │   ├── errno.h │   ├── fcntl.h │   ├── linux │   │   ├── config.h │   │   ├── fdreg.h │   │   ├── fs.h │   │   ├── hdreg.h │   │   ├── head.h │   │   ├── kernel.h │   │   ├── mm.h │   │   ├── sched.h │   │   ├── sys.h │   │   └── tty.h │   ├── signal.h │   ├── stdarg.h │   ├── stddef.h │   ├── string.h │   ├── sys │   │   ├── stat.h │   │   ├── times.h │   │   ├── types.h │   │   ├── utsname.h │   │   └── wait.h │   ├── termios.h │   ├── time.h │   ├── unistd.h │   └── utime.h ├── init │   └── main.c ├── kernel │   ├── Makefile │   ├── asm.s │   ├── blk_drv │   │   ├── Makefile │   │   ├── blk.h │   │   ├── floppy.c │   │   ├── hd.c │   │   ├── ll_rw_blk.c │   │   └── ramdisk.c │   ├── chr_drv │   │   ├── Makefile │   │   ├── console.c │   │   ├── rs_io.s │   │   ├── serial.c │   │   ├── tty_io.c │   │   └── tty_ioctl.c │   ├── exit.c │   ├── fork.c │   ├── math │   │   ├── Makefile │   │   └── math_emulate.c │   ├── mktime.c │   ├── panic.c │   ├── printk.c │   ├── sched.c │   ├── signal.c │   ├── sys.c │   ├── system_call.s │   ├── traps.c │   └── vsprintf.c ├── lib │   ├── Makefile │   ├── _exit.c │   ├── close.c │   ├── ctype.c │   ├── dup.c │   ├── errno.c │   ├── execve.c │   ├── malloc.c │   ├── open.c │   ├── setsid.c │   ├── string.c │   ├── wait.c │   └── write.c ├── linux-0.11.iml ├── mm │   ├── Makefile │   ├── memory.c │   └── page.s └── tools └── build.c 14 directories, 100 files // 真巧,刚好100个文件,也不知道是不是故意为之