2 ; Copyright 2007, Dengg David, david-d@gmx.at. All rights reserved.
3 ; Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved.
4 ; Copyright 2005, Ingo Weinhold, bonefish@users.sf.net.
5 ; Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
6 ; Distributed under the terms of the MIT License.
9 %assign USE_TEST_MENU 0
11 %assign BOOT_BLOCK_START_ADDRESS 0x7c00
13 %assign MBR_SIGNATURE 0xAA55
17 %assign BIOS_VIDEO_SERVICES 0x10
18 %assign BIOS_DISK_SERVICES 0x13
19 %assign BIOS_KEYBOARD_SERVICES 0x16
20 %assign BIOS_REBOOT 0x19 ; dl - boot drive number
21 %assign BIOS_TIME_SERVICES 0x1A
24 %assign SET_VIDEO_MODE 0x00 ; al - mode
26 %assign SET_CURSOR_SHAPE 0x01 ; ch - starting scan line (5 bits)
27 ; cl - ending scan line (5 bits)
29 %assign SET_CURSOR 0x02 ; dl - column
34 %assign GET_CURSOR 0x03 ; bh - page
38 ; ch - starting scan line
39 ; cl - ending scan line
41 %assign SCROLL_UP 0x06 ; al - lines (0: clear screen)
48 %assign WRITE_CHAR 0x09 ; al - char
53 ;%assign WRITE_CHAR 0x0e ; al - char
55 ; bl - foreground color (graphics mode only)
58 %assign READ_DISK_SECTORS 0x02 ; dl - drive
61 ; ch - track 7:0 (0 - 1023)
65 ; -> al - sectors read
66 %assign READ_DRIVE_PARAMETERS 0x08 ; dl - drive
67 ; -> cl - max cylinder 9:8
69 ; ch - max cylinder 7:0
71 ; dl - number of drives (?)
72 %assign CHECK_DISK_EXTENSIONS_PRESENT 0x41 ; bx - 0x55aa
74 ; -> success: carry clear
75 ; ah - extension version
77 ; cx - support bit mask
79 %assign EXTENDED_READ 0x42 ; dl - drive
80 ; ds:si - address packet
81 ; -> success: carry clear
84 %assign FIXED_DISK_SUPPORT 0x1 ; flag indicating fixed disk
85 ; extension command subset
88 %assign READ_CHAR 0x00 ; -> al - ASCII char
91 %assign PROBE_CHAR 0x01 ; -> zf = 0
95 %assign GET_MODIFIER_KEYS 0x02 ;-> al - modifier key bitmask
98 %assign READ_CLOCK 0x00 ; -> cx - high word
102 %assign TICKS_PER_SECOND 19
105 %assign GRAPHIC_MODE_80x25 0x12 ; 640 x 480 graphic mode
107 %assign TEXT_COLUMNS 80 ; Number of columns
108 %assign TEXT_ROWS 25 ; Number of rows
121 %assign LIGHT_GREEN 10
122 %assign LIGHT_CYAN 11
124 %assign LIGHT_MAGENTA 13
128 %assign BRIGHT_COLOR_MASK 8
131 %assign TRIANGLE_TO_RIGHT 16
132 %assign TRIANGLE_TO_LEFT 17
135 %assign KEY_DOWN 0x50
137 %assign KEY_RETURN 0x1C
139 ; Modifier key bitmasks
140 %assign MODIFIER_RIGHT_SHIFT_KEY 0x01
141 %assign MODIFIER_LEFT_SHIFT_KEY 0x02
142 %assign MODIFIER_CONTROL_KEY 0x04
143 %assign MODIFIER_ALT_KEY 0x08
144 %assign MODIFIER_SCROLL_LOCK_KEY 0x10
145 %assign MODIFIER_NUM_LOCK_KEY 0x20
146 %assign MODIFIER_CAPS_LOCK_KEY 0x40
147 %assign MODIFIER_INSERT_KEY 0x80
149 ; String constants with their length
150 %define TITLE 'Haiku Boot Manager'
151 %strlen TITLE_LENGTH TITLE
152 %define SELECT_OS_MESSAGE 'Select an OS from the menu'
153 %strlen SELECT_OS_MESSAGE_LENGTH SELECT_OS_MESSAGE
160 ; nicer way to get the size of a structure
161 %define sizeof(s) s %+ _size
163 ; using a structure in a another structure definition
171 firstLine resb 2 ; low byte used only
179 cursorPosition equ cursorX
184 int BIOS_KEYBOARD_SERVICES
188 %macro CLEAR_SCREEN 0
193 mov dx, (TEXT_ROWS-1) * 0x100 + (TEXT_COLUMNS-1)
194 int BIOS_VIDEO_SERVICES
197 ; Prints a null terminated string
199 ; si ... offset to string
200 %macro PRINT_STRING 0
205 xor bh, bh ; write on page 0
208 mov dx, [bp + cursorPosition]
210 int BIOS_VIDEO_SERVICES
212 inc byte [bp + cursorX]
216 int BIOS_VIDEO_SERVICES
234 ; address packet as required by the EXTENDED_READ BIOS call
241 .offset nstruc quadword
244 struc BootLoaderAddress
245 .device resb 1 ; hard drive number
246 .offset nstruc quadword ; LBA of start start sector
249 ; use code available in stage 1
250 %define printstr printStringStage1
253 mov ax, 0x07c0 ; BOOT_BLOCK_START_ADDRESS / 16
254 mov ds, ax ; Setup segment registers
258 mov sp, 0xFFFF - sizeof(Locals) ; Make stack empty
261 mov [bp + biosDrive], dl ; Store boot drive
262 cld ; String operations increment index
267 mov bh, 0 ; Text output on page 0
269 ; Print title centered at row 2
270 mov dx, 1 * 0x100 + (40 - TITLE_LENGTH / 2)
271 mov [bp + cursorPosition], dx
277 ; Print message centered at second last row
278 mov dx, (TEXT_ROWS-2) * 0x100 + (40 - SELECT_OS_MESSAGE_LENGTH / 2)
279 mov [bp + cursorPosition], dx
282 mov si, kSelectOSMessage
285 ; Chain load rest of boot loader
286 mov ah, EXTENDED_READ ; Load 3 more sectors
287 mov dl, [bp + biosDrive]
289 int BIOS_DISK_SERVICES
290 jc .error ; I/O error
291 jmp stage2 ; Continue in loaded stage 2
300 int BIOS_KEYBOARD_SERVICES
302 mov dl, [bp + biosDrive]
310 int BIOS_VIDEO_SERVICES
311 mov [bp + cursorShape], cx
313 mov ah, SET_CURSOR_SHAPE
315 int BIOS_VIDEO_SERVICES
319 mov cx, [bp + cursorShape]
320 mov ah, SET_CURSOR_SHAPE
321 int BIOS_VIDEO_SERVICES
326 at AddressPacket.packet_size, db 0x10
327 at AddressPacket.block_count, db 0x03
328 at AddressPacket.buffer, dw 0x0200, 0x07c0
329 at AddressPacket.offset, dw 1
335 db SELECT_OS_MESSAGE, 0x00
337 db 'Error loading sectors!', 0x00
339 kStage1UnusedSpace equ 440 - ($-$$)
340 ; Fill the missing space to reach byte 440
341 times kStage1UnusedSpace db 'B'
351 ; Magic marker "AA55" (to identify a valid boot record)
354 ; ======================================================================
355 ; ======================= SECOND SECTOR ================================
356 ; ======================================================================
358 ; Use code available in stage 2
359 %define printstr printStringStage2
361 %assign TIMEOUT_OFF 0xffff
365 mov ax, [defaultItem] ; Select default item
366 mov [bp + selection], ax
368 mov ax, TICKS_PER_SECOND ; Calculate timeout ticks
374 int BIOS_TIME_SERVICES
376 pop ax ; Add current ticks
379 mov [bp + timeoutTicks], ax
380 mov [bp + timeoutTicks + 2], bx
382 mov al, [listItemCount] ; Calculate start row for menu
384 mov bl, TEXT_ROWS / 2
385 sub bl, al ; y = TEXT_ROWS / 2 - number of items / 2
386 mov [bp + firstLine], bl
388 mov ah, GET_MODIFIER_KEYS ; Disable timeout if ALT key is pressed
389 int BIOS_KEYBOARD_SERVICES
390 and al, MODIFIER_ALT_KEY
392 mov word [timeout], TIMEOUT_OFF
397 cmp word [timeout], TIMEOUT_OFF
402 int BIOS_KEYBOARD_SERVICES
403 jnz inputLoop ; cancel timeout if key is pressed
404 call isTimeoutReached
406 jmp bootSelectedPartition
410 int BIOS_TIME_SERVICES
411 cmp cx, [bp + timeoutTicks + 2]
414 cmp dx, [bp + timeoutTicks]
423 ; ================== Wait for a key and do something with it ==================
429 int BIOS_KEYBOARD_SERVICES ; AL = ASCII Code, AH = Scancode
432 je selectNextPartition
435 je selectPreviousPartition
439 jmp bootSelectedPartition
442 mov ax, [bp + selection]
444 cmp ax, [listItemCount]
445 jne .done ; At end of list?
446 xor ax, ax ; Then jump to first entry
448 mov [bp + selection], ax
451 selectPreviousPartition:
452 mov ax, [bp + selection]
454 jnz .done ; At top of list?
455 mov ax, [listItemCount] ; Then jump to last entry
458 mov [bp + selection], ax
462 ; ======================= Print the OS list ============================
464 mov al, [bp + firstLine]
465 mov [bp + cursorY], al
467 mov si, list ; Start at top of list
468 xor cx, cx ; The index of the current item
471 lodsb ; String length incl. 0-terminator
472 add al, 3 ; center menu item
473 shr al, 1 ; x = TEXT_COLUMNS / 2 - length / 2
474 mov dl, TEXT_COLUMNS / 2
476 mov [bp + cursorX], dl
478 mov al, TRIANGLE_TO_RIGHT
480 inc byte [bp + cursorX]
484 mov bl, [kColorTable + di] ; Text color
486 cmp cx, [bp + selection]
487 jne .print ; Selected item reached?
488 xor bl, BRIGHT_COLOR_MASK ; Highlight it
492 add si, sizeof(BootLoaderAddress)
494 add byte [bp + cursorX], 1
495 mov al, TRIANGLE_TO_LEFT
498 inc byte [bp + cursorY]
501 cmp cx, [listItemCount]
506 cmp cx, [bp + selection]
508 mov al, ' ' ; Clear marker
511 jmp printChar ; return from subroutine
514 ; ========================== Chainload ==========================
516 bootSelectedPartition:
520 call getSelectedBootLoaderAddress
521 lodsb ; Set boot drive
524 mov di, bootSectorDAP+AddressPacket.offset ; Copy start sector
525 mov cx, 4 ; It is stored in a quad word
529 loop .copy_start_sector
531 mov ah, EXTENDED_READ ; Now read start sector from HD
532 mov si, bootSectorDAP
533 int BIOS_DISK_SERVICES
535 jc printAndHalt ; Failed to read sector
537 mov ax, [kMBRSignature]
538 cmp ax, MBR_SIGNATURE
539 mov si, kNoBootablePartitionError
540 jne printAndHalt ; Missing signature
544 ; Print "Loading <name>" at top of screen
545 mov word [bp + cursorPosition], 0
546 mov si, kLoadingMessage
550 inc byte [bp + cursorX]
551 call getSelectedMenuItem
552 inc si ; Skip string length byte
558 int BIOS_VIDEO_SERVICES
560 call getSelectedBootLoaderAddress
561 mov dl, [si] ; drive number in dl
563 jmp $$ ; Start loaded boot loader
567 mov dx, (TEXT_ROWS-4) * 0x100 + (TEXT_COLUMNS / 3)
568 mov [bp + cursorPosition], dx
570 mov bx, 0x0F ; Page number and foreground color
573 int BIOS_KEYBOARD_SERVICES
574 mov dl, [bp + biosDrive]
578 ; si address of selected menu item
582 mov si, list ; Search address of start sector
583 ; of the selected item.
584 mov cx, [bp + selection]
585 inc cx ; Number of required iterations
587 xor ah, ah ; The high-byte of the string length
592 lodsb ; Length of menu item name
593 add si, ax ; Skip name to BootLoaderAddess
594 add si, sizeof(BootLoaderAddress)
600 getSelectedBootLoaderAddress:
601 call getSelectedMenuItem
604 add si, ax ; Skip name
606 test dl, 0 ; if drive is 0, use boot drive
607 jz .takeOverBootDrive
610 mov dl, [bp + biosDrive]
617 ; al ... ASCII character
625 xor bh, bh ; Write on page 0
627 mov dx, [bp + cursorPosition]
629 int BIOS_VIDEO_SERVICES
631 inc byte [bp + cursorX]
635 int BIOS_VIDEO_SERVICES
643 ; ================================ DATA ===========================
647 at AddressPacket.packet_size, db 0x10
648 at AddressPacket.block_count, db 0x01
649 at AddressPacket.buffer, dw 0x0000, 0x07c0
653 db BLUE, RED, GREEN, CYAN
655 db 'Error loading sectors', 0x00
656 kNoBootablePartitionError:
657 db 'Not a bootable partition', 0x00
663 defaultItem equ listItemCount + 2
664 timeout equ defaultItem + 2
667 ; dw number of entries
668 ; dw the default entry
669 ; dw the timeout (-1 for none)
671 ; db size of partition name 0-terminated string
672 ; db 0-terminated string with partition name
673 ; db hard drive number
674 ; quadword start sector
713 dw kStage1UnusedSpace