学习linux0.11内核代码——引导启动程序bootsect.s(2)

二、 bootsect.s程序
1、 在PC加电自检后,ROM-BIOS会把引导扇区代码bootsect加载到0x7C00处并执行,执行过程中bootsect把自己移到0x90000处。程序主要负责:
1)把从磁盘第2扇区开始的4个扇区的setup模块(setup.s生成)加载到内存0x90200处(此处为紧接着ROM-BIOS之后),加载后内存如下分布(第一扇区即存放bootsect.s):
这里写图片描述

2) 利用BIOS中断0x13取磁盘参数表中当前启动引导盘的参数
3) 屏幕显示“Loading system…”
4) 把磁盘setup模块后面的system模块加载到内存0x10000
5) 确定根文件系统设备号并保存其设备号于root_dev
6) 跳转到setup程序开始处(即0x90200)执行setup程序

2、 根据源代码分析每一步骤执行过程
1) 执行bootsect过程中,bootsect把自己移到0x90000

…
BOOTSEG  = 0x07c0                      ! original address of boot-sector
INITSEG  = 0x9000                         ! we move boot here - out of the way
…

entry _start
_start:
    mov  ax,#BOOTSEG    
    mov  ds,ax                             !ds寄存器置为0x07c0
    mov  ax,#INITSEG
    mov  es,ax                             !es寄存器置为0x9000
    mov  cx,#256                         !设置计数器,计数256
    sub    si,si                              
    sub    di,di                              !sub是做减法操作,此处将si,di自己减自己,即置0。
                                         !移动时源地址ds:si=0x07c00x0000,目的地址es:di=0x90000x0000
                                         !即将BIOS移动到0x90000x07c0用于放置bootsect.s)
    rep                       !rep指令作用:重复执行后面一句操作,并递减cx的值,直到cx=0停止
    movw                  !movw指令作用:这里从内存[si]处移动cx个字到[di];注意一次的移动单位是“字”,mov指令+w(word)是一次移动一个字
   jmpi  go,INITSEG                 !将BIOS移动到0x9000后,跳转(go)到INITSEG(0x9000

上面一段代码的作用是将bootsect自身从位置0x07c0移动到0x9000处,共256个字(512字节),然后跳转到go的标号处。代码主要设定源地址和目标地址后,使用循环指令rep和移动指令movw进行移动。
不过有点疑问的是汇报mov指令的使用:
mov dst, src
dst是目的操作数,src是源操作数,指令实现的功能是:将源操作数送到目的操作数中,即:(dst) <–(src)
而代码中movw后面并没有跟目的和源操作数,不知道是当时汇编(0.11版本时)格式和现在不同,还是默认目的和源操作数为sd,ea?

2) 把从磁盘第2扇区开始的4个扇区的setup模块(setup.s生成)加载到内存0x90200处

go:        mov  ax,cs
    mov  ds,ax
    mov  es,ax   !ds、es都置成移动后代码所在的段处(0x9000)
! put stack at 0x9ff00. 下面两条指令是将堆栈指针sp指向0x9ff00处(即0x9000:0xff00mov  ss,ax  
   mov  sp,#0xFF00                  ! arbitrary value >>512

在这里,CPU已移动到0x90000位置处执行(注意物理地址=段地址*10H+偏移地址是0x9000*10H+0x0000)。
这段代码的作用是设置几个段寄存器ds、es,另外包括栈寄存器ss和sp,其中ax只是个赋值的中间变量,为后面移动setup模块做好准备。
有疑问的是cs寄存器的值,原谅我找了前面所有代码,都没看到cs的初始化赋值,但是注释意思是cs值为0x9000…
在上面设置好寄存器的值后,接下来是实现在bootsect程序块后紧接着加载setup模块代码数据。
下面代码是利用BIOS的中断INT 0x13将setup模块从磁盘第2个扇区开始读到0x90200处(为什么是0x90200处?因为bootsect放置在0x90000处,大小为512字节,即bootsect所占空间结束为0x90000+512字节,即0x90000+0x00200,而setup模块紧跟其后,所以放置位置只要大于此结束值即可),共读4个扇区。

INT 0x13的使用方法:
ah = 0x20-读磁盘扇区到内存; al = 需要读出的扇区数量;
ch=磁道(柱面)号的低8位;  cl =开始扇区(位0-5),磁道号高2位(位6-7);
dh = 磁头号;  dl = 驱动器号;
es:bx = 指向数据缓冲区; 
如果出错则CF标志置位,ah中是出错码。
load_setup:
    mov  dx,#0x0000                  ! drive 0, head 0  dx为0x0000,即dh为0x00,dl为0x00,即磁头号0,驱动器0
    mov  cx,#0x0002                   ! sector 2, track 0  同上磁道号0(低8位和高2位都是0), 开始扇区为2(从cl的低5位得到)
  mov  bx,#0x0200                  ! address = 512, in INITSEG  数据缓冲区0x90200,注意前面es已设置为0x9000,设置bx为0x0200,即数据缓冲区为0x9000*10H+0x0200=0x90200
    mov  ax,#0x0200+SETUPLEN    ! service 2, nr of sectors SETUPLEN初始设置为4,这里0x0200+4,ah=0x02(读磁盘扇区到内存??,我也不是很明白),al=4(即需要读出4个扇区)。
    int     0x13                    ! read it  打开中断
    jnc     ok_load_setup              ! ok – continue  jnc指令:如果(上条指令)成功,则跳转,即中断INT 0x13成功,则继续执行ok_load_setup
    mov  dx,#0x0000                  !如果不成功,则复位驱动器,并重试(重新跳转函数load_setup)
    mov  ax,#0x0000                   ! reset the diskette
    int     0x13
   j        load_setup

这段主要是对中断INT 0x13的使用,只要寄存器设置能够看懂,那么应该问题不大。

3) 利用BIOS中断0x13取磁盘参数表中当前启动引导盘的参数
取磁盘驱动器参数,使用INT 0x13中断获得,格式如下:
AH=0x08 dl=驱动器号
其返回值为:
(1) 如果出错则CF置位,ah=状态码
(2) ah=0,al=0,bl=驱动器类型
(3) ch=最大磁道号低8位,cl=每磁道最大扇区数(0-5位),最大磁道号高2位(6-7位)
(4) dh=最大磁头数,dl=驱动器数量
(5) es:di 软驱磁盘参数表

mov      dl,#0x00              !驱动器号为0
mov      ax,#0x0800                   ! AH=8,是INT 0x13取磁盘驱动器的参数,AL初始化0,作为返回值
int         0x13                    !打开INT 0x13中断
mov      ch,#0x00
seg cs             !此条指令表示下一条语句的操作数在cs段寄存器所指的段中
!软盘的最大磁道号不会超过256,ch返回最大磁道号低8位,已足够表示它,因此cl位6-7肯定为0,而前面语句ch已置0,说明cx的6-15位为0。
!那么cx的0-5位会返回每磁道最大扇区数,即此时cx值是每磁道最大扇区数。
mov      sectors,cx 
    … …

如果想获得磁盘驱动器的参数,那么应该使用INT 0x13中断的返回值获得,设置初始值ah和dl的值,打开中断,即可。这段代码主要还是获得每磁道的扇区数量,保存在了sectors中。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/cui841923894/article/details/82191858