From 174e3c15af9ac8f7c0cf5794f125bc9247f68a5e Mon Sep 17 00:00:00 2001 From: Evgeniy Ivanov Date: Sat, 14 Jan 2012 22:33:29 +0400 Subject: [PATCH] Import cdboot. --- sys/arch/i386/stand/cdboot/Makefile | 56 +++++ sys/arch/i386/stand/cdboot/cdboot.S | 363 ++++++++++++++++++++++++++++ tools/nbsd_ports | 1 + 3 files changed, 420 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 000000000..7fe141fdd --- /dev/null +++ b/sys/arch/i386/stand/cdboot/Makefile @@ -0,0 +1,56 @@ +# $NetBSD: Makefile,v 1.12 2011/05/20 22:29:55 joerg Exp $ + +S= ${.CURDIR}/../../../.. + +AFLAGS.cdboot.S= ${${ACTIVE_CC} == "clang":?-no-integrated-as:} + +NOMAN= # defined +.include + +STRIPFLAG= # nothing + +LIBCRT0= # nothing +LIBCRTBEGIN= # nothing +LIBCRTEND= # nothing +LIBC= # nothing + +PRIMARY_LOAD_ADDRESS= 0x1000 +SECONDARY_LOAD_ADDRESS= 0x10000 + +PROG= bootxx_cd9660 +SRCS?= cdboot.S + +BINDIR= /usr/mdec +BINMODE= 444 + +.PATH: ${.CURDIR}/.. + +LDFLAGS+= -nostdlib -Wl,-e,start +CPPFLAGS+= -I. -I${.CURDIR}/../lib -I${S} +CPPFLAGS+= -DPRIMARY_LOAD_ADDRESS=${PRIMARY_LOAD_ADDRESS} +CPPFLAGS+= -DSECONDARY_LOAD_ADDRESS=${SECONDARY_LOAD_ADDRESS} +CPPFLAGS+= -DDISABLE_KEYPRESS + +.if ${MACHINE_ARCH} == "x86_64" +LDFLAGS+= -Wl,-m,elf_i386 +AFLAGS+= -m32 +.endif + +BUILDSYMLINKS+= $S/arch/i386/include machine \ + $S/arch/x86/include x86 + +DPSRCS+= machine x86 + +CLEANFILES+= ${PROG}.tmp + +${PROG}: ${OBJS} + ${_MKTARGET_LINK} + ${CC} -o ${PROG}.tmp ${LDFLAGS} -Wl,-Ttext,${PRIMARY_LOAD_ADDRESS} \ + ${OBJS} + @ set -- $$( ${NM} -t d ${PROG}.tmp | grep '\' \ + | ${TOOL_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 000000000..b32d7fa9e --- /dev/null +++ b/sys/arch/i386/stand/cdboot/cdboot.S @@ -0,0 +1,363 @@ +/* $NetBSD: cdboot.S,v 1.12 2011/01/04 16:53:05 jakllsch 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. + * + * 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. + */ + +#include +#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 end /* Where Primary VD is loaded */ +#define ROOTDIR_ADDR end+BLOCK_SIZE /* Where Root Directory is loaded */ +#define LOADER_ADDR SECONDARY_LOAD_ADDRESS + +#ifdef BOOT_FROM_FAT +#define MBR_AFTERBPB 90 /* BPB size in FAT32 partition BR */ +#else +#define MBR_AFTERBPB 62 /* BPB size in floppy master BR */ +#endif + +/* + * See src/sys/sys/bootblock.h for details. + */ +#define MBR_PART_COUNT 4 +#define MBR_PART_OFFSET 446 +#define MBR_PART_SIZE 16 /* sizeof(struct mbr_partition) */ + +/* + * 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) + jmp start1 + + . = start + MBR_AFTERBPB /* skip BPB */ + . = start + MBR_DSN_OFFSET + .long 0 + +/* mbr_bootsel_magic (not used here) */ + . = start + MBR_BS_MAGIC_OFFSET + .word 0 + + . = start + MBR_PART_OFFSET + . = start + MBR_MAGIC_OFFSET +pbr_magic: + .word MBR_MAGIC + .fill 512 /* reserve space for disklabel */ +start1: + jmp 1f + .balign 4 + .long X86_BOOT_MAGIC_1 /* checked by installboot & pbr code */ +boot_params: /* space for patchable variables */ + .long 1f - boot_params /* length of this data area */ +#include + . = start1 + 0x80 /* Space for patching unknown params */ + +1: 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 */ + +#ifndef DISABLE_KEYPRESS + /* + * We can skip boot wait when: + * - there's no hard disk present. + * - there's no active partition in the MBR of the 1st hard disk. + */ + + /* + * Check presence of hard disks. + */ + movw $0x475, %si + movb (%si), %al + testb %al, %al + jz boot_cdrom + + /* + * Find the active partition from the MBR. + */ + 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 boot_cdrom /* CF set on error */ + + movb $1, mbr_loaded + movb $MBR_PART_COUNT, %cl + movw $BOOT_ADDR+MBR_PART_OFFSET, %si +1: + movb (%si), %al + testb $0x80, %al + jnz found_active + addw $MBR_PART_SIZE, %si + decb %cl + testb %cl, %cl + jnz 1b /* If 0, no active partition found */ + jmp boot_cdrom + +found_active: + 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 + cmpb $1, mbr_loaded + jz 1f + 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 */ +1: + 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! */ + jmp panic /* This should be never executed */ +#endif /* !DISABLE_KEYPRESS */ + +boot_cdrom: + movw $str_banner, %si + call message + +/* Read volume descriptor sectors until Primary decriptor found */ + 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 + +/* Read all of root directory */ +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 + +/* Scan directory entries searching for /boot */ +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 + +/* Found /boot, read contents to 0x1000:0 */ +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 + +/* Finally call into code of /boot */ + movl $boot_params, %esi /* Provide boot_params */ + xorl %edx, %edx + movb boot_drive, %dl + xorl %ebx, %ebx /* Zero sector number */ + lcall $LOADER_ADDR/16, $0 + /* fall through on load failure */ +panic: + hlt + jmp panic + +/* + * Read disk sector(s) into memory + * + * %eax = LBA of starting sector + * %ebx = buffer to store sectors + * %dh = number of sectors to read + * + * Long transfers are split onto multiple 64k reads + */ +#define MAX_SECTORS (0x10000/BLOCK_SIZE) +read_sectors: + pushal + movl %eax, edd_lba + shrl $4, %ebx /* Convert buffer addr to seg:0 */ + movw %bx, edd_segment +1: movb %dh, edd_nsecs + cmpb $MAX_SECTORS, %dh + jle 2f /* j if less than 64k */ + movb $MAX_SECTORS, edd_nsecs /* Read 32 sectors - 64k bytes */ +2: movb boot_drive, %dl + movw $edd_packet, %si +read_again: + movb $0x42, %ah + push %dx /* bios shouldn't kill %dh, but ... */ + int $0x13 + pop %dx /* ... better safe than sorry! */ + jc read_fail + addw $0x1000, edd_segment /* Advance segment addr by 64k bytes */ + addl $MAX_SECTORS, edd_lba /* And sector number to match */ + sub edd_nsecs, %dh /* Number of sectors remaining */ + jnz 1b + popal + ret + +read_fail: + cmpb $ERROR_TIMEOUT, %ah + jz read_again + movw $str_read_error, %si + call message + jmp panic + +#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 +mbr_loaded: .byte 0 + +str_banner: .ascii "\r\nNetBSD/x86 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: diff --git a/tools/nbsd_ports b/tools/nbsd_ports index 79e451193..f64ba4e51 100644 --- a/tools/nbsd_ports +++ b/tools/nbsd_ports @@ -45,6 +45,7 @@ dist/bzip2 src/dist/bzip2 share/zoneinfo src/share/zoneinfo sys/arch/i386/stand/bootxx src/sys/arch/i386/stand/bootxx sys/arch/i386/stand/boot src/sys/arch/i386/stand/boot +sys/arch/i386/stand/cdboot src/sys/arch/i386/stand/cdboot sys/arch/i386/stand/mbr src/sys/arch/i386/stand/mbr sys/arch/i386/stand/lib src/sys/arch/i386/stand/lib sys/lib/libsa src/sys/lib/libsa