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

📄 boot12.asm

📁 boot loader bing--boot.asm for fdd and loader c++ -startup.asm
💻 ASM
字号:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; BING first-stage loader
; Copyright (C) 2000, Chris Giese <geezer@execpc.com>
; http://www.execpc.com/~geezer/os
;
; This code goes into sector 0 of the floppy, so it must fit into a single
; disk sector. After being loaded by the BIOS to address 0000:7C00, we:
; 1. search the root directory for the file named at 'second_stage:'.
; 2. load that file into memory at address ADR_SECOND
; 3. jump to the loaded file
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; This value must be a multiple of 16. Chose the location of the second
; stage carefully. This first stage code will cheerfully overwrite
; itself while loading the second stage
ADR_SECOND	equ	00500h

%define ADR_START	7C00h
ADR_STACK	equ	(ADR_START - 32)
ADR_DIRBUF	equ	(ADR_START - 512 * 2)
ADR_FATBUF	equ	(ADR_DIRBUF - 512 * 2)

	ORG ADR_START
start:

; define memory used for scratchpad variables. These are initialized
; at run-time, so there's no need to waste 1st 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 (FAT 12 or FAT 16)
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

; 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 and total_sectors_large are not used by this code,
; but are needed for proper operation of DOS 7 FORMAT /Q
hidden_sectors:		; 1Ch
	dd 0

total_sectors_large:	; 20h
	dd 0

over:
; evidently, some buggy BIOSes load the boot code to 07C0:0000,
; so fix that now
	jmp 0:over2
over2:
	xor ax,ax			; zero DS and SS
	mov ds,ax
	mov ss,ax
	mov bp,over			; for compact relative addressing
	mov sp,ADR_STACK
	cld				; all 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 1st 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 1st sector of disk data area
	mov bx,ax
	mov ax,[num_root_dir_ents]		; entries in root dir
	mov dx,32				; * bytes/entry
	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
	jne err				; 2nd stage file not found

; found 2nd stage, load it. Adding DS to the segment value does nothing
; for a bootloader, but it lets this code work as a .COM file as well.
	mov cx,ds
	add cx,(ADR_SECOND >> 4)
load_2nd:
	mov es,cx

; convert cluster BX to sector value in AX, and get next cluster in BX
	call walk_fat
	jc err

; read an entire cluster
	mov di,[bp - (over - sectors_per_cluster)]
	and di,00FFh
	call read_sectors
	jc err
	add cx,[bp - (over - para_per_cluster)]	; advance mem ptr 1 cluster
	cmp bx,0F00h			; EOF cluter value for FAT12
	jb load_2nd

; put stack at top of tiny segment
	xor ax,ax
	mov sp,ax
%if 0
; jump to second stage that is ORGed 0
	mov ax,(ADR_SECOND >> 4)
	mov ds,ax
	mov es,ax
	mov ss,ax

	jmp (ADR_SECOND >> 4):0
%else
; jump to second stage that is ORGed 100h (.COM file)
	mov ax,((ADR_SECOND - 100h) >> 4)
	mov ds,ax
	mov es,ax
	mov ss,ax

	jmp ((ADR_SECOND - 100h) >> 4):100h
%endif

err:
; not enough room for an error message, so just beep
	mov ax,0E07h			; *** BEEEP ***
	int 10h

; await key pressed
	mov ah,0
	int 16h

; re-start the boot process
	int 19h

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; name:			find_file
; action:		searches for file in root dir of FAT12 floppy
; in:			11-char all-caps filename at SI, [root_start] set
; out (disk error):	CY=1
; out (file not found):	CY=0, ZF=0
; out (found it):	CY=0, ZF=1, BX=starting cluster of file
; modifies:		BX
; minimum CPU:		8088
; notes:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

find_file:
	push es
	push di
	push cx
	push ax

; 1st sector in root directory
		mov ax,[root_start]

		mov bx,ds		; where to load it
		add bx,(ADR_DIRBUF >> 4)
		mov es,bx
find_file_1:
		call read_sector	; one sector at a time
		jc find_file_5		; disk read error
		xor di,di
find_file_2:
		test [es:di],byte 0FFh	; 0 byte = end of root dir
		je find_file_3
		mov cx,11
		push si
		push di			; compare filename to dirent
			rep cmpsb
		pop di
		pop si
		je find_file_4

; if filename comparision failed, advance 32 bytes to next dir entry
		add di,byte 32
		cmp di,[bp - (over -bytes_per_sector)]
		jb find_file_2
		inc ax
		cmp ax,[bp - (over - data_start)]
		jb find_file_1		; go to next sector of root dir

find_file_3:
; did not find the file: return with CY=0, ZF=0
		or al,1
find_file_4:
; found the file
		mov bx,[es:di + 26]	; get starting cluster from dir entry
find_file_5:
	pop ax
	pop cx
	pop di
	pop es
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; name:			walk_fat
; action:		converts cluster value to sector,
;			and gets next cluster of file from FAT
; in:			BX=cluster
; out (disk error):	CY=1
; out (success):	CY=0, AX=first sector of cluster, BX=next cluster
; modifies:		AX, BX
; minimum CPU:		8088
; notes:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

