first cluster find ok
This commit is contained in:
parent
b8277f454f
commit
308d1caf1e
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
*.bin
|
||||
*.img
|
||||
aA1.txt
|
||||
2
Makefile
2
Makefile
@ -13,8 +13,10 @@ everything : $(BOOT_BIN) $(LDR_BIN)
|
||||
@dd if=/dev/zero of=a.img bs=512 count=2880
|
||||
@mkfs -t vfat a.img
|
||||
@dd if=$(BOOT_BIN) of=a.img bs=512 count=1 conv=notrunc
|
||||
@dd if=/dev/zero of=aA1.txt bs=4096 count=1
|
||||
@sudo mount -o loop a.img /mnt
|
||||
@sudo cp $(LDR_BIN) /mnt -v
|
||||
@sudo cp aA1.txt /mnt -v
|
||||
@sudo umount /mnt
|
||||
|
||||
clean :
|
||||
|
||||
350
loader.asm
350
loader.asm
@ -1,9 +1,345 @@
|
||||
org 0400h
|
||||
org 0400h
|
||||
jmp MAIN
|
||||
;----------------------------------------------------------------------------
|
||||
; @param bp+8: selector
|
||||
; @param bp+6: string addr
|
||||
; @param bp+4: length
|
||||
;----------------------------------------------------------------------------
|
||||
; Display string to current cursor
|
||||
DispStr:
|
||||
push bp
|
||||
mov bp, sp
|
||||
pusha
|
||||
push es
|
||||
mov ax, 0300h
|
||||
mov bh, 0
|
||||
int 10h
|
||||
mov ax, [bp + 6]
|
||||
mov cx, [bp + 4]
|
||||
mov es, [bp + 8]
|
||||
mov bp, ax
|
||||
mov ax, 01301h ; AH = 13, AL = 01h
|
||||
mov bx, 0007h ; 页号为0(BH = 0) 黑底白字(BL = 07h)
|
||||
mov dl, 0
|
||||
int 10h
|
||||
|
||||
mov ax, 0B800h
|
||||
mov gs, ax
|
||||
mov ah, 0Fh ; 0000: 黑底 1111: 白字
|
||||
mov al, 'L'
|
||||
mov [gs:((80 * 0 + 39) * 2)], ax ; 屏幕第 0 行, 第 39 列
|
||||
pop es
|
||||
popa
|
||||
pop bp
|
||||
ret
|
||||
;----------------------------------------------------------------------------
|
||||
; @param ax: the int to print
|
||||
;----------------------------------------------------------------------------
|
||||
; print a word as decimal to current cursor
|
||||
|
||||
jmp $ ; 到此停住
|
||||
DispInt:
|
||||
push bp
|
||||
mov bp, sp
|
||||
pusha
|
||||
mov di, 0
|
||||
.loop1:
|
||||
mov dx, 0
|
||||
mov bx, 10
|
||||
div bx ; {dx, ax} / bx(=10) -> ax ... dx
|
||||
push dx
|
||||
inc di
|
||||
test ax, ax
|
||||
jnz .loop1
|
||||
|
||||
.loop2:
|
||||
pop dx
|
||||
mov ax, dx
|
||||
mov ah, 0Eh
|
||||
add al, '0'
|
||||
mov bl, 0Fh
|
||||
int 10H
|
||||
dec di
|
||||
test di, di
|
||||
jnz .loop2
|
||||
|
||||
popa
|
||||
pop bp
|
||||
ret
|
||||
;----------------------------------------------------------------------------
|
||||
; give you a new line
|
||||
;----------------------------------------------------------------------------
|
||||
DispNewline:
|
||||
push bp
|
||||
mov bp, sp
|
||||
pusha
|
||||
mov ax, 0300h
|
||||
mov bh, 0
|
||||
int 10h
|
||||
add dh, 1
|
||||
mov dl, 0
|
||||
|
||||
mov ax, 0200h
|
||||
int 10h
|
||||
|
||||
popa
|
||||
pop bp
|
||||
ret
|
||||
|
||||
;----------------------------------------------------------------------------
|
||||
; 函数名: StringCmp
|
||||
;----------------------------------------------------------------------------
|
||||
; 作用:
|
||||
; 比较 ds:si 和 es:di 处的字符串(比较长度为11,仅为loader.bin所用)
|
||||
; 如果两个字符串相等ax返回1,否则ax返回0
|
||||
StringCmp:
|
||||
push bp
|
||||
mov bp, sp
|
||||
pusha
|
||||
|
||||
mov cx, 11 ; 比较长度为11
|
||||
cld ; 清位保险一下
|
||||
.STARTCMP:
|
||||
lodsb ; ds:si -> al
|
||||
cmp al, byte [es:di]
|
||||
jnz .DIFFERENT
|
||||
inc di
|
||||
dec cx
|
||||
cmp cx, 0
|
||||
jz .SAME
|
||||
jmp .STARTCMP
|
||||
.DIFFERENT:
|
||||
mov word [bp - 2], 0 ; 这里用了一个技巧,这样在popa的时候ax也顺便更新了
|
||||
jmp .ENDCMP
|
||||
.SAME:
|
||||
mov word [bp - 2], 1 ; 下一步就是ENDCMP了,就懒得jump了
|
||||
.ENDCMP:
|
||||
popa
|
||||
pop bp
|
||||
ret
|
||||
|
||||
;----------------------------------------------------------------------------
|
||||
; 函数名: ReadSector
|
||||
;----------------------------------------------------------------------------
|
||||
; 作用:
|
||||
; 将磁盘的数据读入到内存中
|
||||
; ax: 从哪个扇区开始
|
||||
; cx: 读入多少个扇区
|
||||
; (es:bx): 读入的缓冲区的起始地址
|
||||
;
|
||||
; 中断调用传入的参数规范请参考本节实验指导书的实验参考LBA部分
|
||||
ReadSector:
|
||||
push bp
|
||||
mov bp, sp
|
||||
pusha
|
||||
|
||||
mov si, BufferPacket ; ds:si 指向的是BufferPacket的首地址
|
||||
mov word [si + 0], 010h ; buffer_packet_size
|
||||
mov word [si + 2], cx ; sectors
|
||||
mov word [si + 4], bx ; buffer-offset
|
||||
mov word [si + 6], es ; buffer-segment
|
||||
mov word [si + 8], ax ; start_sectors
|
||||
|
||||
mov dl, BS_DrvNum ; 驱动号
|
||||
mov ah, 42h ; 扩展读
|
||||
int 13h
|
||||
jc .ReadFail ; 读取失败,简单考虑就默认bios坏了
|
||||
|
||||
popa
|
||||
pop bp
|
||||
ret
|
||||
.ReadFail:
|
||||
|
||||
jmp $ ; 如果cf位置1,就意味着读入错误,这个时候建议直接开摆
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; 函数名: GetNextCluster
|
||||
;------------------------------------------------------------------------------
|
||||
; 作用:
|
||||
; ax存放的是当前的簇(cluster)号,根据当前的簇号在fat表里查找,找到下一个簇的簇号,并将返回值存放在ax
|
||||
GetNextCluster:
|
||||
push bp
|
||||
mov bp, sp
|
||||
pusha
|
||||
|
||||
mov bx, 3 ; 一个FAT项长度为1.5字节
|
||||
mul bx
|
||||
mov bx, 2 ; ax = floor(clus_number * 1.5)
|
||||
div bx ; 这个时候ax里面放着的是FAT项基地址相对于FAT表开头的字节偏移量
|
||||
; 如果clus_number为奇数,则dx为1,否则为0
|
||||
push dx ; 临时保存奇数标识信息
|
||||
mov dx, 0 ; 下面除法要用到
|
||||
mov bx, BPB_BytsPerSec
|
||||
div bx ; dx:ax / BPB_BytsPerSec
|
||||
; ax <- 商 (基地址在FAT表的第几个扇区)
|
||||
; dx <- 余数 (基地址在扇区内的偏移)
|
||||
mov bx, 0 ; bx <- 0 于是, es:bx = BaseOfSectorBuf:0
|
||||
add ax, SectorNoOfFAT1 ; 此句之后的 ax 就是FAT项所在的扇区号
|
||||
mov cx, 2 ; 读取FAT项所在的扇区, 一次读两个, 避免在边界
|
||||
call ReadSector ; 发生错误, 因为一个FAT项可能跨越两个扇区
|
||||
|
||||
mov bx, dx ; 将偏移量搬回bx
|
||||
mov ax, [es:bx]
|
||||
pop bx ; 取回奇数标识信息
|
||||
cmp bx, 0 ; 如果是第奇数个FAT项还得右移四位
|
||||
jz EvenCluster ; 可能是微软(FAT是微软创建的)第一个亲儿子的原因,有它的历史局限性
|
||||
shr ax, 4 ; 当时的磁盘很脆弱,经常容易写坏,所以需要两张FAT表备份,而且人们能够制作的存储设备的容量很小
|
||||
EvenCluster:
|
||||
and ax, 0FFFh ; 读完需要与一下,因为高位是未定义的,防止ax值有误
|
||||
mov word [bp - 2], ax ; 这里用了一个技巧,这样在popa的时候ax也顺便更新了
|
||||
|
||||
popa
|
||||
pop bp
|
||||
ret
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; @param bp + 4: Filename string addr
|
||||
; @retval ax: first cluster no
|
||||
;------------------------------------------------------------------------------
|
||||
; Find File by name, return first cluster no.
|
||||
|
||||
FuncFindFile:
|
||||
push bp
|
||||
mov bp, sp
|
||||
pusha
|
||||
|
||||
mov word [RootDirSectorNow], SectorNoOfRootDirectory
|
||||
mov word [LeftRootDirSectors], RootDirSectors
|
||||
.FindLoaderInRootDir:
|
||||
mov ax, [RootDirSectorNow]; ax <- 现在正在搜索的扇区号
|
||||
mov bx, OffsetOfSectorBuf ; es:bx = BaseOfSectorBuf:OffsetOfSectorBuf
|
||||
mov cx, 1
|
||||
call ReadSector
|
||||
|
||||
mov si, [bp + 4] ; ds:si -> "LOADER BIN"
|
||||
mov di, OffsetOfSectorBuf ; es:di -> BaseOfSectorBuf:400h = BaseOfSectorBuf*10h+400h
|
||||
mov dx, 10h ; 32(目录项大小) * 16(dx) = 512(BPB_BytsPerSec)
|
||||
|
||||
.CompareFilename:
|
||||
call StringCmp
|
||||
cmp ax, 1
|
||||
jz .LoaderFound ; ax == 1 -> 比对成了
|
||||
dec dx
|
||||
cmp dx, 0
|
||||
jz .GotoNextRootDirSector ; 该扇区的所有目录项都探索完了,去探索下一个扇区
|
||||
add di, 20h ; 32 -> 目录项大小
|
||||
jmp .CompareFilename
|
||||
|
||||
.GotoNextRootDirSector:
|
||||
inc word [RootDirSectorNow] ; 改变正在搜索的扇区号
|
||||
dec word [LeftRootDirSectors] ; ┓
|
||||
cmp word [LeftRootDirSectors], 0 ; ┣ 判断根目录区是不是已经读完
|
||||
jz .NoLoader ; ┛ 如果读完表示没有找到 LOADER.BIN,就直接开摆
|
||||
jmp .FindLoaderInRootDir
|
||||
|
||||
.NoLoader:
|
||||
call DispNewline
|
||||
mov ax, cs
|
||||
push ax
|
||||
mov ax, NotFoundString
|
||||
push ax
|
||||
mov ax, _endNotFoundString - NotFoundString
|
||||
push ax
|
||||
call DispStr
|
||||
add sp, 6
|
||||
jmp $
|
||||
|
||||
.LoaderFound: ; 找到 LOADER.BIN 后便来到这里继续
|
||||
add di, 01Ah ; 0x1a = 26 这个 26 在目录项里偏移量对应的数据是起始簇号(RTFM)
|
||||
mov dx, word [es:di] ; 起始簇号占2字节,读入到dx里
|
||||
|
||||
mov word [bp - 2], dx ; set ax([bp-2]) as retval, popa will set that
|
||||
popa
|
||||
pop bp
|
||||
ret
|
||||
|
||||
MAIN:
|
||||
mov ax, cs ; cs <- 0
|
||||
mov ds, ax ; ds <- 0
|
||||
mov ss, ax ; ss <- 0
|
||||
mov ax, BaseOfSectorBuf
|
||||
mov es, ax ; es <- BaseOfSectorBuf
|
||||
|
||||
call DispNewline
|
||||
mov ax, cs
|
||||
push ax
|
||||
mov ax, StudentString
|
||||
push ax
|
||||
mov ax, _endStudentString - StudentString
|
||||
push ax
|
||||
call DispStr
|
||||
add sp, 6 ; pop for 3 times
|
||||
|
||||
mov ax, LoaderFileName
|
||||
push ax
|
||||
call FuncFindFile
|
||||
mov dx, ax ; temporarily save read result to dx
|
||||
pop ax
|
||||
|
||||
call DispNewline
|
||||
mov ax, cs
|
||||
push ax
|
||||
mov ax, clusternoString
|
||||
push ax
|
||||
mov ax, _endclusternoString - clusternoString
|
||||
push ax
|
||||
call DispStr
|
||||
add sp, 6 ; pop for 3 times
|
||||
mov ax, dx ; dx holds the read result
|
||||
call DispInt
|
||||
|
||||
mov ax, AA1FileName
|
||||
push ax
|
||||
call FuncFindFile
|
||||
mov dx, ax ; temporarily save read result to dx
|
||||
pop ax
|
||||
|
||||
call DispNewline
|
||||
mov ax, cs
|
||||
push ax
|
||||
mov ax, clusternoString
|
||||
push ax
|
||||
mov ax, _endclusternoString - clusternoString
|
||||
push ax
|
||||
call DispStr
|
||||
add sp, 6 ; pop for 3 times
|
||||
mov ax, dx ; dx holds the read result
|
||||
call DispInt
|
||||
jmp $
|
||||
|
||||
;==============================================================================
|
||||
; CONSTANTS
|
||||
;==============================================================================
|
||||
BaseOfStack equ 07c00h ; Boot状态下堆栈基地址(栈底, 从这个位置向低地址生长)
|
||||
; according to osdev, memory from 0x0000:0x7e00 to 0x7000:0xFFFF is free to use
|
||||
BaseOfSectorBuf equ 07000h ; diff from where we are here
|
||||
OffsetOfSectorBuf equ 0000h ; diff from where we are here
|
||||
RootDirSectors equ 14 ; 19~32
|
||||
SectorNoOfRootDirectory equ 19 ; Root Sector starts from 19
|
||||
SectorNoOfFAT1 equ 1
|
||||
DeltaSectorNo equ 31
|
||||
BPB_BytsPerSec equ 512 ; 每扇区字节数
|
||||
BPB_SecPerClus equ 1 ; 每簇多少扇区
|
||||
BPB_RsvdSecCnt equ 1 ; Boot 记录占用多少扇区
|
||||
BPB_NumFATs equ 2 ; 共有多少 FAT 表
|
||||
BPB_RootEntCnt equ 224 ; 根目录文件数最大值
|
||||
BPB_TotSec16 equ 2880 ; 逻辑扇区总数
|
||||
BPB_Media equ 0xF0 ; 媒体描述符
|
||||
BPB_FATSz16 equ 9 ; 每FAT扇区数
|
||||
BPB_SecPerTrk equ 18 ; 每磁道扇区数
|
||||
BPB_NumHeads equ 2 ; 磁头数(面数)
|
||||
BPB_HiddSec equ 0 ; 隐藏扇区数
|
||||
BPB_TotSec32 equ 0 ; 如果 wTotalSectorCount 是 0 由这个值记录扇区数
|
||||
BS_DrvNum equ 80h ; 中断 13 的驱动器号
|
||||
BS_Reserved1 equ 0 ; 未使用
|
||||
BS_BootSig equ 29h ; 扩展引导标记 (29h)
|
||||
BS_VolID equ 0 ; 卷序列号
|
||||
;==============================================================================
|
||||
; dw means initialized DATA
|
||||
;==============================================================================
|
||||
LeftRootDirSectors dw RootDirSectors ; 还未搜索的根目录扇区数
|
||||
RootDirSectorNow dw SectorNoOfRootDirectory ; 目前正在搜索的根目录扇区
|
||||
BufferPacket times 010h db 0 ; ReadSector函数会用到的,用于向int 13h中断的一个缓冲区
|
||||
|
||||
LoaderFileName db "LOADE BIN", 0 ; 8:3, fill with whitespace
|
||||
AA1FileName db "AA1 TXT", 0 ; the 0 at end is for StrCmp
|
||||
StudentString db "This is LiMaoliang's boot" ; size = 25
|
||||
_endStudentString
|
||||
clusternoString db "cluster no:"
|
||||
_endclusternoString
|
||||
NotFoundString db "not found"
|
||||
_endNotFoundString
|
||||
Loading…
Reference in New Issue
Block a user