⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 boot16.txt

📁 FAT16 磁盘格式引导程序.文件是以ASM汇编格式提供的.
💻 TXT
字号:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; First-stage bootloader for CHS FAT16 (DOS/Win) hard disk partition
; Chris Giese <geezer@execpc.com>, http://www.execpc.com/~geezer
;
; BUILD: nasm -f bin -o fat16.bin fat16.asm
;
; DOS INSTALL: partcopy fat12.bin 0 3 -f0
; partcopy fat12.bin 24 1DC -f0 24
;
; UNIX INSTALL: dd bs=1 if=fat12.bin seek= 0 count=3 of=/dev/fd0
; dd bs=1 if=fat12.bin seek=36 count=476 of=/dev/fd0 skip=36
;
; DISCLAIMER: Bootloaders are inherently dangerous.
; If you f*ck up your hard disk, it's your problem.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SS_NAME must be in FAT format: all caps, 11 chars total, 8-char
; filename, 3-char extension, both padded on the right with spaces
%define SS_NAME "LOAD BIN" ; 2nd stage file name
SS_ADR EQU 10000h ; where to load 2nd stage
SS_ORG EQU 100h ; 2nd stage ORG value 
; "No user-serviceable parts beyond this point" :)
; Actually, you can modify it if you want.

; first-stage address offset linear
%define FS_ADR 100h ; 100h 7C00h

; 512-byte stack
ADR_STACK equ (FS_ADR + 400h) ; 500h 8000h

; one-sector directory buffer. FAT sectors may be as large as 4K
ADR_DIRBUF equ ADR_STACK ; 500h 8000h

; one-sector FAT buffer
ADR_FATBUF equ (ADR_DIRBUF + 1000h) ; 1500h 9000h

; use byte-offset addressing from BP for smaller code
%define VAR(x) ((x) - start) + bp

; bootsector loaded at physical address 07C00h, but address 100h
; will work if we load IP and segment registers properly.
; This is also the ORG address of a DOS .COM file
ORG FS_ADR
start:


 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; VARIABLES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
; (1 byte) drive we booted from; 0=A, 80h=C
boot_drive EQU (start - 1)

; (2 bytes) number of 16-byte paragraphs per sector
para_per_sector EQU (boot_drive - 2)

; (2 bytes) number of 32-byte FAT directory entries per sector
dir_ents_per_sector EQU (para_per_sector - 2)

; (2 bytes) sector where the actual disk data starts
; this is relative to partition start, so we need only 16 bits
data_start EQU (dir_ents_per_sector - 2)

jmp short skip_bpb
nop

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; BIOS PARAMETER BLOCK (BPB)
;
; Installation will use the BPB already present on your hard disk.
; The values shown here work only with my hard disk (CHS=261:255:63)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

oem_id: ; offset 03h (03) - not used by this code
db "GEEZER", 0, 0
bytes_per_sector: ; offset 0Bh (11)
dw 512
sectors_per_cluster: ; offset 0Dh (13)
db 64
fat_start:
num_reserved_sectors: ; offset 0Eh (14)
dw 1
num_fats: ; offset 10h (16)
db 2
num_root_dir_ents: ; offset 11h (17)
dw 512
total_sectors: ; offset 13h (19) - not used by this code
dw 0
media_id: ; offset 15h (21) - not used by this code
db 0F0h
sectors_per_fat: ; offset 16h (22)
dw 256
sectors_per_track: ; offset 18h (24)
dw 63
heads: ; offset 1Ah (26)
dw 255
hidden_sectors: ; offset 1Ch (28)
dd 63 * 255
total_sectors_large: ; offset 20h (32) - not used by this code
dd 63 * 255 * 261


 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; CODE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
skip_bpb:
; put CPU into a known state
%ifdef DOS
mov dl,80h ; C: drive
%else
jmp ((7C00h - FS_ADR) >> 4):fix_cs
fix_cs:
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov sp,ADR_STACK
%endif
mov bp,start
mov [VAR(boot_drive)],dl
cld

