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