第四章boot.asm

系统 1464 0

跟上篇日志中间又隔了好几天,懒惰啊

      
         1
      
      
        寻找LOADER.BIN文件的大体思路为:


      
      
         2
      
      
        LOADER.BIN文件存储在A盘中,我们知道A盘的格式是FAT12格式,具体格式见书本P103,其主要是有引导扇区
      
      
         3
      
      
        、FAT1区、FAT2区、根目录区(长度不固定,需要计算)和 数据区组成。引导扇区放的就是我们写的引导代码
      
      
         4
      
      
        boot.bin文件,我们的LOADER.BIN文件是放在数据区中的,而文件的文件名是放在根目录中,因此,如果我
      
      
         5
      
      
        们想查看该盘是否含有我们想要的文件时,我们应该先到根目录中查看是否含有该文件名,如果有,说明该盘存
      
      
         6
      
      
        在该文件,那么下面可以从盘中读取该文件了。
      
      
         7
      
      
        文件在盘中是按照簇来进行存储的,而在FAT12盘中,一个簇中只含有一个扇区,故下面我们只以扇区来进行说
      
      
         8
      
      
        明。所以文件在FAT12中是按照扇区(一个扇区512字节)来进行存储的,所以一个文件一般会占多个扇区,而
      
      
         9
      
      
        每个文件占的扇区数会记录在FAT1区中,我们只要从文件根目录中获取该文件在FAT1区中的起始地址,只要该
      
      
        10
      
      
        地址存储的不是0xFFF说明该文件还占有其他扇区,我们继续读取该地址指向的扇区,直到FAT1项中的值为
      
      
        11
      
      
        0xFFF,这表示文件结束,读取完毕.而根目录也是按照扇区进行存储的,所以我们得从根目录起始扇区开始顺
      
      
        12
      
      
        序读取每个扇区,直到根目录区结束。而每个根目录项是32个字节,因此一个扇区可以有16个根目录项,我们
      
      
        13 
      
      
        挨个比较每个根目录项中的文件名和我们期望查找的文件名是否相同,如果相同就表示已经找到,只要取出根目录项中的DIR_FstClus,然后从FAT1项中取出相应的数据即可。
      
      
        14
      
      
        如果没有找到,那么就到下一个根目录项中查找,如果当前扇区都没有找到,那么读取下一个扇区,直到这个根;目录区结束。
      
    

 

寻找loader.bin的思路

1.首先要明白loader.bin文件的数据部分放在数据区,而关于文件大小,文件名等文件信息放在根目录区

2.所以找文件的时候先到根目录区找到文件名为loader.bin的文件信息,怎么找呢?我们知道,每个文件的信息在根目录中占一项,每项为32字节,每个扇区共有16项;同时我们

还知道根目录开始扇区位19,所以我们从该扇区开始读取数据,每次读一个扇区。在度过一个扇区以后,我们要分析这个扇区中的内容,具体是比较目录项中文件名是否为

loader.bin,若是则在根目录中文件查找完毕

3.在根目录中找到loader.bin的信息之后,我们可以得到该文件在数据区的簇号(扇区号),同时也得到在fat表中的对应的项(index),p131小例子

