操作系统启动步骤解读 (李治军操作系统课笔记1)

总体流程图:

图源:https://www.cnblogs.com/ronny/p/7787259.html

bootsect.S 剖析

一般PC在电源打开时,是由内存中地址FFFF(段地址cs):0000(偏移量ip)(cs<<4+ip)开始执行,此处的内容是一个jump指令,jump到另一个位于ROMBIOS中的位置,开始执行一系列的动作,包括了检查RAM,keyboard,显示器,软硬磁盘等等。
紧接着系统测试码之后,控制权会转移给ROM中的启动程序(ROM bootstrap routine), 这个程序会将磁盘上的零道零扇区读入内存中,至于被读到内存的哪里呢?----绝对位置07C0 :0000(即07C00h处)。

引用来源

这个扇区dedai叫做引导扇区——bootsect.s(后缀为s代表为汇编码)

代码理解:

  • 把bootsec.s代码从0x7c00移动到ox90000中
mov ax,#BOOTSEG                        //BOOTSEG=0X07C0
mov ds,ax                              //INITSEG=0X900
mov ax,#INITSEG                        //SETUPSEG=0X9020
mov es,ax  //产生两个源地址
mov cx,#256
sub si,si
sub di,di
rep movw 
jmpi go,INITSEG

1、rep术语叫做“重复前缀指令”,因为既然是传递字符串,则不可能一个字(节)一个字(节)地传送,所以需要有一个寄存器来控制串长度。这个寄存器就是CX,指令每次执行前都会判断CX的值是否为0(为0结束重复,不为0,CX的值减1),以此来设定重复执行的次数。
2、关于cx的值,由于是要移动一个扇区的数据,一个扇区的大小是512B,但这里的cx=256是因为movsw表示移动两个B,256*2=512B。
3、最后一句表示将跳到CS为0x9000,IP为offset"go"的位置(CS:IP=0x9000:offsetgo),其中INITSEG=0x9000定义于程序开头的部分,而go这个label则恰好是下一行指令所在的位置。

  • 关于load_setup
go:
mov ax,cs//cs=0x9000
……
mov es,ax
……
load_setup:
mov dx,#0x0000
mov cx,#0x0002
mov bx,#0x0200
mov ax,#0200+SETUPLEN
int 0x13  //读磁盘扇区的中断

1、读什么?al=扇区数量,cl=开始扇区
可以看到cl即cx低两位是0x02即从第二个扇区读起,al即ax低两位是SETUPLEN=4即读四个扇区
2、读到哪里?es:bx内存地址
可以看到es=0x9000,bx=0x0200,所以是0x90200,就是在引导扇区之后开始装载setup模块

  • 关于ok_load_setup
……
读光标位置
mov cx,#24//24个字符
……
mov bp,#msg1 //msg1就是要显示的内容
……
int 0x10//中断,显示字符
……
call read_it//继续读后面的扇区

如果要更改显示内容,除了修改msg1还要修改mov cx #字符数

  • 将控制权交给setup
jmpi 0,SETUPSEG

cs:ip=SETUPSEG:0

setup.S 剖析

参考:https://blog.csdn.net/longintchar/article/details/79464007

  • 一些符号常量(与bootsect.s保持一致)
INITSEG  = 0x9000   bootsect.s的段地址
SYSSEG   = 0x1000   system loaded at 0x10000
SETUPSEG = 0x9020   setup.s的段地址
  • 保存光标的位置
mov ax,#INITSEG  //INITSEG = 0x9000
mov ds,ax        // ds = 0x9000
mov ah,#0x03     
xor bh,bh       
int 0x10        
mov [0],dx       

1、int 0x10h类似0x13h,表示中断,寄存器ah存储功能号。此处ah=0x03:获取光标的位置,寄存器bh=页号,返回dh=行,dl=列
详细:INT 0X10H
2、mov [0] dx: 保存光标的行号和列号到ds=0x9000<<4+0处,共占2字节,因为这时候bootsect模块的代码已经没有用了,可以覆盖了。

  • 获取从 1M 处开始的扩展内存大小
mov ah,#0x88
int 0x15
mov [2],ax   //ax = 从1M处开始的扩展内存大小

1、利用 BIOS 中断 0x15 功能号 ah = 0x88 返回:ax=从0xl00000(lM)处开始的扩展内存大小(KB),并保存在内存 0x90002 处
2、什么是扩展内存?
intel最初内存是1M,超出1M的叫做扩展内存
3、为什么要获取扩展内存?
操作系统要管理硬件就要知道内存大小

  • 移动 system 模块到 0x00000
    mov ax,#0x0000
    cld 
    //CLD(cleardirection)清除方向标志,告诉程序si,di向前移动
do_move:
    mov es,ax       //es是目的段地址
    add ax,#0x1000
    cmp ax,#0x9000   
    jz  end_move    //当 ax==0x9000 时结束移动
    mov ds,ax       
    //ds是源段地址,bootsect.s 引导程序将 system 模块读入到 0x10000
    sub di,di        //di = 0
    sub si,si       //si = 0
    mov cx,#0x8000   //重复 0x8000次
    rep             //ds:si --> es:di
    movsw           //每次移动2B.
    jmp do_move    

1、从代码实现来看,每次移动2B,每轮重复0x8000次,0x8000*2=0x10000B=64KB,所以共移动8轮。
2、由此可以理解为什么bootsect.s把自己移动到了0x90000?
system模块放置在0x10000处,当时假设 system 模块最大长度不会超过 0x80000 (512KB),所以从0x10000到0x8ffff都是预留给system模块的,即其末端不会超过内存地址 0x90000,所以 bootsect.s 会把自己移动到0x90000 开始的地方,并把 setup 加载到它的后面。
3、为什么Load system的时候为什么不一次性放在0x00000处?
因为0x00000处开始放的bios中断向量表。现在bios中断已经不需要了,所以可以覆盖了。

  • 进入保护模式
mov ax,#0x0001  
lmsw ax        
jmpi 0,8        ! jmp offset 0 of segment 8 (cs)

1、CR0 是系统内的控制寄存器之一。控制寄存器是一些特殊的寄存器,它们可以控制CPU的一些重要特性。0位是保护允许位PE(Protedted Enable),用于启动保护模式,如果PE位置1,则保护模式启动,如果PE=0,则在实模式下运行。
2、lmsw:置处理器状态字。但是只有操作数的低4位被存入CR0,即只有PE,MP,EM和TS被改写,CR0其他位不受影响。此处把cr0的最后一位设置为1,从实模型进入保护模式。
3、为什么有保护模式?
实模式下的寻址方法只能访问1M(20bit)的内存空间,无法满足需要。后来intel有了32位处理器,寻址空间达到4G,保护模式就是32位机。
(详见浅谈实模式和保护模式
4、jmpi 0, 8:按照保护模式,取到的段基址其实是0x0000,那么这句话就是跳转到地址为0x00000的地方开始执行,也就是system模块的开始部分
5、保护模式下取址:全局描述符表GDT
保护模式并没有抛弃实模式下Seg:Offset这样的寻址方式,只是对Seg的解释发生了变化。实模式下段值可以看作是地址的一部分,而保护模式下,段寄存器还是原来的16位,但它仅仅只是一个索引,它指向一个数据结构的一个表项,这个数据结构就是GDT,存储段的描述符:
1)起始地址(32位)
2)段的大小(20位)
3)段的属性(禁止写入,禁止执行,系统专用等,12位)
GDT详细
在这里插入图片描述ps:小端法!
上图中标红的数字连起来成了段基址(32位),与偏移(32位)相加即jump地址
所以GDT表在启用保护模式之前就要定义好。

system模块

  • head.s
    1、这部分代码实际处于绝对地址0处开始的地方。该部分的代码是在保护模式下执行的,所使用的是AT&T格式的汇编指令与之前使用的as86汇编指令不同。这部分的代码主要功能参考
    2、最后跳转到system模块中的初始化程序main.c中继续执行:
    通过push main压栈;ret跳转到main函数

  • main.c:初始化
    很多xx_init()函数


总结

bootsect.s + setup.s + head.s + main.c实际上就是两步:
读操作系统到内存中 + 初始化

为什么要初始化?
因为操作系统是管理硬件的一套软件,要针对每个硬件初始化一些数据结构方便管理

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
操作系统 治军 pdf》是一本由作者治军撰写的关于操作系统的书籍的电子版PDF文件。操作系统是计算机系统中的一个核心组成部分,它负责管理和控制计算机的硬件和软件资源,使得计算机能够高效地运行各种应用程序。 在这本书中,治军详细介绍了操作系统的基本概念、原理和设计原则。他从操作系统的起源和发展历程出发,讲解了多道、分时和实时操作系统等不同类型的操作系统,并深入解析了其内核结构和功能。此外,书中还讨论了进程管理、内存管理、文件系统、输入输出控制等重要的操作系统主题,为读者提供了全面了解和深入学习的机会。 这本书的PDF版本使得读者可以更加便捷地获取其中的内容,无论是在电脑、平板还是手机上都可以进行阅读。通过阅读这本书,读者可以深入了解操作系统的基本原理和相关技术,有助于他们提升对计算机系统的理解和应用。对于学习计算机科学或相关专业的学生和从事软件开发工作的技术人员来说,这本书是一本宝贵的参考资料。 总之,《操作系统 治军 pdf》是一本全面介绍操作系统的书籍的电子版PDF文件,读者可以通过阅读它来深入了解操作系统的原理和技术。这本书的出现为学习和研究操作系统提供了便利,对于对计算机系统有兴趣的人士来说是一本值得阅读的优秀教材。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值