cdboot.S revision 1.2 1 /* $NetBSD: cdboot.S,v 1.2 2005/07/06 09:22:31 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 * Disk error codes
59 */
60 #define ERROR_TIMEOUT 0x80
61
62 /*
63 * Volume Descriptor types.
64 */
65 #define VD_PRIMARY 1
66 #define VD_SUPPLEMENTARY 2
67 #define VD_TERMINATOR 255
68
69 /* Only actually used entries are listed below */
70
71 /*
72 * Format of Primary Volume Descriptor (8.4)
73 */
74 #define PVD_ROOT_DR 156 /* Offset of Root Directory Record */
75
76 /*
77 * Format of Directory Record (9.1)
78 */
79 #define DR_LEN 0
80 #define DR_EXTENT 2
81 #define DR_DATA_LEN 10
82 #define DR_NAME_LEN 32
83 #define DR_NAME 33
84
85 .text
86 .code16
87 ENTRY(start)
88 xorw %ax, %ax
89 movw %ax, %ds
90 movw %ax, %es
91 movw %ax, %ss
92 movw $BOOT_ADDR, %sp
93 movw %sp, %si
94 movw $start, %di
95 movw $BLOCK_SIZE/2, %cx
96 rep
97 movsw
98 ljmp $0, $real_start
99
100 real_start:
101 movb %dl, boot_drive /* Save boot drive number */
102
103 movw $0x475, %si /* Check presence of hard disks */
104 movb (%si), %al
105 testb %al, %al
106 jz boot_cdrom
107
108 movw $str_press_key, %si
109 call message
110 next_second:
111 movw $str_dot, %si
112 call message
113 decb wait_count
114 jz boot_hard_disk
115 xorb %ah, %ah /* Get system time */
116 int $0x1a
117 movw %dx, %di /* %cx:%dx = number of clock ticks */
118 addw $19, %di /* 19 ~= 18.2 Hz */
119 wait_key:
120 movb $1, %ah /* Check for keystroke */
121 int $0x16
122 jz not_avail /* ZF clear if keystroke available */
123 xorb %ah, %ah /* Read key to flush keyboard buf */
124 int $0x16
125 jmp boot_cdrom
126 not_avail:
127 xorb %ah, %ah /* Get system time */
128 int $0x1a
129 cmpw %dx, %di /* Compare with saved time */
130 jnz wait_key
131 jmp next_second
132
133 boot_hard_disk:
134 movw $str_crlf, %si
135 call message
136 movw $0x0201, %ax /* %al = number of sectors to read */
137 movw $BOOT_ADDR, %bx /* %es:%bx = data buffer */
138 movw $0x0001, %cx /* %ch = low 8 bits of cylinder no */
139 /* %cl = high 2 bits of cyl no & */
140 /* sector number */
141 movw $0x0080, %dx /* %dh = head number */
142 /* %dl = disk number */
143 int $0x13 /* Read MBR into memory */
144 jc panic /* CF set on error */
145 movw %cs, %ax /* Restore initial state */
146 movw %ax, %ds
147 movw %ax, %es
148 movw $0x0080, %dx /* %dl = boot drive number */
149 jmp $0, $BOOT_ADDR /* Jump to MBR! */
150
151 panic:
152 hlt
153 jmp panic
154
155 boot_cdrom:
156 movw $str_banner, %si
157 call message
158 movl $VD_LBA, %eax
159 next_block:
160 movb $1, %dh /* Number of sectors to read */
161 movl $PVD_ADDR, %ebx
162 call read_sectors
163 cmpb $VD_PRIMARY, (%bx) /* Is it Primary Volume Descriptor? */
164 jz pvd_found
165 incl %eax
166 cmpb $VD_TERMINATOR, (%bx)
167 jnz next_block
168 movw $str_no_pvd, %si
169 call message
170 jmp panic
171
172 pvd_found:
173 movw $PVD_ADDR+PVD_ROOT_DR, %bx
174 movl DR_EXTENT(%bx), %eax /* LBA of the root directory */
175 movl DR_DATA_LEN(%bx), %edx
176 shrl $11, %edx /* Convert to number of sectors */
177 movb %dl, %dh /* ... and load it to %dh */
178 movl $ROOTDIR_ADDR, %ebx
179 call read_sectors
180 next_entry:
181 cmpb $0, DR_LEN(%bx)
182 jz last_entry
183 movw %bx, %si
184 addw $DR_NAME, %si
185 movb DR_NAME_LEN(%bx), %cl
186 movw $str_loader, %di
187 1:
188 movb (%si), %al
189 cmpb %al, (%di)
190 jnz fail
191 incw %si
192 incw %di
193 decb %cl
194 jnz 1b
195 jmp load_loader
196 fail:
197 addw DR_LEN(%bx), %bx
198 jmp next_entry
199 last_entry:
200 movw $str_no_loader, %si
201 call message
202 jmp panic
203
204 load_loader:
205 movl DR_EXTENT(%bx), %eax
206 movl DR_DATA_LEN(%bx), %edx
207 addl $(BLOCK_SIZE-1), %edx /* Convert file length to */
208 shrl $11, %edx /* ... number of sectors */
209 movb %dl, %dh
210 movl $LOADER_ADDR, %ebx
211 call read_sectors
212 xorl %esi, %esi /* Don't provide boot_params */
213 xorl %edx, %edx
214 movb boot_drive, %dl
215 xorl %ebx, %ebx /* Zero sector number */
216 lcall $LOADER_ADDR/16, $0
217 jmp panic
218
219 /*
220 * Read disk sector(s) into memory
221 *
222 * %eax = LBA of starting sector
223 * %ebx = buffer to store sectors
224 * %dh = number of sectors to read
225 */
226 read_sectors:
227 pusha
228 movl %eax, edd_lba /* Convert LBA to segment */
229 shrl $4, %ebx
230 movw %bx, edd_segment
231 movb %dh, edd_nsecs
232 movb boot_drive, %dl
233 movw $edd_packet, %si
234 read_again:
235 movb $0x42, %ah
236 int $0x13
237 jc read_fail
238 popa
239 ret
240 read_fail:
241 cmpb $ERROR_TIMEOUT, %ah
242 jz read_again
243 movw $str_read_error, %si
244 call message
245 jmp panic
246
247 /*
248 * For debugging purpose
249 */
250 put_char:
251 pusha
252 movb $0x0e, %ah
253 movw $0x0001, %bx
254 int $0x10
255 popa
256 ret
257
258 #include <message.S>
259
260 edd_packet:
261 edd_len: .word 16
262 edd_nsecs: .word 0 /* Number of sectors to transfer */
263 edd_offset: .word 0
264 edd_segment: .word 0
265 edd_lba: .quad 0
266
267 wait_count: .byte 6
268 boot_drive: .byte 0
269
270 str_banner: .ascii "\r\nNetBSD/i386 cd9660 Primary Bootstrap"
271 str_crlf: .asciz "\r\n"
272 str_press_key: .asciz "\r\nPress any key to boot from CD"
273 str_dot: .asciz "."
274 str_read_error: .asciz "Can't read CD"
275 str_no_pvd: .asciz "Can't find Primary Volume Descriptor"
276 str_no_loader: .asciz "Can't find /boot"
277 str_loader: .asciz "BOOT.;1"
278
279 /* Used to calculate free bytes */
280 free_space = end - .
281
282 . = start + BLOCK_SIZE
283 end:
284