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