x86的开机过程(上)

之前学习的时候,就仅仅针对于应用层面,但是在实习的时候,却发现,操作系统在工作中用到的也是挺多的,为此,最近就跟着bilibili上李治军老师的操作系统的课重新学一遍操作系统

1.计算机的工作原理

学过计算机导论的都知道,现代计算机模型基于的是冯诺伊曼结构,主要由io输入输出设备,控制器,存储器,运算器构成
我们的代码存储在存储器中的,将pc指针指向的某段存储在存储器中的程序放入运算器中进行执行
简单来说就4个字,取址执行

2.x86开机执行的操作(上)

刚才说过了,计算机的工作原理其实就是取址执行,如果你的地址中没有对应的代码的话,它就没办法执行了,所以在x86中,最开始的地址的值还有地址里面的程序都是写死的,此时的CS寄存器被设置成了0xFFFF,IP寄存器被设置成0x0000
在微机原理中我们知道,一段代码的地址是由寄存器的地址和对应的偏移地址两者构成,
也就是CS<<4的值加上IP地址,算出来的结果是0xFFFF0
然后pc指针读取到这个0xFFFF0的地址之后就会从内存中找到对应的代码,这段位于BIOS上的,它是固化在主板上的小型软件,会对我们的硬件进行自检,如果自检不合格的话,也就不会执行后面的操作


记得我们之前说过的,冯诺伊曼体系结构下的几个构成
1.控制器
2.运算器
3.存储器
前面3个我们都说过了,唯独输入输出的IO设备没有说
刚才BIOS已经进行了自检了,成功的话,那么也就说明你的输入输出设备没有问题,这个时候会通过IO设备将磁盘0磁道0扇区读取到内存的0x7c00处
这里的磁盘也就是我们常说的存储,比如说一台电脑是16+512GB
其中这个512GB就代表这个磁盘的大小,但是实际上我们用到的不会刚好512GB,一定是比它小的
1个是因为制造商那边制造的是512,000,000,000Byte的硬盘,然后我们的系统是二进制的,
除以1个1.24的话,其实也就是大约476.84GB
还有一个就是因为我们的一部分操作系统也写到磁盘中的


这里补充1个知识点,0磁道0扇区指的是操作系统的引导扇区,1个扇区是512字节
将0磁道0扇区的读到0x7c00处之后就会把当前的寄存器CS和IP分别置称0x07c0和0x0000

算一下它的地址刚好就是0x07c00也就是刚才从磁盘中写入到内存中的地址

2.1引导扇区(boot扇区)代码

操作系统引导扇区的代码是在bootsect.s下面写着的
为什么这块引导扇区的代码用的是汇编代码而不是其他的语言比如c语言,这是因为在c语言或者其他语言中我们定义一个变量比如int a;这个a变量定义了,但是我们无法确定以及保证这个a在内存中具体的位置,但是汇编语言可以做到
我们可以看看代码

SYSSIZE = 0x3000 ! system模块大小
 
SETUPLEN = 4                                ! setup扇区数
BOOTSEG  = 0x07c0                        ! bootsector原始地址
INITSEG  = 0x9000                        ! bootsector移动的目标地址
SETUPSEG = 0x9020                        ! setup地址
SYSSEG   = 0x1000                        ! system加载位置
ENDSEG   = SYSSEG + SYSSIZE                ! where to stop loading
 
entry _start                                ! 程序入口为_start


_start:
 
! 初始化DS、ES、SI、DI,并把CX设置为扇区大小。
        mov        ax,#BOOTSEG
        mov        ds,ax
        mov        ax,#INITSEG
        mov        es,ax
        mov        cx,#256
        sub        si,si
        sub        di,di
    
! 复制DS:SI内容到ES:DI,即bootsect的256字(512字节)。
        rep        movw
 
! IP置go,CS置INITSEG,并跳转执行。
        jmpi        go,INITSEG

这里先提3点比较重要的

  1. ds和es都是段寄存器,si和di是变址寄存器,ds和si进行搭配计算出地址,es和di进行搭配计算出地址
  2. movw的作用是把ds:si的字复制到es:di
  3. Jmpi a b是把b赋值给cs,把a赋值给ip,然后跳转到b的a处执行代码 所以我们就可以理解这段代码的作用首先 把BOOTSEG(0x07c0)赋值给ds,把INITSEG(0x9000)赋值给es
    然后将ds:si中的256个字复制到es:di中最后将0x9000赋值给cs,go赋值给ip进行跳转
2.1.1go代码(load_setup)

go的代码在这块

