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