一个64位操作系统的设计与实现,3-2原码解释
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
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-1)512=14
SectorNumOfRootDirStart equ 19 ;根目录起始地址,公式 引导扇区数(1)+FAT表扇区数(9)*表份数(2)=19
SectorNumOfFAT1Start equ 1 ;起始扇区编号,由于前面有编号为0的引导区故从1开始
SectorBalance equ 17 ;平衡文件 起始簇号与数据簇号的差值,根目录起始簇号-2即19-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 ;介质描述符表示0xf0是3.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 ;滚动范围左上角坐标0,0
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 [RootDirS
izeForLoop] ;扇区数减一,到下一个查找项
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 ;结束标志