go:     mov        ax,cs
        mov        ds,ax
        mov        es,ax
        mov        ss,ax
        mov        sp,#0xFF00                ! arbitrary value >>512
 
! 读入setup的4个扇区。0x13是BIOS读磁盘扇区的中断,AH=0x02读磁盘,AL=0x04扇区数,CH=0x00柱面号,CL=0x02开始扇区,DH=0x00磁头号,DL=0x00驱动器号,ES:BX=0x90200内存地址。
load_setup:
        mov        dx,#0x0000
        mov        cx,#0x0002
        mov        bx,#0x0200
        mov        ax,#0x0200+SETUPLEN
        int        0x13
        jnc        ok_load_setup                ! ok - continue
        mov        dx,#0x0000
        mov        ax,#0x0000                ! reset the diskette
        int        0x13
        j        load_setup

这里也先提几点比较重要的

  1. int 0x13表示的是bios读磁盘扇区的中断,前面我们的操作是把引导扇区的代码读到0x7000中然后执行引导扇区的代码,在这段代码中,我们将引导扇区的256个字复制到es:di中然后将0x7000赋值给cs,
    int
    0x13就是继续读扇区里面的代码,其中ah代表着开始读磁盘,al代表扇区的数量,ch代表从哪里开始读扇区,es:bx表示将内容读到哪儿
  2. 这里ax,#0x0200+SETUPLEN,而al是ax的低8位也就是SETUPLEN最后为4(在上面的上面的代码里面有写) 然后 cx,#0x0002,ch是它的低8位也就是2
    es:bx我们在前面给es赋值为0x9000,bx这里是0x0200,所以es:bx为0x90000+0x200=0x9200

go里面的代码就是从磁盘中的第二个扇区开始读4个扇区到内存的0x90200处
因为我们的boot扇区是第一个扇区,所以现在读的就是第二个扇区了然后读4个扇区到0x90200
然后我们的setup扇区刚好就是4个扇区,也刚好在boot扇区后面,所以这个的目的就是把setup扇区读到0x90200处
然后再14行jnc ok_load_setup就执行ok_load_setup代码

2.1.2ok_load_setup代码
ok_load_setup:
! 获取磁盘驱动器参数,特别是扇区/磁道数。
        mov        dl,#0x00
        mov        ax,#0x0800                ! AH=8 is get drive parameters
        int        0x13
        mov        ch,#0x00
        seg cs
        mov        sectors,cx
        mov        ax,#INITSEG
        mov        es,ax
        
! 打印一些信息,0x10是BIOS的显示字符中断,BP指出字符地址。
        mov        ah,#0x03                ! read cursor pos
        xor        bh,bh
        int        0x10
        mov        cx,#24
        mov        bx,#0x0007                ! page 0, attribute 7 (normal)
        mov        bp,#msg1
        mov        ax,#0x1301                ! write string, move cursor
        int        0x10
 
! 使用read_it读入system。
        mov        ax,#SYSSEG
        mov        es,ax                ! segment of 0x010000
        call        read_it
...
! 跳转到0x9020:0x0000执行setup。
        jmpi        0,SETUPSEG
...



msg1:
        .byte 13,10
        .ascii "Loading system ..."
        .byte 13,10,13,10

这里需要关注有2个int 0x10的代码 其中第一个 int 0x10

 mov        ah,#0x03               
 xor        bh,bh
 int        0x10

它的主要作用是为了读取光标的位置
然后第二个int 0x10

 mov      bp,#msg1
 mov      ax,#0x1301                
 int      0x10

这个代码是一个用来显示字符的中断,bp表示你要显示在显示器上的那段东西在哪儿,也就是在msg1的地址这块,然后显示在显示器光标的位置也就是我们第一次int
0x10那儿

所以这段代码的作用其实
第一个就是把msg1上的东西展示在屏幕光标上,windows上,linux上,mac上的都不同
第二个就是

jmpi        0,SETUPSEG

也就是将cs设置成0x9020 然后ip设置成0然后跳转到0x90200上,这块也就是跳转到setup

所以我们总结一下从x86开机到boot扇区读入完的过程,首先最开始从存储器中的0xFFFF0中读取代码,这块就是来进行外设的检查,看看主板啊,那些东西存不存在问题,然后就把磁盘中引导扇区的代码读取到0x7c00处执行引导扇区的代码,它会首先把引导扇区的256个字节复制到0x90000处然后跳转go处执行代码,它先将setup扇区的4个扇区读取到0x90200处然后将msg的内容展示在屏幕光标处最后跳转到0x90200处执行setup扇区的相应的代码

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值