; calculate some values that we need
mov ax,[VAR(bytes_per_sector)]
mov cl,4
shr ax,cl
mov [VAR(para_per_sector)],ax

mov ax,[VAR(bytes_per_sector)]
mov bx,32 ; bytes/dirent
xor dx,dx
div bx
mov [VAR(dir_ents_per_sector)],ax

; CX=num_root_dir_sectors
mov ax,[VAR(num_root_dir_ents)]
mul bx
div word [VAR(bytes_per_sector)]
mov cx,ax

; DX:AX=LBA sector number of start of root dir
xor ah,ah
mov al,[VAR(num_fats)]
mul word [VAR(sectors_per_fat)]
add ax,[VAR(num_reserved_sectors)]

push ax
add ax,cx
mov [VAR(data_start)],ax
pop ax

; scan root dir for file. We don't bother to check for deleted entries,
; or 'virgin' entries (first byte = 0) that mark end of dir
mov bx,ADR_DIRBUF
next_sect:
call read_sector_chs
jc disk_error
mov si,bx
push cx
mov cx,[VAR(dir_ents_per_sector)]
next_ent:
mov di,ss_name
push si
push cx
mov cx,11 ; 8.3 FAT filename
rep cmpsb
pop cx
pop si
je found_it
add si,32 ; bytes/dirent
loop next_ent
pop cx
add ax,byte 1 ; next sector
adc dx,byte 0
loop next_sect
mov al,'F' ; file not found; display blinking 'F'

; 'hide' the next 2-byte instruction by converting it to CMP AX,NNNN
; I learned this trick from Microsoft's Color Computer BASIC :)
db 3Dh
disk_error:
mov al,'R' ; disk read error; display blinking 'R'
error:
mov ah,9Fh ; blinking blue-on-white attribute
mov bx,0B800h ; xxx - assumes color emulation…
mov es,bx ; …should still be able to hear the beep
mov [es:0],ax

mov ax,0E07h ; *** BEEEP ***
int 10h
%ifdef DOS
mov ax,4C01h
int 21h
%else
mov ah,0 ; await key pressed
int 16h

int 19h ; re-start the boot process
%endif

found_it:
; leave the old CX value on the stack to save a byte or two
; Get conventional memory size (Kbytes) in AX
int 12h

; subtract load address
; xxx - fix this for DOS
sub ax,(SS_ADR >> 10)

; convert from K to bytes
mov dx,1024
mul dx

; 32-bit file size (4 bytes) is at [si + 28]
; If second stage file is too big…
sub ax,[si + 28]
sbb dx,[si + 30]

; …display a blinking 'M'
mov al,'M'
jc error

; get starting cluster of file
mov si,[si + 26]

; set load address DI:BX
xor bx,bx
%ifdef DOS
mov di,ds
add di,(SS_ADR >> 4)
%else
mov di,(SS_ADR >> 4)
%endif
load_cluster:
; convert cluster to 32-bit LBA sector value; and get next cluster
call walk_fat
jc disk_error

; load an entire cluster
xor ch,ch
mov cl,[VAR(sectors_per_cluster)]
load_sector:
mov es,di
call read_sector_chs
jc disk_error
add ax,byte 1
adc dx,byte 0
add di,[VAR(para_per_sector)]

; xxx - this will always load an entire cluster (e.g. 64 sectors),
; even if the file is shorter than this
loop load_sector
; done?
cmp si,0FFF8h ; end-of-cluster chain value for FAT16
jb load_cluster

; jump to second stage loaded at SS_ADR and ORGed to address SS_ORG
%ifdef DOS
mov ax,ds
add ax,((SS_ADR - SS_ORG) >> 4)
%else
mov ax,((SS_ADR - SS_ORG) >> 4)
%endif
mov ds,ax
mov es,ax

; we leave SS:SP as they were
push ax
push word SS_ORG
retf

 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; name: read_sector_chs
; action: reads one disk sector using INT 13h AH=02h
; in: DX:AX=LBA number of sector to read (absolute)
; ES:BX -> buffer
; out (disk error): CY=1
; out (success): CY=0
; modifies: (nothing)
; minimum CPU: 8088
; notes:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
read_sector_chs:
push di
push si
push dx
push cx
push ax

