1b76ca311SAxel Dörfler; 2b76ca311SAxel Dörfler; Copyright 2007, Dengg David, david-d@gmx.at. All rights reserved. 3b76ca311SAxel Dörfler; Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. 4b76ca311SAxel Dörfler; Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. 549c044abSAxel Dörfler; Copyright 2011, Axel Dörfler, axeld@pinc-software.de. 6b76ca311SAxel Dörfler; Distributed under the terms of the MIT License. 7b76ca311SAxel Dörfler 8b76ca311SAxel Dörfler 9b76ca311SAxel Dörfler%assign USE_TEST_MENU 0 10b76ca311SAxel Dörfler 11b76ca311SAxel Dörfler%assign BOOT_BLOCK_START_ADDRESS 0x7c00 12b76ca311SAxel Dörfler 13b76ca311SAxel Dörfler%assign MBR_SIGNATURE 0xAA55 14b76ca311SAxel Dörfler 15b76ca311SAxel Dörfler; BIOS calls 16b76ca311SAxel Dörfler 17b76ca311SAxel Dörfler%assign BIOS_VIDEO_SERVICES 0x10 18b76ca311SAxel Dörfler%assign BIOS_DISK_SERVICES 0x13 19b76ca311SAxel Dörfler%assign BIOS_KEYBOARD_SERVICES 0x16 20b76ca311SAxel Dörfler%assign BIOS_REBOOT 0x19 ; dl - boot drive number 21b76ca311SAxel Dörfler%assign BIOS_TIME_SERVICES 0x1A 22b76ca311SAxel Dörfler 23b76ca311SAxel Dörfler; video services 24b76ca311SAxel Dörfler%assign SET_VIDEO_MODE 0x00 ; al - mode 25b76ca311SAxel Dörfler 26b76ca311SAxel Dörfler%assign SET_CURSOR_SHAPE 0x01 ; ch - starting scan line (5 bits) 27b76ca311SAxel Dörfler ; cl - ending scan line (5 bits) 28b76ca311SAxel Dörfler 29b76ca311SAxel Dörfler%assign SET_CURSOR 0x02 ; dl - column 30b76ca311SAxel Dörfler ; dh - row 31b76ca311SAxel Dörfler ; bh - page 32b76ca311SAxel Dörfler 33b76ca311SAxel Dörfler 34b76ca311SAxel Dörfler%assign GET_CURSOR 0x03 ; bh - page 35b76ca311SAxel Dörfler ; -> dl - column 36b76ca311SAxel Dörfler ; dh - row 37b76ca311SAxel Dörfler ; Cursor shape: 38b76ca311SAxel Dörfler ; ch - starting scan line 39b76ca311SAxel Dörfler ; cl - ending scan line 40b76ca311SAxel Dörfler 41b76ca311SAxel Dörfler%assign SCROLL_UP 0x06 ; al - lines (0: clear screen) 42b76ca311SAxel Dörfler ; bh - attribute 43b76ca311SAxel Dörfler ; ch - upper line 44b76ca311SAxel Dörfler ; cl - left column 45b76ca311SAxel Dörfler ; dh - lower line 46b76ca311SAxel Dörfler ; dl - right column 47b76ca311SAxel Dörfler 48b76ca311SAxel Dörfler%assign WRITE_CHAR 0x09 ; al - char 49b76ca311SAxel Dörfler ; bh - page 50b76ca311SAxel Dörfler ; bl - attribute 51b76ca311SAxel Dörfler ; cx - count 52b76ca311SAxel Dörfler 53b76ca311SAxel Dörfler;%assign WRITE_CHAR 0x0e ; al - char 54b76ca311SAxel Dörfler ; bh - page 55b76ca311SAxel Dörfler ; bl - foreground color (graphics mode only) 56b76ca311SAxel Dörfler 57b76ca311SAxel Dörfler; disk services 58b76ca311SAxel Dörfler%assign READ_DISK_SECTORS 0x02 ; dl - drive 59b76ca311SAxel Dörfler ; es:bx - buffer 60b76ca311SAxel Dörfler ; dh - head (0 - 15) 61b76ca311SAxel Dörfler ; ch - track 7:0 (0 - 1023) 62b76ca311SAxel Dörfler ; cl - track 9:8, 63b76ca311SAxel Dörfler ; sector (1 - 17) 64b76ca311SAxel Dörfler ; al - sector count 65b76ca311SAxel Dörfler ; -> al - sectors read 66b76ca311SAxel Dörfler%assign READ_DRIVE_PARAMETERS 0x08 ; dl - drive 67b76ca311SAxel Dörfler ; -> cl - max cylinder 9:8 68b76ca311SAxel Dörfler ; - sectors per track 69b76ca311SAxel Dörfler ; ch - max cylinder 7:0 70b76ca311SAxel Dörfler ; dh - max head 71b76ca311SAxel Dörfler ; dl - number of drives (?) 72b76ca311SAxel Dörfler%assign CHECK_DISK_EXTENSIONS_PRESENT 0x41 ; bx - 0x55aa 73b76ca311SAxel Dörfler ; dl - drive 74b76ca311SAxel Dörfler ; -> success: carry clear 75b76ca311SAxel Dörfler ; ah - extension version 76b76ca311SAxel Dörfler ; bx - 0xaa55 77b76ca311SAxel Dörfler ; cx - support bit mask 78b76ca311SAxel Dörfler ; -> error: carry set 79b76ca311SAxel Dörfler%assign EXTENDED_READ 0x42 ; dl - drive 80b76ca311SAxel Dörfler ; ds:si - address packet 81b76ca311SAxel Dörfler ; -> success: carry clear 82b76ca311SAxel Dörfler ; -> error: carry set 83b76ca311SAxel Dörfler 84b76ca311SAxel Dörfler%assign FIXED_DISK_SUPPORT 0x1 ; flag indicating fixed disk 85b76ca311SAxel Dörfler ; extension command subset 86b76ca311SAxel Dörfler 87b76ca311SAxel Dörfler; keyboard services 88b76ca311SAxel Dörfler%assign READ_CHAR 0x00 ; -> al - ASCII char 89b76ca311SAxel Dörfler ; ah - scan code 90b76ca311SAxel Dörfler 91b76ca311SAxel Dörfler%assign PROBE_CHAR 0x01 ; -> zf = 0 92b76ca311SAxel Dörfler ; al - ASCII char 93b76ca311SAxel Dörfler ; ah - scan code 94b76ca311SAxel Dörfler 95b76ca311SAxel Dörfler%assign GET_MODIFIER_KEYS 0x02 ;-> al - modifier key bitmask 96b76ca311SAxel Dörfler 97b76ca311SAxel Dörfler; timer services 98b76ca311SAxel Dörfler%assign READ_CLOCK 0x00 ; -> cx - high word 99b76ca311SAxel Dörfler ; dx - low word 100b76ca311SAxel Dörfler ; one tick = 1/18.2s 101b76ca311SAxel Dörfler 102b76ca311SAxel Dörfler%assign TICKS_PER_SECOND 19 103b76ca311SAxel Dörfler 104b76ca311SAxel Dörfler; video modes 105b76ca311SAxel Dörfler%assign GRAPHIC_MODE_80x25 0x12 ; 640 x 480 graphic mode 106b76ca311SAxel Dörfler 107b76ca311SAxel Dörfler%assign TEXT_COLUMNS 80 ; Number of columns 108b76ca311SAxel Dörfler%assign TEXT_ROWS 25 ; Number of rows 109b76ca311SAxel Dörfler 110b76ca311SAxel Dörfler; Colors 111b76ca311SAxel Dörfler%assign BLACK 0 112b76ca311SAxel Dörfler%assign BLUE 1 113b76ca311SAxel Dörfler%assign GREEN 2 114b76ca311SAxel Dörfler%assign CYAN 3 115b76ca311SAxel Dörfler%assign RED 4 116b76ca311SAxel Dörfler%assign MAGENTA 5 117b76ca311SAxel Dörfler%assign BROWN 6 118b76ca311SAxel Dörfler%assign LIGHT_GRAY 7 119b76ca311SAxel Dörfler%assign DARK_GRAY 8 120b76ca311SAxel Dörfler%assign LIGHT_BLUE 9 121b76ca311SAxel Dörfler%assign LIGHT_GREEN 10 122b76ca311SAxel Dörfler%assign LIGHT_CYAN 11 123b76ca311SAxel Dörfler%assign LIGHT_RED 12 124b76ca311SAxel Dörfler%assign LIGHT_MAGENTA 13 125b76ca311SAxel Dörfler%assign YELLOW 14 126b76ca311SAxel Dörfler%assign WHITE 15 127b76ca311SAxel Dörfler 128b76ca311SAxel Dörfler%assign BRIGHT_COLOR_MASK 8 129b76ca311SAxel Dörfler 130b76ca311SAxel Dörfler; Characters 131b76ca311SAxel Dörfler%assign TRIANGLE_TO_RIGHT 16 132b76ca311SAxel Dörfler%assign TRIANGLE_TO_LEFT 17 133b76ca311SAxel Dörfler 134b76ca311SAxel Dörfler; Key codes 135b76ca311SAxel Dörfler%assign KEY_DOWN 0x50 136b76ca311SAxel Dörfler%assign KEY_UP 0x48 137*786f0456SAxel Dörfler%assign KEY_PAGE_DOWN 0x51 138*786f0456SAxel Dörfler%assign KEY_PAGE_UP 0x49 139*786f0456SAxel Dörfler%assign KEY_HOME 0x47 140*786f0456SAxel Dörfler%assign KEY_END 0x4f 141b76ca311SAxel Dörfler%assign KEY_RETURN 0x1C 142b76ca311SAxel Dörfler 143b76ca311SAxel Dörfler; Modifier key bitmasks 144b76ca311SAxel Dörfler%assign MODIFIER_RIGHT_SHIFT_KEY 0x01 145b76ca311SAxel Dörfler%assign MODIFIER_LEFT_SHIFT_KEY 0x02 146b76ca311SAxel Dörfler%assign MODIFIER_CONTROL_KEY 0x04 147b76ca311SAxel Dörfler%assign MODIFIER_ALT_KEY 0x08 148b76ca311SAxel Dörfler%assign MODIFIER_SCROLL_LOCK_KEY 0x10 149b76ca311SAxel Dörfler%assign MODIFIER_NUM_LOCK_KEY 0x20 150b76ca311SAxel Dörfler%assign MODIFIER_CAPS_LOCK_KEY 0x40 151b76ca311SAxel Dörfler%assign MODIFIER_INSERT_KEY 0x80 152b76ca311SAxel Dörfler 153b76ca311SAxel Dörfler; String constants with their length 154b76ca311SAxel Dörfler%define TITLE 'Haiku Boot Manager' 155b76ca311SAxel Dörfler%strlen TITLE_LENGTH TITLE 156b76ca311SAxel Dörfler%define SELECT_OS_MESSAGE 'Select an OS from the menu' 157b76ca311SAxel Dörfler%strlen SELECT_OS_MESSAGE_LENGTH SELECT_OS_MESSAGE 158b76ca311SAxel Dörfler 159b76ca311SAxel Dörfler; 16 bit code 16074a14969SFrançois RevolSECTION .text 161b76ca311SAxel DörflerBITS 16 162b76ca311SAxel Dörfler 163b76ca311SAxel Dörfler 164b76ca311SAxel Dörfler; nicer way to get the size of a structure 165b76ca311SAxel Dörfler%define sizeof(s) s %+ _size 166b76ca311SAxel Dörfler 167b76ca311SAxel Dörfler; using a structure in a another structure definition 168b76ca311SAxel Dörfler%macro nstruc 1-2 1 169b76ca311SAxel Dörfler resb sizeof(%1) * %2 170b76ca311SAxel Dörfler%endmacro 171b76ca311SAxel Dörfler 172b76ca311SAxel Dörfler; Variables on stack 173b76ca311SAxel Dörflerstruc Locals 174b76ca311SAxel Dörfler selection resw 1 175b76ca311SAxel Dörfler firstLine resb 2 ; low byte used only 176b76ca311SAxel Dörfler timeoutTicks resd 1 177b76ca311SAxel Dörfler cursorX resb 1 178b76ca311SAxel Dörfler cursorY resb 1 179b76ca311SAxel Dörfler cursorShape resw 1 18089f0e174SAxel Dörfler biosDrive resb 1 181b76ca311SAxel Dörflerendstruc 182b76ca311SAxel Dörfler 183b76ca311SAxel DörflercursorPosition equ cursorX 184b76ca311SAxel Dörfler 185b76ca311SAxel Dörfler%macro DEBUG_PAUSE 0 186b76ca311SAxel Dörfler push ax 187b76ca311SAxel Dörfler mov ah, READ_CHAR 188b76ca311SAxel Dörfler int BIOS_KEYBOARD_SERVICES 189b76ca311SAxel Dörfler pop ax 190b76ca311SAxel Dörfler%endmacro 191b76ca311SAxel Dörfler 192b76ca311SAxel Dörfler%macro CLEAR_SCREEN 0 193b76ca311SAxel Dörfler mov ah, SCROLL_UP 194b76ca311SAxel Dörfler xor al, al 195b76ca311SAxel Dörfler mov bh, WHITE 196b76ca311SAxel Dörfler xor cx, cx 197b76ca311SAxel Dörfler mov dx, (TEXT_ROWS-1) * 0x100 + (TEXT_COLUMNS-1) 198b76ca311SAxel Dörfler int BIOS_VIDEO_SERVICES 199b76ca311SAxel Dörfler%endmacro 200b76ca311SAxel Dörfler 201b76ca311SAxel Dörfler; Prints a null terminated string 202b76ca311SAxel Dörfler; bl ... color 203b76ca311SAxel Dörfler; si ... offset to string 204b76ca311SAxel Dörfler%macro PRINT_STRING 0 205b76ca311SAxel Dörfler push ax 206b76ca311SAxel Dörfler push bx 207b76ca311SAxel Dörfler push cx 208b76ca311SAxel Dörfler push dx 209b76ca311SAxel Dörfler xor bh, bh ; write on page 0 210b76ca311SAxel Dörfler jmp .loop_condition 2117c5dfbadSFrançois Revol.loop: 212b76ca311SAxel Dörfler mov dx, [bp + cursorPosition] 213b76ca311SAxel Dörfler mov ah, SET_CURSOR 214b76ca311SAxel Dörfler int BIOS_VIDEO_SERVICES 215b76ca311SAxel Dörfler 216b76ca311SAxel Dörfler inc byte [bp + cursorX] 217b76ca311SAxel Dörfler 218b76ca311SAxel Dörfler mov cx, 1 219b76ca311SAxel Dörfler mov ah, WRITE_CHAR 220b76ca311SAxel Dörfler int BIOS_VIDEO_SERVICES 2217c5dfbadSFrançois Revol.loop_condition: 222b76ca311SAxel Dörfler lodsb 223b76ca311SAxel Dörfler cmp al, 0 224b76ca311SAxel Dörfler jnz .loop 225b76ca311SAxel Dörfler pop dx 226b76ca311SAxel Dörfler pop cx 227b76ca311SAxel Dörfler pop bx 228b76ca311SAxel Dörfler pop ax 229b76ca311SAxel Dörfler ret 230b76ca311SAxel Dörfler%endmacro 231b76ca311SAxel Dörfler 232b76ca311SAxel Dörfler; 64 bit value 233b76ca311SAxel Dörflerstruc quadword 234b76ca311SAxel Dörfler .lower resd 1 235b76ca311SAxel Dörfler .upper resd 1 236b76ca311SAxel Dörflerendstruc 237b76ca311SAxel Dörfler 238b76ca311SAxel Dörfler; address packet as required by the EXTENDED_READ BIOS call 239b76ca311SAxel Dörflerstruc AddressPacket 240b76ca311SAxel Dörfler .packet_size resb 1 241b76ca311SAxel Dörfler .reserved1 resb 1 242b76ca311SAxel Dörfler .block_count resb 1 243b76ca311SAxel Dörfler .reserved2 resb 1 244b76ca311SAxel Dörfler .buffer resd 1 245b76ca311SAxel Dörfler .offset nstruc quadword 246b76ca311SAxel Dörflerendstruc 247b76ca311SAxel Dörfler 248b76ca311SAxel Dörflerstruc BootLoaderAddress 249b76ca311SAxel Dörfler .device resb 1 ; hard drive number 250b76ca311SAxel Dörfler .offset nstruc quadword ; LBA of start start sector 251b76ca311SAxel Dörflerendstruc 252b76ca311SAxel Dörfler 253b76ca311SAxel Dörfler; use code available in stage 1 254b76ca311SAxel Dörfler%define printstr printStringStage1 255b76ca311SAxel Dörfler 256b76ca311SAxel Dörflerstage1: 25749c044abSAxel Dörfler mov ax, 0x07c0 ; BOOT_BLOCK_START_ADDRESS / 16 258b76ca311SAxel Dörfler mov ds, ax ; Setup segment registers 259b76ca311SAxel Dörfler mov es, ax 260b76ca311SAxel Dörfler mov ss, ax 261b76ca311SAxel Dörfler 262b76ca311SAxel Dörfler mov sp, 0xFFFF - sizeof(Locals) ; Make stack empty 263b76ca311SAxel Dörfler mov bp, sp 264b76ca311SAxel Dörfler 26589f0e174SAxel Dörfler mov [bp + biosDrive], dl ; Store boot drive 26649c044abSAxel Dörfler cld ; String operations increment index 26749c044abSAxel Dörfler ; registers 268b76ca311SAxel Dörfler CLEAR_SCREEN 269b76ca311SAxel Dörfler call hideCursor 270b76ca311SAxel Dörfler 271b76ca311SAxel Dörfler mov bh, 0 ; Text output on page 0 272b76ca311SAxel Dörfler 273b76ca311SAxel Dörfler ; Print title centered at row 2 274b76ca311SAxel Dörfler mov dx, 1 * 0x100 + (40 - TITLE_LENGTH / 2) 275b76ca311SAxel Dörfler mov [bp + cursorPosition], dx 276b76ca311SAxel Dörfler 277b76ca311SAxel Dörfler mov si, kTitle 278b76ca311SAxel Dörfler mov bl, WHITE 279b76ca311SAxel Dörfler call printstr 280b76ca311SAxel Dörfler 281b76ca311SAxel Dörfler ; Print message centered at second last row 282b76ca311SAxel Dörfler mov dx, (TEXT_ROWS-2) * 0x100 + (40 - SELECT_OS_MESSAGE_LENGTH / 2) 283b76ca311SAxel Dörfler mov [bp + cursorPosition], dx 284b76ca311SAxel Dörfler 285b76ca311SAxel Dörfler mov bl, LIGHT_GRAY 286b76ca311SAxel Dörfler mov si, kSelectOSMessage 287b76ca311SAxel Dörfler call printstr 288b76ca311SAxel Dörfler 289b76ca311SAxel Dörfler ; Chain load rest of boot loader 290b76ca311SAxel Dörfler mov ah, EXTENDED_READ ; Load 3 more sectors 29189f0e174SAxel Dörfler mov dl, [bp + biosDrive] 292b76ca311SAxel Dörfler mov si, nextStageDAP 293b76ca311SAxel Dörfler int BIOS_DISK_SERVICES 294b76ca311SAxel Dörfler jc .error ; I/O error 295b76ca311SAxel Dörfler jmp stage2 ; Continue in loaded stage 2 296b76ca311SAxel Dörfler 297b76ca311SAxel Dörfler.error: 298b76ca311SAxel Dörfler call showCursor 299b76ca311SAxel Dörfler mov si, kError 300b76ca311SAxel Dörfler mov bl, RED 301b76ca311SAxel Dörfler call printstr 302b76ca311SAxel Dörfler 303b76ca311SAxel Dörfler mov ah, READ_CHAR 304b76ca311SAxel Dörfler int BIOS_KEYBOARD_SERVICES 305b76ca311SAxel Dörfler 30689f0e174SAxel Dörfler mov dl, [bp + biosDrive] 307b76ca311SAxel Dörfler int BIOS_REBOOT 308b76ca311SAxel Dörfler 309b76ca311SAxel DörflerprintStringStage1: 310b76ca311SAxel Dörfler PRINT_STRING 311b76ca311SAxel Dörfler 312b76ca311SAxel DörflerhideCursor: 313b76ca311SAxel Dörfler mov ah, GET_CURSOR 314b76ca311SAxel Dörfler int BIOS_VIDEO_SERVICES 315b76ca311SAxel Dörfler mov [bp + cursorShape], cx 316b76ca311SAxel Dörfler 317b76ca311SAxel Dörfler mov ah, SET_CURSOR_SHAPE 318b76ca311SAxel Dörfler mov cx, 0x2000 319b76ca311SAxel Dörfler int BIOS_VIDEO_SERVICES 320b76ca311SAxel Dörfler ret 321b76ca311SAxel Dörfler 322b76ca311SAxel DörflershowCursor: 323b76ca311SAxel Dörfler mov cx, [bp + cursorShape] 324b76ca311SAxel Dörfler mov ah, SET_CURSOR_SHAPE 325b76ca311SAxel Dörfler int BIOS_VIDEO_SERVICES 326b76ca311SAxel Dörfler ret 327b76ca311SAxel Dörfler 328b76ca311SAxel DörflernextStageDAP: 329b76ca311SAxel Dörfler istruc AddressPacket 330b76ca311SAxel Dörfler at AddressPacket.packet_size, db 0x10 331b76ca311SAxel Dörfler at AddressPacket.block_count, db 0x03 332b76ca311SAxel Dörfler at AddressPacket.buffer, dw 0x0200, 0x07c0 333b76ca311SAxel Dörfler at AddressPacket.offset, dw 1 334b76ca311SAxel Dörfler iend 335b76ca311SAxel Dörfler 336b76ca311SAxel DörflerkTitle: 337b76ca311SAxel Dörfler db TITLE, 0x00 338b76ca311SAxel DörflerkSelectOSMessage: 339b76ca311SAxel Dörfler db SELECT_OS_MESSAGE, 0x00 340b76ca311SAxel DörflerkError: 341b76ca311SAxel Dörfler db 'Error loading sectors!', 0x00 342b76ca311SAxel Dörfler 343b76ca311SAxel DörflerkStage1UnusedSpace equ 440 - ($-$$) 344b76ca311SAxel Dörfler ; Fill the missing space to reach byte 440 345b76ca311SAxel Dörfler times kStage1UnusedSpace db 'B' 346b76ca311SAxel Dörfler 347cf3c703bSFrançois RevolkDiskSignature: 348b76ca311SAxel Dörfler dw 0, 0 3497c5dfbadSFrançois RevolkReserved: 350b76ca311SAxel Dörfler dw 0 3517c5dfbadSFrançois RevolkPartitionTable: 352b76ca311SAxel Dörfler times 64 db 0 353b76ca311SAxel Dörfler 354b76ca311SAxel DörflerkMBRSignature: 355b76ca311SAxel Dörfler ; Magic marker "AA55" (to identify a valid boot record) 356b76ca311SAxel Dörfler dw MBR_SIGNATURE 357b76ca311SAxel Dörfler 358b76ca311SAxel Dörfler; ====================================================================== 359b76ca311SAxel Dörfler; ======================= SECOND SECTOR ================================ 360b76ca311SAxel Dörfler; ====================================================================== 361b76ca311SAxel Dörfler 36289f0e174SAxel Dörfler; Use code available in stage 2 363b76ca311SAxel Dörfler%define printstr printStringStage2 364b76ca311SAxel Dörfler 365b76ca311SAxel Dörfler%assign TIMEOUT_OFF 0xffff 366b76ca311SAxel Dörfler 367b76ca311SAxel Dörfler 368b76ca311SAxel Dörflerstage2: 369b76ca311SAxel Dörfler mov ax, [defaultItem] ; Select default item 370b76ca311SAxel Dörfler mov [bp + selection], ax 371b76ca311SAxel Dörfler 372b76ca311SAxel Dörfler mov ax, TICKS_PER_SECOND ; Calculate timeout ticks 373b76ca311SAxel Dörfler mul word [timeout] 374b76ca311SAxel Dörfler mov bx, dx 375b76ca311SAxel Dörfler push ax 376b76ca311SAxel Dörfler 377b76ca311SAxel Dörfler mov ah, READ_CLOCK 378b76ca311SAxel Dörfler int BIOS_TIME_SERVICES 379b76ca311SAxel Dörfler 380b76ca311SAxel Dörfler pop ax ; Add current ticks 381b76ca311SAxel Dörfler add ax, dx 382b76ca311SAxel Dörfler adc bx, cx 383b76ca311SAxel Dörfler mov [bp + timeoutTicks], ax 384b76ca311SAxel Dörfler mov [bp + timeoutTicks + 2], bx 385b76ca311SAxel Dörfler 386b76ca311SAxel Dörfler mov al, [listItemCount] ; Calculate start row for menu 387b76ca311SAxel Dörfler shr al, 1 388b76ca311SAxel Dörfler mov bl, TEXT_ROWS / 2 389b76ca311SAxel Dörfler sub bl, al ; y = TEXT_ROWS / 2 - number of items / 2 390b76ca311SAxel Dörfler mov [bp + firstLine], bl 391b76ca311SAxel Dörfler 392b76ca311SAxel Dörfler mov ah, GET_MODIFIER_KEYS ; Disable timeout if ALT key is pressed 393b76ca311SAxel Dörfler int BIOS_KEYBOARD_SERVICES 394b76ca311SAxel Dörfler and al, MODIFIER_ALT_KEY 395b76ca311SAxel Dörfler jz showMenu 396b76ca311SAxel Dörfler mov word [timeout], TIMEOUT_OFF 397b76ca311SAxel Dörfler 398b76ca311SAxel DörflershowMenu: 399b76ca311SAxel Dörfler call printMenu 400b76ca311SAxel Dörfler 401b76ca311SAxel Dörfler cmp word [timeout], TIMEOUT_OFF 402b76ca311SAxel Dörfler je inputLoop 403b76ca311SAxel Dörfler 404b76ca311SAxel DörflertimeoutLoop: 405b76ca311SAxel Dörfler mov ah, PROBE_CHAR 406b76ca311SAxel Dörfler int BIOS_KEYBOARD_SERVICES 407b76ca311SAxel Dörfler jnz inputLoop ; cancel timeout if key is pressed 408b76ca311SAxel Dörfler call isTimeoutReached 409b76ca311SAxel Dörfler jnc timeoutLoop 410b76ca311SAxel Dörfler jmp bootSelectedPartition 411b76ca311SAxel Dörfler 412b76ca311SAxel DörflerisTimeoutReached: 413b76ca311SAxel Dörfler mov ah, READ_CLOCK 414b76ca311SAxel Dörfler int BIOS_TIME_SERVICES 415b76ca311SAxel Dörfler cmp cx, [bp + timeoutTicks + 2] 416b76ca311SAxel Dörfler jb .returnFalse 417b76ca311SAxel Dörfler ja .returnTrue 418b76ca311SAxel Dörfler cmp dx, [bp + timeoutTicks] 419b76ca311SAxel Dörfler ja .returnTrue 420b76ca311SAxel Dörfler.returnFalse: 421b76ca311SAxel Dörfler clc 422b76ca311SAxel Dörfler ret 423b76ca311SAxel Dörfler.returnTrue: 424b76ca311SAxel Dörfler stc 425b76ca311SAxel Dörfler ret 426b76ca311SAxel Dörfler 427b76ca311SAxel Dörfler; ================== Wait for a key and do something with it ================== 428b76ca311SAxel DörflermainLoop: 429b76ca311SAxel Dörfler call printMenu 430b76ca311SAxel Dörfler 431b76ca311SAxel DörflerinputLoop: 432b76ca311SAxel Dörfler mov ah, READ_CHAR 433b76ca311SAxel Dörfler int BIOS_KEYBOARD_SERVICES ; AL = ASCII Code, AH = Scancode 434b76ca311SAxel Dörfler 435b76ca311SAxel Dörfler cmp ah, KEY_DOWN 436b76ca311SAxel Dörfler je selectNextPartition 437b76ca311SAxel Dörfler 438*786f0456SAxel Dörfler cmp ah, KEY_PAGE_DOWN 439*786f0456SAxel Dörfler je selectLastPartition 440*786f0456SAxel Dörfler cmp ah, KEY_END 441*786f0456SAxel Dörfler je selectLastPartition 442*786f0456SAxel Dörfler 443b76ca311SAxel Dörfler cmp ah, KEY_UP 444b76ca311SAxel Dörfler je selectPreviousPartition 445b76ca311SAxel Dörfler 446*786f0456SAxel Dörfler cmp ah, KEY_PAGE_UP 447*786f0456SAxel Dörfler je selectFirstPartition 448*786f0456SAxel Dörfler cmp ah, KEY_HOME 449*786f0456SAxel Dörfler je selectFirstPartition 450*786f0456SAxel Dörfler 451b76ca311SAxel Dörfler cmp ah, KEY_RETURN 452b76ca311SAxel Dörfler jne inputLoop 453b76ca311SAxel Dörfler jmp bootSelectedPartition 454b76ca311SAxel Dörfler 455b76ca311SAxel DörflerselectNextPartition: 456b76ca311SAxel Dörfler mov ax, [bp + selection] 457b76ca311SAxel Dörfler inc ax 458b76ca311SAxel Dörfler cmp ax, [listItemCount] 459b76ca311SAxel Dörfler jne .done ; At end of list? 460b76ca311SAxel Dörfler xor ax, ax ; Then jump to first entry 461b76ca311SAxel Dörfler.done: 462b76ca311SAxel Dörfler mov [bp + selection], ax 463b76ca311SAxel Dörfler jmp mainLoop 464b76ca311SAxel Dörfler 465*786f0456SAxel DörflerselectLastPartition: 466*786f0456SAxel Dörfler mov ax, [listItemCount] 467*786f0456SAxel Dörfler dec ax 468*786f0456SAxel Dörfler mov [bp + selection], ax 469*786f0456SAxel Dörfler jmp mainLoop 470*786f0456SAxel Dörfler 471b76ca311SAxel DörflerselectPreviousPartition: 472b76ca311SAxel Dörfler mov ax, [bp + selection] 473b76ca311SAxel Dörfler or ax, ax 474b76ca311SAxel Dörfler jnz .done ; At top of list? 475b76ca311SAxel Dörfler mov ax, [listItemCount] ; Then jump to last entry 476b76ca311SAxel Dörfler.done: 477b76ca311SAxel Dörfler dec ax 478b76ca311SAxel Dörfler mov [bp + selection], ax 479b76ca311SAxel Dörfler jmp mainLoop 480b76ca311SAxel Dörfler 481*786f0456SAxel DörflerselectFirstPartition: 482*786f0456SAxel Dörfler xor ax, ax 483*786f0456SAxel Dörfler mov [bp + selection], ax 484*786f0456SAxel Dörfler jmp mainLoop 485*786f0456SAxel Dörfler 486b76ca311SAxel Dörfler 487b76ca311SAxel Dörfler; ======================= Print the OS list ============================ 488b76ca311SAxel DörflerprintMenu: 489b76ca311SAxel Dörfler mov al, [bp + firstLine] 490b76ca311SAxel Dörfler mov [bp + cursorY], al 491b76ca311SAxel Dörfler 492b76ca311SAxel Dörfler mov si, list ; Start at top of list 493b76ca311SAxel Dörfler xor cx, cx ; The index of the current item 494b76ca311SAxel Dörfler 495b76ca311SAxel Dörfler.loop: 496b76ca311SAxel Dörfler lodsb ; String length incl. 0-terminator 497b76ca311SAxel Dörfler add al, 3 ; center menu item 498b76ca311SAxel Dörfler shr al, 1 ; x = TEXT_COLUMNS / 2 - length / 2 499b76ca311SAxel Dörfler mov dl, TEXT_COLUMNS / 2 500b76ca311SAxel Dörfler sub dl, al 501b76ca311SAxel Dörfler mov [bp + cursorX], dl 502b76ca311SAxel Dörfler 503b76ca311SAxel Dörfler mov al, TRIANGLE_TO_RIGHT 504b76ca311SAxel Dörfler call updateMarker 505b76ca311SAxel Dörfler inc byte [bp + cursorX] 506b76ca311SAxel Dörfler 507b76ca311SAxel Dörfler mov di, cx 508b76ca311SAxel Dörfler and di, 3 509b76ca311SAxel Dörfler mov bl, [kColorTable + di] ; Text color 510b76ca311SAxel Dörfler 511b76ca311SAxel Dörfler cmp cx, [bp + selection] 512b76ca311SAxel Dörfler jne .print ; Selected item reached? 513b76ca311SAxel Dörfler xor bl, BRIGHT_COLOR_MASK ; Highlight it 514b76ca311SAxel Dörfler 515b76ca311SAxel Dörfler.print: 516b76ca311SAxel Dörfler call printstr 517b76ca311SAxel Dörfler add si, sizeof(BootLoaderAddress) 518b76ca311SAxel Dörfler 519b76ca311SAxel Dörfler add byte [bp + cursorX], 1 520b76ca311SAxel Dörfler mov al, TRIANGLE_TO_LEFT 521b76ca311SAxel Dörfler call updateMarker 522b76ca311SAxel Dörfler 523b76ca311SAxel Dörfler inc byte [bp + cursorY] 524b76ca311SAxel Dörfler inc cx 525b76ca311SAxel Dörfler 526b76ca311SAxel Dörfler cmp cx, [listItemCount] 527b76ca311SAxel Dörfler jne .loop 528b76ca311SAxel Dörfler ret 529b76ca311SAxel Dörfler 530b76ca311SAxel DörflerupdateMarker: 531b76ca311SAxel Dörfler cmp cx, [bp + selection] 532b76ca311SAxel Dörfler je .print 533b76ca311SAxel Dörfler mov al, ' ' ; Clear marker 5347c5dfbadSFrançois Revol.print: 535b76ca311SAxel Dörfler mov bl, WHITE 536b76ca311SAxel Dörfler jmp printChar ; return from subroutine 537b76ca311SAxel Dörfler 538b76ca311SAxel Dörfler 539b76ca311SAxel Dörfler; ========================== Chainload ========================== 540b76ca311SAxel Dörfler 541b76ca311SAxel DörflerbootSelectedPartition: 542b76ca311SAxel Dörfler 543b76ca311SAxel Dörfler call showCursor 544b76ca311SAxel Dörfler 545b76ca311SAxel Dörfler call getSelectedBootLoaderAddress 546b76ca311SAxel Dörfler lodsb ; Set boot drive 547b76ca311SAxel Dörfler mov dl, al 548b76ca311SAxel Dörfler 549b76ca311SAxel Dörfler mov di, bootSectorDAP+AddressPacket.offset ; Copy start sector 550b76ca311SAxel Dörfler mov cx, 4 ; It is stored in a quad word 5517c5dfbadSFrançois Revol.copy_start_sector: 552b76ca311SAxel Dörfler lodsw 553b76ca311SAxel Dörfler stosw 554b76ca311SAxel Dörfler loop .copy_start_sector 555b76ca311SAxel Dörfler 556b76ca311SAxel Dörfler mov ah, EXTENDED_READ ; Now read start sector from HD 557b76ca311SAxel Dörfler mov si, bootSectorDAP 558b76ca311SAxel Dörfler int BIOS_DISK_SERVICES 559b76ca311SAxel Dörfler mov si, kReadError 560b76ca311SAxel Dörfler jc printAndHalt ; Failed to read sector 561b76ca311SAxel Dörfler 562b76ca311SAxel Dörfler mov ax, [kMBRSignature] 563b76ca311SAxel Dörfler cmp ax, MBR_SIGNATURE 564b76ca311SAxel Dörfler mov si, kNoBootablePartitionError 565b76ca311SAxel Dörfler jne printAndHalt ; Missing signature 566b76ca311SAxel Dörfler 567b76ca311SAxel Dörfler CLEAR_SCREEN 568b76ca311SAxel Dörfler 569b76ca311SAxel Dörfler ; Print "Loading <name>" at top of screen 570b76ca311SAxel Dörfler mov word [bp + cursorPosition], 0 571b76ca311SAxel Dörfler mov si, kLoadingMessage 572b76ca311SAxel Dörfler mov bl, LIGHT_GRAY 573b76ca311SAxel Dörfler call printstr 574b76ca311SAxel Dörfler 575b76ca311SAxel Dörfler inc byte [bp + cursorX] 576b76ca311SAxel Dörfler call getSelectedMenuItem 577b76ca311SAxel Dörfler inc si ; Skip string length byte 578b76ca311SAxel Dörfler call printstr 579b76ca311SAxel Dörfler 580b76ca311SAxel Dörfler mov dx, 0x100 581b76ca311SAxel Dörfler xor bh, bh 582b76ca311SAxel Dörfler mov ah, SET_CURSOR 583b76ca311SAxel Dörfler int BIOS_VIDEO_SERVICES 584b76ca311SAxel Dörfler 585b76ca311SAxel Dörfler call getSelectedBootLoaderAddress 586b76ca311SAxel Dörfler mov dl, [si] ; drive number in dl 587b76ca311SAxel Dörfler 588b76ca311SAxel Dörfler jmp $$ ; Start loaded boot loader 589b76ca311SAxel Dörfler 590b76ca311SAxel Dörfler 591b76ca311SAxel DörflerprintAndHalt: 592b76ca311SAxel Dörfler mov dx, (TEXT_ROWS-4) * 0x100 + (TEXT_COLUMNS / 3) 593b76ca311SAxel Dörfler mov [bp + cursorPosition], dx 594b76ca311SAxel Dörfler 595b76ca311SAxel Dörfler mov bx, 0x0F ; Page number and foreground color 596b76ca311SAxel Dörfler call printstr 597b76ca311SAxel Dörfler mov ah, READ_CHAR 598b76ca311SAxel Dörfler int BIOS_KEYBOARD_SERVICES 5990e193080SAxel Dörfler mov dl, [bp + biosDrive] 600b76ca311SAxel Dörfler int BIOS_REBOOT 601b76ca311SAxel Dörfler 602b76ca311SAxel Dörfler; Output: 603b76ca311SAxel Dörfler; si address of selected menu item 604b76ca311SAxel Dörfler; Trashes: 605b76ca311SAxel Dörfler; ax, cx 606b76ca311SAxel DörflergetSelectedMenuItem: 607b76ca311SAxel Dörfler mov si, list ; Search address of start sector 608b76ca311SAxel Dörfler ; of the selected item. 609b76ca311SAxel Dörfler mov cx, [bp + selection] 610b76ca311SAxel Dörfler inc cx ; Number of required iterations 611b76ca311SAxel Dörfler 612b76ca311SAxel Dörfler xor ah, ah ; The high-byte of the string length 613b76ca311SAxel Dörfler ; see loop body 614b76ca311SAxel Dörfler jmp .entry 615b76ca311SAxel Dörfler 616b76ca311SAxel Dörfler.loop: 617b76ca311SAxel Dörfler lodsb ; Length of menu item name 618b76ca311SAxel Dörfler add si, ax ; Skip name to BootLoaderAddess 619b76ca311SAxel Dörfler add si, sizeof(BootLoaderAddress) 620b76ca311SAxel Dörfler 621b76ca311SAxel Dörfler.entry: 622b76ca311SAxel Dörfler loop .loop 623b76ca311SAxel Dörfler ret 624b76ca311SAxel Dörfler 625b76ca311SAxel DörflergetSelectedBootLoaderAddress: 626b76ca311SAxel Dörfler call getSelectedMenuItem 627b76ca311SAxel Dörfler lodsb 628b76ca311SAxel Dörfler xor ah, ah 629b76ca311SAxel Dörfler add si, ax ; Skip name 63049c044abSAxel Dörfler mov dl, [si] 63149c044abSAxel Dörfler test dl, 0 ; if drive is 0, use boot drive 63249c044abSAxel Dörfler jz .takeOverBootDrive 63349c044abSAxel Dörfler ret 63449c044abSAxel Dörfler.takeOverBootDrive: 63589f0e174SAxel Dörfler mov dl, [bp + biosDrive] 63649c044abSAxel Dörfler mov [si], dl 637b76ca311SAxel Dörfler ret 638b76ca311SAxel Dörfler 639b76ca311SAxel DörflerprintStringStage2: 640b76ca311SAxel Dörfler PRINT_STRING 641b76ca311SAxel Dörfler 642b76ca311SAxel Dörfler; al ... ASCII character 643b76ca311SAxel Dörfler; bl ... color 644b76ca311SAxel DörflerprintChar: 645b76ca311SAxel Dörfler push ax 646b76ca311SAxel Dörfler push bx 647b76ca311SAxel Dörfler push cx 648b76ca311SAxel Dörfler push dx 649b76ca311SAxel Dörfler 650b76ca311SAxel Dörfler xor bh, bh ; Write on page 0 651b76ca311SAxel Dörfler 652b76ca311SAxel Dörfler mov dx, [bp + cursorPosition] 653b76ca311SAxel Dörfler mov ah, SET_CURSOR 654b76ca311SAxel Dörfler int BIOS_VIDEO_SERVICES 655b76ca311SAxel Dörfler 656b76ca311SAxel Dörfler inc byte [bp + cursorX] 657b76ca311SAxel Dörfler 658b76ca311SAxel Dörfler mov cx, 1 659b76ca311SAxel Dörfler mov ah, WRITE_CHAR 660b76ca311SAxel Dörfler int BIOS_VIDEO_SERVICES 661b76ca311SAxel Dörfler 662b76ca311SAxel Dörfler pop dx 663b76ca311SAxel Dörfler pop cx 664b76ca311SAxel Dörfler pop bx 665b76ca311SAxel Dörfler pop ax 666b76ca311SAxel Dörfler ret 667b76ca311SAxel Dörfler 668b76ca311SAxel Dörfler; ================================ DATA =========================== 669b76ca311SAxel Dörfler 670b76ca311SAxel DörflerbootSectorDAP: 671b76ca311SAxel Dörfler istruc AddressPacket 672b76ca311SAxel Dörfler at AddressPacket.packet_size, db 0x10 673b76ca311SAxel Dörfler at AddressPacket.block_count, db 0x01 674b76ca311SAxel Dörfler at AddressPacket.buffer, dw 0x0000, 0x07c0 675b76ca311SAxel Dörfler iend 676b76ca311SAxel Dörfler 677b76ca311SAxel DörflerkColorTable: 678b76ca311SAxel Dörfler db BLUE, RED, GREEN, CYAN 679b76ca311SAxel DörflerkReadError: 680b76ca311SAxel Dörfler db 'Error loading sectors', 0x00 681b76ca311SAxel DörflerkNoBootablePartitionError: 682b76ca311SAxel Dörfler db 'Not a bootable partition', 0x00 683b76ca311SAxel DörflerkLoadingMessage: 684b76ca311SAxel Dörfler db 'Loading', 0x00 685b76ca311SAxel Dörfler 686b76ca311SAxel Dörfler 687b76ca311SAxel DörflerlistItemCount: 688b76ca311SAxel DörflerdefaultItem equ listItemCount + 2 689b76ca311SAxel Dörflertimeout equ defaultItem + 2 690b76ca311SAxel Dörflerlist equ timeout + 2 691b76ca311SAxel Dörfler 692b76ca311SAxel Dörfler; dw number of entries 693b76ca311SAxel Dörfler; dw the default entry 694b76ca311SAxel Dörfler; dw the timeout (-1 for none) 695b76ca311SAxel Dörfler; entry: 696b76ca311SAxel Dörfler; db size of partition name 0-terminated string 697b76ca311SAxel Dörfler; db 0-terminated string with partition name 698b76ca311SAxel Dörfler; db hard drive number 699b76ca311SAxel Dörfler; quadword start sector 700b76ca311SAxel Dörfler 701b76ca311SAxel Dörfler%if USE_TEST_MENU 702b76ca311SAxel Dörfler dw 0x06 703b76ca311SAxel Dörfler 704b76ca311SAxel Dörfler dw 2 705b76ca311SAxel Dörfler 706b76ca311SAxel Dörfler dw 5 707b76ca311SAxel Dörfler 708b76ca311SAxel Dörfler db 0x06 709b76ca311SAxel Dörfler db 'HAIKU', 0 710b76ca311SAxel Dörfler db 0x80 711b76ca311SAxel Dörfler dw 1, 0, 0, 0 712b76ca311SAxel Dörfler 713b76ca311SAxel Dörfler db 0x08 714b76ca311SAxel Dörfler db 'FreeBSD', 0 715b76ca311SAxel Dörfler db 0x80 716b76ca311SAxel Dörfler dw 0x003F, 0, 0, 0 717b76ca311SAxel Dörfler 718b76ca311SAxel Dörfler db 0x04 719b76ca311SAxel Dörfler db 'DOS', 0 720b76ca311SAxel Dörfler db 0x80 721b76ca311SAxel Dörfler dw 0x003E, 0, 0, 0 722b76ca311SAxel Dörfler 723b76ca311SAxel Dörfler db 0x06 724b76ca311SAxel Dörfler db 'LINUX', 0 725b76ca311SAxel Dörfler db 0x80 726b76ca311SAxel Dörfler dw 0x003F, 0, 0, 0 727b76ca311SAxel Dörfler 728b76ca311SAxel Dörfler db 0x08 729b76ca311SAxel Dörfler db 'BeOS R5', 0 730b76ca311SAxel Dörfler db 0x80 731b76ca311SAxel Dörfler dw 0x003F, 0, 0, 0 732b76ca311SAxel Dörfler 733b76ca311SAxel Dörfler db 0x07 734b76ca311SAxel Dörfler db 'OpenBSD', 0 735b76ca311SAxel Dörfler db 0x80 736b76ca311SAxel Dörfler dw 0xAAAA, 0, 0, 0 737b76ca311SAxel Dörfler 738b76ca311SAxel Dörfler dw kStage1UnusedSpace 739b76ca311SAxel Dörfler%endif 740b76ca311SAxel Dörfler 741