xref: /haiku/src/apps/bootmanager/bootman.S (revision 74a14969eca780b3182182044406a6934885a381)
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
137b76ca311SAxel Dörfler%assign KEY_RETURN						0x1C
138b76ca311SAxel Dörfler
139b76ca311SAxel Dörfler; Modifier key bitmasks
140b76ca311SAxel Dörfler%assign MODIFIER_RIGHT_SHIFT_KEY		0x01
141b76ca311SAxel Dörfler%assign MODIFIER_LEFT_SHIFT_KEY			0x02
142b76ca311SAxel Dörfler%assign MODIFIER_CONTROL_KEY			0x04
143b76ca311SAxel Dörfler%assign MODIFIER_ALT_KEY				0x08
144b76ca311SAxel Dörfler%assign MODIFIER_SCROLL_LOCK_KEY		0x10
145b76ca311SAxel Dörfler%assign MODIFIER_NUM_LOCK_KEY			0x20
146b76ca311SAxel Dörfler%assign MODIFIER_CAPS_LOCK_KEY			0x40
147b76ca311SAxel Dörfler%assign MODIFIER_INSERT_KEY				0x80
148b76ca311SAxel Dörfler
149b76ca311SAxel Dörfler; String constants with their length
150b76ca311SAxel Dörfler%define TITLE							'Haiku Boot Manager'
151b76ca311SAxel Dörfler%strlen TITLE_LENGTH					TITLE
152b76ca311SAxel Dörfler%define SELECT_OS_MESSAGE				'Select an OS from the menu'
153b76ca311SAxel Dörfler%strlen SELECT_OS_MESSAGE_LENGTH		SELECT_OS_MESSAGE
154b76ca311SAxel Dörfler
155b76ca311SAxel Dörfler; 16 bit code
156*74a14969SFrançois RevolSECTION .text
157b76ca311SAxel DörflerBITS 16
158b76ca311SAxel Dörfler
159b76ca311SAxel Dörfler
160b76ca311SAxel Dörfler; nicer way to get the size of a structure
161b76ca311SAxel Dörfler%define sizeof(s)	s %+ _size
162b76ca311SAxel Dörfler
163b76ca311SAxel Dörfler; using a structure in a another structure definition
164b76ca311SAxel Dörfler%macro  nstruc  1-2	 1
165b76ca311SAxel Dörfler					resb	sizeof(%1) * %2
166b76ca311SAxel Dörfler%endmacro
167b76ca311SAxel Dörfler
168b76ca311SAxel Dörfler; Variables on stack
169b76ca311SAxel Dörflerstruc	Locals
170b76ca311SAxel Dörfler	selection		resw	1
171b76ca311SAxel Dörfler	firstLine		resb	2 ; low byte used only
172b76ca311SAxel Dörfler	timeoutTicks	resd	1
173b76ca311SAxel Dörfler	cursorX			resb	1
174b76ca311SAxel Dörfler	cursorY			resb	1
175b76ca311SAxel Dörfler	cursorShape		resw	1
17689f0e174SAxel Dörfler	biosDrive		resb	1
177b76ca311SAxel Dörflerendstruc
178b76ca311SAxel Dörfler
179b76ca311SAxel DörflercursorPosition		equ cursorX
180b76ca311SAxel Dörfler
181b76ca311SAxel Dörfler%macro DEBUG_PAUSE 0
182b76ca311SAxel Dörfler	push	ax
183b76ca311SAxel Dörfler	mov		ah, READ_CHAR
184b76ca311SAxel Dörfler	int		BIOS_KEYBOARD_SERVICES
185b76ca311SAxel Dörfler	pop		ax
186b76ca311SAxel Dörfler%endmacro
187b76ca311SAxel Dörfler
188b76ca311SAxel Dörfler%macro CLEAR_SCREEN 0
189b76ca311SAxel Dörfler	mov		ah, SCROLL_UP
190b76ca311SAxel Dörfler	xor		al, al
191b76ca311SAxel Dörfler	mov		bh, WHITE
192b76ca311SAxel Dörfler	xor		cx, cx
193b76ca311SAxel Dörfler	mov		dx, (TEXT_ROWS-1) * 0x100 + (TEXT_COLUMNS-1)
194b76ca311SAxel Dörfler	int		BIOS_VIDEO_SERVICES
195b76ca311SAxel Dörfler%endmacro
196b76ca311SAxel Dörfler
197b76ca311SAxel Dörfler; Prints a null terminated string
198b76ca311SAxel Dörfler; bl ... color
199b76ca311SAxel Dörfler; si ... offset to string
200b76ca311SAxel Dörfler%macro PRINT_STRING 0
201b76ca311SAxel Dörfler	push	ax
202b76ca311SAxel Dörfler	push	bx
203b76ca311SAxel Dörfler	push	cx
204b76ca311SAxel Dörfler	push	dx
205b76ca311SAxel Dörfler	xor		bh, bh								; write on page 0
206b76ca311SAxel Dörfler	jmp		.loop_condition
207b76ca311SAxel Dörfler.loop
208b76ca311SAxel Dörfler	mov		dx, [bp + cursorPosition]
209b76ca311SAxel Dörfler	mov		ah, SET_CURSOR
210b76ca311SAxel Dörfler	int		BIOS_VIDEO_SERVICES
211b76ca311SAxel Dörfler
212b76ca311SAxel Dörfler	inc		byte [bp + cursorX]
213b76ca311SAxel Dörfler
214b76ca311SAxel Dörfler	mov		cx, 1
215b76ca311SAxel Dörfler	mov		ah, WRITE_CHAR
216b76ca311SAxel Dörfler	int		BIOS_VIDEO_SERVICES
217b76ca311SAxel Dörfler.loop_condition
218b76ca311SAxel Dörfler	lodsb
219b76ca311SAxel Dörfler	cmp		al, 0
220b76ca311SAxel Dörfler	jnz		.loop
221b76ca311SAxel Dörfler	pop		dx
222b76ca311SAxel Dörfler	pop		cx
223b76ca311SAxel Dörfler	pop		bx
224b76ca311SAxel Dörfler	pop		ax
225b76ca311SAxel Dörfler	ret
226b76ca311SAxel Dörfler%endmacro
227b76ca311SAxel Dörfler
228b76ca311SAxel Dörfler; 64 bit value
229b76ca311SAxel Dörflerstruc   quadword
230b76ca311SAxel Dörfler	.lower			resd	1
231b76ca311SAxel Dörfler	.upper			resd	1
232b76ca311SAxel Dörflerendstruc
233b76ca311SAxel Dörfler
234b76ca311SAxel Dörfler; address packet as required by the EXTENDED_READ BIOS call
235b76ca311SAxel Dörflerstruc   AddressPacket
236b76ca311SAxel Dörfler	.packet_size	resb	1
237b76ca311SAxel Dörfler	.reserved1		resb	1
238b76ca311SAxel Dörfler	.block_count	resb	1
239b76ca311SAxel Dörfler	.reserved2		resb	1
240b76ca311SAxel Dörfler	.buffer			resd	1
241b76ca311SAxel Dörfler	.offset			nstruc	quadword
242b76ca311SAxel Dörflerendstruc
243b76ca311SAxel Dörfler
244b76ca311SAxel Dörflerstruc	BootLoaderAddress
245b76ca311SAxel Dörfler	.device			resb	1			; hard drive number
246b76ca311SAxel Dörfler	.offset			nstruc	quadword	; LBA of start start sector
247b76ca311SAxel Dörflerendstruc
248b76ca311SAxel Dörfler
249b76ca311SAxel Dörfler; use code available in stage 1
250b76ca311SAxel Dörfler%define printstr printStringStage1
251b76ca311SAxel Dörfler
252b76ca311SAxel Dörflerstage1:
25349c044abSAxel Dörfler	mov		ax, 0x07c0						; BOOT_BLOCK_START_ADDRESS / 16
254b76ca311SAxel Dörfler	mov		ds, ax							; Setup segment registers
255b76ca311SAxel Dörfler	mov		es, ax
256b76ca311SAxel Dörfler	mov		ss, ax
257b76ca311SAxel Dörfler
258b76ca311SAxel Dörfler	mov		sp, 0xFFFF - sizeof(Locals)		; Make stack empty
259b76ca311SAxel Dörfler	mov		bp, sp
260b76ca311SAxel Dörfler
26189f0e174SAxel Dörfler	mov		[bp + biosDrive], dl			; Store boot drive
26249c044abSAxel Dörfler	cld										; String operations increment index
26349c044abSAxel Dörfler											; registers
264b76ca311SAxel Dörfler	CLEAR_SCREEN
265b76ca311SAxel Dörfler	call	hideCursor
266b76ca311SAxel Dörfler
267b76ca311SAxel Dörfler	mov		bh, 0							; Text output on page 0
268b76ca311SAxel Dörfler
269b76ca311SAxel Dörfler	; Print title centered at row 2
270b76ca311SAxel Dörfler	mov		dx, 1 * 0x100 + (40 - TITLE_LENGTH / 2)
271b76ca311SAxel Dörfler	mov		[bp + cursorPosition], dx
272b76ca311SAxel Dörfler
273b76ca311SAxel Dörfler	mov		si, kTitle
274b76ca311SAxel Dörfler	mov		bl, WHITE
275b76ca311SAxel Dörfler	call	printstr
276b76ca311SAxel Dörfler
277b76ca311SAxel Dörfler	; Print message centered at second last row
278b76ca311SAxel Dörfler	mov		dx, (TEXT_ROWS-2) * 0x100 + (40 - SELECT_OS_MESSAGE_LENGTH / 2)
279b76ca311SAxel Dörfler	mov		[bp + cursorPosition], dx
280b76ca311SAxel Dörfler
281b76ca311SAxel Dörfler	mov		bl, LIGHT_GRAY
282b76ca311SAxel Dörfler	mov		si, kSelectOSMessage
283b76ca311SAxel Dörfler	call	printstr
284b76ca311SAxel Dörfler
285b76ca311SAxel Dörfler	; Chain load rest of boot loader
286b76ca311SAxel Dörfler	mov		ah, EXTENDED_READ				; Load 3 more sectors
28789f0e174SAxel Dörfler	mov		dl, [bp + biosDrive]
288b76ca311SAxel Dörfler	mov		si, nextStageDAP
289b76ca311SAxel Dörfler	int		BIOS_DISK_SERVICES
290b76ca311SAxel Dörfler	jc		.error							; I/O error
291b76ca311SAxel Dörfler	jmp		stage2							; Continue in loaded stage 2
292b76ca311SAxel Dörfler
293b76ca311SAxel Dörfler.error:
294b76ca311SAxel Dörfler	call	showCursor
295b76ca311SAxel Dörfler	mov		si, kError
296b76ca311SAxel Dörfler	mov		bl, RED
297b76ca311SAxel Dörfler	call	printstr
298b76ca311SAxel Dörfler
299b76ca311SAxel Dörfler	mov		ah, READ_CHAR
300b76ca311SAxel Dörfler	int		BIOS_KEYBOARD_SERVICES
301b76ca311SAxel Dörfler
30289f0e174SAxel Dörfler	mov		dl, [bp + biosDrive]
303b76ca311SAxel Dörfler	int		BIOS_REBOOT
304b76ca311SAxel Dörfler
305b76ca311SAxel DörflerprintStringStage1:
306b76ca311SAxel Dörfler	PRINT_STRING
307b76ca311SAxel Dörfler
308b76ca311SAxel DörflerhideCursor:
309b76ca311SAxel Dörfler	mov		ah, GET_CURSOR
310b76ca311SAxel Dörfler	int		BIOS_VIDEO_SERVICES
311b76ca311SAxel Dörfler	mov		[bp + cursorShape], cx
312b76ca311SAxel Dörfler
313b76ca311SAxel Dörfler	mov		ah, SET_CURSOR_SHAPE
314b76ca311SAxel Dörfler	mov		cx, 0x2000
315b76ca311SAxel Dörfler	int		BIOS_VIDEO_SERVICES
316b76ca311SAxel Dörfler	ret
317b76ca311SAxel Dörfler
318b76ca311SAxel DörflershowCursor:
319b76ca311SAxel Dörfler	mov		cx, [bp + cursorShape]
320b76ca311SAxel Dörfler	mov		ah, SET_CURSOR_SHAPE
321b76ca311SAxel Dörfler	int		BIOS_VIDEO_SERVICES
322b76ca311SAxel Dörfler	ret
323b76ca311SAxel Dörfler
324b76ca311SAxel DörflernextStageDAP:
325b76ca311SAxel Dörfler	istruc AddressPacket
326b76ca311SAxel Dörfler		at AddressPacket.packet_size,	db		0x10
327b76ca311SAxel Dörfler		at AddressPacket.block_count,	db		0x03
328b76ca311SAxel Dörfler		at AddressPacket.buffer,		dw		0x0200, 0x07c0
329b76ca311SAxel Dörfler		at AddressPacket.offset,		dw		1
330b76ca311SAxel Dörfler	iend
331b76ca311SAxel Dörfler
332b76ca311SAxel DörflerkTitle:
333b76ca311SAxel Dörfler	db		TITLE, 0x00
334b76ca311SAxel DörflerkSelectOSMessage:
335b76ca311SAxel Dörfler	db		SELECT_OS_MESSAGE, 0x00
336b76ca311SAxel DörflerkError:
337b76ca311SAxel Dörfler	db		'Error loading sectors!', 0x00
338b76ca311SAxel Dörfler
339b76ca311SAxel DörflerkStage1UnusedSpace	equ	440 - ($-$$)
340b76ca311SAxel Dörfler	; Fill the missing space to reach byte 440
341b76ca311SAxel Dörfler	times kStage1UnusedSpace db 'B'
342b76ca311SAxel Dörfler
343cf3c703bSFrançois RevolkDiskSignature:
344b76ca311SAxel Dörfler	dw		0, 0
345b76ca311SAxel DörflerkReserved
346b76ca311SAxel Dörfler	dw		0
347b76ca311SAxel DörflerkPartitionTable
348b76ca311SAxel Dörfler	times	64 db 0
349b76ca311SAxel Dörfler
350b76ca311SAxel DörflerkMBRSignature:
351b76ca311SAxel Dörfler	; Magic marker "AA55" (to identify a valid boot record)
352b76ca311SAxel Dörfler	dw		MBR_SIGNATURE
353b76ca311SAxel Dörfler
354b76ca311SAxel Dörfler; ======================================================================
355b76ca311SAxel Dörfler; ======================= SECOND SECTOR ================================
356b76ca311SAxel Dörfler; ======================================================================
357b76ca311SAxel Dörfler
35889f0e174SAxel Dörfler; Use code available in stage 2
359b76ca311SAxel Dörfler%define printstr printStringStage2
360b76ca311SAxel Dörfler
361b76ca311SAxel Dörfler%assign	TIMEOUT_OFF		0xffff
362b76ca311SAxel Dörfler
363b76ca311SAxel Dörfler
364b76ca311SAxel Dörflerstage2:
365b76ca311SAxel Dörfler	mov		ax, [defaultItem]					; Select default item
366b76ca311SAxel Dörfler	mov		[bp + selection], ax
367b76ca311SAxel Dörfler
368b76ca311SAxel Dörfler	mov		ax, TICKS_PER_SECOND				; Calculate timeout ticks
369b76ca311SAxel Dörfler	mul		word [timeout]
370b76ca311SAxel Dörfler	mov		bx, dx
371b76ca311SAxel Dörfler	push	ax
372b76ca311SAxel Dörfler
373b76ca311SAxel Dörfler	mov		ah, READ_CLOCK
374b76ca311SAxel Dörfler	int		BIOS_TIME_SERVICES
375b76ca311SAxel Dörfler
376b76ca311SAxel Dörfler	pop		ax									; Add current ticks
377b76ca311SAxel Dörfler	add		ax, dx
378b76ca311SAxel Dörfler	adc		bx, cx
379b76ca311SAxel Dörfler	mov		[bp + timeoutTicks], ax
380b76ca311SAxel Dörfler	mov		[bp + timeoutTicks + 2], bx
381b76ca311SAxel Dörfler
382b76ca311SAxel Dörfler	mov		al, [listItemCount]					; Calculate start row for menu
383b76ca311SAxel Dörfler	shr		al, 1
384b76ca311SAxel Dörfler	mov		bl, TEXT_ROWS / 2
385b76ca311SAxel Dörfler	sub		bl, al								; y = TEXT_ROWS / 2 - number of items / 2
386b76ca311SAxel Dörfler	mov		[bp + firstLine], bl
387b76ca311SAxel Dörfler
388b76ca311SAxel Dörfler	mov		ah, GET_MODIFIER_KEYS				; Disable timeout if ALT key is pressed
389b76ca311SAxel Dörfler	int		BIOS_KEYBOARD_SERVICES
390b76ca311SAxel Dörfler	and		al, MODIFIER_ALT_KEY
391b76ca311SAxel Dörfler	jz		showMenu
392b76ca311SAxel Dörfler	mov		word [timeout], TIMEOUT_OFF
393b76ca311SAxel Dörfler
394b76ca311SAxel DörflershowMenu:
395b76ca311SAxel Dörfler	call	printMenu
396b76ca311SAxel Dörfler
397b76ca311SAxel Dörfler	cmp		word [timeout], TIMEOUT_OFF
398b76ca311SAxel Dörfler	je		inputLoop
399b76ca311SAxel Dörfler
400b76ca311SAxel DörflertimeoutLoop:
401b76ca311SAxel Dörfler	mov		ah, PROBE_CHAR
402b76ca311SAxel Dörfler	int		BIOS_KEYBOARD_SERVICES
403b76ca311SAxel Dörfler	jnz		inputLoop							; cancel timeout if key is pressed
404b76ca311SAxel Dörfler	call	isTimeoutReached
405b76ca311SAxel Dörfler	jnc		timeoutLoop
406b76ca311SAxel Dörfler	jmp		bootSelectedPartition
407b76ca311SAxel Dörfler
408b76ca311SAxel DörflerisTimeoutReached:
409b76ca311SAxel Dörfler	mov		ah, READ_CLOCK
410b76ca311SAxel Dörfler	int		BIOS_TIME_SERVICES
411b76ca311SAxel Dörfler	cmp		cx, [bp + timeoutTicks + 2]
412b76ca311SAxel Dörfler	jb		.returnFalse
413b76ca311SAxel Dörfler	ja		.returnTrue
414b76ca311SAxel Dörfler	cmp		dx, [bp + timeoutTicks]
415b76ca311SAxel Dörfler	ja		.returnTrue
416b76ca311SAxel Dörfler.returnFalse:
417b76ca311SAxel Dörfler	clc
418b76ca311SAxel Dörfler	ret
419b76ca311SAxel Dörfler.returnTrue:
420b76ca311SAxel Dörfler	stc
421b76ca311SAxel Dörfler	ret
422b76ca311SAxel Dörfler
423b76ca311SAxel Dörfler; ================== Wait for a key and do something with it ==================
424b76ca311SAxel DörflermainLoop:
425b76ca311SAxel Dörfler	call	printMenu
426b76ca311SAxel Dörfler
427b76ca311SAxel DörflerinputLoop:
428b76ca311SAxel Dörfler	mov		ah, READ_CHAR
429b76ca311SAxel Dörfler	int		BIOS_KEYBOARD_SERVICES				; AL = ASCII Code, AH = Scancode
430b76ca311SAxel Dörfler
431b76ca311SAxel Dörfler	cmp		ah, KEY_DOWN
432b76ca311SAxel Dörfler	je		selectNextPartition
433b76ca311SAxel Dörfler
434b76ca311SAxel Dörfler	cmp		ah, KEY_UP
435b76ca311SAxel Dörfler	je		selectPreviousPartition
436b76ca311SAxel Dörfler
437b76ca311SAxel Dörfler	cmp		ah, KEY_RETURN
438b76ca311SAxel Dörfler	jne		inputLoop
439b76ca311SAxel Dörfler	jmp		bootSelectedPartition
440b76ca311SAxel Dörfler
441b76ca311SAxel DörflerselectNextPartition:
442b76ca311SAxel Dörfler	mov		ax, [bp + selection]
443b76ca311SAxel Dörfler	inc		ax
444b76ca311SAxel Dörfler	cmp		ax, [listItemCount]
445b76ca311SAxel Dörfler	jne		.done								; At end of list?
446b76ca311SAxel Dörfler	xor		ax, ax								; Then jump to first entry
447b76ca311SAxel Dörfler.done:
448b76ca311SAxel Dörfler	mov		[bp + selection], ax
449b76ca311SAxel Dörfler	jmp		mainLoop
450b76ca311SAxel Dörfler
451b76ca311SAxel DörflerselectPreviousPartition:
452b76ca311SAxel Dörfler	mov		ax, [bp + selection]
453b76ca311SAxel Dörfler	or		ax, ax
454b76ca311SAxel Dörfler	jnz		.done								; At top of list?
455b76ca311SAxel Dörfler	mov		ax, [listItemCount]					; Then jump to last entry
456b76ca311SAxel Dörfler.done:
457b76ca311SAxel Dörfler	dec		ax
458b76ca311SAxel Dörfler	mov		[bp + selection], ax
459b76ca311SAxel Dörfler	jmp		mainLoop
460b76ca311SAxel Dörfler
461b76ca311SAxel Dörfler
462b76ca311SAxel Dörfler; ======================= Print the OS list ============================
463b76ca311SAxel DörflerprintMenu:
464b76ca311SAxel Dörfler	mov		al, [bp + firstLine]
465b76ca311SAxel Dörfler	mov		[bp + cursorY], al
466b76ca311SAxel Dörfler
467b76ca311SAxel Dörfler	mov		si, list							; Start at top of list
468b76ca311SAxel Dörfler	xor		cx, cx								; The index of the current item
469b76ca311SAxel Dörfler
470b76ca311SAxel Dörfler.loop:
471b76ca311SAxel Dörfler	lodsb										; String length incl. 0-terminator
472b76ca311SAxel Dörfler	add		al, 3								; center menu item
473b76ca311SAxel Dörfler	shr		al, 1								; x = TEXT_COLUMNS / 2 - length / 2
474b76ca311SAxel Dörfler	mov		dl, TEXT_COLUMNS / 2
475b76ca311SAxel Dörfler	sub		dl, al
476b76ca311SAxel Dörfler	mov		[bp + cursorX], dl
477b76ca311SAxel Dörfler
478b76ca311SAxel Dörfler	mov		al, TRIANGLE_TO_RIGHT
479b76ca311SAxel Dörfler	call	updateMarker
480b76ca311SAxel Dörfler	inc		byte [bp + cursorX]
481b76ca311SAxel Dörfler
482b76ca311SAxel Dörfler	mov		di, cx
483b76ca311SAxel Dörfler	and		di, 3
484b76ca311SAxel Dörfler	mov		bl, [kColorTable + di]				; Text color
485b76ca311SAxel Dörfler
486b76ca311SAxel Dörfler	cmp		cx, [bp + selection]
487b76ca311SAxel Dörfler	jne		.print								; Selected item reached?
488b76ca311SAxel Dörfler	xor		bl, BRIGHT_COLOR_MASK				; Highlight it
489b76ca311SAxel Dörfler
490b76ca311SAxel Dörfler.print:
491b76ca311SAxel Dörfler	call	printstr
492b76ca311SAxel Dörfler	add		si, sizeof(BootLoaderAddress)
493b76ca311SAxel Dörfler
494b76ca311SAxel Dörfler	add		byte [bp + cursorX], 1
495b76ca311SAxel Dörfler	mov		al, TRIANGLE_TO_LEFT
496b76ca311SAxel Dörfler	call	updateMarker
497b76ca311SAxel Dörfler
498b76ca311SAxel Dörfler	inc		byte [bp + cursorY]
499b76ca311SAxel Dörfler	inc		cx
500b76ca311SAxel Dörfler
501b76ca311SAxel Dörfler	cmp		cx, [listItemCount]
502b76ca311SAxel Dörfler	jne		.loop
503b76ca311SAxel Dörfler	ret
504b76ca311SAxel Dörfler
505b76ca311SAxel DörflerupdateMarker:
506b76ca311SAxel Dörfler	cmp		cx, [bp + selection]
507b76ca311SAxel Dörfler	je		.print
508b76ca311SAxel Dörfler	mov		al, ' '								; Clear marker
509b76ca311SAxel Dörfler.print
510b76ca311SAxel Dörfler	mov		bl, WHITE
511b76ca311SAxel Dörfler	jmp		printChar							; return from subroutine
512b76ca311SAxel Dörfler
513b76ca311SAxel Dörfler
514b76ca311SAxel Dörfler; ========================== Chainload ==========================
515b76ca311SAxel Dörfler
516b76ca311SAxel DörflerbootSelectedPartition:
517b76ca311SAxel Dörfler
518b76ca311SAxel Dörfler	call	showCursor
519b76ca311SAxel Dörfler
520b76ca311SAxel Dörfler	call	getSelectedBootLoaderAddress
521b76ca311SAxel Dörfler	lodsb										; Set boot drive
522b76ca311SAxel Dörfler	mov		dl, al
523b76ca311SAxel Dörfler
524b76ca311SAxel Dörfler	mov		di, bootSectorDAP+AddressPacket.offset	; Copy start sector
525b76ca311SAxel Dörfler	mov		cx, 4								; It is stored in a quad word
526b76ca311SAxel Dörfler.copy_start_sector
527b76ca311SAxel Dörfler	lodsw
528b76ca311SAxel Dörfler	stosw
529b76ca311SAxel Dörfler	loop .copy_start_sector
530b76ca311SAxel Dörfler
531b76ca311SAxel Dörfler	mov		ah, EXTENDED_READ					; Now read start sector from HD
532b76ca311SAxel Dörfler	mov		si, bootSectorDAP
533b76ca311SAxel Dörfler	int		BIOS_DISK_SERVICES
534b76ca311SAxel Dörfler	mov		si, kReadError
535b76ca311SAxel Dörfler	jc		printAndHalt						; Failed to read sector
536b76ca311SAxel Dörfler
537b76ca311SAxel Dörfler	mov		ax, [kMBRSignature]
538b76ca311SAxel Dörfler	cmp		ax, MBR_SIGNATURE
539b76ca311SAxel Dörfler	mov		si, kNoBootablePartitionError
540b76ca311SAxel Dörfler	jne		printAndHalt						; Missing signature
541b76ca311SAxel Dörfler
542b76ca311SAxel Dörfler	CLEAR_SCREEN
543b76ca311SAxel Dörfler
544b76ca311SAxel Dörfler	; Print "Loading <name>" at top of screen
545b76ca311SAxel Dörfler	mov		word [bp + cursorPosition], 0
546b76ca311SAxel Dörfler	mov		si, kLoadingMessage
547b76ca311SAxel Dörfler	mov		bl, LIGHT_GRAY
548b76ca311SAxel Dörfler	call	printstr
549b76ca311SAxel Dörfler
550b76ca311SAxel Dörfler	inc		byte [bp + cursorX]
551b76ca311SAxel Dörfler	call	getSelectedMenuItem
552b76ca311SAxel Dörfler	inc		si									; Skip string length byte
553b76ca311SAxel Dörfler	call	printstr
554b76ca311SAxel Dörfler
555b76ca311SAxel Dörfler	mov		dx, 0x100
556b76ca311SAxel Dörfler	xor		bh, bh
557b76ca311SAxel Dörfler	mov		ah, SET_CURSOR
558b76ca311SAxel Dörfler	int		BIOS_VIDEO_SERVICES
559b76ca311SAxel Dörfler
560b76ca311SAxel Dörfler	call	getSelectedBootLoaderAddress
561b76ca311SAxel Dörfler	mov		dl, [si]							; drive number in dl
562b76ca311SAxel Dörfler
563b76ca311SAxel Dörfler	jmp		$$									; Start loaded boot loader
564b76ca311SAxel Dörfler
565b76ca311SAxel Dörfler
566b76ca311SAxel DörflerprintAndHalt:
567b76ca311SAxel Dörfler	mov		dx, (TEXT_ROWS-4) * 0x100 + (TEXT_COLUMNS / 3)
568b76ca311SAxel Dörfler	mov		[bp + cursorPosition], dx
569b76ca311SAxel Dörfler
570b76ca311SAxel Dörfler	mov		bx, 0x0F							; Page number and foreground color
571b76ca311SAxel Dörfler	call	printstr
572b76ca311SAxel Dörfler	mov		ah, READ_CHAR
573b76ca311SAxel Dörfler	int		BIOS_KEYBOARD_SERVICES
5740e193080SAxel Dörfler	mov		dl, [bp + biosDrive]
575b76ca311SAxel Dörfler	int		BIOS_REBOOT
576b76ca311SAxel Dörfler
577b76ca311SAxel Dörfler; Output:
578b76ca311SAxel Dörfler;	si	address of selected menu item
579b76ca311SAxel Dörfler; Trashes:
580b76ca311SAxel Dörfler;	ax, cx
581b76ca311SAxel DörflergetSelectedMenuItem:
582b76ca311SAxel Dörfler	mov		si, list							; Search address of start sector
583b76ca311SAxel Dörfler												; of the selected item.
584b76ca311SAxel Dörfler	mov		cx, [bp + selection]
585b76ca311SAxel Dörfler	inc		cx									; Number of required iterations
586b76ca311SAxel Dörfler
587b76ca311SAxel Dörfler	xor		ah, ah								; The high-byte of the string length
588b76ca311SAxel Dörfler												; see loop body
589b76ca311SAxel Dörfler	jmp		.entry
590b76ca311SAxel Dörfler
591b76ca311SAxel Dörfler.loop:
592b76ca311SAxel Dörfler	lodsb										; Length of menu item name
593b76ca311SAxel Dörfler	add		si, ax								; Skip name to BootLoaderAddess
594b76ca311SAxel Dörfler	add		si, sizeof(BootLoaderAddress)
595b76ca311SAxel Dörfler
596b76ca311SAxel Dörfler.entry:
597b76ca311SAxel Dörfler	loop	.loop
598b76ca311SAxel Dörfler	ret
599b76ca311SAxel Dörfler
600b76ca311SAxel DörflergetSelectedBootLoaderAddress:
601b76ca311SAxel Dörfler	call	getSelectedMenuItem
602b76ca311SAxel Dörfler	lodsb
603b76ca311SAxel Dörfler	xor		ah, ah
604b76ca311SAxel Dörfler	add		si, ax								; Skip name
60549c044abSAxel Dörfler	mov		dl, [si]
60649c044abSAxel Dörfler	test	dl, 0								; if drive is 0, use boot drive
60749c044abSAxel Dörfler	jz		.takeOverBootDrive
60849c044abSAxel Dörfler	ret
60949c044abSAxel Dörfler.takeOverBootDrive:
61089f0e174SAxel Dörfler	mov		dl, [bp + biosDrive]
61149c044abSAxel Dörfler	mov		[si], dl
612b76ca311SAxel Dörfler	ret
613b76ca311SAxel Dörfler
614b76ca311SAxel DörflerprintStringStage2:
615b76ca311SAxel Dörfler	PRINT_STRING
616b76ca311SAxel Dörfler
617b76ca311SAxel Dörfler; al ... ASCII character
618b76ca311SAxel Dörfler; bl ... color
619b76ca311SAxel DörflerprintChar:
620b76ca311SAxel Dörfler	push	ax
621b76ca311SAxel Dörfler	push	bx
622b76ca311SAxel Dörfler	push	cx
623b76ca311SAxel Dörfler	push	dx
624b76ca311SAxel Dörfler
625b76ca311SAxel Dörfler	xor		bh, bh								; Write on page 0
626b76ca311SAxel Dörfler
627b76ca311SAxel Dörfler	mov		dx, [bp + cursorPosition]
628b76ca311SAxel Dörfler	mov		ah, SET_CURSOR
629b76ca311SAxel Dörfler	int		BIOS_VIDEO_SERVICES
630b76ca311SAxel Dörfler
631b76ca311SAxel Dörfler	inc		byte [bp + cursorX]
632b76ca311SAxel Dörfler
633b76ca311SAxel Dörfler	mov		cx, 1
634b76ca311SAxel Dörfler	mov		ah, WRITE_CHAR
635b76ca311SAxel Dörfler	int		BIOS_VIDEO_SERVICES
636b76ca311SAxel Dörfler
637b76ca311SAxel Dörfler	pop		dx
638b76ca311SAxel Dörfler	pop		cx
639b76ca311SAxel Dörfler	pop		bx
640b76ca311SAxel Dörfler	pop		ax
641b76ca311SAxel Dörfler	ret
642b76ca311SAxel Dörfler
643b76ca311SAxel Dörfler; ================================ DATA ===========================
644b76ca311SAxel Dörfler
645b76ca311SAxel DörflerbootSectorDAP:
646b76ca311SAxel Dörfler	istruc AddressPacket
647b76ca311SAxel Dörfler		at AddressPacket.packet_size,	db		0x10
648b76ca311SAxel Dörfler		at AddressPacket.block_count,	db		0x01
649b76ca311SAxel Dörfler		at AddressPacket.buffer,		dw		0x0000, 0x07c0
650b76ca311SAxel Dörfler	iend
651b76ca311SAxel Dörfler
652b76ca311SAxel DörflerkColorTable:
653b76ca311SAxel Dörfler	db BLUE, RED, GREEN, CYAN
654b76ca311SAxel DörflerkReadError:
655b76ca311SAxel Dörfler	db		'Error loading sectors', 0x00
656b76ca311SAxel DörflerkNoBootablePartitionError:
657b76ca311SAxel Dörfler	db		'Not a bootable partition', 0x00
658b76ca311SAxel DörflerkLoadingMessage:
659b76ca311SAxel Dörfler	db		'Loading', 0x00
660b76ca311SAxel Dörfler
661b76ca311SAxel Dörfler
662b76ca311SAxel DörflerlistItemCount:
663b76ca311SAxel DörflerdefaultItem			equ		listItemCount + 2
664b76ca311SAxel Dörflertimeout				equ		defaultItem + 2
665b76ca311SAxel Dörflerlist				equ		timeout + 2
666b76ca311SAxel Dörfler
667b76ca311SAxel Dörfler; dw number of entries
668b76ca311SAxel Dörfler; dw the default entry
669b76ca311SAxel Dörfler; dw the timeout (-1 for none)
670b76ca311SAxel Dörfler; entry:
671b76ca311SAxel Dörfler; db size of partition name 0-terminated string
672b76ca311SAxel Dörfler; db 0-terminated string with partition name
673b76ca311SAxel Dörfler; db hard drive number
674b76ca311SAxel Dörfler; quadword start sector
675b76ca311SAxel Dörfler
676b76ca311SAxel Dörfler%if USE_TEST_MENU
677b76ca311SAxel Dörfler	dw		0x06
678b76ca311SAxel Dörfler
679b76ca311SAxel Dörfler	dw		2
680b76ca311SAxel Dörfler
681b76ca311SAxel Dörfler	dw		5
682b76ca311SAxel Dörfler
683b76ca311SAxel Dörfler	db		0x06
684b76ca311SAxel Dörfler	db		'HAIKU', 0
685b76ca311SAxel Dörfler	db		0x80
686b76ca311SAxel Dörfler	dw		1, 0, 0, 0
687b76ca311SAxel Dörfler
688b76ca311SAxel Dörfler	db		0x08
689b76ca311SAxel Dörfler	db		'FreeBSD', 0
690b76ca311SAxel Dörfler	db		0x80
691b76ca311SAxel Dörfler	dw		0x003F, 0, 0, 0
692b76ca311SAxel Dörfler
693b76ca311SAxel Dörfler	db		0x04
694b76ca311SAxel Dörfler	db		'DOS', 0
695b76ca311SAxel Dörfler	db		0x80
696b76ca311SAxel Dörfler	dw		0x003E, 0, 0, 0
697b76ca311SAxel Dörfler
698b76ca311SAxel Dörfler	db		0x06
699b76ca311SAxel Dörfler	db		'LINUX', 0
700b76ca311SAxel Dörfler	db		0x80
701b76ca311SAxel Dörfler	dw		0x003F, 0, 0, 0
702b76ca311SAxel Dörfler
703b76ca311SAxel Dörfler	db		0x08
704b76ca311SAxel Dörfler	db		'BeOS R5', 0
705b76ca311SAxel Dörfler	db		0x80
706b76ca311SAxel Dörfler	dw		0x003F, 0, 0, 0
707b76ca311SAxel Dörfler
708b76ca311SAxel Dörfler	db		0x07
709b76ca311SAxel Dörfler	db		'OpenBSD', 0
710b76ca311SAxel Dörfler	db		0x80
711b76ca311SAxel Dörfler	dw		0xAAAA, 0, 0, 0
712b76ca311SAxel Dörfler
713b76ca311SAxel Dörfler	dw		kStage1UnusedSpace
714b76ca311SAxel Dörfler%endif
715b76ca311SAxel Dörfler
716