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