📄 bootload.asm
字号:
BITS 16
SECTION .text
buffer EQU 512
image_size EQU 512
; ================================================================
; IBM-PC DISK BOOT LOADER FOR PROTECTED MODE EMBEDDED APPLICATIONS
;
; This boot laoder loads a file called "EMBEDDED.BIN" from
; the same diskette into memory starting at physical address
; zero. Before transferring control to the application, it
; enables the A20 line to make memory above 1MB accessible
; and disables the interrupt system. The application is
; responsible for establishing its own protected mode
; interrupt service routines and for putting the processor
; into protected mode.
; ================================================================
; ----------------------------------------------------------------
; Disk Area Sectors
; ----------------------- ----------------------------------
; Boot Loader (this code) 1
; FAT #1 sctrs_per_fat
; FAT #2 sctrs_per_fat
; Root Directory (32 * dir_entries) / bytes_per_sctr
; Files Area .....
; ----------------------------------------------------------------
ORG 0
Boot_Loader: JMP start
oem_name: DB 'EMBEDDED' ; Windows writes over these bytes!
; ----------------------------------------------------------------
; Bios Parameter Block (BPB)
; ----------------------------------------------------------------
bytes_per_sctr: DW 512 ; Bytes per sector
sctrs_per_clust:DB 1 ; Sectors per cluster
rsvd_sectors: DW 1 ; Reserved sectors (the boot sector)
number_fats: DB 2 ; Number of FATs
dir_entries: DW 224 ; Number of root-directory entries
total_sctrs: DW 2880 ; Total sectors in logical volume
media_desc: DB 0F0h ; Media descriptor byte
sctrs_per_fat: DW 9 ; Sectors per FAT
; ----------------------------------------------------------------
; Additional information (MS/DOS 3.0)
; ----------------------------------------------------------------
sctrs_per_track:DW 18 ; Sectors per track
number_heads: DW 2 ; Number of heads
hidden_sctrs: DW 0 ; Number of hidden sectors
; ----------------------------------------------------------------
; Additional information (MS/DOS 4.0)
; ----------------------------------------------------------------
DW 0 ; MSW of 'hidden_sctrs' (above)
ttl_sctrs_vol: DD 0 ; total log sctrs in log volume
phys_drive: DB 0 ; physical drive number
DB 0 ; reserved
ext_boot_sig: DB 29h ; extended boot signature
volume_id: DD 0 ; 32-bit binary volume ID
volume_label: DB 'BOOT.LOADER' ; volume label
DB '????????' ; reserved
; ----------------------------------------------------------------
; Additional information written by COPYBOOT.EXE
; ----------------------------------------------------------------
fat_nibbles: DW 0 ; 4-bit Nibbles per FAT entry
bytes_per_clust:DW 0 ; Bytes per cluster
dir_sector0: DW 0 ; log sctr # of 1st sctr in dir area
data_sector0: DW 0 ; log sctr # of 1st sctr in files area
dir_sectors: DW 0 ; # directory sectors
paras_per_clust:DW 0 ; paragraphs per cluster
kb_needed: DW 0 ; total KB memory req'd by loader
end_of_chain: DW 0 ; FAT12 => 0FFFH or FAT16 => FFFFH
; ----------------------------------------------------------------
; Additional data NOT written by COPYBOOT.EXE
; ----------------------------------------------------------------
file2load: DB 'EMBEDDEDBIN' ; Filename: "EMBEDDED.BIN"
; ----------------------------------------------------------------
start: ; Loader routine starts here
; ----------------------------------------------------------------
STI ; Just in case
CLD ; Needed by all REP's that follow
XOR AX,AX
MOV SS,AX ; The ROM BIOS only uses the lower
MOV SP,0400h ; half of the interrupt vector table
; Relocate myself to the top of base memory
PUSH CS
POP DS
CALL next ; PUSH offset of 'next'
next: POP SI
SUB SI,next ; DS:SI = source address
INT 12H ; AX = Memory Size in KB
SUB AX,[kb_needed+SI] ; Reserve room for loader
SHL AX,6 ; AX = target segment
MOV ES,AX
XOR DI,DI ; ES:DI = target address
MOV CX,image_size
REP MOVSB
PUSH ES
MOV AX,continue
PUSH AX
RETF
continue: MOV AX,CS ; Now initialize DS and ES
MOV DS,AX ; so that our offsets are
MOV ES,AX ; meaningful.
MOV DI,[dir_sector0]; Load root directory
MOV BP,[dir_sectors]; into the buffer
LEA BX,[buffer]
CALL Read_Sectors ; (Modifies AX,BX,CX,DX,SI,DI,BP)
CALL Find_File ; (Modifies BX,CX,BP,SI)
PUSH DI ; DI = 1st cluster #
MOV DI,[rsvd_sectors] ; Load FAT into the buffer
MOV BP,[sctrs_per_fat]
LEA BX,[buffer]
CALL Read_Sectors ; (Modifies AX,BX,CX,DX,SI,DI,BP)
POP DI
MOV BX,0080H ; load address = 0080:0000
MOV ES,BX
BL1: CALL Read_Cluster ; (Modifies AX, CX, DX, BP, SI, ES)
CALL Next_Cluster ; (Modifies AX, CX, DX)
MOV AX,DI
AND AX,0FFF0h
CMP AX,[end_of_chain]
JNE BL1
; save ending paragraph # for later
PUSH ES
; Turn off floppy drive light
MOV CX,100
WaitForDrive: INT 08h ; Forced timer tick
LOOP WaitForDrive
; Make memory above 1MB accessible
CALL Enable_A20
; The BIOS, its ISRs, and the interrupt vector
; table are no longer needed. Disable interrupts
; before writing over the interrupt vector table
; and the BIOS data area just above it.
CLI
; Relocate image to 0000:0000
; Can't use the stack anymore!
POP BP ; retrieve ending src paragraph #
MOV AX,0080H ; source segment
XOR BX,BX ; destination segment
MOV DX,[paras_per_clust]
MOV SP,[bytes_per_clust]
BL2: MOV CX,SP ; reload byte count
MOV DS,AX
MOV ES,BX
XOR SI,SI
XOR DI,DI
REP MOVSB
ADD AX,DX
ADD BX,DX
CMP AX,BP
JB BL2
; transfer control to the application
DB 0EAh ; An direct intersegment
DW 0,0 ; jump to 0000:0000
Find_File:
; ----------------------------------------------------------------
; Parameters: None
; Returns: DI = Starting Cluster
; Modifies: BX, CX, BP, SI
; ----------------------------------------------------------------
MOV BP,[dir_entries]; #entries to search
XOR BX,BX ; start w/entry #0
FF1: CMP BYTE [buffer+BX],0
JE FF3 ; done if rest is unused
TEST BYTE [buffer+BX+11],00011000B
JNZ FF4 ; skip if dir or vol label
LEA SI,[file2load] ; compare filename
LEA DI,[buffer+BX]
MOV CX,11
REP CMPSB
JE FF2
FF4: ADD BX,32 ; BX -> next entry
DEC BP ; any more entries?
JNZ FF1
FF3: HLT ; file not found
FF2: MOV DI,[buffer+BX+1Ah]
RET
Read_Cluster:
; ----------------------------------------------------------------
; Parameters: DI = current cluster # (Preserved)
; ES = buffer segment
; Returns: Nothing
; Modifies: AX, CX, DX, BP, ES, SI
; ----------------------------------------------------------------
PUSH DI
MOVZX BP,BYTE [sctrs_per_clust]
LEA AX,[DI-2] ; 1st cluster in file space is #2
MUL BP
ADD AX,[data_sector0]
MOV DI,AX ; DI = 1st logical sector
XOR BX,BX ; load at offset 0 of segment
CALL Read_Sectors ; (Modifies AX,BX,CX,DX,SI,DI,BP)
MOV AX,ES
ADD AX,[paras_per_clust]
MOV ES,AX
POP DI
RET
Next_Cluster:
; ----------------------------------------------------------------
; Parameters: DI = current cluster #
; Returns: DI = next cluster #
; Modifies: AX, CX, DX
; ----------------------------------------------------------------
MOV AX,DI
MUL WORD [fat_nibbles] ; (DX will be zero)
SHR AX,1 ; AX = rel offset into FAT entries
PUSHF ; CF = 1: Left-Aligned FAT12 entry
MOV DI,AX
POP AX
MOV DI,[buffer+DI]
CMP WORD [fat_nibbles],4 ; FAT12 or FAT16?
JE NC2 ; If FAT16, we're done.
SHR AX,1 ; Get CF
JNC NC1
SHR DI,4 ; Left-aligned FAT12
NC1: AND DI,0FFFH
NC2: RET
Read_Sectors:
; ----------------------------------------------------------------
; Parameters: DI = 1st logical sector #
; BP = sector count
; ES:BX = load address
; Returns: Nothing
; Modifies: AX, BX, CX, DX, SI, DI, BP
; ----------------------------------------------------------------
MOV SI,3 ; retry count
RS1: MOV AX,DI
DIV BYTE [sctrs_per_track]
XOR DX,DX ; DL = drive 0
SHR AL,1
RCL DH,1 ; DH = head
INC AH ; disk sectors start at 1
XCHG AL,AH
MOV CX,AX ; CH = track, CL = sector
MOV AX,0201H ; Read 1 sector
INT 13H
JNC RS3
DEC SI ; decrement retry count
JNZ RS2
HLT ; halt after 3 attempts
RS2: XOR AX,AX ; reset disk...
INT 13H
JMP RS1 ; ...and try again
RS3: MOV SI,3 ; reset retry count
ADD BX,[bytes_per_sctr]
INC DI ; next logical sector
DEC BP ; any more?
JNZ RS1
RET
Wait8042:
; ----------------------------------------------------------------
; Wait for 8042 to complete previous command.
; ----------------------------------------------------------------
XOR CX,CX ; CX=65536 for timeout value
Wait8042Loop: IN AL,64h ; Read the status port, find
TEST AL,00000010b ; out if the buffer is full
LOOPNZ Wait8042Loop ; Loop until buffer empty
RET
Enable_A20:
; ----------------------------------------------------------------
; Enable the A20 line to make memory above 1MB accessible
; ----------------------------------------------------------------
CALL Wait8042 ; Be sure 8042 is ready
JNZ EnableA20Failed
MOV AL,~00101110b ; Prepare to Write output port
OUT 64h,AL
CALL Wait8042
JNZ EnableA20Failed
MOV AL,~00100000b ; Enable the A20 line
OUT 60h,AL
CALL Wait8042
JNZ EnableA20Failed
XOR CX,CX ; Command started; give
EnableA20Wait: LOOP EnableA20Wait ; it time to complete.
RET
EnableA20Failed:HLT
TIMES 510 - ($-$$) DB 0
DW 0AA55h
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -