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