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