; DX:AX==LBA sector number
; add partition start (= number of hidden sectors)
add ax,[VAR(hidden_sectors + 0)]
adc dx,[VAR(hidden_sectors + 2)]

; convert to CHS. Use two-step "extended precision" divide to avoid
; overflow or use of 32-bit DIV. See section 9.3.5 of Randall
; Hyde's "Art of Assembly"
xor ch,ch
mov cl,[VAR(sectors_per_track)]

mov si,ax
mov ax,dx
xor dx,dx
div cx
xchg si,ax
div cx
xchg si,dx

; DX:AX==quotient, SI==remainder==sector (S) - 1
xor ch,ch
mov cl,[VAR(heads)]

mov di,ax
mov ax,dx
xor dx,dx
div cx
xchg di,ax
div cx
xchg di,dx

; DX:AX==quotient==cylinder ?, DI==remainder==head (H)
; error if cylinder >=1024
or dx,dx ; DX != 0; so cyl >= 65536
stc
jne rsc_end
cmp ah,4 ; AH >= 4; so cyl >= 1024
cmc
jb rsc_end

; finish moving variables into registers for INT 13h AH=02h
mov dx,di
mov dh,dl ; DH==head
inc si
mov cx,si ; CL 5:0 == sector
mov ch,al ; CH==cyl 7:0
shl cl,1
shl cl,1
shr ah,1
rcr cl,1
shr ah,1
rcr cl,1 ; CL 7:6 == cylinder 9:8
mov dl,[VAR(boot_drive)]; DL = drive
mov ax,0201h ; AH = 02h, AL = num_sectors
int 13h
jnc rsc_end
; reset drive
xor ax,ax
int 13h
jc rsc_end
; try read again
mov ax,0201h
int 13h
rsc_end:
pop ax
pop cx
pop dx
pop si
pop di
ret

 
 
   
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; name: walk_fat
; action: converts cluster number to sector number and
; finds next cluster in chain
; in: SI = cluster
; out (disk error): CY=1
; out (success): CY=0, SI = next cluster, DX:AX = sector number
; modifies: AX, DX, SI
; minimum CPU: 8088
; notes:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
walk_fat:
push es
push bx

; cluster 2 is the first data cluster
lea ax,[si - 2]

; convert from clusters to sectors
mov dh,0
mov dl,[VAR(sectors_per_cluster)]
mul dx
add ax,[VAR(data_start)]
adc dx,byte 0

; DX:AX is return value: save it
push dx
push ax

; prepare to load FAT
%ifdef DOS
mov ax,ds
add ax,(ADR_FATBUF >> 4)
%else
mov ax,(ADR_FATBUF >> 4)
%endif
mov es,ax
xor bx,bx

; FAT16 entries are 16 bits, bytes are 8 bits. Ratio is 2
xor dx,dx
mov ax,si
shl ax,1
rcl dx,1

; DX:AX b8:0 =byte offset into FAT sector (9 bits assumes 512-byte sectors)
; DX:AX b?:9 =which sector of FAT to load
div word [VAR(bytes_per_sector)]

; remainder is byte offset into FAT sector: put it in SI
mov si,dx

; quotient in AX is FAT sector: add FAT starting sector
add ax,[VAR(fat_start)]

; check the FAT buffer to see if this sector is already loaded
; (simple disk cache; speeds things up a little)
cmp ax,[curr_sector]
je wf_1
mov [curr_sector],ax

; read the target FAT sector
xor dx,dx
call read_sector_chs
wf_1:
; CY set if error. Get 16 bits from FAT
mov si,[es:bx + si]
pop ax
pop dx
pop bx
pop es
ret


 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; DATA
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; which sector is in the FAT buffer
; this is relative to partition start, so we need only 16 bits
curr_sector:
dw -1
ss_name:
db SS_NAME

; pad with NOPs to offset 510
times (510 + $$ - $) nop

; 2-byte magic bootsector signature
db 55h, 0AAh

 
 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -