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个文件,也不知道是不是故意为之