My MBR

I'm using NASM to write my real mode code, and I use file extension “nasm” to separate them from other assembler files. This makes the build process able to automatically select the correct assembler.

Current state:
1. Copy 512 bytes to new location.
2. Load 64-bit set-up code.
3. Load kernel loader.
4. Execute 64-bit set-up code.

Function seek: Convert absolute sector number into CHS values directly acceptable for INT13h (AH=02).

[bits 16]
 
struc	PT_ENT		;Partition table entry
	BootFlag		resb	1
	BeginHead		resb	1
	BeginSector		resb	1
	BeginCyl		resb	1
	SystemID		resb	1
	EndHead			resb	1
	EndSector		resb	1
	EndCyl			resb	1
	RelSectorLow	resw	1
	RelSectorHigh	resw	1
	NumSectorsLow	resw	1
	NumSectorsHigh	resw	1
endstruc
 
%include "mbr/mem.inc"
 
[org loc_MBR]
 
SEGMENT START align=16			;At 0:7C00
 
start:
; register 'dl' contains boot disk number
	cli
	xor	cx, cx			; Set segment registers to zero
						; cs - Code Segment (we're here, so it's obviously zero - or erroneously 0x07C0)
	mov	es, cx			; Extra Segment
	mov	ss, cx			; Stack Segment
	mov	sp, loc_STACK	; Top of stack
	mov	ds, cx			; Data Segment
	mov	di, loc_MBR		; Destination for stream
	mov	si, bootpoint	; Source of stream
	cld					; Clear direction flag (stream increment)
	mov	ch, 1			; cx = 256
	rep movsw			; word move = 512 bytes copy, one HD sector
	jmp	0x0000:continue	; far JMP to copy of self
 
SEGMENT MAIN align=16			;At 0:7A00 + START.length
continue:
	mov [drive.disk], dl
	sti					; enable interrupts
	; grab drive geometry for LBA/CHS conversion
	mov ah, 8			; check drive parameters
	xor di, di
	int 13h
	mov [drive.H], dh		; last head
	mov al, cl
	and al, 0x3F			; mask sectors
	mov [drive.S], al		; sectors per track
	xchg ch, cl				; swap ch/cl - 76543210.98xxxxxx -> 98xxxxxx.76543210
	shr ch, 6				; shift ch   - xxxxxx98.76543210
	mov [drive.C], cx		; last cylinder
	mov al, [drive.H]		; grab last head
	inc al					; make head-count
	mul byte [drive.S]			; make sectors per cylinder
	mov [drive.HSmpx], ax	; sectors per cylinder
 
 
load64:
	mov	si, 3			; three tries
try64:
	mov ax, 1			; sector 1
	call seek			; grab CHS -> dx 0080, cx 0002, ax 0000
	mov	ah, 02h			; "read CHS"
	mov	al, 20			; 20 = space between loader point and stack (20 x 512 = 10240)
	mov	bx, loc_LOADER	; mem
	int	13h				; 'dl' contains boot disk from MBR entry
	jnc	loadloader		; success
	dec	si				; retry count
	jnz	try64
	jmp fail
 
loadloader:
	mov	si, 3			; three tries
try:
	mov ax, 21			; sector 21
	call seek			; grab CHS
	mov	ah, 02h			; "read CHS"
	mov	al, 40			; 10 sectors
	mov	bx, loc_ELF		; mem
	int	13h				; 'dl' contains boot disk from MBR entry
	jnc	ok				; success
	dec	si				; retry count
	jnz	try
	jmp fail
 
fail:
	mov	bx, 0x15		;   bold attribute
	mov ah, 0x0E
	mov al, 'F'
	int 10h
crap:
	cli
	hlt
	jmp crap
 
ok:
	cli
	jmp	loc_LOADER		; set up for 64-bit, long mode, and bootloader
 
; input:
;	ax: zero-based sector to find
; output: (int13-02 compatible)
;	dl: drive
;	dh: head
;	cx: cyl.sec - C 76543210.98xxxxxx - S xxxxxxxx.xx543210
; example
; dh: 02    H:0-2			3 heads per cylinder
; cx: 0802	C:0-8 S:1-2		9 cylinders, 2 sectors per track
; makes sector 21: C/H/S = 3/1/2 = 3x6+2x1+(2-1)
;	mov	cx, 0x0302			; C=3 / S=2
;	mov dh, 1				; H=1
seek:
	push bx
	xor dx, dx				; DIV input DX:AX
	div word [drive.HSmpx]	; operation DX:AX / HSmpx = AX.DX
	xchg ah, al				; xxxxxx98.76543210 -> 76543210.xxxxxx98
	shl al, 6				; 76543210.98xxxxxx
	mov cx, ax				; set cylinder
	mov ax, dx				; set remainder - ((LBA/mpx)*mpx) -> AX
	xor dx, dx				; zero DX (DX:AX)
	xor bh, bh				; zero
	mov bl, byte [drive.S]	; grab sectors per track
	div bx					; remainder / S
	mov dh, al				; set head
	inc dl					; remainder is sector, sector is 1-based
	or cl, dl				; insert sector
	mov dl, [drive.disk]	; set disk
	pop bx
	ret
 
drive:
	.disk	db 0		; BIOS-supplied drive number
	.C		dw 0		; last cylinder, 0->
	.H		db 0		; last head, 0->
	.S		db 0		; sector per track, 1->
	.HSmpx	dw 0		; HxS per cylinder
 
 
 
 
; put segment FINAL at the end of the sector
SEGMENT FINAL start=loc_MBR+0x200-2-4*PT_ENT_size
 
PartitionTable	db	0x80		;BootFlag		resb	1
				db	1			;BeginHead       resb	1	8 bit
				db	1			;BeginSector     resb	1	6 bit
				db	0			;BeginCyl        resb	1	10 bit
				db	0xED		;SystemID        resb	1	ED - Evil Duck
				db	2			;EndHead         resb	1	8 bit
				db	2			;EndSector       resb	1	6 bit
				db	0			;EndCyl          resb	1	10 bit
				dw	2			;RelSectorLow    resw	1
				dw	0			;RelSectorHigh   resw	1
				dw	1000		;NumSectorsLow   resw	1
				dw	0			;NumSectorsHigh  resw	1
 
PartitionTable2  resb PT_ENT_size
PartitionTable3  resb PT_ENT_size
PartitionTable4  resb PT_ENT_size
	dw	0xAA55