cdboot.S revision 1.4 1 /* $NetBSD: cdboot.S,v 1.4 2005/07/20 03:27:51 junyoung Exp $ */
2
3 /*-
4 * Copyright (c) 2005 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Bang Jun-Young.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * This is a primary boot loader that loads a secondary boot loader
41 * directly from CD without performing floppy/hard disk emulation as
42 * described by the El Torito specification.
43 *
44 * TODO:
45 * - Support for loading secondary boot loader > 64kB
46 */
47
48 #include <machine/asm.h>
49
50 #define BOOT_ADDR 0x7c00
51 #define BLOCK_SIZE 2048 /* Default for ISO 9660 */
52 #define VD_LBA 16 /* LBA of Volume Descriptor (VD) */
53 #define PVD_ADDR 0x1000 /* Where Primary VD is loaded */
54 #define ROOTDIR_ADDR 0x1800 /* Where Root Directory is loaded */
55 #define LOADER_ADDR SECONDARY_LOAD_ADDRESS
56
57 /*
58 * See src/sys/sys/bootblock.h for details.
59 */
60 #define MBR_PART_COUNT 4
61 #define MBR_PART_OFFSET 446
62 #define MBR_PART_SIZE 16 /* sizeof(struct mbr_partition) */
63
64 /*
65 * Disk error codes
66 */
67 #define ERROR_TIMEOUT 0x80
68
69 /*
70 * Volume Descriptor types.
71 */
72 #define VD_PRIMARY 1
73 #define VD_SUPPLEMENTARY 2
74 #define VD_TERMINATOR 255
75
76 /* Only actually used entries are listed below */
77
78 /*
79 * Format of Primary Volume Descriptor (8.4)
80 */
81 #define PVD_ROOT_DR 156 /* Offset of Root Directory Record */
82
83 /*
84 * Format of Directory Record (9.1)
85 */
86 #define DR_LEN 0
87 #define DR_EXTENT 2
88 #define DR_DATA_LEN 10
89 #define DR_NAME_LEN 32
90 #define DR_NAME 33
91
92 .text
93 .code16
94 ENTRY(start)
95 xorw %ax, %ax
96 movw %ax, %ds
97 movw %ax, %es
98 movw %ax, %ss
99 movw $BOOT_ADDR, %sp
100 movw %sp, %si
101 movw $start, %di
102 movw $BLOCK_SIZE/2, %cx
103 rep
104 movsw
105 ljmp $0, $real_start
106
107 real_start:
108 movb %dl, boot_drive /* Save boot drive number */
109
110 #ifndef DISABLE_KEYPRESS
111 /*
112 * We can skip boot wait when:
113 * - there's no hard disk present.
114 * - there's no active partition in the MBR of the 1st hard disk.
115 */
116
117 /*
118 * Check presence of hard disks.
119 */
120 movw $0x475, %si
121 movb (%si), %al
122 testb %al, %al
123 jz boot_cdrom
124
125 /*
126 * Find the active partition from the MBR.
127 */
128 movw $0x0201, %ax /* %al = number of sectors to read */
129 movw $BOOT_ADDR, %bx /* %es:%bx = data buffer */
130 movw $0x0001, %cx /* %ch = low 8 bits of cylinder no */
131 /* %cl = high 2 bits of cyl no & */
132 /* sector number */
133 movw $0x0080, %dx /* %dh = head number */
134 /* %dl = disk number */
135 int $0x13 /* Read MBR into memory */
136 jc boot_cdrom /* CF set on error */
137
138 movb $1, mbr_loaded
139 movb $MBR_PART_COUNT, %cl
140 movw $BOOT_ADDR+MBR_PART_OFFSET, %si
141 1:
142 movb (%si), %al
143 testb $0x80, %al
144 jnz found_active
145 addw $MBR_PART_SIZE, %si
146 decb %cl
147 testb %cl, %cl
148 jnz 1b /* If 0, no active partition found */
149 jmp boot_cdrom
150
151 found_active:
152 movw $str_press_key, %si
153 call message
154 next_second:
155 movw $str_dot, %si
156 call message
157 decb wait_count
158 jz boot_hard_disk
159 xorb %ah, %ah /* Get system time */
160 int $0x1a
161 movw %dx, %di /* %cx:%dx = number of clock ticks */
162 addw $19, %di /* 19 ~= 18.2 Hz */
163 wait_key:
164 movb $1, %ah /* Check for keystroke */
165 int $0x16
166 jz not_avail /* ZF clear if keystroke available */
167 xorb %ah, %ah /* Read key to flush keyboard buf */
168 int $0x16
169 jmp boot_cdrom
170 not_avail:
171 xorb %ah, %ah /* Get system time */
172 int $0x1a
173 cmpw %dx, %di /* Compare with saved time */
174 jnz wait_key
175 jmp next_second
176
177 boot_hard_disk:
178 movw $str_crlf, %si
179 call message
180 cmpb $1, mbr_loaded
181 jz 1f
182 movw $0x0201, %ax /* %al = number of sectors to read */
183 movw $BOOT_ADDR, %bx /* %es:%bx = data buffer */
184 movw $0x0001, %cx /* %ch = low 8 bits of cylinder no */
185 /* %cl = high 2 bits of cyl no & */
186 /* sector number */
187 movw $0x0080, %dx /* %dh = head number */
188 /* %dl = disk number */
189 int $0x13 /* Read MBR into memory */
190 jc panic /* CF set on error */
191 1:
192 movw %cs, %ax /* Restore initial state */
193 movw %ax, %ds
194 movw %ax, %es
195 movw $0x0080, %dx /* %dl = boot drive number */
196 jmp $0, $BOOT_ADDR /* Jump to MBR! */
197 jmp panic /* This should be never executed */
198 #endif /* !DISABLE_KEYPRESS */
199
200 boot_cdrom:
201 movw $str_banner, %si
202 call message
203 movl $VD_LBA, %eax
204 next_block:
205 movb $1, %dh /* Number of sectors to read */
206 movl $PVD_ADDR, %ebx
207 call read_sectors
208 cmpb $VD_PRIMARY, (%bx) /* Is it Primary Volume Descriptor? */
209 jz pvd_found
210 incl %eax
211 cmpb $VD_TERMINATOR, (%bx)
212 jnz next_block
213 movw $str_no_pvd, %si
214 call message
215 jmp panic
216
217 pvd_found:
218 movw $PVD_ADDR+PVD_ROOT_DR, %bx
219 movl DR_EXTENT(%bx), %eax /* LBA of the root directory */
220 movl DR_DATA_LEN(%bx), %edx
221 shrl $11, %edx /* Convert to number of sectors */
222 movb %dl, %dh /* ... and load it to %dh */
223 movl $ROOTDIR_ADDR, %ebx
224 call read_sectors
225 next_entry:
226 cmpb $0, DR_LEN(%bx)
227 jz last_entry
228 movw %bx, %si
229 addw $DR_NAME, %si
230 movb DR_NAME_LEN(%bx), %cl
231 movw $str_loader, %di
232 1:
233 movb (%si), %al
234 cmpb %al, (%di)
235 jnz fail
236 incw %si
237 incw %di
238 decb %cl
239 jnz 1b
240 jmp load_loader
241 fail:
242 addw DR_LEN(%bx), %bx
243 jmp next_entry
244 last_entry:
245 movw $str_no_loader, %si
246 call message
247 jmp panic
248
249 load_loader:
250 movl DR_EXTENT(%bx), %eax
251 movl DR_DATA_LEN(%bx), %edx
252 addl $(BLOCK_SIZE-1), %edx /* Convert file length to */
253 shrl $11, %edx /* ... number of sectors */
254 movb %dl, %dh
255 movl $LOADER_ADDR, %ebx
256 call read_sectors
257 xorl %esi, %esi /* Don't provide boot_params */
258 xorl %edx, %edx
259 movb boot_drive, %dl
260 xorl %ebx, %ebx /* Zero sector number */
261 lcall $LOADER_ADDR/16, $0
262 /* fall through on load failure */
263 panic:
264 hlt
265 jmp panic
266
267 /*
268 * Read disk sector(s) into memory
269 *
270 * %eax = LBA of starting sector
271 * %ebx = buffer to store sectors
272 * %dh = number of sectors to read
273 */
274 read_sectors:
275 pusha
276 movl %eax, edd_lba /* Convert LBA to segment */
277 shrl $4, %ebx
278 movw %bx, edd_segment
279 movb %dh, edd_nsecs
280 movb boot_drive, %dl
281 movw $edd_packet, %si
282 read_again:
283 movb $0x42, %ah
284 int $0x13
285 jc read_fail
286 popa
287 ret
288 read_fail:
289 cmpb $ERROR_TIMEOUT, %ah
290 jz read_again
291 movw $str_read_error, %si
292 call message
293 jmp panic
294
295 /*
296 * For debugging purpose
297 */
298 put_char:
299 pusha
300 movb $0x0e, %ah
301 movw $0x0001, %bx
302 int $0x10
303 popa
304 ret
305
306 #include <message.S>
307
308 edd_packet:
309 edd_len: .word 16
310 edd_nsecs: .word 0 /* Number of sectors to transfer */
311 edd_offset: .word 0
312 edd_segment: .word 0
313 edd_lba: .quad 0
314
315 wait_count: .byte 6
316 boot_drive: .byte 0
317 mbr_loaded: .byte 0
318
319 str_banner: .ascii "\r\nNetBSD/i386 cd9660 Primary Bootstrap"
320 str_crlf: .asciz "\r\n"
321 str_press_key: .asciz "\r\nPress any key to boot from CD"
322 str_dot: .asciz "."
323 str_read_error: .asciz "Can't read CD"
324 str_no_pvd: .asciz "Can't find Primary Volume Descriptor"
325 str_no_loader: .asciz "Can't find /boot"
326 str_loader: .asciz "BOOT.;1"
327
328 /* Used to calculate free bytes */
329 free_space = end - .
330
331 . = start + BLOCK_SIZE
332 end:
333