4.反复根据步骤三得到信息读完整个文件

      
          1
      
      
        ;
      
      
        %define    _BOOT_DEBUG_    ; 做 Boot Sector 时一定将此行注释掉!将此行打开后用 nasm Boot.asm -o Boot.com 做成一个.COM文件易于调试
      
      
          2
      
      
          3
      
      
        %ifdef    _BOOT_DEBUG_


      
      
          4
      
           org  0100h            
      
        ;
      
      
         调试状态, 做成 .COM 文件, 可调试
      
      
          5
      
      
        %else


      
      
          6
      
           org  07c00h            
      
        ;
      
      
         Boot 状态, Bios 将把 Boot Sector 加载到 0:7C00 处并开始执行
      
      
          7
      
      
        %endif


      
      
          8
      
      
          9
      
      
        ;
      
      
        ================================================================================================
      
      
         10
      
      
        %ifdef    _BOOT_DEBUG_


      
      
         11
      
       BaseOfStack        equ    0100h    
      
        ;
      
      
         调试状态下堆栈基地址(栈底, 从这个位置向低地址生长)
      
      
         12
      
      
        %else


      
      
         13
      
       BaseOfStack        equ    07c00h    
      
        ;
      
      
         Boot状态下堆栈基地址(栈底, 从这个位置向低地址生长)
      
      
         14
      
      
        %endif


      
      
         15
      
      
         16
      
       BaseOfLoader        equ    09000h    
      
        ;
      
      
         LOADER.BIN 被加载到的位置 ----  段地址
      
      
         17
      
       OffsetOfLoader        equ    0100h    
      
        ;
      
      
         LOADER.BIN 被加载到的位置 ---- 偏移地址
      
      
         18
      
      
         19
      
       RootDirSectors        equ    
      
        14
      
      
        ;
      
      
         根目录占用空间
      
      
         20
      
       SectorNoOfRootDirectory    equ    
      
        19
      
      
        ;
      
      
         Root Directory 的第一个扇区号
      
      
         21
      
       SectorNoOfFAT1        equ    
      
        1
      
      
        ;
      
      
         FAT1 的第一个扇区号    = BPB_RsvdSecCnt
      
      
         22
      
       DeltaSectorNo        equ    
      
        17
      
      
        ;
      
      
         DeltaSectorNo = BPB_RsvdSecCnt + (BPB_NumFATs * FATSz) - 2
      
      
         23
      
      
        ;
      
      
         文件的开始Sector号 = DirEntry中的开始Sector号 + 根目录占用Sector数目 + DeltaSectorNo
      
      
         24
      
      
        ;
      
      
        ================================================================================================
      
      
         25
      
      
         26
      
      
        jmp
      
       short LABEL_START        
      
        ;
      
      
         Start to boot.
      
      
         27
      
      
        nop
      
      
        ;
      
      
         这个 nop 不可少
      
      
         28
      
      
         29
      
      
        ;
      
      
         下面是 FAT12 磁盘的头
      
      
         30
      
           BS_OEMName    DB 
      
        '
      
      
        ForrestY
      
      
        '
      
      
        ;
      
      
         OEM String, 必须 8 个字节
      
      
         31
      
           BPB_BytsPerSec    DW 
      
        512
      
      
        ;
      
      
         每扇区字节数
      
      
         32
      
           BPB_SecPerClus    DB 
      
        1
      
      
        ;
      
      
         每簇多少扇区
      
      
         33
      
           BPB_RsvdSecCnt    DW 
      
        1
      
      
        ;
      
      
         Boot 记录占用多少扇区
      
      
         34
      
           BPB_NumFATs    DB 
      
        2
      
      
        ;
      
      
         共有多少 FAT 表
      
      
         35
      
           BPB_RootEntCnt    DW 
      
        224
      
      
        ;
      
      
         根目录文件数最大值
      
      
         36
      
           BPB_TotSec16    DW 
      
        2880
      
      
        ;
      
      
         逻辑扇区总数
      
      
         37
      
           BPB_Media    DB 0xF0        
      
        ;
      
      
         媒体描述符
      
      
         38
      
           BPB_FATSz16    DW 
      
        9
      
      
        ;
      
      
         每FAT扇区数
      
      
         39
      
           BPB_SecPerTrk    DW 
      
        18
      
      
        ;
      
      
         每磁道扇区数
      
      
         40
      
           BPB_NumHeads    DW 
      
        2
      
      
        ;
      
      
         磁头数(面数)
      
      
         41
      
           BPB_HiddSec    DD 
      
        0
      
      
        ;
      
      
         隐藏扇区数
      
      
         42
      
           BPB_TotSec32    DD 
      
        0
      
      
        ;
      
      
         如果 wTotalSectorCount 是 0 由这个值记录扇区数
      
      
         43
      
           BS_DrvNum    DB 
      
        0
      
      
        ;
      
      
         中断 13 的驱动器号
      
      
         44
      
           BS_Reserved1    DB 
      
        0
      
      
        ;
      
      
         未使用
      
      
         45
      
           BS_BootSig    DB 29h        
      
        ;
      
      
         扩展引导标记 (29h)
      
      
         46
      
           BS_VolID    DD 
      
        0
      
      
        ;
      
      
         卷序列号
      
      
         47
      
           BS_VolLab    DB 
      
        '
      
      
        Tinix0.01  
      
      
        '
      
      
        ;
      
      
         卷标, 必须 11 个字节
      
      
         48
      
           BS_FileSysType    DB 
      
        '
      
      
        FAT12   
      
      
        '
      
      
        ;
      
      
         文件系统类型, 必须 8个字节  
      
      
         49
      
      
         50
      
      
        LABEL_START:
      
      
         51
      
      
        mov
      
      
            ax, cs


      
      
         52
      
      
        mov
      
      
            ds, ax


      
      
         53
      
      
        mov
      
      
            es, ax


      
      
         54
      
      
        mov
      
      
            ss, ax


      
      
         55
      
      
        mov
      
      
            sp, BaseOfStack


      
      
         56
      
      
         57
      
      
        ;
      
      
         清屏
      
      
         58
      
      
        mov
      
          ax, 0600h        
      
        ;
      
      
         AH = 6,  AL = 0h
      
      
         59
      
      
        mov
      
          bx, 0700h        
      
        ;
      
      
         黑底白字(BL = 07h)
      
      
         60
      
      
        mov
      
          cx, 
      
        0
      
      
        ;
      
      
         左上角: (0, 0)
      
      
         61
      
      
        mov
      
          dx, 0184fh        
      
        ;
      
      
         右下角: (80, 50)
      
      
         62
      
      
        int
      
          10h            
      
        ;
      
      
         int 10h
      
      
         63
      
      
         64
      
      
        mov
      
          dh, 
      
        0
      
      
        ;
      
      
         "Booting  "
      
      
         65
      
      
        call
      
          DispStr            
      
        ;
      
      
         显示字符串
      
      
         66
      
      
         67
      
      
        xor
      
          ah, ah    
      
        ;
      
      
      
         68
      
      
        xor
      
          dl, dl    
      
        ;
      
      
         ┣ 软驱复位
      
      
         69
      
      
        int
      
          13h    
      
        ;
      
      
      
         70
      
      
         71
      
      
        ;
      
      
         下面在 A 盘的根目录寻找 LOADER.BIN
      
      
         72
      
      
        mov
      
      
            word [wSectorNo], SectorNoOfRootDirectory


      
      
         73
      
      
        LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
      
      
         74
      
      
        cmp
      
          word [wRootDirSizeForLoop], 
      
        0
      
      
        ;
      
      
      
         75
      
      
        jz
      
          LABEL_NO_LOADERBIN        
      
        ;
      
      
         ┣ 判断根目录区是不是已经读完
      
      
         76
      
      
        dec
      
          word [wRootDirSizeForLoop]    
      
        ;
      
      
         ┛ 如果读完表示没有找到 LOADER.BIN
      
      
         77
      
      
        mov
      
      
            ax, BaseOfLoader


      
      
         78
      
      
        mov
      
          es, ax            
      
        ;
      
      
         es <- BaseOfLoader
      
      
         79
      
      
        mov
      
          bx, OffsetOfLoader    
      
        ;
      
      
         bx <- OffsetOfLoader    于是, es:bx = BaseOfLoader:OffsetOfLoader
      
      
         80
      
      
        mov
      
          ax, [wSectorNo]    
      
        ;
      
      
         ax <- Root Directory 中的某 Sector 号
      
      
         81
      
      
        mov
      
          cl, 
      
        1
      
      
         82
      
      
        call
      
      
            ReadSector


      
      
         83
      
      
         84
      
      
        mov
      
          si, LoaderFileName    
      
        ;
      
      
         ds:si -> "LOADER  BIN"
      
      
         85
      
      
        mov
      
          di, OffsetOfLoader    
      
        ;
      
      
         es:di -> BaseOfLoader:0100 = BaseOfLoader*10h+100
      
      
         86
      
      
        cld
      
      
         87
      
      
        mov
      
          dx, 10h 
      
        ;
      
      
        这里为什么是16,因为目录项中每项为32字节,每个扇区为32字节,所以共有16项
      
      
         88
      
      
        LABEL_SEARCH_FOR_LOADERBIN:
      
      
         89
      
      
        cmp
      
          dx, 
      
        0
      
      
        ;
      
      
         ┓循环次数控制,
      
      
         90
      
      
        jz
      
          LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR    
      
        ;
      
      
         ┣如果已经读完了一个 Sector,
      
      
         91
      
      
        dec
      
          dx                                            
      
        ;
      
      
         ┛就跳到下一个 Sector
      
      
         92
      
      
        mov
      
          cx, 
      
        11
      
      
        ;
      
      
        11个字符,有一个不一样则不是所要找的文件
      
      
         93
      
      
        LABEL_CMP_FILENAME:
      
      
         94
      
      
        cmp
      
          cx, 
      
        0
      
      
         95
      
      
        jz
      
          LABEL_FILENAME_FOUND    
      
        ;
      
      
         如果比较了 11 个字符都相等, 表示找到
      
      
         96
      
      
        dec
      
      
            cx


      
      
         97
      
      
        lodsb
      
      
        ;
      
      
         ds:si -> al
      
      
         98
      
      
        cmp
      
          al, byte [
      
        es:
      
      
        di]


      
      
         99
      
      
        jz
      
      
            LABEL_GO_ON


      
      
        100
      
      
        jmp
      
          LABEL_DIFFERENT        
      
        ;
      
      
         只要发现不一样的字符就表明本 DirectoryEntry 不是
      
      
        101
      
      
        ;
      
      
         我们要找的 LOADER.BIN
      
      
        102
      
      
        LABEL_GO_ON:
      
      
        103
      
      
        inc
      
      
            di


      
      
        104
      
      
        jmp
      
          LABEL_CMP_FILENAME    
      
        ;
      
      
            继续循环
      
      
        105
      
      
        106
      
      
        LABEL_DIFFERENT:
      
      
        107
      
      
        and
      
          di, 0FFE0h                        
      
        ;
      
      
         else ┓    di &= E0 为了让它指向本条目开头
      
      
        108
      
      
        add
      
          di, 20h                            
      
        ;
      
      
      
        109
      
      
        mov
      
          si, LoaderFileName                    
      
        ;
      
      
             ┣ di += 20h  下一个目录条目
      
      
        110
      
      
        jmp
      
          LABEL_SEARCH_FOR_LOADERBIN
      
        ;
      
      
      
        111
      
      
        112
      
      
        LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
      
      
        113
      
      
        add
      
          word [wSectorNo], 
      
        1
      
      
        114
      
      
        jmp
      
      
            LABEL_SEARCH_IN_ROOT_DIR_BEGIN


      
      
        115
      
      
        116
      
      
        LABEL_NO_LOADERBIN:
      
      
        117
      
      
        mov
      
          dh, 
      
        2
      
      
        ;
      
      
         "No LOADER."
      
      
        118
      
      
        call
      
          DispStr            
      
        ;
      
      
         显示字符串
      
      
        119
      
      
        %ifdef    _BOOT_DEBUG_


      
      
        120
      
      
        mov
      
          ax, 4c00h        
      
        ;
      
      
      
        121
      
      
        int
      
          21h            
      
        ;
      
      
         ┛没有找到 LOADER.BIN, 回到 DOS
      
      
        122
      
      
        %else


      
      
        123
      
      
        jmp
      
          $            
      
        ;
      
      
         没有找到 LOADER.BIN, 死循环在这里
      
      
        124
      
      
        %endif


      
      
        125
      
      
        126
      
      
        LABEL_FILENAME_FOUND:
      
      
        ;
      
      
         找到 LOADER.BIN 后便来到这里继续
      
      
        127
      
      
        mov
      
      
            ax, RootDirSectors


      
      
        128
      
      
        and
      
          di, 0FFE0h        
      
        ;
      
      
         di -> 当前条目的开始
      
      
        129
      
      
        add
      
          di, 01Ah        
      
        ;
      
      
         di -> 首 Sector,该条目对应的开始簇号(扇区号),看根目录条目格式表
      
      
        130
      
      
        mov
      
          cx, word [
      
        es:
      
      
        di]


      
      
        131
      
      
        push
      
          cx            
      
        ;
      
      
         保存此 Sector 在 FAT 中的序号
      
      
        132
      
      
        add
      
      
            cx, ax


      
      
        133
      
      
        add
      
          cx, DeltaSectorNo    
      
        ;
      
      
         这句完成时 cl 里面变成 LOADER.BIN 的起始扇区号 (从 0 开始数的序号)
      
      
        134
      
      
        mov
      
      
            ax, BaseOfLoader


      
      
        135
      
      
        mov
      
          es, ax            
      
        ;
      
      
         es <- BaseOfLoader
      
      
        136
      
      
        mov
      
          bx, OffsetOfLoader    
      
        ;
      
      
         bx <- OffsetOfLoader    于是, es:bx = BaseOfLoader:OffsetOfLoader = BaseOfLoader * 10h + OffsetOfLoader
      
      
        137
      
      
        mov
      
          ax, cx            
      
        ;
      
      
         ax <- Sector 号
      
      
        138
      
      
        139
      
      
        LABEL_GOON_LOADING_FILE:
      
      
        140
      
      
        push
      
          ax            
      
        ;
      
      
      
        141
      
      
        push
      
          bx            
      
        ;
      
      
      
        142
      
      
        mov
      
          ah, 0Eh            
      
        ;
      
      
         ┃ 每读一个扇区就在 "Booting  " 后面打一个点, 形成这样的效果:
      
      
        143
      
      
        mov
      
          al, 
      
        '
      
      
        .
      
      
        '
      
      
        ;
      
      
      
        144
      
      
        mov
      
          bl, 0Fh            
      
        ;
      
      
         ┃ Booting ......
      
      
        145
      
      
        int
      
          10h            
      
        ;
      
      
         ┃AL=字符,BH=页码,BL=颜色(只适用于图形模式)
      
      
        146
      
      
        pop
      
          bx            
      
        ;
      
      
      
        147
      
      
        pop
      
          ax            
      
        ;
      
      
      
        148
      
      
        149
      
      
        mov
      
          cl, 
      
        1
      
      
        150
      
      
        call
      
      
            ReadSector


      
      
        151
      
      
        pop
      
          ax            
      
        ;
      
      
         取出此 Sector 在 FAT 中的序号,见132行
      
      
        152
      
      
        call
      
      
            GetFATEntry


      
      
        153
      
      
        cmp
      
      
            ax, 0FFFh


      
      
        154
      
      
        jz
      
      
            LABEL_FILE_LOADED


      
      
        155
      
      
        push
      
          ax            
      
        ;
      
      
         保存 Sector 在 FAT 中的序号
      
      
        156
      
      
        mov
      
      
            dx, RootDirSectors


      
      
        157
      
      
        add
      
      
            ax, dx


      
      
        158
      
      
        add
      
      
            ax, DeltaSectorNo


      
      
        159
      
      
        add
      
      
            bx, [BPB_BytsPerSec]


      
      
        160
      
      
        jmp
      
      
            LABEL_GOON_LOADING_FILE


      
      
        161
      
      
        LABEL_FILE_LOADED:
      
      
        162
      
      
        163
      
      
        mov
      
          dh, 
      
        1
      
      
        ;
      
      
         "Ready."
      
      
        164
      
      
        call
      
          DispStr            
      
        ;
      
      
         显示字符串
      
      
        165
      
      
        166
      
      
        ;
      
      
         *****************************************************************************************************
      
      
        167
      
      
        jmp
      
      
        BaseOfLoader:
      
      OffsetOfLoader    
      
        ;
      
      
         这一句正式跳转到已加载到内存中的 LOADER.BIN 的开始处
      
      
        168
      
      
        ;
      
      
         开始执行 LOADER.BIN 的代码
      
      
        169
      
      
        ;
      
      
         Boot Sector 的使命到此结束
      
      
        170
      
      
        ;
      
      
         *****************************************************************************************************
      
      
        171
      
      
        172
      
      
        173
      
      
        174
      
      
        ;
      
      
        ============================================================================
      
      
        175
      
      
        ;
      
      
        变量
      
      
        176
      
      
        ;
      
      
        ----------------------------------------------------------------------------
      
      
        177
      
       wRootDirSizeForLoop    dw    RootDirSectors    
      
        ;
      
      
         Root Directory 占用的扇区数, 在循环中会递减至零.
      
      
        178
      
       wSectorNo        dw    
      
        0
      
      
        ;
      
      
         要读取的扇区号
      
      
        179
      
       bOdd            db    
      
        0
      
      
        ;
      
      
         奇数还是偶数
      
      
        180
      
      
        181
      
      
        ;
      
      
        ============================================================================
      
      
        182
      
      
        ;
      
      
        字符串
      
      
        183
      
      
        ;
      
      
        ----------------------------------------------------------------------------
      
      
        184
      
       LoaderFileName        db    
      
        "
      
      
        LOADER  BIN
      
      
        "
      
      , 
      
        0
      
      
        ;
      
      
         LOADER.BIN 之文件名
      
      
        185
      
      
        ;
      
      
         为简化代码, 下面每个字符串的长度均为 MessageLength
      
      
        186
      
       MessageLength        equ    
      
        9
      
      
        187
      
      
        BootMessage:
      
              db    
      
        "
      
      
        Booting  
      
      
        "
      
      
        ;
      
      
         9字节, 不够则用空格补齐. 序号 0
      
      
        188
      
       Message1        db    
      
        "
      
      
        Ready.   
      
      
        "
      
      
        ;
      
      
         9字节, 不够则用空格补齐. 序号 1
      
      
        189
      
       Message2        db    
      
        "
      
      
        No LOADER
      
      
        "
      
      
        ;
      
      
         9字节, 不够则用空格补齐. 序号 2
      
      
        190
      
      
        ;
      
      
        ============================================================================
      
      
        191
      
      
        192
      
      
        193
      
      
        ;
      
      
        ----------------------------------------------------------------------------
      
      
        194
      
      
        ;
      
      
         函数名: DispStr
      
      
        195
      
      
        ;
      
      
        ----------------------------------------------------------------------------
      
      
        196
      
      
        ;
      
      
         作用:
      
      
        197
      
      
        ;
      
      
            显示一个字符串, 函数开始时 dh 中应该是字符串序号(0-based)
      
      
        198
      
      
        DispStr:
      
      
        199
      
      
        mov
      
      
            ax, MessageLength


      
      
        200
      
      
        mul
      
      
            dh


      
      
        201
      
      
        add
      
      
            ax, BootMessage


      
      
        202
      
      
        mov
      
          bp, ax            
      
        ;
      
      
      
        203
      
      
        mov
      
          ax, ds            
      
        ;
      
      
         ┣ ES:BP = 串地址
      
      
        204
      
      
        mov
      
          es, ax            
      
        ;
      
      
      
        205
      
      
        mov
      
          cx, MessageLength    
      
        ;
      
      
         CX = 串长度
      
      
        206
      
      
        mov
      
          ax, 01301h        
      
        ;
      
      
         AH = 13,  AL = 01h
      
      
        207
      
      
        mov
      
          bx, 0007h        
      
        ;
      
      
         页号为0(BH = 0) 黑底白字(BL = 07h)
      
      
        208
      
      
        mov
      
          dl, 
      
        0
      
      
        209
      
      
        int
      
          10h            
      
        ;
      
      
         int 10h
      
      
        210
      
      
        ret
      
      
        211
      
      
        212
      
      
        213
      
      
        ;
      
      
        ----------------------------------------------------------------------------
      
      
        214
      
      
        ;
      
      
         函数名: ReadSector
      
      
        215
      
      
        ;
      
      
        ----------------------------------------------------------------------------
      
      
        216
      
      
        ;
      
      
         作用:
      
      
        217
      
      
        ;
      
      
            从第 ax 个 Sector 开始, 将 cl 个 Sector 读入 es:bx 中
      
      
        218
      
      
        ReadSector:
      
      
        219
      
      
        ;
      
      
         -----------------------------------------------------------------------
      
      
        220
      
      
        ;
      
      
         怎样由扇区号求扇区在磁盘中的位置 (扇区号 -> 柱面号, 起始扇区, 磁头号)
      
      
        221
      
      
        ;
      
      
         -----------------------------------------------------------------------
      
      
        222
      
      
        ;
      
      
         设扇区号为 x
      
      
        223
      
      
        ;
      
      
                                   ┌ 柱面号 = y >> 1
      
      
        224
      
      
        ;
      
      
               x           ┌ 商 y ┤
      
      
        225
      
      
        ;
      
      
         -------------- => ┤      └ 磁头号 = y & 1
      
      
        226
      
      
        ;
      
      
          每磁道扇区数     │
      
      
        227
      
      
        ;
      
      
                           └ 余 z => 起始扇区号 = z + 1
      
      
        228
      
      
        push
      
      
            bp


      
      
        229
      
      
        mov
      
      
            bp, sp


      
      
        230
      
      
        sub
      
          esp, 
      
        2
      
      
        ;
      
      
         辟出两个字节的堆栈区域保存要读的扇区数: byte [bp-2]
      
      
        231
      
      
        232
      
      
        mov
      
          byte [bp-
      
        2
      
      
        ], cl


      
      
        233
      
      
        push
      
          bx            
      
        ;
      
      
         保存 bx
      
      
        234
      
      
        mov
      
          bl, [BPB_SecPerTrk]    
      
        ;
      
      
         bl: 除数
      
      
        235
      
      
        div
      
          bl            
      
        ;
      
      
         y 在 al 中, z 在 ah 中
      
      
        236
      
      
        inc
      
          ah            
      
        ;
      
      
         z ++
      
      
        237
      
      
        mov
      
          cl, ah            
      
        ;
      
      
         cl <- 起始扇区号
      
      
        238
      
      
        mov
      
          dh, al            
      
        ;
      
      
         dh <- y
      
      
        239
      
      
        shr
      
          al, 
      
        1
      
      
        ;
      
      
         y >> 1 (其实是 y/BPB_NumHeads, 这里BPB_NumHeads=2)
      
      
        240
      
      
        mov
      
          ch, al            
      
        ;
      
      
         ch <- 柱面号
      
      
        241
      
      
        and
      
          dh, 
      
        1
      
      
        ;
      
      
         dh & 1 = 磁头号
      
      
        242
      
      
        pop
      
          bx            
      
        ;
      
      
         恢复 bx
      
      
        243
      
      
        ;
      
      
         至此, "柱面号, 起始扇区, 磁头号" 全部得到 ^^^^^^^^^^^^^^^^^^^^^^^^
      
      
        244
      
      
        mov
      
          dl, [BS_DrvNum]        
      
        ;
      
      
         驱动器号 (0 表示 A 盘)
      
      
        245
      
       .
      
        GoOnReading:
      
      
        246
      
      
        mov
      
          ah, 
      
        2
      
      
        ;
      
      
      
        247
      
      
        mov
      
          al, byte [bp-
      
        2
      
      ]        
      
        ;
      
      
         读 al 个扇区
      
      
        248
      
      
        int
      
      
            13h


      
      
        249
      
      
        jc
      
          .GoOnReading        
      
        ;
      
      
         如果读取错误 CF 会被置为 1, 这时就不停地读, 直到正确为止
      
      
        250
      
      
        251
      
      
        add
      
          esp, 
      
        2
      
      
        252
      
      
        pop
      
      
            bp


      
      
        253
      
      
        254
      
      
        ret
      
      
        255
      
      
        256
      
      
        ;
      
      
        ----------------------------------------------------------------------------
      
      
        257
      
      
        ;
      
      
         函数名: GetFATEntry
      
      
        258
      
      
        ;
      
      
        ----------------------------------------------------------------------------
      
      
        259
      
      
        ;
      
      
         作用:
      
      
        260
      
      
        ;
      
      
            找到序号为 ax 的 Sector 在 FAT 中的条目, 结果放在 ax 中
      
      
        261
      
      
        ;
      
      
            需要注意的是, 中间需要读 FAT 的扇区到 es:bx 处, 所以函数一开始保存了 es 和 bx
      
      
        262
      
      
        GetFATEntry:
      
      
        263
      
      
        push
      
      
            es


      
      
        264
      
      
        push
      
      
            bx


      
      
        265
      
      
        push
      
      
            ax


      
      
        266
      
      
        mov
      
          ax, BaseOfLoader    
      
        ;
      
      
      
        267
      
      
        sub
      
          ax, 0100h        
      
        ;
      
      
         ┣ 在 BaseOfLoader 后面留出 4K 空间用于存放 FAT,注意这里是0100,而不是01000
      
      
        268
      
      
        mov
      
          es, ax            
      
        ;
      
      
      
        269
      
      
        pop
      
      
            ax


      
      
        270
      
      
        mov
      
          byte [bOdd], 
      
        0
      
      
        271
      
      
        mov
      
          bx, 
      
        3
      
      
        272
      
      
        mul
      
          bx            
      
        ;
      
      
         dx:ax = ax * 3
      
      
        273
      
      
        mov
      
          bx, 
      
        2
      
      
        274
      
      
        div
      
          bx            
      
        ;
      
      
         dx:ax / 2  ==>  ax <- 商, dx <- 余数
      
      
        275
      
      
        cmp
      
          dx, 
      
        0
      
      
        276
      
      
        jz
      
      
            LABEL_EVEN


      
      
        277
      
      
        mov
      
          byte [bOdd], 
      
        1
      
      
        278
      
      
        LABEL_EVEN:
      
      
        ;
      
      
        偶数
      
      
        279
      
      
        xor
      
          dx, dx            
      
        ;
      
      
         现在 ax 中是 FATEntry 在 FAT 中的偏移量. 下面来计算 FATEntry 在哪个扇区中(FAT占用不止一个扇区)
      
      
        280
      
      
        mov
      
      
            bx, [BPB_BytsPerSec]


      
      
        281
      
      
        div
      
          bx            
      
        ;
      
      
         dx:ax / BPB_BytsPerSec  ==>    ax <- 商   (FATEntry 所在的扇区相对于 FAT 来说的扇区号)
      
      
        282
      
      
        ;
      
      
                        dx <- 余数 (FATEntry 在扇区内的偏移)。
      
      
        283
      
      
        push
      
      
            dx


      
      
        284
      
      
        mov
      
          bx, 
      
        0
      
      
        ;
      
      
         bx <- 0    于是, es:bx = (BaseOfLoader - 100):00 = (BaseOfLoader - 100) * 10h
      
      
        285
      
      
        add
      
          ax, SectorNoOfFAT1    
      
        ;
      
      
         此句执行之后的 ax 就是 FATEntry 所在的扇区号
      
      
        286
      
      
        mov
      
          cl, 
      
        2
      
      
        287
      
      
        call
      
          ReadSector        
      
        ;
      
      
         读取 FATEntry 所在的扇区, 一次读两个, 避免在边界发生错误, 因为一个 FATEntry 可能跨越两个扇区
      
      
        288
      
      
        pop
      
      
            dx


      
      
        289
      
      
        add
      
      
            bx, dx


      
      
        290
      
      
        mov
      
          ax, [
      
        es:
      
      
        bx]


      
      
        291
      
      
        cmp
      
          byte [bOdd], 
      
        1
      
      
        292
      
      
        jnz
      
      
            LABEL_EVEN_2


      
      
        293
      
      
        shr
      
          ax, 
      
        4
      
      
        294
      
      
        LABEL_EVEN_2:
      
      
        295
      
      
        and
      
      
            ax, 0FFFh


      
      
        296
      
      
        297
      
      
        LABEL_GET_FAT_ENRY_OK:
      
      
        298
      
      
        299
      
      
        pop
      
      
            bx


      
      
        300
      
      
        pop
      
      
            es


      
      
        301
      
      
        ret
      
      
        302
      
      
        ;
      
      
        ----------------------------------------------------------------------------
      
      
        303
      
      
        304
      
       times     
      
        510
      
      -($-$$)    db    
      
        0
      
      
        ;
      
      
         填充剩下的空间,使生成的二进制代码恰好为512字节
      
      
        305
      
       dw     0xaa55                
      
        ;
      
      
         结束标志
      
    

参考:

http://blog.chinaunix.net/uid-27024249-id-3449728.html

http://blog.csdn.net/robbie1314/article/details/5765117

http://blog.csdn.net/asd8182651/article/details/7388541

第四章boot.asm


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论