vfs: check userland buffers before reading them.
[haiku.git] / src / apps / bootmanager / bootman.S
blobb2960358440887fe0c3002a05cfd8bc60bcd749c
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
15 ; BIOS calls
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
23 ; video services
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
30                                                                                                 ; dh - row
31                                                                                                 ; bh - page
34 %assign GET_CURSOR                                              0x03    ; bh - page
35                                                                                                 ; -> dl - column
36                                                                                                 ;       dh - row
37                                                                                                 ;       Cursor shape:
38                                                                                                 ;       ch - starting scan line
39                                                                                                 ;       cl - ending scan line
41 %assign SCROLL_UP                                               0x06    ; al - lines (0: clear screen)
42                                                                                                 ; bh - attribute
43                                                                                                 ; ch - upper line
44                                                                                                 ; cl - left column
45                                                                                                 ; dh - lower line
46                                                                                                 ; dl - right column
48 %assign WRITE_CHAR                                              0x09    ; al - char
49                                                                                                 ; bh - page
50                                                                                                 ; bl - attribute
51                                                                                                 ; cx - count
53 ;%assign WRITE_CHAR                                             0x0e    ; al - char
54                                                                                                 ; bh - page
55                                                                                                 ; bl - foreground color (graphics mode only)
57 ; disk services
58 %assign READ_DISK_SECTORS                               0x02    ; dl    - drive
59                                                                                                 ; es:bx - buffer
60                                                                                                 ; dh    - head (0 - 15)
61                                                                                                 ; ch    - track 7:0 (0 - 1023)
62                                                                                                 ; cl    - track 9:8,
63                                                                                                 ;                sector (1 - 17)
64                                                                                                 ; al    - sector count
65                                                                                                 ; -> al - sectors read
66 %assign READ_DRIVE_PARAMETERS                   0x08    ; dl - drive
67                                                                                                 ; -> cl - max cylinder 9:8
68                                                                                                 ;          - sectors per track
69                                                                                                 ;       ch - max cylinder 7:0
70                                                                                                 ;       dh - max head
71                                                                                                 ;       dl - number of drives (?)
72 %assign CHECK_DISK_EXTENSIONS_PRESENT   0x41    ; bx - 0x55aa
73                                                                                                 ; dl - drive
74                                                                                                 ; -> success: carry clear
75                                                                                                 ;       ah - extension version
76                                                                                                 ;       bx - 0xaa55
77                                                                                                 ;       cx - support bit mask
78                                                                                                 ; -> error: carry set
79 %assign EXTENDED_READ                                   0x42    ; dl - drive
80                                                                                                 ; ds:si - address packet
81                                                                                                 ; -> success: carry clear
82                                                                                                 ; -> error: carry set
84 %assign FIXED_DISK_SUPPORT                              0x1             ; flag indicating fixed disk
85                                                                                                 ; extension command subset
87 ; keyboard services
88 %assign READ_CHAR                                               0x00    ; -> al - ASCII char
89                                                                                                 ;       ah - scan code
91 %assign PROBE_CHAR                                              0x01    ; -> zf = 0
92                                                                                                 ;       al - ASCII char
93                                                                                                 ;       ah - scan code
95 %assign GET_MODIFIER_KEYS                               0x02    ;-> al - modifier key bitmask
97 ; timer services
98 %assign READ_CLOCK                                              0x00    ; -> cx - high word
99                                                                                                 ;       dx - low word
100                                                                                                 ;       one tick = 1/18.2s
102 %assign TICKS_PER_SECOND                                19
104 ; video modes
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
110 ; Colors
111 %assign BLACK                                                   0
112 %assign BLUE                                                    1
113 %assign GREEN                                                   2
114 %assign CYAN                                                    3
115 %assign RED                                                             4
116 %assign MAGENTA                                                 5
117 %assign BROWN                                                   6
118 %assign LIGHT_GRAY                                              7
119 %assign DARK_GRAY                                               8
120 %assign LIGHT_BLUE                                              9
121 %assign LIGHT_GREEN                                             10
122 %assign LIGHT_CYAN                                              11
123 %assign LIGHT_RED                                               12
124 %assign LIGHT_MAGENTA                                   13
125 %assign YELLOW                                                  14
126 %assign WHITE                                                   15
128 %assign BRIGHT_COLOR_MASK                               8
130 ; Characters
131 %assign TRIANGLE_TO_RIGHT                               16
132 %assign TRIANGLE_TO_LEFT                                17
134 ; Key codes
135 %assign KEY_DOWN                                                0x50
136 %assign KEY_UP                                                  0x48
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
155 ; 16 bit code
156 SECTION .text
157 BITS 16
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
164 %macro  nstruc  1-2      1
165                                         resb    sizeof(%1) * %2
166 %endmacro
168 ; Variables on stack
169 struc   Locals
170         selection               resw    1
171         firstLine               resb    2 ; low byte used only
172         timeoutTicks    resd    1
173         cursorX                 resb    1
174         cursorY                 resb    1
175         cursorShape             resw    1
176         biosDrive               resb    1
177 endstruc
179 cursorPosition          equ cursorX
181 %macro DEBUG_PAUSE 0
182         push    ax
183         mov             ah, READ_CHAR
184         int             BIOS_KEYBOARD_SERVICES
185         pop             ax
186 %endmacro
188 %macro CLEAR_SCREEN 0
189         mov             ah, SCROLL_UP
190         xor             al, al
191         mov             bh, WHITE
192         xor             cx, cx
193         mov             dx, (TEXT_ROWS-1) * 0x100 + (TEXT_COLUMNS-1)
194         int             BIOS_VIDEO_SERVICES
195 %endmacro
197 ; Prints a null terminated string
198 ; bl ... color
199 ; si ... offset to string
200 %macro PRINT_STRING 0
201         push    ax
202         push    bx
203         push    cx
204         push    dx
205         xor             bh, bh                                                          ; write on page 0
206         jmp             .loop_condition
207 .loop:
208         mov             dx, [bp + cursorPosition]
209         mov             ah, SET_CURSOR
210         int             BIOS_VIDEO_SERVICES
212         inc             byte [bp + cursorX]
214         mov             cx, 1
215         mov             ah, WRITE_CHAR
216         int             BIOS_VIDEO_SERVICES
217 .loop_condition:
218         lodsb
219         cmp             al, 0
220         jnz             .loop
221         pop             dx
222         pop             cx
223         pop             bx
224         pop             ax
225         ret
226 %endmacro
228 ; 64 bit value
229 struc   quadword
230         .lower                  resd    1
231         .upper                  resd    1
232 endstruc
234 ; address packet as required by the EXTENDED_READ BIOS call
235 struc   AddressPacket
236         .packet_size    resb    1
237         .reserved1              resb    1
238         .block_count    resb    1
239         .reserved2              resb    1
240         .buffer                 resd    1
241         .offset                 nstruc  quadword
242 endstruc
244 struc   BootLoaderAddress
245         .device                 resb    1                       ; hard drive number
246         .offset                 nstruc  quadword        ; LBA of start start sector
247 endstruc
249 ; use code available in stage 1
250 %define printstr printStringStage1
252 stage1:
253         mov             ax, 0x07c0                                              ; BOOT_BLOCK_START_ADDRESS / 16
254         mov             ds, ax                                                  ; Setup segment registers
255         mov             es, ax
256         mov             ss, ax
258         mov             sp, 0xFFFF - sizeof(Locals)             ; Make stack empty
259         mov             bp, sp
261         mov             [bp + biosDrive], dl                    ; Store boot drive
262         cld                                                                             ; String operations increment index
263                                                                                         ; registers
264         CLEAR_SCREEN
265         call    hideCursor
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
273         mov             si, kTitle
274         mov             bl, WHITE
275         call    printstr
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
281         mov             bl, LIGHT_GRAY
282         mov             si, kSelectOSMessage
283         call    printstr
285         ; Chain load rest of boot loader
286         mov             ah, EXTENDED_READ                               ; Load 3 more sectors
287         mov             dl, [bp + biosDrive]
288         mov             si, nextStageDAP
289         int             BIOS_DISK_SERVICES
290         jc              .error                                                  ; I/O error
291         jmp             stage2                                                  ; Continue in loaded stage 2
293 .error:
294         call    showCursor
295         mov             si, kError
296         mov             bl, RED
297         call    printstr
299         mov             ah, READ_CHAR
300         int             BIOS_KEYBOARD_SERVICES
302         mov             dl, [bp + biosDrive]
303         int             BIOS_REBOOT
305 printStringStage1:
306         PRINT_STRING
308 hideCursor:
309         mov             ah, GET_CURSOR
310         int             BIOS_VIDEO_SERVICES
311         mov             [bp + cursorShape], cx
313         mov             ah, SET_CURSOR_SHAPE
314         mov             cx, 0x2000
315         int             BIOS_VIDEO_SERVICES
316         ret
318 showCursor:
319         mov             cx, [bp + cursorShape]
320         mov             ah, SET_CURSOR_SHAPE
321         int             BIOS_VIDEO_SERVICES
322         ret
324 nextStageDAP:
325         istruc AddressPacket
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
330         iend
332 kTitle:
333         db              TITLE, 0x00
334 kSelectOSMessage:
335         db              SELECT_OS_MESSAGE, 0x00
336 kError:
337         db              'Error loading sectors!', 0x00
339 kStage1UnusedSpace      equ     440 - ($-$$)
340         ; Fill the missing space to reach byte 440
341         times kStage1UnusedSpace db 'B'
343 kDiskSignature:
344         dw              0, 0
345 kReserved:
346         dw              0
347 kPartitionTable:
348         times   64 db 0
350 kMBRSignature:
351         ; Magic marker "AA55" (to identify a valid boot record)
352         dw              MBR_SIGNATURE
354 ; ======================================================================
355 ; ======================= SECOND SECTOR ================================
356 ; ======================================================================
358 ; Use code available in stage 2
359 %define printstr printStringStage2
361 %assign TIMEOUT_OFF             0xffff
364 stage2:
365         mov             ax, [defaultItem]                                       ; Select default item
366         mov             [bp + selection], ax
368         mov             ax, TICKS_PER_SECOND                            ; Calculate timeout ticks
369         mul             word [timeout]
370         mov             bx, dx
371         push    ax
373         mov             ah, READ_CLOCK
374         int             BIOS_TIME_SERVICES
376         pop             ax                                                                      ; Add current ticks
377         add             ax, dx
378         adc             bx, cx
379         mov             [bp + timeoutTicks], ax
380         mov             [bp + timeoutTicks + 2], bx
382         mov             al, [listItemCount]                                     ; Calculate start row for menu
383         shr             al, 1
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
391         jz              showMenu
392         mov             word [timeout], TIMEOUT_OFF
394 showMenu:
395         call    printMenu
397         cmp             word [timeout], TIMEOUT_OFF
398         je              inputLoop
400 timeoutLoop:
401         mov             ah, PROBE_CHAR
402         int             BIOS_KEYBOARD_SERVICES
403         jnz             inputLoop                                                       ; cancel timeout if key is pressed
404         call    isTimeoutReached
405         jnc             timeoutLoop
406         jmp             bootSelectedPartition
408 isTimeoutReached:
409         mov             ah, READ_CLOCK
410         int             BIOS_TIME_SERVICES
411         cmp             cx, [bp + timeoutTicks + 2]
412         jb              .returnFalse
413         ja              .returnTrue
414         cmp             dx, [bp + timeoutTicks]
415         ja              .returnTrue
416 .returnFalse:
417         clc
418         ret
419 .returnTrue:
420         stc
421         ret
423 ; ================== Wait for a key and do something with it ==================
424 mainLoop:
425         call    printMenu
427 inputLoop:
428         mov             ah, READ_CHAR
429         int             BIOS_KEYBOARD_SERVICES                          ; AL = ASCII Code, AH = Scancode
431         cmp             ah, KEY_DOWN
432         je              selectNextPartition
434         cmp             ah, KEY_UP
435         je              selectPreviousPartition
437         cmp             ah, KEY_RETURN
438         jne             inputLoop
439         jmp             bootSelectedPartition
441 selectNextPartition:
442         mov             ax, [bp + selection]
443         inc             ax
444         cmp             ax, [listItemCount]
445         jne             .done                                                           ; At end of list?
446         xor             ax, ax                                                          ; Then jump to first entry
447 .done:
448         mov             [bp + selection], ax
449         jmp             mainLoop
451 selectPreviousPartition:
452         mov             ax, [bp + selection]
453         or              ax, ax
454         jnz             .done                                                           ; At top of list?
455         mov             ax, [listItemCount]                                     ; Then jump to last entry
456 .done:
457         dec             ax
458         mov             [bp + selection], ax
459         jmp             mainLoop
462 ; ======================= Print the OS list ============================
463 printMenu:
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
470 .loop:
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
475         sub             dl, al
476         mov             [bp + cursorX], dl
478         mov             al, TRIANGLE_TO_RIGHT
479         call    updateMarker
480         inc             byte [bp + cursorX]
482         mov             di, cx
483         and             di, 3
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
490 .print:
491         call    printstr
492         add             si, sizeof(BootLoaderAddress)
494         add             byte [bp + cursorX], 1
495         mov             al, TRIANGLE_TO_LEFT
496         call    updateMarker
498         inc             byte [bp + cursorY]
499         inc             cx
501         cmp             cx, [listItemCount]
502         jne             .loop
503         ret
505 updateMarker:
506         cmp             cx, [bp + selection]
507         je              .print
508         mov             al, ' '                                                         ; Clear marker
509 .print:
510         mov             bl, WHITE
511         jmp             printChar                                                       ; return from subroutine
514 ; ========================== Chainload ==========================
516 bootSelectedPartition:
518         call    showCursor
520         call    getSelectedBootLoaderAddress
521         lodsb                                                                           ; Set boot drive
522         mov             dl, al
524         mov             di, bootSectorDAP+AddressPacket.offset  ; Copy start sector
525         mov             cx, 4                                                           ; It is stored in a quad word
526 .copy_start_sector:
527         lodsw
528         stosw
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
534         mov             si, kReadError
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
542         CLEAR_SCREEN
544         ; Print "Loading <name>" at top of screen
545         mov             word [bp + cursorPosition], 0
546         mov             si, kLoadingMessage
547         mov             bl, LIGHT_GRAY
548         call    printstr
550         inc             byte [bp + cursorX]
551         call    getSelectedMenuItem
552         inc             si                                                                      ; Skip string length byte
553         call    printstr
555         mov             dx, 0x100
556         xor             bh, bh
557         mov             ah, SET_CURSOR
558         int             BIOS_VIDEO_SERVICES
560         call    getSelectedBootLoaderAddress
561         mov             dl, [si]                                                        ; drive number in dl
563         jmp             $$                                                                      ; Start loaded boot loader
566 printAndHalt:
567         mov             dx, (TEXT_ROWS-4) * 0x100 + (TEXT_COLUMNS / 3)
568         mov             [bp + cursorPosition], dx
570         mov             bx, 0x0F                                                        ; Page number and foreground color
571         call    printstr
572         mov             ah, READ_CHAR
573         int             BIOS_KEYBOARD_SERVICES
574         mov             dl, [bp + biosDrive]
575         int             BIOS_REBOOT
577 ; Output:
578 ;       si      address of selected menu item
579 ; Trashes:
580 ;       ax, cx
581 getSelectedMenuItem:
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
588                                                                                                 ; see loop body
589         jmp             .entry
591 .loop:
592         lodsb                                                                           ; Length of menu item name
593         add             si, ax                                                          ; Skip name to BootLoaderAddess
594         add             si, sizeof(BootLoaderAddress)
596 .entry:
597         loop    .loop
598         ret
600 getSelectedBootLoaderAddress:
601         call    getSelectedMenuItem
602         lodsb
603         xor             ah, ah
604         add             si, ax                                                          ; Skip name
605         mov             dl, [si]
606         test    dl, 0                                                           ; if drive is 0, use boot drive
607         jz              .takeOverBootDrive
608         ret
609 .takeOverBootDrive:
610         mov             dl, [bp + biosDrive]
611         mov             [si], dl
612         ret
614 printStringStage2:
615         PRINT_STRING
617 ; al ... ASCII character
618 ; bl ... color
619 printChar:
620         push    ax
621         push    bx
622         push    cx
623         push    dx
625         xor             bh, bh                                                          ; Write on page 0
627         mov             dx, [bp + cursorPosition]
628         mov             ah, SET_CURSOR
629         int             BIOS_VIDEO_SERVICES
631         inc             byte [bp + cursorX]
633         mov             cx, 1
634         mov             ah, WRITE_CHAR
635         int             BIOS_VIDEO_SERVICES
637         pop             dx
638         pop             cx
639         pop             bx
640         pop             ax
641         ret
643 ; ================================ DATA ===========================
645 bootSectorDAP:
646         istruc AddressPacket
647                 at AddressPacket.packet_size,   db              0x10
648                 at AddressPacket.block_count,   db              0x01
649                 at AddressPacket.buffer,                dw              0x0000, 0x07c0
650         iend
652 kColorTable:
653         db BLUE, RED, GREEN, CYAN
654 kReadError:
655         db              'Error loading sectors', 0x00
656 kNoBootablePartitionError:
657         db              'Not a bootable partition', 0x00
658 kLoadingMessage:
659         db              'Loading', 0x00
662 listItemCount:
663 defaultItem                     equ             listItemCount + 2
664 timeout                         equ             defaultItem + 2
665 list                            equ             timeout + 2
667 ; dw number of entries
668 ; dw the default entry
669 ; dw the timeout (-1 for none)
670 ; entry:
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
676 %if USE_TEST_MENU
677         dw              0x06
679         dw              2
681         dw              5
683         db              0x06
684         db              'HAIKU', 0
685         db              0x80
686         dw              1, 0, 0, 0
688         db              0x08
689         db              'FreeBSD', 0
690         db              0x80
691         dw              0x003F, 0, 0, 0
693         db              0x04
694         db              'DOS', 0
695         db              0x80
696         dw              0x003E, 0, 0, 0
698         db              0x06
699         db              'LINUX', 0
700         db              0x80
701         dw              0x003F, 0, 0, 0
703         db              0x08
704         db              'BeOS R5', 0
705         db              0x80
706         dw              0x003F, 0, 0, 0
708         db              0x07
709         db              'OpenBSD', 0
710         db              0x80
711         dw              0xAAAA, 0, 0, 0
713         dw              kStage1UnusedSpace
714 %endif