linux 0.11 version 启动代码分析(bootsect.s)

来源:互联网 发布:知乎 chorm无法登陆 编辑:程序博客网 时间:2024/05/01 22:15

综述

启动代码位于/boot/,包含三个文件,均为汇编编写

/boot/bootsect.s

启动扇区的代码,位于启动扇区,即磁盘的0磁道,0磁头,第一扇区,bios运行之后会跳转到0x7c00处执行代码,这一段的代码则是将位于0x7c00处等待执行的代码。

!! SYS_SIZE is the number of clicks (16 bytes) to be loaded.! 0x3000 is 0x30000 bytes = 196kB, more than enough for current! versions of linux!!! SYSSIZE 为要加载的系统大小,对于当前版本linux来说是足够的!SYSSIZE = 0x3000!!    bootsect.s        (C) 1991 Linus Torvalds!! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves! iself out of the way to address 0x90000, and jumps there.!! It then loads 'setup' directly after itself (0x90200), and the system! at 0x10000, using BIOS interrupts. !! NOTE! currently system is at most 8*65536 bytes long. This should be no! problem, even in the future. I want to keep it simple. This 512 kB! kernel size should be enough, especially as this doesn't contain the! buffer cache as in minix!! The loader has been made as simple as possible, and continuos! read errors will result in a unbreakable loop. Reboot by hand. It! loads pretty fast by getting whole sectors at a time whenever possible.!!    bootsect.s        (C) 1991 Linus Torvalds版权所有!! bootsect.sbios启动过程当中被加载到0x7c00处,然后把它自己移动到0x90000处,再跳转到0x90000处执行! ! 需要注意的是当前system8×65536字节大小,在没有像minix中包含的缓冲区高速缓存的情况下!512KB的内核大小是足够的,即使在之后的版本当中也应该是足够的。!! NOTE! currently system is at most 8*65536 bytes long. This should be no! problem, even in the future. I want to keep it simple. This 512 kB! kernel size should be enough, especially as this doesn't contain the! buffer cache as in minix!! The loader has been made as simple as possible, and continuos! read errors will result in a unbreakable loop. Reboot by hand. It! loads pretty fast by getting whole sectors at a time whenever possible.!!! 加载程序越简单越好,如果持续读取出错将会导致死循环,只能手动重启,加载过程尽量做到一次读取! 整个扇区,所以加载的会很快! .globl begtext, begdata, begbss, endtext, enddata, endbss                        .text                                                                           begtext:.data                                                                            begdata:.bss                                                                             begbss:.text                       !text,data,bss段放在一起,没有分区SETUPLEN = 4                ! setup占扇区数量 BOOTSEG  = 0x07c0           ! bootsect的最初地址INITSEG  = 0x9000            ! bootsect将会移动到整个地址SETUPSEG = 0x9020            ! setup的开始位置SYSSEG   = 0x1000            !system加载的位置ENDSEG   = SYSSEG + SYSSIZE        ! system加载位置结束                   !ROOT_DEV:0x000 - 作为启动的软驱类型!         0x301 - 第一个驱动器上的第一个分区ROOT_DEV = 0x306                                                                 entry start                 ! 入口地址为startstart:    mov    ax,#BOOTSEG                                                               mov    ds,ax                                                                     mov    ax,#INITSEG                                                               mov    es,ax                                                                     mov    cx,#256                                                                   sub    si,si                                                                      sub    di,di                                                                     rep    !0x7c00:0x0000位置处256字节复制到0x9000:0x0000处,一次两个字节    movw                                                                             jmpi    go,INITSEG ! 跳转至INITSEG段的go处,即复制之后位于0x90000处的下一条语句位置   go:    mov    ax,cs                                                                  mov    ds,ax    mov    es,ax! put stack at 0x9ff00.   ! cs, ds, es, ss指向0x90000处                                                           mov    ss,ax    mov    sp,#0xFF00        ! arbitrary value >>512                              ! 栈指针sp指向0x9FF00! load the setup-sectors directly after the bootblock.!boot块后直接加载setup模块! Note that 'es' is already set up.! 此时es已经设置过了load_setup:! setup 模块加载    mov    dx,#0x0000        ! drive 0, head 0                                    ! dh为磁头号,dl为驱动器号,磁盘则位7置位    mov    cx,#0x0002        ! sector 2, track 0                                  ! ch为磁道号的低8位,cl为开始扇区(位05)与磁道号高二位(位67mov    bx,#0x0200        ! address = 512, in INITSEG   ! es:bx为目的地址,即0x9000:0x0200,0x92000位置    mov    ax,#0x0200+SETUPLEN    ! service 2, nr of sectors  ! ah中为0x13号中断的功能号,即2号,al中为需要执行的扇区数量! 0x13号中断2号功能为将指定扇区的内容加载到内存里    int    0x13            ! read it                                              ! 执行中断0x13    jnc    ok_load_setup        ! ok - continue                                  ! 执行成功,跳转至ok_load_setup    mov    dx,#0x0000                                                            ! 中断失败,复位驱动器,此时ah功能号为0x00    mov    ax,#0x0000        ! reset the diskette                                    int    0x13                                                                   ! 执行0x13号中断,0号功能,复位驱动器    j    load_setup                                                               ! 回到load_setup重新加载ok_load_setup:! Get disk drive parameters, specifically nr of sectors/track                    ! 获取磁盘参数,尤其是扇区和磁道的数量    mov    dl,#0x00                                                                 ! 通过dl指定磁盘    mov    ax,#0x0800        ! AH=8 is get drive parameters                           ! ah(功能号)为0x08,0x13号中断0x08号功能,执行读取磁盘信息,并且返回信息放在cxint    0x13                                                                         mov    ch,#0x00                                                                !ch设置为0,其实是将磁道号清空    seg cs     mov    sectors,cx                                                               ! 之前提到了扇区数不会超过256,所以al的低高两位为0cx此时为扇区数! 将扇区数赋值给变量sectors    mov    ax,#INITSEG    mov    es,ax                                                                    ! es已改变,重新指向INITSEG! Print some inane message    mov    ah,#0x03        ! read cursor pos                                        ! 通过中断0x10,功能号0x03,读取光标位置    xor    bh,bh    int    0x10    mov    cx,#24                                                                  ! 通过中断0x10打印消息    mov    bx,#0x0007        ! page 0, attribute 7 (normal)    mov    bp,#msg1    mov    ax,#0x1301        ! write string, move cursor    int    0x10! ok, we've written the message, now                                             ! we want to load the system (at 0x10000)                                        ! 接下来将system加载到0x10000    mov    ax,#SYSSEG    mov    es,ax        ! segment of 0x010000                                    ! es指向 0x010000    call    read_it                                                              ! 调用子程序read_it,进行加载    call    kill_motor                                                            ! 调用子程序kill_motor,关闭软驱motor! 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, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending! on the number of sectors that the BIOS reports currently.! 然后我们检查要使用的root设备,如果设备已经被定义了,那么就直接使用给出的设备! 否则就根据bios目前给出的扇区数量决定使用/dev/PS0 (2, 28)(1.44m软驱)! 或者 ! /dev/at0 (2,8) (1.2m软驱)    seg cs    mov    ax,root_dev                                                               ! 是否已经指定了root设备?    cmp    ax,#0    jne    root_defined                                                              ! root设备指定了,即不为0,则跳到root_defined子程序    seg cs    mov    bx,sectors                                                                ! 扇区数量放入bx中,准备进行比较    mov    ax,#0x0208        ! /dev/ps0 - 1.2Mb                                       ! 1.2Mb软驱的扇区数量    cmp    bx,#15                                                                         je    root_defined                                                                ! 如果是1.2Mb软驱,跳转    mov    ax,#0x021c        ! /dev/PS0 - 1.44Mb                                      ! 判断是否为1.4Mb软驱    cmp    bx,#18    je    root_defined                                                               ! 跳转undef_root:                             jmp undef_rootundef_root,死循环(未指定root_device也不为1.2m软驱和1.4m软驱则死循环)root_defined:                                                                       ! root设备已经指定    seg cs    mov    root_dev,ax                                                              ! 保存root设备号! after that (everyting loaded), we jump to                                         ! the setup-routine loaded directly after! the bootblock:! 所有的都加载完毕之后进入setup    jmpi    0,SETUPSEG                                                              ! 跳转到setup! This routine loads the system at address 0x10000, making sure! no 64kB boundaries are crossed. We try to load it as fast as! possible, loading whole tracks whenever we can.!! in:    es - starting address segment (normally 0x1000)!! !! 输入:    es - 开始地址的内存段(一般为  0x1000)!sread:    .word 1+SETUPLEN    ! sectors read of current track                  !已读扇区head:    .word 0            ! current head                                     !当前的磁头track:    .word 0            ! current track                                   !当前磁道read_it:                                                                       mov ax,es                                                                ! 检测es是否在0x1000处,此时esax0x1000    test ax,#0x0fffdie:    jne die            ! es must be at 64kB boundary                          ! es必须为0x1000,如果不是就死机    xor bx,bx        ! bx is starting address within segment !检测通过,清空bx         bx = 0rp_read:                                                                    !循环读取    mov ax,es                                                                ! 根据cs位置判断是否已经加载完毕,第一次的时候esax0x1000    cmp ax,#ENDSEG        ! have we loaded all yet?                             jb ok1_read                                                              ! 没有加载完毕,跳转至ok1_read    ret         ok1_read:    seg cs    mov ax,sectors                                                               ! 扇区数量放入ax中,(sectors1518sub ax,sread                                                                 ! 减去已读扇区数量 sread5ax减法后为10    mov cx,ax                                                                    ! 将未读扇区数量放入cxshl cx,#9                                                                    ! 计算需要读取的字节数 cx * 512 = 10h * 512 = 8 * 1K = 8K    add cx,bx                                                                    ! 计算段内偏移    jnc ok2_read                                                                 ! cf位无进位跳转    je ok2_read                                                                  ! zf位置位则跳转    xor ax,ax                                                                    ! 清空ax    sub ax,bx                                                                    ! 求补    shr ax,#9                                                                    ! 计算最多可读长度ok2_read:                                                                      ! 读取64k以内数据    call read_track                                                              ! 读取磁道    mov cx,ax                                                                    ! 保存ax    add ax,sread                                                                 ! 当前所读取的扇区数    seg cs    cmp ax,sectors                                                               ! 对比需要读取扇区数    jne ok3_read                                                                 ! 如果当前磁道还未读取扇区,则跳转至ok3_read继续读取    mov ax,#1                                                                    ! 如果当前磁头面已经读取完毕,则读取下一磁头面    sub ax,head                                                                  ! 如果是0磁头,则跳转至ok4_read读1磁头面    jne ok4_read                                                                 ! 如果不是,读下一磁道    inc track                    ok4_read:    mov head,ax                                                                  ! 保存当前磁头号    xor ax,ax  ! 清空ax,准备保存已读扇区ok3_read:    mov sread,ax                                                                 ! 保存已读取扇区数    shl cx,#9                                                                    ! 计算读取的长度    add bx,cx                                                                    ! 调整当前段内数据开始位置    jnc rp_read                                                                  ! 如果小于64k边界值,跳转至rp_read继续读取    mov ax,es                                                                    ! 已经读取64k数据,调整es位置    add ax,#0x1000                                                                   mov es,ax                                                                        xor bx,bx                                                                    ! 清除段内偏移值    jmp rp_read                                                                  ! 跳转至rp_read继续读取read_track:                                                                     ! 读取磁道函数    push ax                                                                     ! axbxcxdx入栈保存    push bx    push cx    push dx    mov dx,track                                                                ! 当前磁道号    mov cx,sread                                                                ! 当前已读扇区数    inc cx                                                                      ! 读取扇区数    mov ch,dl                                                                   ! ch中为当前磁头号    mov dx,head                                                                 ! 取磁头号    mov dh,dl                                                                  ! dh为磁头号    mov dl,#0                                                                   ! 当前驱动器号    and dx,#0x0100                                                              ! 确保磁头号不大于1    mov ah,#2                                                                   ! int 0x13功能号2读磁盘到内存    int 0x13                                                                    ! 执行中断,进行读取    jc bad_rt                                                                   ! 判断是否出错,出错则跳转至bad_rt处理    pop dx                                                                      ! 如果读取成功则弹出入栈寄存器,并跳出此函数    pop cx    pop bx    pop ax    retbad_rt:    mov ax,#0                                                              ! ah为零    mov dx,#0                                                                  ! 指定驱动器    int 0x13                                                                   ! 重置磁盘驱动器    pop dx                                                                     ! 弹出寄存器    pop cx    pop bx    pop ax    jmp read_track                                                             ! 跳转至前面重新读取/* * This procedure turns off the floppy drive motor, so * that we enter the kernel in a known state, and * don't have to worry about it later. */ /* * 这个过程是关闭软驱马达, 这样我们进入内核状态我们就能知道它的状态 * 之后就不用关心了 */kill_motor:    push dx                                                                       ! dx入栈保存    mov dx,#0x3f2                                                                 ! 软驱控制器端口    mov al,#0                                                                     ! 命令字    outb                                                                          ! 写入命令    pop dx                                                                        ! dx出栈    ret                                                                           ! 返回sectors:                                                                       !之前用于存储扇区数量的变量    .word 0msg1:                                                                           !要显示的信息    .byte 13,10                                                                   !回车换行的ASII码    .ascii "Loading system ..."    .byte 13,10,13,10.org 508                                                                        !从地址508处开始root_dev:                                                                       !定义根设备变量    .word ROOT_DEVboot_flag:                                                                      !启动扇区的标志    .word 0xAA55.textendtext:.dataenddata:.bssendbss:
0 0
原创粉丝点击