📄 fat12-f.asm
字号:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; First-stage bootloader for FAT12 (DOS) floppy disk
; Chris Giese <geezer@execpc.com>, http://www.execpc.com/~geezer/os
;
; INSTALLATION:
; 1. The kernel or second-stage bootloader loaded by this code must
; meet these restrictions:
; - Must start running in real mode (16-bit mode)
; - Must be in binary format (entry point == start of file)
; - Must be stored in the root directory of the disk
;
; 2. Change the equates/defines below as necessary:
; equate default value what is it?
; ------ ------------- -----------
; SS_ADR 10000h Load address of kernel/second stage
; - Must be >= 500h
; - Preferably >= 8600h
; - Must be a multiple of 10h
;
; SS_ORG 00100h ORG (origin) value of assembled
; kernel/second stage. Must be a
; multiple of 10h
;
; SS_NAME "LOADER BIN" Name of second-stage code on disk.
; This name must be in FAT format:
; - 8-character filename
; - 3-character extension immediately
; following filename
; - Filename and extension are both
; capitalized
; - Filename and extension are both
; padded on the right with spaces
;
; 3. Assemble this file with NASM:
; nasm -f bin -o fat12-f.bin fat12-f.asm
;
; 4. Format a floppy disk and make a FAT12 filesystem on it:
; (DOS) format /u a:
; (Linux) superformat /dev/fd0 ; mkdosfs /dev/fd0 1440
; -OR-
; superformat -s 21 /dev/fd0 ; mkdosfs /dev/fd0 1680
;
; 5. Copy the kernel/second stage to the root directory of
; the floppy disk, and name it according to SS_NAME:
; (DOS) copy second_stage a:\loader.bin
; (Linux) mount /dev/fd0 /mnt
; cp second_stage /mnt/loader.bin
; umount /mnt
;
; 6. Install this first-stage code into the bootsector (sector 0) of
; the floppy disk, avoiding the existing BIOS parameter block:
; (DOS) partcopy fat12-f.bin 0 3 -f0
; partcopy fat12-f.bin 24 1DC -f0 24
; (Linux) dd if=fat12-f.bin skip=0 count=3 of=/dev/fd0
; dd if=fat12-f.bin skip=36 count=476 of=/dev/fd0 seek=36
;
; I don't recommend using RAWRITE because:
; - the version of RAWRITE I used was buggy, and trashed sector 1
; (the first FAT) when I used it to install code in sector 0
; - RAWRITE can not write partial sectors, so this code will work
; only with 1.44 meg floppies (unless the default BIOS parameter
; block is changed)
;
; DOS users can get John Fine's PARTCOPY (Partial Copy; PCOPY) here:
; http://www.execpc.com/~geezer/johnfine
;
; MEMORY MAP:
; real-mode interrupt vectors (IVT): 00000-003FF
; BIOS data segment: 00400-004FF
; (unused memory): 00500-07B7F
; first-stage variables: 07B80-07BFF
; first-stage code (512 bytes): 07C00-07DFF FS_ADR
; first-stage stack: 07E00-07FFF (max) FS_ADR + 200h
; first-stage directory buffer: 08000-081FF FS_ADR + 400h
; first-stage FAT buffer: 08200-085FF FS_ADR + 600h
; (unused memory): 08600-0FFFF
; default second-stage load address: 10000-
;
; OPERATION:
; If there is an error loading the second stage (LOADER.BIN was not
; found, or there was a disk error), then this code will display a
; short error message, beep, await a key pressed, and re-start the
; boot process via INT 19h. You can eject the floppy disk before
; pressing a key to boot from the hard disk instead.
;
; POSSIBLE BUGS:
; - Do I need CLI and STI?
; - Should I set SP to something safe before calling the 2nd stage?
; - Testing:
; - test on 8088-based machine
; - test with various disk sizes (different CHS values)
; - see if it works with large kernel/second stage
; - see if it works on a hard disk with no partition table
; and a FAT12 filesystem starting at sector 0
; - Do I need to patch the floppy parameter table at interrupt
; vector 1Eh, like the DOS/Windows bootsector does? Maybe put
; the new FPT at address 0522h for DOS compatability, and change
; SS_ADR to 0600h or more. *** FPT CODE NEEDS ABOUT 36 BYTES ***
;
; TO DO:
; - Make this code smaller?
; - Some parts of this code assume 512 bytes per sector.
; Is this a problem? Maybe for 2.88 meg floppies?
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SS_ADR equ 10000h
SS_ORG equ 100h
%define SS_NAME "LOADER BIN"
;
; "No user-serviceable parts beyond this point" :)
;
FAT12_EOF equ 0FF8h
; first-stage address
%ifdef DOS
%define FS_ADR 100h ; .COM file for testing
%else
%define FS_ADR 7C00h
%endif
; 512 bytes for stack
ADR_STACK equ (FS_ADR + 400h)
; 512 bytes for one-sector directory buffer
ADR_DIRBUF equ (FS_ADR + 400h)
; 1024 bytes for two-sector FAT buffer (two sectors because FAT12
; entries are 12 bits and may straddle a 512-byte sector boundary)
ADR_FATBUF equ (FS_ADR + 600h)
ORG FS_ADR
start:
; define memory used for scratchpad variables. These are initialized
; at run-time, so there's no need to waste first-stage memory on them.
; Put them just below 'start'
; (1 byte) drive we booted from; 0=A, 80h=C
boot_drive EQU (start - 1)
; (2 bytes) sector where root directory starts
root_start EQU (boot_drive - 2)
; (2 bytes) sector where the actual disk data starts
data_start EQU (root_start - 2)
; (2 bytes) number of 16-byte paragraphs per sector
para_per_sector EQU (data_start - 2)
; (2 bytes) number of 16-byte paragraphs per cluster
para_per_cluster EQU (para_per_sector - 2)
jmp short over ; skip over BPB
nop
; minimal, default BIOS Parameter Block (BPB)
oem_id: ; 03h not used by this code
db "GEEZER", 0, 0
bytes_per_sector: ; 0Bh
dw 512
sectors_per_cluster: ; 0Dh
db 1
fat_start:
num_reserved_sectors: ; 0Eh
dw 1
num_fats: ; 10h
db 2
num_root_dir_ents: ; 11h
dw 224
total_sectors: ; 13h not used by this code
dw 2880 ; 2880 for 1.44 meg, 3360 for 1.68 meg
media_id: ; 15h not used by this code
db 0F0h
sectors_per_fat: ; 16h
dw 9
sectors_per_track: ; 18h
dw 18 ; 18 for 1.44 meg, 21 for 1.68 meg
heads: ; 1Ah
dw 2
hidden_sectors: ; 1Ch
dd 0
total_sectors_large: ; 20h not used by this code
dd 0
over:
%ifdef DOS
xor dl,dl
%else
; evidently some buggy BIOSes jump to 07C0:0000, so fix that now
jmp 0:over2
%endif
over2:
; ...and some BIOSes don't zero DS, so do that as well
mov ax,cs
mov ds,ax
mov ss,ax ; zero SS, too
mov sp,ADR_STACK
mov bp,over ; for relative addressing
cld ; string operations go up
; save [boot_drive] from DL. BIOS sets DL=0 if
; booting from drive A, DL=80h if booting from drive C
mov [bp - (over - boot_drive)],dl
; compute first sector of root directory
mov al,[num_fats] ; number of FATs
cbw ; "mov ah,0"
mul word [bp - (over - sectors_per_fat)] ; multiply by sectors/FAT
add ax,[bp - (over - fat_start)] ; plus reserved sectors
mov [root_start],ax
; compute first sector of disk data area
mov bx,ax
mov ax,[num_root_dir_ents] ; entries in root dir
mov dl,32 ; * bytes/entry (assume DH=0)
mul dx ; == bytes in root dir
div word [bp - (over - bytes_per_sector)] ; / bytes per sector
add ax,bx ; = sectors
mov [data_start],ax
; compute number of 16-byte paragraphs per disk sector
mov dx,[bp - (over - bytes_per_sector)]
mov cl,4
shr dx,cl
mov [bp - (over - para_per_sector)],dx
; compute number of 16-byte paragraphs per FAT cluster
mov al,[sectors_per_cluster]
cbw
mul dx ; DX still=paragraphs/sector
mov dx,ax
mov [bp - (over - para_per_cluster)],dx
; OK, everything is set up for 'find_file', 'walk_fat', and 'read_sectors'
; Find the file named at 'second_stage:' in the root directory
mov si,second_stage
call find_file
jc err ; disk error
; if second-stage file not found, display blinking 'F'
mov ax,9F46h
jne err2
; get conventional memory size
int 12h
; subtract starting second stage address to get available mem
sub ax,(SS_ADR >> 10)
; convert from K to bytes
xor dh,dh
mov dl,ah
mov ah,al
xor al,al
shl ax,1
rcl dx,1
shl ax,1
rcl dx,1
; if second stage file is too big...
sub ax,[es:di + 28]
sbb dx,[es:di + 30]
; ...display a blinking 'M'
mov ax,9F4Dh
jc err2
; found second-stage, load it
%ifdef DOS
mov di,ds
add di,(SS_ADR >> 4)
%else
mov di,(SS_ADR >> 4)
%endif
load_2nd:
mov es,di
; convert cluster BX to sector value in DX:AX, and get next cluster in BX
call walk_fat
jc err
; read an entire cluster
xor ch,ch
mov cl,[bp - (over - sectors_per_cluster)]
call read_sectors
jc err
add di,[bp - (over - para_per_cluster)] ; advance mem ptr 1 cluster
cmp bx,FAT12_EOF ; EOF cluster value
jb load_2nd
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -