操作系统入门(六) –readdisk.asm

来源:互联网 发布:算法基础 下载 编辑:程序博客网 时间:2024/05/15 00:26

; ==================================
;; 文件: readdisk.asm
;; 作用: 需要调用的读读磁盘文件子程序

;; 创建日期:2006/04/30 flyback
;; 修改日期:2006/05/07 flyback
;; 
http://blog.csdn.net/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