代码改变世界

操作系统的引导 boot.asm

2017-09-05 19:02  仁者无敌68  阅读(385)  评论(0)    收藏  举报
.model tiny ;小内存模式
.386p  ;支持386指令
.code  ;代码段
start:        ;下面的跳转指令主要作用是把cs设置为0x07c0
db 0eah
dw go
dw 7c0h

;软盘固定参数
bpbOEM db "My OS "
bpbBytesPerSector DW 512
bpbSectorsPerCluster DB 1
bpbReservedSectors DW 1
bpbNumberOfFATs DB 2
bpbRootEntries DW 224
bpbTotalSectors DW 2880
bpbMedia DB 0f0h ;; 0xF1
bpbSectorsPerFAT DW 9
bpbSectorsPerTrack DW 18
bpbHeadsPerCylinder DW 2
bpbHiddenSectors DD 0
bpbTotalSectorsBig DD 0
bsDriveNumber DB 0
bsUnused DB 0
bsExtBootSignature DB 029h
bsSerialNumber DD 0a0a1a2a3h
bsVolumeLabel DB "MOS FLOPPY ",0
bsFileSystem DB "FAT12 ",0

go:
mov ax,06000h
mov sp,ax     ;设置堆栈
mov ax,900h ;读取根目录到9000h位置
mov es,ax
xor bx,bx
;第19扇区存储了根目录
mov ch,0 ;柱面
mov dh,1 ;
mov cl,2 ;扇区

mov ah,2 ;功能2,读磁盘
mov al,14 ;读取扇区数目,根目录大小为14个扇区,这是固定值
mov dl,0 ;从软盘读取
int 13h

mov ax,0b80h
mov es,ax
xor bx,bx
mov ch,0
mov dh,0
mov cl,2 ;从第2扇区读,fat起始扇区
mov ah,2
mov al,9 ;总共读9个扇区,整个fat表
mov dl,0
int 13h
; 解压FAT
mov ax,0b80h
mov ds,ax
mov ax,0ca0h
mov es,ax
mov di,0;buffer
mov si,0;fatstart

mov cx,3*512
de_fat:
xor ax,ax
mov al,byte ptr [si]
mov ah,byte ptr [si+1]
and ah,0fh
stosw

xor ax,ax
mov ax,WORD ptr [si+1]
shr ax,1
shr ax,1
shr ax,1
shr ax,1
and ah,0fh
stosw

add si,3
loop de_fat

;在根目录中查找文件
mov ax,07c0h
mov ds,ax
mov es,ax
mov dx,9000h-7c00h
findfile:
mov di,dx
cld
mov cx,11
lea si,kn
repz cmpsb
jz L1 ;找到了文件
jnz L2 ;没找到,继续
L1:
;加载文件,33扇区为数据起始扇区,1扇区启动分区,18扇区fat表,14扇区根目录
add dx,1ah ; 1a处存放了起始簇
mov si,dx
mov ax,07c0h
mov ds,ax
mov es,ax
mov ax, WORD ptr [si] ;取文件第一簇
push ax
;然后读文件内容
;数据起始地址是4200h,对应第2簇,所以第0簇应该是,4200h-400h =3e00h,扇区为3e00h/200h = 31
;打算加载到0x90000,512K这个地方,内核还剩余512K-32K = 480K
mov WORD ptr [buffer],9000h

call readsector
add WORD ptr [buffer],20h
;读完了第一簇
;每次读完,di自动加200h
;读簇内容
pop si
;mov si,WORD ptr cu
read_cu:
shl si,1
mov ax,0ca0h
mov ds,ax
mov ax,WORD ptr [si]
push ax
cmp ax,0fffh
je load_ok
;读取ax为起始扇区的内容
call readsector
pop si
add WORD ptr [buffer],20h
jmp read_cu

load_ok:
mov ax,13h
int 10h

db 0eah
dw 0
dw 9000h

jmp $

L2:
add dx,32
cmp dx,14*512
jb findfile
load_failure:
jmp $
;函数功能,读指定扇区内容到指定内存
;逻辑扇区和CHS的转换关系
;    C = ( 19 / 18 ) / 2 = 0;柱面
; H = ( 19 / 18 ) % 2 = 1 ;磁头
; S = ( 19 % 18 ) + 1 = 2;扇区
readsector:
pusha
add ax,31
mov WORD ptr ds:[log_sec],ax
mov bx,36
xor dx,dx
div bx
mov BYTE ptr [cyl],al
mov ax,WORD ptr [log_sec]
mov bx,18
xor dx,dx
div bx
xor dx,dx
mov bx,2
div bx
mov BYTE ptr [head],dl
mov ax,WORD ptr [log_sec]
mov bx,18
xor dx,dx
div bx
inc dl
mov BYTE ptr [sec],dl

mov ax,WORD ptr [buffer]
mov es,ax
xor bx,bx

mov ch,BYTE ptr [cyl] ;c
mov dh,BYTE ptr [head] ;h
mov cl,BYTE ptr [sec] ;s

mov ah,2 ;function :read
mov al,1 ;sector to read
mov dl,0 ; 软驱a
int 13h
popa
ret
DispStr:
mov ax,BootMsg
mov bp,ax
mov cx,end_BootMsg-BootMsg
mov ax,01301h
mov bx,000ch
mov dl,0
int 10h
ret
BootMsg: db "can't find kernel",0
end_BootMsg:
buffer: dw 0
log_sec: dw 0
cyl: db 0
head: db 0
sec: db 0
kn: db 'SETUP EXE',0

org 510
dw 0aa55h
end start

 

此文件加载了根木目到0x9000,此后setup可以在根目录中查找kernel文件,并加载内核