;########################################################################################
;# #
;# 软盘引导扇区源代码 #
;# 1、将引导代码移送至内存9000H:0000处,并转去继续执行 #
;# 2、设置段寄存器DS→9000H;ES→磁盘参数表50H;FS→临时数据区9040H; #
;# GS→磁盘缓冲区9060H;SS,SP→堆栈段9020H:01ffH #
;# 3、将磁盘参数表读入内存0050H:0000处,磁盘参数表的位置由格式化程序或系统传送程序设置 #
;# 4、根据根目录表所在的逻辑扇区号,计算它的物理磁头号、磁道号、逻辑扇区号 #
;# 5、将根目录表所在的第一个扇区的内容读入内存9060H:0000 #
;# 6、要想引导系统,必须将引导文件放在根目录表的第一个目录项中。 #
;# 所以这一步分析根目录表的第一项文件名是否是系统引导文件“LDLoader.sys” #
;# 7、计算系统引导文件LDLoader.sys占用的扇区数,目录项偏移20B处是文件的大小 #
;# 8、将LDLoader.sys文件读入系统内存0070:0000。这里又有一个先决条件, #
;# 即LDloader.sys文件放在磁盘用户数据区开头的连续扇区中。 #
;# 9、JMP 0070H:0000,完成系统引导,转去执行LDLoader.sys。 #
;# 最后修改时间:2012年10月26日 #
;########################################################################################
;======================宏变量定义区===========================================================================
SECS_OF_CYLINDER_DISKINFO equ 0ch ;每磁道扇区数在磁盘参数表中的位置
HEADS_OF_DISK_DISKINFO equ 9 ;磁盘总的磁头数在磁盘参数表中的位置
FDT_LBA_NUMBER_DISKINFO equ 13h ;首张根目录表起始逻辑扇区号在磁盘参数表中的位置
BYTE_OF_SECTOR_DISKINFO equ 0eh ;每扇区字节数在磁盘参数表中的位置
DATA_LOGICNUM_DISKINFO equ 17h ;磁盘数据区起始逻辑扇区号在磁盘参数表中的位置
LDLOADER_SIZE_OFFSET equ 13h ;LDLOADER文件的大小在目录项中的位置
;======================宏变量定义结束=========================================================================
org 0
jmp Entry
;磁盘参数
DiskType db 0 ;磁盘类型,驱动器号(编号法则为:磁盘的第一个分区为0,第二个为1,依次类推。若为硬盘,则第7位置1
;也就是若是硬盘第一个分区则设成0x80,软盘则为0x00)
DiskInfoHead db 0 ;磁盘参数表所在的磁头号
DiskInfoCyl db 0 ;磁盘参数表所在的磁道号
DiskInfoSector db 2 ;磁盘参数表所在的扇区号
;将自身移至内存9000h:0000
Entry:
;使DS:SI→7C00H:0000,ES:DI→9000H:0000
xor si,si
xor di,di
mov ax,7c0h
mov ds,ax
mov ax,9000h
mov es,ax
mov cx,512
cld
rep movsb
jmp 9000h:Start
;主体代码
Start:
;设置段寄存器DS→9000H;ES→磁盘参数表50H;FS→临时数据区9040H;GS→磁盘缓冲区9060H;SS,SP→堆栈段9020H:01ffH
mov ax,9000h
mov ds,ax
mov ax,50h
mov es,ax
mov ax,9040h
mov fs,ax
mov ax,9060h
mov gs,ax
mov ax,9020h
mov ss,ax
mov sp,01ffh
;将磁盘参数表读入内存0050:0000
mov dh,[DiskInfoHead]
mov ch,[DiskInfoCyl]
mov cl,[DiskInfoSector]
push es
mov bx,50h
mov es,bx
mov bx,0
call ReadDisk
pop es
jnc next ;读磁盘成功跳转,否则显示错误信息
NonSysErr:
mov ax,cs
mov es,ax
mov ax,ErrorMSG
mov bp,ax
mov cx,SystemName-ErrorMSG
call TypeMSG
xor ax,ax
int 16h
jmp 0FFFFh:0000
;将根目录表首扇区内容读入内存9060:0000簇列表缓冲区中
next:
mov eax,[es:FDT_LBA_NUMBER_DISKINFO] ;根目录表起始逻辑扇区号在磁盘参数表第0fh字节处
call SubDiskAddress ;计算物理磁头、扇区、磁道号
push es
mov bx,9060h
mov es,bx
xor bx,bx
call ReadDisk
pop es
jc NonSysErr
;检查首张根目录表第一个目录项文件名是否为:“LDLoader.sys”
mov di,0
mov si,SystemName
mov cx,12
CMPstr:
mov dl,[gs:di]
mov dh,[ds:si]
cmp dl,dh
jne NonSysErr
inc di
inc si
loop CMPstr
inc di
mov dl,[gs:di] ;检查该目录项最后一个字符是否是0
cmp dl,0
jne NonSysErr
;检查文件大小是否大于零,目录项偏移13h处是文件的大小
mov eax,[gs:LDLOADER_SIZE_OFFSET]
cmp eax,0
je NonSysErr
;下面开始读取LDLoader.sys文件
;1、计算文件占用扇区数
xor edx,edx
xor ebx,ebx
mov bx,[es:BYTE_OF_SECTOR_DISKINFO]
div ebx
cmp edx,0
je next1
inc eax
next1:
;2、将LDLoader.sys文件占用的扇区数保存在内存9040h:0100h中
mov [fs:100h],eax
;3、开始读文件LDLoader.sys,读至内存0070:0000开始的内存中
mov word [fs:104h],70h ;存放文件的段地址
mov word [fs:106h],0 ;偏移地址
mov ax,0ffffh
sub ax,[es:BYTE_OF_SECTOR_DISKINFO] ;偏移地址上限
inc ax
mov [fs:108h],ax
mov eax,[es:DATA_LOGICNUM_DISKINFO]
mov [fs:110h],eax
ReadLBR:
mov eax,[fs:110h]
call SubDiskAddress
push es
mov es,[fs:104h]
mov bx,[fs:106h]
call ReadDisk
pop es
mov ax,[fs:106h]
cmp ax ,[fs:108h]
jne GoOn
mov word [fs:106h],0
add word [fs:104h],1000h
jmp GoOn2
GoOn:
mov ax,[es:BYTE_OF_SECTOR_DISKINFO]
add [fs:106h],ax
GoOn2:
inc dword [fs:110h]
dec dword [fs:100h]
cmp dword [fs:100h],0
jnz ReadLBR
jmp 0070h:0000
;=============================================================================================
;根据逻辑扇区号计算对应磁盘的磁头号、磁道号、扇区号
;逻辑扇区号与物理扇区换算关系:逻辑扇区按照扇区号、磁头号、柱面号(或磁道号)增长的顺序连续分配
;假设:LH---LinDos逻辑扇区0的磁头号
; LC---LinDos逻辑扇区0的柱面号
; LS---LinDos逻辑扇区0的扇区号
; NS---每磁道扇区数
; NH---磁盘总的磁头数
;若已知某扇区柱面号C,磁头号H,扇区号S,则其对应的逻辑扇区号RS公式为:
; RS=NH*NS*(C-LC)+NS*(H-LH)+(S-DS)
;若已知某扇区的逻辑扇区号RS,则其对应的柱面号C,磁头号H,扇区号S公式为:
; S=(RS MOD NS)+LS
; H=((RS DIV NS) MOD NH)+LH
; C=((RS DIV NS)DIV NH)+LC
;入口参数: EAX:逻辑扇区号
;出口参数: CH—柱面,CL—扇区,DH—磁头
;=============================================================================================
SubDiskAddress:
;1、计算物理扇区号
xor edx,edx
xor ecx,ecx
mov cx,[es:SECS_OF_CYLINDER_DISKINFO] ;磁盘参数表第8字节处,存放着磁盘每磁道扇区数的信息。
div ecx
inc edx ;此时EAX中存放的是(RS/NS)的商,EDX中存放的是余数
mov [fs:150h],dl ;保存物理扇区号
;2、计算磁头号及柱面号
xor ecx,ecx
xor edx,edx
mov cl,[es:HEADS_OF_DISK_DISKINFO] ;磁盘参数表第5字节处,存放着磁盘总的磁头数
div ecx
mov dh,dl ;EDX中存放的是((RS / NS) / NH)的余数,也即物理磁头号,EAX中存放中存放的是商,也即柱面号。
mov ch,al
mov cl,[fs:150h]
ret
;===============================
;读磁盘扇区功能,读入一个扇区
;入:
; CH—柱面,CL—扇区,DH—磁头
; ES:BX=缓冲区地址
;出: CF=0—操作成功,AH=00H,AL=传输的扇区数
; CF=1—操作失败,AH=状态码
;===============================
ReadDisk:
mov ax,0201h
mov dl,[DiskType]
int 13h
ret
;===============================
;显示字符串函数
;入口参数:ES:BP,字符串地址
; CX,字符串长度
;
;
;===============================
TypeMSG:
push cx
mov ah,3 ;调用int 10H 03H功能,获得光标坐标
mov bh,0
int 10h
pop cx
mov ax,1301h ;调用int 10H 13H功能,显示字符串
mov bx,0fh
int 10h
ret
ErrorMSG db "None system or disk error!",13,10,"Press anykey to restart your computer!"
SystemName db "LDLoader.sys"
times 510-($-$$) db 0
dw 0aa55h
开发操作系统实践(五)——新的引导扇区代码
最新推荐文章于 2021-03-14 20:57:50 发布