《一个64位操作系统的设计与实现》3-2、3-3,boot.asm,代码注释,每行都注释

由于引导区只能有512字节,做了代码优化

org 07c00h  ;BIOS引导地址
BaseOfStack equ 0x7c00  ;栈基
;=========设置Loader物理地址 10000h 1000h*10h+00h
BaseOfLoader equ 0x1000 ;Loader基址
OffsetOfLoader equ 0x00 ;Loader偏移量
;=========FAT12配置
RootDirSectors equ 14   ;根目录扇区数,公式(可容纳目录项数(224*(每项字节数)32+扇区字节数(512)-1)/扇区字节数(512)=(224*32+512-1512=14
SectorNumOfRootDirStart equ 19  ;根目录起始地址,公式 引导扇区数(1)+FAT表扇区数(9*表份数(2)=19
SectorNumOfFAT1Start equ 1  ;起始扇区编号,由于前面有编号为0的引导区故从1开始
SectorBalance equ 17    ;平衡文件 起始簇号与数据簇号的差值,根目录起始簇号-219-2,,FAT项
;========FAT12文件习题 引导扇区结构
    jmp short Label_Start   ;跳转到引导程序
    nop                     ;凑够3个字节
    BS_OEMName  db 'LiHao   ';生产产厂商名,必须是8个字符,不足以空格补充
    BPB_BytesPerSec dw 512  ;每扇区字节数
    BPB_SecPerClus  db 1    ;每蔟扇区数
    BPB_RsvdSecCnt  dw 1    ;保留扇区数
    BPB_NumFATs db  2       ;FAT表备份数
    BPB_RootEntCnt  dw  224 ;根可容纳项目数 2个字节225-1
    BPB_TotSec16    dw  2880;总共扇区数
    BPB_Media   db  0xf0    ;介质描述符表示0xf03.5寸高密码软盘
    BPB_FATSz16 dw  9       ;每个FAT扇区数
    BPB_SecPerTrk   dw  18  ;每个磁道扇区数
    BPB_NumHeads    dw  2   ;磁头数
    BPB_HiddSec dd  0       ;隐藏扇区数
    BPB_TotSec32    dd  0   ;当BPB_TotSec16为0时由这个值记录总扇区数
    BS_DrvNum   db  0       ;int 13h的驱动号,第一个软盘驱动器设置为0
    BS_Reserved1    db  0   ;未使用
    BS_BootSig  db  0x29    ;扩展引导标记
    BS_VolID    dd  0       ;卷序列号
    BS_VolLab   db  'boot loader';卷标11字节长
    BS_FileSysType  db  'FAT12   ';文件系统类型,操作系统不使用该字段判定
Label_Start:

    mov ax,cs
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov sp,BaseOfStack
;==========清屏
    mov ax,0600h    ;清屏
    mov bx,0700h    ;清屏
    mov cx,0        ;滚动范围左上角坐标00
    mov dx,0184fh   ;右下角坐标(80,50)
    int 10h         ;
;=========设置焦点
    ; mov ax,0200h  
    ; mov bx,0000h  ;页码为0
    ; mov dx,0000h  ;游标行列数为0
    ; int 10h
;========显示字符串
    mov cx,10       ;cx=串长  
    mov bl,07h      ;黑底白字
    mov dh,00h      ;行号
    mov ax,ds       ;es:bp显示字符串地址
    mov es,ax
    mov bp,StartBootMessage
    call DispStr
;=======复位
    xor ah,ah
    xor dl,dl
    int 13h
;=======查找 loader.bin
;根目录每32B保存一个文件的信息,0-11表示文件名和扩展名
;此程序是在根目录里面一个扇区有16个文件信息,依次读出并与要查找的文件名比较
    mov word [SectorNo],SectorNumOfRootDirStart ;用SectorNo保存根目录起始地址
Label_Search_In_Root_Dir_Begin:             ;在根目录扇区查找载入一个扇区
    cmp word [RootDirSizeForLoop],0         ;判断是否查完根目录
    jz Label_No_LoaderBin                   ;读完根目录则显示查找不到
    dec word [RootDirSizeForLoop]           ;扇区数减一,到下一个查找项
    mov ax,00h
    mov es,ax
    mov bx,8000h                            ;es:BX读取内容存放位置
    mov ax,[SectorNo]                       ;要读取的扇区
    mov cl,1                                ;读取扇区数
    call Func_ReadOneSector                 ;读一个扇区
    mov si,LoaderFileName                   ;si<-LoaderFileName,ds:si文件名所在地址
    mov di,8000h                            ;es:si,读出来的文件所在位置
    cld                                     ;lodsb方向为正cf置0
    mov dx,10h                              ;每个扇区可容纳扇区数512/32=10h
Label_Search_For_LoaderBin:
    cmp dx,0                                ;此扇区是否读完
    jz Label_Goto_Next_Sector_In_Root_Dir   ;下一扇区
    dec dx                                  ;要查找的扇区数减一
    mov cx,11                               ;保存文件名+扩展名长度,即比较次数
Label_Cmp_FileName:                         ;文件名匹配
    cmp cx,0                                ;是不是全部匹配
    jz Label_FileName_Found                 ;找到文件
    dec cx                                  ;匹配下一个字符
    lodsb                                   ;加载字符
    cmp al,byte [es:di]                     ;比较是否匹配
    jz Label_Go_On                          ;匹配继续
    jmp Label_Different                     ;不匹配
Label_Go_On:        
    inc di                                  ;di++下一个字符
    jmp Label_Cmp_FileName                  ;判断匹配
Label_Different:
    and di,0ffe0h                           ;第五为置零
    add di,20h                              ;下一个条目的文件名处
    mov si, LoaderFileName
    jmp Label_Search_For_LoaderBin
Label_Goto_Next_Sector_In_Root_Dir:
    add word [SectorNo],1                   ;查找的扇区地址加一
    jmp Label_Search_In_Root_Dir_Begin      ;下一个扇区判断
;======显示错误提示信息
Label_No_LoaderBin: 
    mov bl,8ch      ;黑底红字闪烁
    mov cx,8        ;cx=串长
    mov dx,0100h        ;起始行;起始列        
    mov ax,ds       ;es:bp显示字符串地址
    mov es,ax
    mov bp,NoLoaderMessage
    call DispStr
    jmp $
;=========从软盘中读取数据
;参数
;ax=读取扇区地址
;cx=读取扇区数
;返回值es:bx   
;LAB扇区好/每磁道扇区数=Q........R
;柱面号=Q>>1(其实是Q/BPB_NumHeads)因为BPB_NumHead为2 所以右移一位
;磁头号=Q&1
;扇区号=R+1 扇区是从1开始的
Func_ReadOneSector:
    push bp     ;
    mov bp,sp   
    sub esp,2           ;开辟两个字节的栈空间,存放保存要读取的扇区数
    mov byte [bp-2],cl  ;保存要读出的扇区数
    push    bx              ;保存bx
    ;由LAB格式转换为CHS格式 
    mov bl,[BPB_SecPerTrk]  ;除数每个磁道扇区数
    div bl                  ;商Q在al中,余数R在ah中
    inc ah                  ;得到扇区号
    mov cl,ah               ;读取扇配置区号13-02中断
    mov dh,al               
    and dh,1                ;磁头号配置13-02中断
    mov ch,al
    shr ch,1                ;磁道号
    pop BX                  ;恢复BX
    mov dl,[BS_DrvNum]      ;设置驱动号
Label_Go_On_Reading:
    mov ah,2                ;ah中断代号
    mov al,byte [bp-2]      ;将之前存储的读取字节数,放到al,配置13-02中断
    int 13h
    jc Label_Go_On_Reading  ;如果读取失败会将CF位置1,这时要不停读,直到成功
    add esp,2               ;释放之前申请空间
    pop bp                  ;恢复bp
    ret
;=======找到文件
Label_FileName_Found:
;显示File Found串
    mov cx,10       ;cx=串长
    mov bl,0Eh      ;黑底红字
    mov dh,01h      ;起始行        
    mov ax,ds       ;es:bp显示字符串地址
    mov es,ax
    mov bp,FileFound
    call DispStr
;根据真实扇区
;目录项的ah存放起始蔟号,
;起始簇号+RootDirSectors+SectorBalance就是实际扇区(线性)
    mov ax,RootDirSectors   ;ax保存根目录的扇区号
    and di,0ffe0h           ;将第5位置0,其他保留,当前文件条目的开始
    add di,01ah             ;将第五位置为1ah,即保存文件起始簇号位
    mov cx,word [es:di]     ;将起始簇号保存到cx中
    push cx                 ;保存簇号为以后计算使用
    add cx,ax               ;
    add cx,SectorBalance    ;根据FAT计算真实扇区
    mov ax,BaseOfLoader
    mov es,ax
    mov bx,OffsetOfLoader   ;es:bx加载内存地址,读取的内容保存到这
    mov ax,cx               ;扇区号
Label_Go_On_Loading_File:
;=====10-0e中断,显示字符
    push ax
    push bx
    mov ax,0e2eh;2eh代表'.'ascii值,即要显示的字符
    mov  bl,0fh ;前景色
    int 10h
    pop bx
    pop ax

    mov cl,1    ;读一个扇区
    call Func_ReadOneSector ;调用读一个扇区的函数
    pop ax                  ;
    call Func_GetFATEntry   ;
    cmp ax,0fffh            ;文件最后一个蔟标志
    jz  Label_File_Loaded   ;跳转到加载文件程序
    push ax                 ;保存FAT序号
    mov dx,RootDirSectors   ;重新计算扇区
    add ax,dx
    add ax,SectorBalance
    add bx,[BPB_BytesPerSec]
    jmp Label_Go_On_Loading_File
Label_File_Loaded:
    jmp BaseOfLoader:OffsetOfLoader;这一句正式跳转到已加载到内
                        ; 存中的 LOADER.BIN 的开始处,
                        ; 开始执行 OADER.BIN 的代码。
                        ; Boot Sector 的使命到此结束。

;=======根据扇区号求FAT值
;中间要读取FAT条目到es:bx处
;由于每个FAT项占12位,包含一个字节和另一个字节的一半。
;分两种情况,如果是偶数蔟,则3210|76543210,
;                  奇数蔟,则76543210|7654
;因为ax是16位,如果是奇数蔟76543210(by3)|76543210(by2),只需将ax右移4位即可
;              如果是偶数蔟76543210(by2)|76543210(by1),只要底12位即and ax,0fff
;ax*3再除2 商代表FATEntry 所在的扇区相对于 FAT 的扇区号,余数 (FATEntry 在扇区内的偏移)
;为防止越界一次读两个字节
Func_GetFATEntry:
    push es
    push bx
    push ax

    mov ax,00
    mov es,ax   ;设置段值00
    pop ax

    mov byte [odd],0    ;初始化[odd],表示奇偶,默认偶
    mov bx,3            ;初始化乘数
    mul bx              ;Dx:ax=ax*3
    mov bx,2
    div bx              ;dx:ax=ax/2 ax商dx余数
    cmp dx,0
    jz Label_Even       ;判断是不是偶数
    mov byte [odd],1    ;将odd置1表示偶数

Label_Even:
    xor dx,dx       ;清空dx
    mov bx,[BPB_BytesPerSec];每个扇区字节数
    div bx                  ;dx:ax/BPB_BytesPerSec(512)
                            ; dx:ax / BPB_BytsPerSec
                            ;  ax <- 商 (FATEntry 所在的扇区相对于 FAT 的扇区号)
                            ;  dx <- 余数 (FATEntry 在扇区内的偏移)。
    push dx
    mov bx,8000h            ;
    add ax,SectorNumOfFAT1Start;ax为FATEntry的扇区号
    mov cl,2
    call Func_ReadOneSector ;读两个字节避免在边界发生错误
    pop dx
    add bx,dx               ;
    mov ax,[es:bx]          ;es:bx为读出的扇区内容,放入ax
    cmp byte [odd],1            ;判断是否是奇数,因为偶数操作完再进行奇数调整,数值不变
    jnz Label_Even_2        ;奇数跳转
    shr ax,4                ;偶数右移4位
Label_Even_2:
    and ax,0fffh            ;奇数,高4位置0
    pop bx
    pop es
    ret

;=======显示字符串
;显示字符串,默认黑底白字
;同中断
DispStr:
    mov ax,1301h        ;显示字符串
    mov dl,00h          ;列号
    mov bh,00h      ;页号0
    int 10h         ;调用10号中断
    ret
;=======tmp 变量
RootDirSizeForLoop dw RootDirSectors    ;根目录扇区数,用来记录查询次数
SectorNo           dw 0;    要读取
odd                db 0;    表示奇偶,0偶,1奇
;=======显示提示信息串 
StartBootMessage:       db "Start Boot"             
NoLoaderMessage:        db "No Found"
FileFound:              db "File Found"
LoaderFileName:         db "LOADER  BIN",0          ;加载的文件名,必须11b没有.
;======填充0 
times   510-($-$$) db 0;$当前行,$$第一行,生成的代码恰好为512字节
dw      0xaa55      ;结束标志
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李浩441605458

创作不易

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值