系统启动bootsect.s linux

一般pc在电源一开时,是由内存中地址ffff:0000开始执行(这个地址一定在rom bi

os中,rom bios一般是在feoooh到fffffh中),而此处的内容则是一个jump指令,jump到另一个位於rom bios中的位置,开始执行一系列的动作,包括了检查ram,keyboard,显示器,软硬磁盘等等,这些动作是由系统测试代码 (post,system test code)来执行的,随着制作bios厂商的不同而会有些许差异,但都是大同小异,读者可自行观察自家机器开机时,萤幕上所显示的检查讯息。

紧接着系统测试码之后,控制权会转移给rom中的启动程序(rom bootstrap routine),这个程序会将磁盘上的第零轨第零扇区读入内存中(这就是一般所谓的boot sector,如果你曾接触过电脑病毒,就大概听过它的大名),至於被读到内存的哪里呢? --绝对位置07c0:0000(即07c00h处),这是ibm系列pc的特性。而位在linux开机磁盘的boot sector上的正是linux的bootsect程序,也就是说,bootsect是第一个被读入内存中并执行的程序。现在,我们可以开始来看看到底bootsect做了什么。

 

第一步

 首先,bootsect将它"自己"从被rom bios载入的绝对地址0x7c00处搬到0x90000处,

然后利用一个jmpi(jump indirectly)的指令,跳到新位置的jmpi的下一行去执行,

       movw     $bootseg, %ax                   #$bootseg          = 0x07c0

       movw     %ax, %ds

       movw     $initseg, %ax               #$initseg        = def_initseg=0x0x9000

       movw     %ax, %es

       movw     $256, %cx                #256word s== 512bytes

       subw      %si, %si

subw      %di, %di

       cld

       rep

       movsw

       ljmp $initseg, $go

 

第二步

  接着,将其他segment registers包括ds,es,ss都指向0x9000这个位置,与cs看齐

。另外将sp及dx指向一任意位移地址( offset ),这个地址等一下会用来存放磁盘参数

表(disk para- meter table )

go:   movw     $0x4000-12, %di        # 0x4000 is an arbitrary value >=

              # length of bootsect + length of

                                   # setup + room for stack;

                                   # 12 is disk parm size.

       movw     %ax, %ds             # ax and es already contain initseg

       movw     %ax, %ss

       movw     %di, %sp             # put stack at initseg:0x4000-12.sp=0x94000-12,12byte放磁盘参数

 

第三步

  接着利用bios中断服务int 13h的第0号功能,重置磁盘控制器,使得刚才的设定发

挥功能。主要是为了一次读扇区数目增加,增加效率。

# many bios's default disk parameter tables will not recognize

# multi-sector reads beyond the maximum sector number specified

# in the default diskette parameter tables - this may mean 7

# sectors in some cases.

#

# since single sector reads are slow and out of the question,

# we must take care of this by creating new parameter tables

# (for the first disk) in ram.  we will set the maximum sector

# count to 36 - the most we will encounter on an ed 2.88. 

#

# high doesn't hurt.  low does.

#

# segments are as follows: ds = es = ss = cs = initseg, fs = 0,

# and gs is unused.

 

       movw     %cx, %fs              # set fs to 0

movw     $0x78, %bx              # fs:bx is parameter table address,磁盘参数已经由bios读到这个地址了,就是物理地址0x78

       pushw    %ds

       ldsw           %fs:(%bx), %si           # ds:si is source  ds:si==0x0000:0x78

       movb      $6, %cl                # copy 12 bytes

pushw    %di               # di = 0x4000-12.

       rep                       # don't need cld -> done on line 66

       movsw                 #ds:si--àes:di

       popw     %di

       popw     %ds

       movb      $36, 0x4(%di)             # patch sector count,用36重置

       movw     %di, %fs:(%bx)

       movw     %es, %fs:2(%bx)

       xorb       %ah, %ah             # reset fdc

       xorb       %dl, %dl

       int   $0x13   

                               

第四步

  完成重置磁盘控制器之后,bootsect就从磁盘上读入紧邻着bootsect的setup程序,

也就是setup.s,此读入动作是利用bios中断服务int 13h的第2号功能。setup的image将

会读入至程序所指定的内存绝对地址0x90200处,也就是在内存中紧邻着bootsect 所在

的位置。待setup的image读入内存后,利用bios中断服务int 13h的第2号功能读取目前

磁盘的参数。

xorw      %dx, %dx            # drive 0, head 0

       movb      $0x02, %cl           # sector 2, track 0

       movw     $0x0200, %bx            # address = 512, in initseg ,0x90200

       movb      $0x02, %ah          # service 2, "read sector(s)"

       movb      setup_sects, %al   # (assume all on head 0, track 0) setup_sects=4,读取的扇区数

       int    $0x13                  # read it,setup.s位于内存物理地址0x90200,

       jnc   ok_load_setup             # ok – continue

    #读盘错误处理

pushw    %ax                     # dump error code  出错处理,ax得到错误码

       call  print_nl

       movw     %sp, %bp

       call  print_hex

       popw     %ax      

       jmp load_setup

 

ok_load_setup:

# get disk drive parameters, specifically number of sectors/track.

 

# it seems that there is no bios call to get the number of sectors.

# guess 36 sectors if sector 36 can be read, 18 sectors if sector 18

# can be read, 15 if sector 15 can be read.  otherwise guess 9.

movw   $disksizes, %si              # table of sizes to try   在文件末尾定义了数据disksizes:      .byte  36, 18, 15, 9

probe_loop:

       lodsb            #(al)<-((si)),(si)<-(si)+1

       cbtw                            # extend to word,al->ax

       movw     %ax, sectors   #sectors: .word  0

       cmpw     $disksizes+4, %si

       jae   got_sectors           #jae不低于,或者高于或者等于,或进位位为0则转移if all else fails, try 9。就是36,18,15,9都测试过了,就跳到got_sectors

   

       xchgw    %cx, %ax             # cx = track and sector

       xorw      %dx, %dx            # drive 0, head 0

       xorb              %bl, %bl

       movb      setup_sects, %bh

       incb        %bh

       shlb        %bh                     # address after setup (es = cs)

movw     $0x0201, %ax             # service 2, 1 sector

       int    $0x13

       jc    probe_loop          # try next value,就是从0头,0磁道,读取第36,18,15号扇区,看能否成功,如果成功就跳到got_sectors,否则就再测试下一个数。把内容读到setup.s后面的内存中,这些扇区内容没有什么意义,只是为了测试sectors/track。

 

第五步

  再来,就要读入真正linux的kernel了,也就是你可以在linux的根目录下看到的"v

mlinuz" 。在读入前,将会先呼叫bios中断服务int 10h 的第3号功能,读取游标位置,

之后再呼叫bios 中断服务int 10h的第13h号功能,在萤幕上输出字串"loading",这个

字串在boot linux时都会首先被看到,相信大家应该觉得很眼熟吧。

got_sectors:

       movw     $initseg, %ax

       movw     %ax, %es             # set up es

       movb      $0x03, %ah          # read cursor pos

       xorb      %bh, %bh

       int    $0x10       #调用10号中断,功能3,读取光标的位置

 

       movw     $9, %cx

       movw     $0x0007, %bx            # page 0, attribute 7 (normal)

       movw    $msg1, %bp

       movw    $0x1301, %ax         # write string, move cursor

       int    $0x10                  # tell the user we're loading..在光标处打印msg1的内容,msg1=’loading…..’;

movw     $sysseg, %ax        # ok, we've written the message, now ,$sysseg=0x1000

       movw     %ax, %es             # we want to load system (at 0x10000)

       call  read_it       #读取vmlinux到0x10000,大小为0x7f00,会已最快的速度去读,方法就是用前面测试的sectors/track,一次读完整个磁道。

       call  kill_motor

       call  print_nl

 

第六步

  接下来做的事是检查root device,之后就仿照一开始的方法,利用indirect jump

 跳至刚刚已读入的setup部份

 

# after that we check which root-device to use. if the device is

# defined (!= 0), nothing is done and the given device is used.

# otherwise, one of /dev/fd0h2880 (2,32) or /dev/ps0 (2,28) or /dev/at0 (2,8)

# depending on the number of sectors we pretend to know we have.

movw     root_dev, %ax

       orw %ax, %ax

       jne   root_defined

   

       movw     sectors, %bx

       movw     $0x0208, %ax             # /dev/ps0 - 1.2mb

       cmpw     $15, %bx

       je    root_defined

   

       movb      $0x1c, %al           # /dev/ps0 - 1.44mb

       cmpw     $18, %bx

       je    root_defined

   

       movb      $0x20, %al           # /dev/fd0h2880 - 2.88mb

       cmpw     $36, %bx

       je    root_defined

       movb      $0, %al                # /dev/fd0 - autodetect

root_defined:

       movw     %ax, root_dev

 

# after that (everything loaded), we jump to the setup-routine

# loaded directly after the bootblock:

 

       ljmp       $setupseg, $0  #jmp to 0x90200

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Exxos/archive/2008/03/07/2156915.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值