walk_fat:
	push es
	push di
	push dx
	push cx
		mov ax,bx

; cluster 2 is the first data cluster
		dec ax
		dec ax

; convert from clusters to sectors
		mov dh,0
		mov dl,[bp - (over - sectors_per_cluster)]
		mul dx
		add ax,[bp - (over - data_start)]

; save sector in AX
		push ax
			mov ax,ds
			add ax,(ADR_FATBUF >> 4)
			mov es,ax

; FAT12 entries are 12 bits, bytes are 8 bits. Ratio is 3 / 2,
; so multiply cluster by 3, and divide by 2 later.
			mov ax,bx
			shl ax,1	; entry * 2
			add ax,bx	; + entry = entry * 3
			mov bx,ax

; BX:0		=use high or low 12 bits of 16-bit value read from FAT
; BX:9...BX:1	=byte offset into FAT sector (9 assumes 512-byte sectors)
; BX:?...BX:10	=which sector of FAT to load
;
; figure out which FAT sectors to load
			shr ax,1
			xor dx,dx
			div word [bp - (over - bytes_per_sector)]
			add ax,[bp - (over - fat_start)]
; leave the remainder (byte offset) in DX

; check the FAT buffer to see if this sector is already loaded
			cmp ax,[bp - (over - curr_sector)]
			je walk_fat_1
			mov [curr_sector],ax

; read the target FAT sector plus the sector after it
; (in case the 12-bit FAT entry straddles the two sectors)
			mov di,2
			call read_sectors
			jc walk_fat_4
walk_fat_1:
; point to correct entry in loaded FAT
			mov di,dx
; get 16 bits from FAT
			mov ax,[es:di]

; look at BX:0 to see if we want the high 12 bits or the low 12 bits
			shr bx,1
			jc walk_fat_2
			and ax,0FFFh	; CY=1: use low 12 bits
			jmp short walk_fat_3
walk_fat_2:
			mov cl,4
			shr ax,cl	; CY=0: use high 12 bits
walk_fat_3:
			mov bx,ax

; clear CY bit to signal success
			clc
walk_fat_4:
	pop ax
	pop cx
	pop dx
	pop di
	pop es
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; name:			read_cluster
;			read_sector
;			read_sectors
; action:		reads one or more disk sectors into memory
; in:			ES:0=address of memory where sectors should be read
;			AX=first sector to read
;			DI=number of sectors to read
;				(not used for read_cluster or read_sector)
; out (disk error):	CY=1
; out (success):	CY=0
; modifies:		read_cluster and read_sector modify DI
; minimum CPU:		8088
; notes:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

read_cluster:
	mov di,[bp - (over - sectors_per_cluster)]
	and di,00FFh
	jmp short read_sectors

read_sector:
	mov di,1

read_sectors:
; read DI sectors, starting with sector AX into RAM at ES:0
	push es
	push di
	push si
	push dx
	push cx
	push bx
	push ax
		mov si,ax		; SI=sector
		xor bx,bx		; ES:BX -> buffer
read_sectors_1:
		mov ax,si
		xor dx,dx		; DX:AX=sector
		div word [bp - (over - sectors_per_track)]
		mov cx,dx
		inc cx			; CL=sector
		xor dx,dx
		div word [bp - (over - heads)]
		mov dh,dl		; DH=head
		mov ch,al		; CH=cylinder 7:0
		mov dl,[bp - (over - boot_drive)]
		shl cl,1
		shl cl,1		; trying to use only
		shr ah,1		; 8088 asm here...
		rcr cl,1
		shr ah,1
		rcr cl,1		; CL7:6=cylinder 9:8, CL5:0=sector
; read one sector
		mov ax,0201h
		int 13h
		jnc read_sectors_3

; disk error; recalibrate/reset drive. This _must_ be done immediately after
; the failed call to INT 13h AH=02, while the floppy is still spinning.
		mov ah,0
		int 13h
		jc read_sectors_4
; try the read again. If it fails a second time, give up.
		mov ax,0201h
		int 13h
		jc read_sectors_4

read_sectors_3:
; advance memory pointer
		mov cx,es
		add cx,[bp - (over - para_per_sector)]
		mov es,cx
; next sector
		inc si
		dec di
		jne read_sectors_1

; clear CY bit to signal success
		clc
read_sectors_4:
	pop ax
	pop bx
	pop cx
	pop dx
	pop si
	pop di
	pop es
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 1st-stage data
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

curr_sector:	; which sector is in the FAT buffer
	dw -1

; name of the second stage bootloader. 11 characters exactly,
; upper case only, filename on the left, extension on the right,
; space padding in the middle
second_stage:
	db "LOADER  BIN"

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

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

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 2nd-stage code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; second:
; ADR_SECOND	EQU ((second - start) + ADR_START)

⌨️ 快捷键说明

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