cdboot.S revision 1.5 1 /* $NetBSD: cdboot.S,v 1.5 2005/10/06 08:19:46 dyoung 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 #include <sys/bootblock.h>
50
51 #define BOOT_ADDR 0x7c00
52 #define BLOCK_SIZE 2048 /* Default for ISO 9660 */
53 #define VD_LBA 16 /* LBA of Volume Descriptor (VD) */
54 #define PVD_ADDR 0x1000 /* Where Primary VD is loaded */
55 #define ROOTDIR_ADDR 0x1800 /* Where Root Directory is loaded */
56 #define LOADER_ADDR SECONDARY_LOAD_ADDRESS
57
58 #ifdef BOOT_FROM_FAT
59 #define MBR_AFTERBPB 90 /* BPB size in FAT32 partition BR */
60 #else
61 #define MBR_AFTERBPB 62 /* BPB size in floppy master BR */
62 #endif
63
64 /*
65 * See src/sys/sys/bootblock.h for details.
66 */
67 #define MBR_PART_COUNT 4
68 #define MBR_PART_OFFSET 446
69 #define MBR_PART_SIZE 16 /* sizeof(struct mbr_partition) */
70
71 /*
72 * Disk error codes
73 */
74 #define ERROR_TIMEOUT 0x80
75
76 /*
77 * Volume Descriptor types.
78 */
79 #define VD_PRIMARY 1
80 #define VD_SUPPLEMENTARY 2
81 #define VD_TERMINATOR 255
82
83 /* Only actually used entries are listed below */
84
85 /*
86 * Format of Primary Volume Descriptor (8.4)
87 */
88 #define PVD_ROOT_DR 156 /* Offset of Root Directory Record */
89
90 /*
91 * Format of Directory Record (9.1)
92 */
93 #define DR_LEN 0
94 #define DR_EXTENT 2
95 #define DR_DATA_LEN 10
96 #define DR_NAME_LEN 32
97 #define DR_NAME 33
98
99 .text
100 .code16
101 ENTRY(start)
102 jmp start1
103
104 . = start + MBR_AFTERBPB /* skip BPB */
105 . = start + MBR_DSN_OFFSET
106 .long 0
107
108 /* mbr_bootsel_magic (not used here) */
109 . = start + MBR_BS_MAGIC_OFFSET
110 .word 0
111
112 . = start + MBR_PART_OFFSET
113 . = start + MBR_MAGIC_OFFSET
114 pbr_magic:
115 .word MBR_MAGIC
116 .fill 512 /* reserve space for disklabel */
117 start1:
118 jmp 1f
119 .balign 4
120 .long X86_BOOT_MAGIC_1 /* checked by installboot & pbr code */
121 boot_params: /* space for patchable variables */
122 .long 1f - boot_params /* length of this data area */
123 #include <boot_params.S>
124 . = start1 + 0x80 /* Space for patching unknown params */
125
126 1: xorw %ax, %ax
127 movw %ax, %ds
128 movw %ax, %es
129 movw %ax, %ss
130 movw $BOOT_ADDR, %sp
131 movw %sp, %si
132 movw $start, %di
133 movw $BLOCK_SIZE/2, %cx
134 rep
135 movsw
136 ljmp $0, $real_start
137
138 real_start:
139 movb %dl, boot_drive /* Save boot drive number */
140
141 #ifndef DISABLE_KEYPRESS
142 /*
143 * We can skip boot wait when:
144 * - there's no hard disk present.
145 * - there's no active partition in the MBR of the 1st hard disk.
146 */
147
148 /*
149 * Check presence of hard disks.
150 */
151 movw $0x475, %si
152 movb (%si), %al
153 testb %al, %al
154 jz boot_cdrom
155
156 /*
157 * Find the active partition from the MBR.
158 */
159 movw $0x0201, %ax /* %al = number of sectors to read */
160 movw $BOOT_ADDR, %bx /* %es:%bx = data buffer */
161 movw $0x0001, %cx /* %ch = low 8 bits of cylinder no */
162 /* %cl = high 2 bits of cyl no & */
163 /* sector number */
164 movw $0x0080, %dx /* %dh = head number */
165 /* %dl = disk number */
166 int $0x13 /* Read MBR into memory */
167 jc boot_cdrom /* CF set on error */
168
169 movb $1, mbr_loaded
170 movb $MBR_PART_COUNT, %cl
171 movw $BOOT_ADDR+MBR_PART_OFFSET, %si
172 1:
173 movb (%si), %al
174 testb $0x80, %al
175 jnz found_active
176 addw $MBR_PART_SIZE, %si
177 decb %cl
178 testb %cl, %cl
179 jnz 1b /* If 0, no active partition found */
180 jmp boot_cdrom
181
182 found_active:
183 movw $str_press_key, %si
184 call message
185 next_second:
186 movw $str_dot, %si
187 call message
188 decb wait_count
189 jz boot_hard_disk
190 xorb %ah, %ah /* Get system time */
191 int $0x1a
192 movw %dx, %di /* %cx:%dx = number of clock ticks */
193 addw $19, %di /* 19 ~= 18.2 Hz */
194 wait_key:
195 movb $1, %ah /* Check for keystroke */
196 int $0x16
197 jz not_avail /* ZF clear if keystroke available */
198 xorb %ah, %ah /* Read key to flush keyboard buf */
199 int $0x16
200 jmp boot_cdrom
201 not_avail:
202 xorb %ah, %ah /* Get system time */
203 int $0x1a
204 cmpw %dx, %di /* Compare with saved time */
205 jnz wait_key
206 jmp next_second
207
208 boot_hard_disk:
209 movw $str_crlf, %si
210 call message
211 cmpb $1, mbr_loaded
212 jz 1f
213 movw $0x0201, %ax /* %al = number of sectors to read */
214 movw $BOOT_ADDR, %bx /* %es:%bx = data buffer */
215 movw $0x0001, %cx /* %ch = low 8 bits of cylinder no */
216 /* %cl = high 2 bits of cyl no & */
217 /* sector number */
218 movw $0x0080, %dx /* %dh = head number */
219 /* %dl = disk number */
220 int $0x13 /* Read MBR into memory */
221 jc panic /* CF set on error */
222 1:
223 movw %cs, %ax /* Restore initial state */
224 movw %ax, %ds
225 movw %ax, %es
226 movw $0x0080, %dx /* %dl = boot drive number */
227 jmp $0, $BOOT_ADDR /* Jump to MBR! */
228 jmp panic /* This should be never executed */
229 #endif /* !DISABLE_KEYPRESS */
230
231 boot_cdrom:
232 movw $str_banner, %si
233 call message
234 movl $VD_LBA, %eax
235 next_block:
236 movb $1, %dh /* Number of sectors to read */
237 movl $PVD_ADDR, %ebx
238 call read_sectors
239 cmpb $VD_PRIMARY, (%bx) /* Is it Primary Volume Descriptor? */
240 jz pvd_found
241 incl %eax
242 cmpb $VD_TERMINATOR, (%bx)
243 jnz next_block
244 movw $str_no_pvd, %si
245 call message
246 jmp panic
247
248 pvd_found:
249 movw $PVD_ADDR+PVD_ROOT_DR, %bx
250 movl DR_EXTENT(%bx), %eax /* LBA of the root directory */
251 movl DR_DATA_LEN(%bx), %edx
252 shrl $11, %edx /* Convert to number of sectors */
253 movb %dl, %dh /* ... and load it to %dh */
254 movl $ROOTDIR_ADDR, %ebx
255 call read_sectors
256 next_entry:
257 cmpb $0, DR_LEN(%bx)
258 jz last_entry
259 movw %bx, %si
260 addw $DR_NAME, %si
261 movb DR_NAME_LEN(%bx), %cl
262 movw $str_loader, %di
263 1:
264 movb (%si), %al
265 cmpb %al, (%di)
266 jnz fail
267 incw %si
268 incw %di
269 decb %cl
270 jnz 1b
271 jmp load_loader
272 fail:
273 addw DR_LEN(%bx), %bx
274 jmp next_entry
275 last_entry:
276 movw $str_no_loader, %si
277 call message
278 jmp panic
279
280 load_loader:
281 movl DR_EXTENT(%bx), %eax
282 movl DR_DATA_LEN(%bx), %edx
283 addl $(BLOCK_SIZE-1), %edx /* Convert file length to */
284 shrl $11, %edx /* ... number of sectors */
285 movb %dl, %dh
286 movl $LOADER_ADDR, %ebx
287 call read_sectors
288 movl $boot_params, %esi /* Provide boot_params */
289 xorl %edx, %edx
290 movb boot_drive, %dl
291 xorl %ebx, %ebx /* Zero sector number */
292 lcall $LOADER_ADDR/16, $0
293 /* fall through on load failure */
294 panic:
295 hlt
296 jmp panic
297
298 /*
299 * Read disk sector(s) into memory
300 *
301 * %eax = LBA of starting sector
302 * %ebx = buffer to store sectors
303 * %dh = number of sectors to read
304 */
305 read_sectors:
306 pusha
307 movl %eax, edd_lba /* Convert LBA to segment */
308 shrl $4, %ebx
309 movw %bx, edd_segment
310 movb %dh, edd_nsecs
311 movb boot_drive, %dl
312 movw $edd_packet, %si
313 read_again:
314 movb $0x42, %ah
315 int $0x13
316 jc read_fail
317 popa
318 ret
319 read_fail:
320 cmpb $ERROR_TIMEOUT, %ah
321 jz read_again
322 movw $str_read_error, %si
323 call message
324 jmp panic
325
326 /*
327 * For debugging purpose
328 */
329 put_char:
330 pusha
331 movb $0x0e, %ah
332 movw $0x0001, %bx
333 int $0x10
334 popa
335 ret
336
337 #include <message.S>
338
339 edd_packet:
340 edd_len: .word 16
341 edd_nsecs: .word 0 /* Number of sectors to transfer */
342 edd_offset: .word 0
343 edd_segment: .word 0
344 edd_lba: .quad 0
345
346 wait_count: .byte 6
347 boot_drive: .byte 0
348 mbr_loaded: .byte 0
349
350 str_banner: .ascii "\r\nNetBSD/i386 cd9660 Primary Bootstrap"
351 str_crlf: .asciz "\r\n"
352 str_press_key: .asciz "\r\nPress any key to boot from CD"
353 str_dot: .asciz "."
354 str_read_error: .asciz "Can't read CD"
355 str_no_pvd: .asciz "Can't find Primary Volume Descriptor"
356 str_no_loader: .asciz "Can't find /boot"
357 str_loader: .asciz "BOOT.;1"
358
359 /* Used to calculate free bytes */
360 free_space = end - .
361
362 . = start + BLOCK_SIZE
363 end:
364