From 0da67fb4ba69d6419065b9438cd4a67c6bf8d211 Mon Sep 17 00:00:00 2001 From: junyoung Date: Wed, 15 Jun 2005 06:38:45 +0000 Subject: [PATCH] Initial commit of cdboot, a primary boot loader that loads a secondary boot loader directly from CD without performing floppy/hard disk emulation as described by the El Torito specification. --- sys/arch/i386/stand/cdboot/Makefile | 63 +++++++ sys/arch/i386/stand/cdboot/cdboot.S | 277 ++++++++++++++++++++++++++++ 2 files changed, 340 insertions(+) create mode 100644 sys/arch/i386/stand/cdboot/Makefile create mode 100644 sys/arch/i386/stand/cdboot/cdboot.S diff --git a/sys/arch/i386/stand/cdboot/Makefile b/sys/arch/i386/stand/cdboot/Makefile new file mode 100644 index 000000000000..c199cca8c058 --- /dev/null +++ b/sys/arch/i386/stand/cdboot/Makefile @@ -0,0 +1,63 @@ +# $NetBSD: Makefile,v 1.1 2005/06/15 06:38:45 junyoung Exp $ + +S= ${.CURDIR}/../../../../../ + +NOMAN= # defined +STRIPFLAG= # nothing + +LIBCRT0= # nothing +LIBCRTBEGIN= # nothing +LIBCRTEND= # nothing +LIBC= # nothing + +PRIMARY_LOAD_ADDRESS=0x600 +SECONDARY_LOAD_ADDRESS=0x10000 + +.include + +PROG= cdboot +SRCS?= cdboot.S + +BINDIR= /usr/mdec +BINMODE=444 + +.PATH: ${.CURDIR}/.. + +LDFLAGS+= -e start +CPPFLAGS+= -I. -I${.CURDIR}/../lib -I${S} +CPPFLAGS+= -DPRIMARY_LOAD_ADDRESS=${PRIMARY_LOAD_ADDRESS} +CPPFLAGS+= -DSECONDARY_LOAD_ADDRESS=${SECONDARY_LOAD_ADDRESS} + +.if ${MACHINE} == "amd64" +LDFLAGS+= -m elf_i386 +AFLAGS+= -m32 +.endif + +.if !make(obj) && !make(clean) && !make(cleandir) +.BEGIN: machine x86 +.NOPATH: machine x86 +.endif + +realdepend realall: machine x86 +CLEANFILES+= machine x86 + +machine:: + -rm -f $@ + ln -s $S/arch/i386/include $@ + +x86:: + -rm -f $@ + ln -s $S/arch/x86/include $@ + +${OBJS}: machine x86 + +CLEANFILES+= ${PROG}.tmp + +${PROG}: ${OBJS} + ${LD} -o ${PROG}.tmp ${LDFLAGS} -Ttext ${PRIMARY_LOAD_ADDRESS} ${OBJS} + @ set -- $$( ${NM} -t d ${PROG}.tmp | grep '\' | sed 's/^0*//' ); \ + echo "#### There are $$1 free bytes in ${PROG}" + ${OBJCOPY} -O binary ${PROG}.tmp ${PROG} + rm -f ${PROG}.tmp + +.include diff --git a/sys/arch/i386/stand/cdboot/cdboot.S b/sys/arch/i386/stand/cdboot/cdboot.S new file mode 100644 index 000000000000..9b44651c4e8d --- /dev/null +++ b/sys/arch/i386/stand/cdboot/cdboot.S @@ -0,0 +1,277 @@ +/* $NetBSD: cdboot.S,v 1.1 2005/06/15 06:38:45 junyoung Exp $ */ + +/*- + * Copyright (c) 2005 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Bang Jun-Young. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This is a primary boot loader that loads a secondary boot loader + * directly from CD without performing floppy/hard disk emulation as + * described by the El Torito specification. + * + * TODO: + * - Support for loading secondary boot loader > 64kB + */ + +#include + +#define BOOT_ADDR 0x7c00 +#define BLOCK_SIZE 2048 /* Default for ISO 9660 */ +#define VD_LBA 16 /* LBA of Volume Descriptor (VD) */ +#define PVD_ADDR 0x1000 /* Where Primary VD is loaded */ +#define ROOTDIR_ADDR 0x1800 /* Where Root Directory is loaded */ +#define LOADER_ADDR SECONDARY_LOAD_ADDRESS + +/* + * Disk error codes + */ +#define ERROR_TIMEOUT 0x80 + +/* + * Volume Descriptor types. + */ +#define VD_PRIMARY 1 +#define VD_SUPPLEMENTARY 2 +#define VD_TERMINATOR 255 + +/* Only actually used entries are listed below */ + +/* + * Format of Primary Volume Descriptor (8.4) + */ +#define PVD_ROOT_DR 156 /* Offset of Root Directory Record */ + +/* + * Format of Directory Record (9.1) + */ +#define DR_LEN 0 +#define DR_EXTENT 2 +#define DR_DATA_LEN 10 +#define DR_NAME_LEN 32 +#define DR_NAME 33 + + .text + .code16 +ENTRY(start) + xorw %ax, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw $BOOT_ADDR, %sp + movw %sp, %si + movw $start, %di + movw $BLOCK_SIZE/2, %cx + rep + movsw + ljmp $0, $real_start + +real_start: + movb %dl, boot_drive /* Save boot drive number */ + movw $str_press_key, %si + call message +next_second: + movw $str_dot, %si + call message + decb wait_count + jz boot_hard_disk + xorb %ah, %ah /* Get system time */ + int $0x1a + movw %dx, %di /* %cx:%dx = number of clock ticks */ + addw $19, %di /* 19 ~= 18.2 Hz */ +wait_key: + movb $1, %ah /* Check for keystroke */ + int $0x16 + jz not_avail /* ZF clear if keystroke available */ + xorb %ah, %ah /* Read key to flush keyboard buf */ + int $0x16 + jmp boot_cdrom +not_avail: + xorb %ah, %ah /* Get system time */ + int $0x1a + cmpw %dx, %di /* Compare with saved time */ + jnz wait_key + jmp next_second + +boot_hard_disk: + movw $str_crlf, %si + call message + movw $0x0201, %ax /* %al = number of sectors to read */ + movw $BOOT_ADDR, %bx /* %es:%bx = data buffer */ + movw $0x0001, %cx /* %ch = low 8 bits of cylinder no */ + /* %cl = high 2 bits of cyl no & */ + /* sector number */ + movw $0x0080, %dx /* %dh = head number */ + /* %dl = disk number */ + int $0x13 /* Read MBR into memory */ + jc panic /* CF set on error */ + movw %cs, %ax /* Restore initial state */ + movw %ax, %ds + movw %ax, %es + movw $0x0080, %dx /* %dl = boot drive number */ + jmp $0, $BOOT_ADDR /* Jump to MBR! */ + +panic: + hlt + jmp panic + +boot_cdrom: + movw $str_banner, %si + call message + movl $VD_LBA, %eax +next_block: + movb $1, %dh /* Number of sectors to read */ + movl $PVD_ADDR, %ebx + call read_sectors + cmpb $VD_PRIMARY, (%bx) /* Is it Primary Volume Descriptor? */ + jz pvd_found + incl %eax + cmpb $VD_TERMINATOR, (%bx) + jnz next_block + movw $str_no_pvd, %si + call message + jmp panic + +pvd_found: + movw $PVD_ADDR+PVD_ROOT_DR, %bx + movl DR_EXTENT(%bx), %eax /* LBA of the root directory */ + movl DR_DATA_LEN(%bx), %edx + shrl $11, %edx /* Convert to number of sectors */ + movb %dl, %dh /* ... and load it to %dh */ + movl $ROOTDIR_ADDR, %ebx + call read_sectors +next_entry: + cmpb $0, DR_LEN(%bx) + jz last_entry + movw %bx, %si + addw $DR_NAME, %si + movb DR_NAME_LEN(%bx), %cl + movw $str_loader, %di +1: + movb (%si), %al + cmpb %al, (%di) + jnz fail + incw %si + incw %di + decb %cl + jnz 1b + jmp load_loader +fail: + addw DR_LEN(%bx), %bx + jmp next_entry +last_entry: + movw $str_no_loader, %si + call message + jmp panic + +load_loader: + movl DR_EXTENT(%bx), %eax + movl DR_DATA_LEN(%bx), %edx + addl $(BLOCK_SIZE-1), %edx /* Convert file length to */ + shrl $11, %edx /* ... number of sectors */ + movb %dl, %dh + movl $LOADER_ADDR, %ebx + call read_sectors + xorl %esi, %esi /* Don't provide boot_params */ + xorl %edx, %edx + movb boot_drive, %dl + xorl %ebx, %ebx /* Zero sector number */ + lcall $LOADER_ADDR/16, $0 + jmp panic + +/* + * Read disk sector(s) into memory + * + * %eax = LBA of starting sector + * %ebx = buffer to store sectors + * %dh = number of sectors to read + */ +read_sectors: + pusha + movl %eax, edd_lba /* Convert LBA to segment */ + shrl $4, %ebx + movw %bx, edd_segment + movb %dh, edd_nsecs + movb boot_drive, %dl + movw $edd_packet, %si +read_again: + movb $0x42, %ah + int $0x13 + jc read_fail + popa + ret +read_fail: + cmpb $ERROR_TIMEOUT, %ah + jz read_again + movw $str_read_error, %si + call message + jmp panic + +/* + * For debugging purpose + */ +put_char: + pusha + movb $0x0e, %ah + movw $0x0001, %bx + int $0x10 + popa + ret + +#include + +edd_packet: +edd_len: .word 16 +edd_nsecs: .word 0 /* Number of sectors to transfer */ +edd_offset: .word 0 +edd_segment: .word 0 +edd_lba: .quad 0 + +wait_count: .byte 6 +boot_drive: .byte 0 + +str_banner: .ascii "\r\nNetBSD/i386 cd9660 Primary Bootstrap" +str_crlf: .asciz "\r\n" +str_press_key: .asciz "\r\nPress any key to boot from CD" +str_dot: .asciz "." +str_read_error: .asciz "Can't read CD" +str_no_pvd: .asciz "Can't find Primary Volume Descriptor" +str_no_loader: .asciz "Can't find /boot" +str_loader: .asciz "BOOT.;1" + +/* Used to calculate free bytes */ +free_space = end - . + + . = start + BLOCK_SIZE +end: