%assign USE_TEST_MENU 0
%assign BOOT_BLOCK_START_ADDRESS 0x7c00
%assign MBR_SIGNATURE 0xAA55
%assign BIOS_VIDEO_SERVICES 0x10
%assign BIOS_DISK_SERVICES 0x13
%assign BIOS_KEYBOARD_SERVICES 0x16
%assign BIOS_REBOOT 0x19
%assign BIOS_TIME_SERVICES 0x1A
%assign SET_VIDEO_MODE 0x00
%assign SET_CURSOR_SHAPE 0x01
%assign SET_CURSOR 0x02
%assign GET_CURSOR 0x03
%assign SCROLL_UP 0x06
%assign WRITE_CHAR 0x09
%assign READ_DISK_SECTORS 0x02
%assign READ_DRIVE_PARAMETERS 0x08
%assign CHECK_DISK_EXTENSIONS_PRESENT 0x41
%assign EXTENDED_READ 0x42
%assign FIXED_DISK_SUPPORT 0x1
%assign READ_CHAR 0x00
%assign PROBE_CHAR 0x01
%assign GET_MODIFIER_KEYS 0x02
%assign READ_CLOCK 0x00
%assign TICKS_PER_SECOND 19
%assign GRAPHIC_MODE_80x25 0x12
%assign TEXT_COLUMNS 80
%assign TEXT_ROWS 25
%assign BLACK 0
%assign BLUE 1
%assign GREEN 2
%assign CYAN 3
%assign RED 4
%assign MAGENTA 5
%assign BROWN 6
%assign LIGHT_GRAY 7
%assign DARK_GRAY 8
%assign LIGHT_BLUE 9
%assign LIGHT_GREEN 10
%assign LIGHT_CYAN 11
%assign LIGHT_RED 12
%assign LIGHT_MAGENTA 13
%assign YELLOW 14
%assign WHITE 15
%assign BRIGHT_COLOR_MASK 8
%assign TRIANGLE_TO_RIGHT 16
%assign TRIANGLE_TO_LEFT 17
%assign KEY_DOWN 0x50
%assign KEY_UP 0x48
%assign KEY_PAGE_DOWN 0x51
%assign KEY_PAGE_UP 0x49
%assign KEY_HOME 0x47
%assign KEY_END 0x4f
%assign KEY_RETURN 0x1C
%assign MODIFIER_RIGHT_SHIFT_KEY 0x01
%assign MODIFIER_LEFT_SHIFT_KEY 0x02
%assign MODIFIER_CONTROL_KEY 0x04
%assign MODIFIER_ALT_KEY 0x08
%assign MODIFIER_SCROLL_LOCK_KEY 0x10
%assign MODIFIER_NUM_LOCK_KEY 0x20
%assign MODIFIER_CAPS_LOCK_KEY 0x40
%assign MODIFIER_INSERT_KEY 0x80
%define TITLE 'Haiku Boot Manager'
%strlen TITLE_LENGTH TITLE
%define SELECT_OS_MESSAGE 'Select an OS from the menu'
%strlen SELECT_OS_MESSAGE_LENGTH SELECT_OS_MESSAGE
SECTION .text
BITS 16
%define sizeof(s) s %+ _size
%macro nstruc 1-2 1
resb sizeof(%1) * %2
%endmacro
struc Locals
selection resw 1
firstLine resb 2
timeoutTicks resd 1
cursorX resb 1
cursorY resb 1
cursorShape resw 1
biosDrive resb 1
endstruc
cursorPosition equ cursorX
%macro DEBUG_PAUSE 0
push ax
mov ah, READ_CHAR
int BIOS_KEYBOARD_SERVICES
pop ax
%endmacro
%macro CLEAR_SCREEN 0
mov ah, SCROLL_UP
xor al, al
mov bh, WHITE
xor cx, cx
mov dx, (TEXT_ROWS-1) * 0x100 + (TEXT_COLUMNS-1)
int BIOS_VIDEO_SERVICES
%endmacro
%macro PRINT_STRING 0
push ax
push bx
push cx
push dx
xor bh, bh
jmp .loop_condition
.loop:
mov dx, [bp + cursorPosition]
mov ah, SET_CURSOR
int BIOS_VIDEO_SERVICES
inc byte [bp + cursorX]
mov cx, 1
mov ah, WRITE_CHAR
int BIOS_VIDEO_SERVICES
.loop_condition:
lodsb
cmp al, 0
jnz .loop
pop dx
pop cx
pop bx
pop ax
ret
%endmacro
struc quadword
.lower resd 1
.upper resd 1
endstruc
struc AddressPacket
.packet_size resb 1
.reserved1 resb 1
.block_count resb 1
.reserved2 resb 1
.buffer resd 1
.offset nstruc quadword
endstruc
struc BootLoaderAddress
.device resb 1
.offset nstruc quadword
endstruc
%define printstr printStringStage1
stage1:
mov ax, 0x07c0
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0xFFFF - sizeof(Locals)
mov bp, sp
mov [bp + biosDrive], dl
cld
CLEAR_SCREEN
call hideCursor
mov bh, 0
mov dx, 1 * 0x100 + (40 - TITLE_LENGTH / 2)
mov [bp + cursorPosition], dx
mov si, kTitle
mov bl, WHITE
call printstr
mov dx, (TEXT_ROWS-2) * 0x100 + (40 - SELECT_OS_MESSAGE_LENGTH / 2)
mov [bp + cursorPosition], dx
mov bl, LIGHT_GRAY
mov si, kSelectOSMessage
call printstr
mov ah, EXTENDED_READ
mov dl, [bp + biosDrive]
mov si, nextStageDAP
int BIOS_DISK_SERVICES
jc .error
jmp stage2
.error:
call showCursor
mov si, kError
mov bl, RED
call printstr
mov ah, READ_CHAR
int BIOS_KEYBOARD_SERVICES
mov dl, [bp + biosDrive]
int BIOS_REBOOT
printStringStage1:
PRINT_STRING
hideCursor:
mov ah, GET_CURSOR
int BIOS_VIDEO_SERVICES
mov [bp + cursorShape], cx
mov ah, SET_CURSOR_SHAPE
mov cx, 0x2000
int BIOS_VIDEO_SERVICES
ret
showCursor:
mov cx, [bp + cursorShape]
mov ah, SET_CURSOR_SHAPE
int BIOS_VIDEO_SERVICES
ret
nextStageDAP:
istruc AddressPacket
at AddressPacket.packet_size, db 0x10
at AddressPacket.block_count, db 0x03
at AddressPacket.buffer, dw 0x0200, 0x07c0
at AddressPacket.offset, dw 1
iend
kTitle:
db TITLE, 0x00
kSelectOSMessage:
db SELECT_OS_MESSAGE, 0x00
kError:
db 'Error loading sectors!', 0x00
kStage1UnusedSpace equ 440 - ($-$$)
times kStage1UnusedSpace db 'B'
kDiskSignature:
dw 0, 0
kReserved:
dw 0
kPartitionTable:
times 64 db 0
kMBRSignature:
dw MBR_SIGNATURE
%define printstr printStringStage2
%assign TIMEOUT_OFF 0xffff
stage2:
mov ax, [defaultItem]
mov [bp + selection], ax
mov ax, TICKS_PER_SECOND
mul word [timeout]
mov bx, dx
push ax
mov ah, READ_CLOCK
int BIOS_TIME_SERVICES
pop ax
add ax, dx
adc bx, cx
mov [bp + timeoutTicks], ax
mov [bp + timeoutTicks + 2], bx
mov al, [listItemCount]
shr al, 1
mov bl, TEXT_ROWS / 2
sub bl, al
mov [bp + firstLine], bl
mov ah, GET_MODIFIER_KEYS
int BIOS_KEYBOARD_SERVICES
and al, MODIFIER_ALT_KEY
jz showMenu
mov word [timeout], TIMEOUT_OFF
showMenu:
call printMenu
cmp word [timeout], TIMEOUT_OFF
je inputLoop
timeoutLoop:
mov ah, PROBE_CHAR
int BIOS_KEYBOARD_SERVICES
jnz inputLoop
call isTimeoutReached
jnc timeoutLoop
jmp bootSelectedPartition
isTimeoutReached:
mov ah, READ_CLOCK
int BIOS_TIME_SERVICES
cmp cx, [bp + timeoutTicks + 2]
jb .returnFalse
ja .returnTrue
cmp dx, [bp + timeoutTicks]
ja .returnTrue
.returnFalse:
clc
ret
.returnTrue:
stc
ret
mainLoop:
call printMenu
inputLoop:
mov ah, READ_CHAR
int BIOS_KEYBOARD_SERVICES
cmp ah, KEY_DOWN
je selectNextPartition
cmp ah, KEY_PAGE_DOWN
je selectLastPartition
cmp ah, KEY_END
je selectLastPartition
cmp ah, KEY_UP
je selectPreviousPartition
cmp ah, KEY_PAGE_UP
je selectFirstPartition
cmp ah, KEY_HOME
je selectFirstPartition
cmp ah, KEY_RETURN
jne inputLoop
jmp bootSelectedPartition
selectNextPartition:
mov ax, [bp + selection]
inc ax
cmp ax, [listItemCount]
jne .done
xor ax, ax
.done:
mov [bp + selection], ax
jmp mainLoop
selectLastPartition:
mov ax, [listItemCount]
dec ax
mov [bp + selection], ax
jmp mainLoop
selectPreviousPartition:
mov ax, [bp + selection]
or ax, ax
jnz .done
mov ax, [listItemCount]
.done:
dec ax
mov [bp + selection], ax
jmp mainLoop
selectFirstPartition:
xor ax, ax
mov [bp + selection], ax
jmp mainLoop
printMenu:
mov al, [bp + firstLine]
mov [bp + cursorY], al
mov si, list
xor cx, cx
.loop:
lodsb
add al, 3
shr al, 1
mov dl, TEXT_COLUMNS / 2
sub dl, al
mov [bp + cursorX], dl
mov al, TRIANGLE_TO_RIGHT
call updateMarker
inc byte [bp + cursorX]
mov di, cx
and di, 3
mov bl, [kColorTable + di]
cmp cx, [bp + selection]
jne .print
xor bl, BRIGHT_COLOR_MASK
.print:
call printstr
add si, sizeof(BootLoaderAddress)
add byte [bp + cursorX], 1
mov al, TRIANGLE_TO_LEFT
call updateMarker
inc byte [bp + cursorY]
inc cx
cmp cx, [listItemCount]
jne .loop
ret
updateMarker:
cmp cx, [bp + selection]
je .print
mov al, ' '
.print:
mov bl, WHITE
jmp printChar
bootSelectedPartition:
call showCursor
call getSelectedBootLoaderAddress
lodsb
mov dl, al
mov di, bootSectorDAP+AddressPacket.offset
mov cx, 4
.copy_start_sector:
lodsw
stosw
loop .copy_start_sector
mov ah, EXTENDED_READ
mov si, bootSectorDAP
int BIOS_DISK_SERVICES
mov si, kReadError
jc printAndHalt
mov ax, [kMBRSignature]
cmp ax, MBR_SIGNATURE
mov si, kNoBootablePartitionError
jne printAndHalt
CLEAR_SCREEN
mov word [bp + cursorPosition], 0
mov si, kLoadingMessage
mov bl, LIGHT_GRAY
call printstr
inc byte [bp + cursorX]
call getSelectedMenuItem
inc si
call printstr
mov dx, 0x100
xor bh, bh
mov ah, SET_CURSOR
int BIOS_VIDEO_SERVICES
call getSelectedBootLoaderAddress
mov dl, [si]
jmp $$
printAndHalt:
mov dx, (TEXT_ROWS-4) * 0x100 + (TEXT_COLUMNS / 3)
mov [bp + cursorPosition], dx
mov bx, 0x0F
call printstr
mov ah, READ_CHAR
int BIOS_KEYBOARD_SERVICES
mov dl, [bp + biosDrive]
int BIOS_REBOOT
getSelectedMenuItem:
mov si, list
mov cx, [bp + selection]
inc cx
xor ah, ah
jmp .entry
.loop:
lodsb
add si, ax
add si, sizeof(BootLoaderAddress)
.entry:
loop .loop
ret
getSelectedBootLoaderAddress:
call getSelectedMenuItem
lodsb
xor ah, ah
add si, ax
mov dl, [si]
test dl, 0
jz .takeOverBootDrive
ret
.takeOverBootDrive:
mov dl, [bp + biosDrive]
mov [si], dl
ret
printStringStage2:
PRINT_STRING
printChar:
push ax
push bx
push cx
push dx
xor bh, bh
mov dx, [bp + cursorPosition]
mov ah, SET_CURSOR
int BIOS_VIDEO_SERVICES
inc byte [bp + cursorX]
mov cx, 1
mov ah, WRITE_CHAR
int BIOS_VIDEO_SERVICES
pop dx
pop cx
pop bx
pop ax
ret
bootSectorDAP:
istruc AddressPacket
at AddressPacket.packet_size, db 0x10
at AddressPacket.block_count, db 0x01
at AddressPacket.buffer, dw 0x0000, 0x07c0
iend
kColorTable:
db BLUE, RED, GREEN, CYAN
kReadError:
db 'Error loading sectors', 0x00
kNoBootablePartitionError:
db 'Not a bootable partition', 0x00
kLoadingMessage:
db 'Loading', 0x00
listItemCount:
defaultItem equ listItemCount + 2
timeout equ defaultItem + 2
list equ timeout + 2
%if USE_TEST_MENU
dw 0x06
dw 2
dw 5
db 0x06
db 'HAIKU', 0
db 0x80
dw 1, 0, 0, 0
db 0x08
db 'FreeBSD', 0
db 0x80
dw 0x003F, 0, 0, 0
db 0x04
db 'DOS', 0
db 0x80
dw 0x003E, 0, 0, 0
db 0x06
db 'LINUX', 0
db 0x80
dw 0x003F, 0, 0, 0
db 0x08
db 'BeOS R5', 0
db 0x80
dw 0x003F, 0, 0, 0
db 0x07
db 'OpenBSD', 0
db 0x80
dw 0xAAAA, 0, 0, 0
dw kStage1UnusedSpace
%endif