Here comes an assembly code for a boot loader that works with both partitioning schemes. It's
well commented, to make it understand easier. It does not include the GPT parser, it's just
a boot sector (only 512 bytes long), but it can be used by anyone writing it's own GPT capable
chain loader or operating system.
;*********************************************************************
;* *
;* OS/3D - written by Zoltan Baldaszti (aka Turdus) in 2008 *
;* License: CC-by-nc-3.0, this file can be distibuted separately *
;* Compilation: nasm -f bin multiboot.asm -o mubr.bin *
;* *
;* This is a Multi Boot Record Loader. This briliant piece of code *
;* is compatible with MBR _and_ GPT, it can be used as volume boot *
;* as well as master boot record. If it's installed as MBR, it's *
;* 100% compatible with original IBM PC BIOS code. It's also able *
;* to load a specific firmware (maybe a chain loader) regardless *
;* of partitioning scheme. The only restriction is that it has to *
;* occupy continous sectors, and the 2nd sector must start with *
;* the word 'FIRMWARE', and initcode right after it. Maximum size *
;* of this code can be 29k (up to offset 7C00h starting at 0A08h). *
;* This boot record code can be loaded anywhere in memory, not *
;* necessarly 7C00h, it will relocate itself to offset 0600h. And *
;* all of this requires no more than 298 bytes. Cool, isn't it? *
;* *
;* memory occupied: 0600-800 *
;* *
;* partitioned layout (MBR): *
;* sect 0 Multi boot record *
;* sect 1-x unused (maybe GUID partition table) *
;* sect x firmware *
;* sect x partition begins, filesystem *
;* *
;* partitioned layout (VBR): *
;* sect 0 Master boot record *
;* sect 1-x unused (maybe GUID partition table) *
;* sect x firmware *
;* sect x partition begins, Multi boot record *
;* sect x filesystem *
;* *
;* partitionless layout: *
;* sect 0 Multi boot record *
;* sect 1 firmware *
;* sect x filesystem *
;* *
;*********************************************************************
;--------------------------Macros----------------------------
%macro writestr 1
push si
mov si, %1
call writestrfunc
pop si
%endmacro
%macro die 1
mov si, %1
call diefunc
%endmacro
;-----------------BIOS called ENTRY POINT--------------------
ORG 0600h
BITS 16
multi_boot_record:
cli
jmp short .skipdata
.id db "MuBRLoader",0 ;Multi Boot Record Loader
.version db 00h,1bh ;version 0.0.1beta
.copyrgt db "CC-by-nc-3.0 (c)Zoltan Baldaszti"
; gap till 30h
times 30h-($-$$) db 0
.skipdata: ;NOTE: not sure about 32 bit processor yet, so we have to
;use 16 bit operands
;relocate our code to offset 600h
xor ax, ax
mov ss, ax
mov sp, 580h
push ax
pop es
push ax
pop ds
;find our position in memory.
call .getaddress
.getaddress: pop ax
sub ax, .getaddress-multi_boot_record
mov si, ax
sti
cld
mov di, 0600h
mov cx, 100h
repnz movsw
jmp 0:.start
.start: ;get boot drive code - original MBR passes it,
;so all bootmanager should
mov byte [bootdrive], dl
writestr .system
call checklba
jnc .lbaok
die lbanotf
.lbaok: ;we have to load the mbr beacuse we may be loaded as
;volume boot record or via EFI
call loadmbr
jc .nombr
cmp word [07DFEh], 0AA55h
je .mbrok
.nombr: die mbrnotf
.mbrok: mov byte [07DFEh], 0
;try to load firmware - it's a continous area on disk
;started at given sector with maximum size of 7400h bytes
;(800h-7C00h in memory)
;doesn't matter if we can load it or not,
;we still want to search for partitions
mov byte [lbapacket.count], byte 58
mov byte [lbapacket.addr0+1], byte 08h
mov si, firmware_addr
mov di, lbapacket.sect0
lodsw
stosw
lodsw
stosw
call loadsectorfunc
;searching for active partition or GPT scheme
mov si, word 07DBEh
.nextpartition:
cmp si, word 07DFEh
jge .noos
mov al, byte [si]
mov ah, byte [si+4]
mov bx, word [si+8]
mov dx, word [si+10]
add si, byte 16
cmp al, byte 80h ;check for active partition
je .partitionok
cmp ah, byte 0EEh ;check for GPT
jne .nextpartition
;save the partition info
.partitionok: mov byte [fstype], ah
mov word [beginsec], bx
mov word [beginsec+2], dx
;load partition's first eight sector
mov word [lbapacket.sect0], bx
mov word [lbapacket.sect1], dx
mov byte [lbapacket.count], byte 8
mov byte [lbapacket.addr0+1], byte 07Ch
call loadsectorfunc
;do we have a firmware?
;if so, don't bother none, it will handle all the rest of it.
cmp word [0A00h], "FI"
jne .nofirmware
cmp word [0A02h], "RM"
jne .nofirmware
cmp word [0A04h], "WA"
jne .nofirmware
cmp word [0A06h], "RE"
jne .nofirmware
;invoke firmware code
jmp 0A08h
.nofirmware: ;if no, continue with standard boot mechanism
;check if it's a valid boot record
cmp word [07DFEh], 0AA55h
jne .noos
mov dl, byte [bootdrive]
jmp 0:07C00h
.noos: die osnotfound
;*********************************************************************
;* functions *
;*********************************************************************
;check for lba presistance
checklba:
cmp dl, byte 80h
jl .nolba
mov ah, byte 41h
mov bx, word 55AAh
int 13h
jc .nolba
cmp bx, word 0AA55h
jne .nolba
test cl, byte 1
jnz .lbaend
.nolba: stc
.lbaend: ret
;loads an LBA sector
loadmbr:
loadsectorfunc:
mov ah, byte 42h
mov dl, byte [bootdrive]
mov si, lbapacket
int 13h
ret
;ds:si zero terminated string to write
writestrfunc:
lodsb
or al, al
jz .end
mov ah, byte 0Eh
mov bx, word 11
int 10h
jmp writestrfunc
.end: ret
;writes the reason and die
diefunc:
writestr panic
call writestrfunc
haltsystem: xor ax, ax
int 16h
reset: int 19h
;*********************************************************************
;* data area *
;*********************************************************************
panic: db "-PANIC: ",0
lbanotf: db "no LBA support",0
mbrnotf: db "no partitions",0
osnotfound: db "no operating system or firmware",0
bootdrive: db 0
fstype: db 0
beginsec: dd 0
lbapacket:
.size: dw 16
.count: dw 1
.addr0: dw 07C00h
.addr1: dw 0
.sect0: dw 0
.sect1: dw 0
.sect2: dw 0
.sect3: dw 0
times 01BAh-($-$$) db 0
;right before the partition table the firmware address
firmware_addr: dd 1
;fake partition table
db 80h ;bootable
db 0,0,0 ;CHS not used
db 03dh ;fs type
db 0,0,0 ;CHS not used
dd 59 ;start LBA
dd 0ffffffh ;end LBA
times 01FEh-($-$$) db 0
db 55h,0AAh
;*********************************************************************
;* end of Multi Boot Record *
;*********************************************************************