; ==================================
;; 文件: readdisk.asm
;; 作用: 需要调用的读读磁盘文件子程序
;; 创建日期:2006/04/30 flyback
;; 修改日期:2006/05/07 flyback
;; http://blog.youkuaiyun.com/flyback
;; fly-back@163.com
; ==================================
[bits 16]
[extern _pntchr]
[extern _cls]
[extern _NextLine]
[extern _Num2Str]
[extern _ShowAddress]
[global _readsystem]
segment .data
align 4
progress db '.', 0
Load db ' Loading system file now, please wait', 0
ErrorMsg db ' An error occur!',0
SystemFileName db 'SYSTEM IMG'
SystemFileNameLen equ $ - SystemFileName
protectmode db ' Goto protected mode',0
LoadRootMsg db ' Loading root',0
LoadFileDescriptor db ' Loading file descriptor',0
LoadSystemImage db ' Loading system file image',0
NotFound db ' File not found!', 0
bpsadd equ 0xb ;brBPS DW 0x200 ; 000Bh - 每扇区的字节数 512
spcadd equ 0xd ;brSPC DB 0x01 ; 000Dh - 每簇扇区数
rescountadd equ 0xe ;brResCount DW 0x0001 ; 000Eh - 保留扇区数
fatsadd equ 0x10 ;brFATs DB 0x02 ; 0010h - FAT 备份数
rootentriesadd equ 0x11 ;brRootEntries DW 0x00e0 ; 0011h - 根目录入口数
sectorscountadd equ 0x13 ;brSectorCount DW 2880 ; 0013h - 磁盘容量扇区数< 32MB
mediaadd equ 0x15 ;brMedia DB 240 ; 0015h - 媒体描述符
spfadd equ 0x16 ;brSPF DW 9 ; 0016h - 每FAT扇区数
sphadd equ 0x18 ;brSPH DW 18 ; 0018h - 每磁道扇区数
hpcadd equ 0x1a ;brHPC DW 2 ; 001Ah - 盘面数
hideadd equ 0x1c ;brHidden DD 0 ; 001Ch - 隐藏扇区数
sectors equ 0x20 ;brSectors DD 0 ; 0020h - 如果大于32m的扇区总数
;DB 0 ; 0024h - 物理驱动器号
;DB 0 ; 0025h - 系统保留
;DB 29H ; 0026h - 扩展扇区标记(包含29h)
;brSerialNum DD 00000006H ; 0027h - 卷ID
;brLabel DB 'teachosdisk' ; 002Bh - 卷标
;brFSID DB 'FAT12 ' ; 0036h - 系统保留
SYSSEG equ 0x9000
SYSOFF equ 0x1000
Sector db 0x00
Head db 0x00
Track db 0x00
datasector dw 0x0000 ; 33 数据区起始扇区号
cluster dw 0x0000
segment .text
;*************************************************************************
; PROCEDURE ReadSec
; 从ax+1的地方把cx个扇区载入到es:bx的内存
; 注意扇区是从2开始,1扇区已经读入了
;*************************************************************************
ReadSec:
.Main:
.secloop:
push ax
push bx
push cx ;protect ax, bx, cx
call LBACHS ; 调用转换
mov ah, 0x02 ; BIOS 读取扇区命令
mov al, 0x01 ; 一个扇区
lea si, [dword Track]
mov ch, [si] ; track
lea si, [dword Sector]
mov cl, [si] ; sector
lea si, [dword Head]
mov dh, [si] ; head
mov dl, 0 ; 因为是a:所以为0
int 0x13 ; 调用中断
jnc .SUCCESS ; test for read error
xor ax, ax
pop cx
pop bx
pop ax
jnz near .secloop
jmp failure ; 错误则显示出错信息并停止
.SUCCESS
lea si,[dword progress]
call _pntchr
pop cx
pop bx
pop ax
add bx, [fs:bpsadd] ; 读取下一个扇区的内容
inc ax
loop .gotomain ; cx -= 1, if cx != 0, jmp .main
ret
; 到.Main已经不能用普通跳转了
; 因为loop只能是short jmp
.gotomain:
jmp near .Main
;*************************************************************************
; PROCEDURE LBACHS
; 转换逻辑块访问为读取磁盘所使用的磁道,盘面,扇区
; 相对扇区 = (逻辑扇区 / 每磁道扇区数) + 1
; 相对盘面 = (逻辑扇区 / 每磁道扇区数) MOD 盘面数
; 相对磁道 = 逻辑扇区 / (每磁道扇区数 * 盘面数)
;*************************************************************************
LBACHS:
xor dx, dx ; dx = 0
div WORD [fs:sphadd] ; div m16: ax/18 -> 商:ax 余数:dx
inc dl ;
lea si,[dword Sector]
mov [si], dl ; sector No relative to the Track
xor dx, dx ; dx = 0
div word [fs:hpcadd] ; ax/2 -> 商:ax 余数:dx
lea si, [dword Head]
mov [si], dl ;
lea si, [dword Track]
mov [si], al ;
ret
;*************************************************************************
; PROCEDURE ClusterLBA
; 转换单元访问到直接扇区访问
; LBA = (cluster - 2) * sectors per cluster
;*************************************************************************
ClusterLBA:
sub ax, 0x0002 ; zero base cluster number
xor cx, cx
mov cl, BYTE [fs:spcadd] ; convert byte to word
mul cx
lea si, [dword datasector]
add ax, [si] ; base data sector
ret
_readsystem:
lea si, [dword Load]
call _pntchr
mov ax, 0x7c0
mov fs, ax
mov es, ax
loadroot:
call _NextLine
lea si, [dword LoadRootMsg]
call _pntchr
mov cx, 0
mov dx, 0
mov ax, 0x0020 ; 32个字节/文件
; mul WORD [brRootEntries] ; 32*224(文件数) = 7168 (最多所有文件所占的字节数)
mul word [fs:rootentriesadd]
; div WORD [brBPS] ; 7168/512 = 14 (Root dir) 文件的目录描述字节占用的扇区数14
div word [fs:bpsadd]
xchg ax, cx ; CX = 14
; mov al, [brFATs] ; 2
mov al, [fs:fatsadd]
; mul word [brSPF] ; 9 * 2 = 18
mul word [fs:spfadd]
; add ax, word [brResCount] ; 18 + 1 now AX = 19
add ax, word [fs:rescountadd]
; mov WORD[datasector], ax ; 目录起始的扇区 19
lea si, [dword datasector]
mov [si], ax
; add WORD[datasector], cx ; 数据区起始扇区 33
lea si, [dword datasector]
add [si], cx
; 目录放入0x0200内存
mov bx, 0x0200
call ReadSec
; 比较目录中是否有SYS.img文件存在
; mov cx, WORD [brRootEntries] ; CX:224 在目录的所有文件中寻找
mov cx, [fs:rootentriesadd]
mov ax, fs
mov es, ax
mov di, 0x0200 ; 从目录入口处开始 0x200
.LOOP:
push cx ; 保护 CX = 224
mov cx, SystemFileNameLen ; 8个文件名称和3个扩展名称
lea si, [dword SystemFileName] ;
push di
repe cmpsb ; stop compare if cx >0 or the
; first unequal is met(zf=1)!
pop di
je loadfiledec ;if zf = 1, jmp LOAD_FAT!(Seek OK!)
pop cx
add di, 0x0020 ; 跳到下一个目录入口
loop .LOOP ; cx 自动减
call _NextLine
lea si, [dword NotFound]
call _pntchr
jmp failure
; 载入文件描述子节
loadfiledec:
pop cx ; 有一个cx的值没有弹出来
; 把启动的镜像文件system.img文件的起始单元保存起来
call _NextLine
lea si, [dword LoadFileDescriptor]
call _pntchr
; call _NextLine
mov dx, [fs:di + 0x001A] ;the file's first cluster
lea si, [dword cluster]
mov [si], dx ; store the first cluster
; 计算fat的大小并保存到07c00:0x0200(ds:bx)
xor ax, ax
mov al, BYTE [fs:fatsadd] ; al:2
mul WORD [fs:spfadd] ; AH:18 = 9*2
mov cx, ax ; CX:18
; 读取数据放入到0x7c00:0x0200 ds:bx
; mov ax, WORD [brResCount] ; AX:1
mov ax, WORD [fs:rescountadd] ; AX:1
mov bx, 0x0200 ;
call ReadSec ; AX:1 CX:18 BX:0200
; 读取img 放入 9000:0x1000处
mov ax, SYSSEG
mov es, ax
mov bx, SYSOFF
push bx
LOAD_IMAGE:
call _NextLine
lea si, [dword LoadSystemImage]
call _pntchr
; mov ax, WORD [cluster] ; cluster to read
lea si, [dword cluster]
mov ax, [si] ; cluster to read
pop bx ; buffer to read into
call ClusterLBA ; convert cluster to LBA
; AX:[cluster] ES:BX[9000:0000](dest)
xor cx, cx
mov cl, BYTE [fs:spcadd] ; CL:1
call ReadSec ; AX:LBA CX:1 BX:0000 ES:0100
push bx
; 计算下一个单元
lea si, [dword cluster]
;mov ax, WORD [cluster] ; identify current cluster
mov ax, [si] ; identify current cluster
mov cx, ax ; copy current cluster
mov dx, ax ; copy current cluster
shr dx, 0x0001 ; divide by two
add cx, dx ; sum for (3/2)
mov bx, 0x200 ; location of FAT in memory
add bx, cx ; index into FAT
mov dx, [fs:bx] ; read two bytes from FAT
test ax, 0x0001
jnz .ODD_CLUSTER
.EVEN_CLUSTER:
and dx, 0000111111111111b ; take low twelve bits
jmp .DONE
.ODD_CLUSTER:
shr dx, 0x0004 ; take high twelve bits
.DONE:
; mov WORD [cluster], dx ; store new cluster
lea si ,[dword cluster]
mov [si], dx ; store new cluster
cmp dx, 0x0FF0 ; test for end of file,>=0x0FF0: end or bad!
jb LOAD_IMAGE ; if dx<0x0ff0 (CF=1), jmp Load_image
DONE:
pop bx ; 有一个多出来的bx在stack里面
ret
; 回到主程序,这时system.img
; 已经被装在0x9000:0x1000的地方
; 只要设置好保护模式的条件就可以跳转了
failure:
call _NextLine
lea si,[dword ErrorMsg]
call _pntchr
call _NextLine
hlt