From: Evgeniy Ivanov Date: Tue, 10 Jan 2012 10:01:31 +0000 (+0400) Subject: Import sys/arch/i386/stand/mbr. X-Git-Tag: v3.2.0~73 X-Git-Url: http://zhaoyanbai.com/repos/FAQ?a=commitdiff_plain;h=6acebc04b6ef9bef93e88445c396983c564df841;p=minix.git Import sys/arch/i386/stand/mbr. --- diff --git a/sys/arch/i386/stand/mbr/Makefile b/sys/arch/i386/stand/mbr/Makefile new file mode 100644 index 000000000..ca815ac35 --- /dev/null +++ b/sys/arch/i386/stand/mbr/Makefile @@ -0,0 +1,6 @@ +# $NetBSD: Makefile,v 1.4 2011/08/17 00:25:05 jakllsch Exp $ + +SUBDIR= mbr mbr_bootsel mbr_ext mbr_com0 mbr_com0_9600 +SUBDIR+= gptmbr + +.include diff --git a/sys/arch/i386/stand/mbr/Makefile.mbr b/sys/arch/i386/stand/mbr/Makefile.mbr new file mode 100644 index 000000000..5dc35ab1c --- /dev/null +++ b/sys/arch/i386/stand/mbr/Makefile.mbr @@ -0,0 +1,56 @@ +# $NetBSD: Makefile.mbr,v 1.18 2011/05/20 15:05:02 joerg Exp $ + +S= ${.CURDIR}/../../../../.. + +NOMAN= # defined + +LIBCRT0= # nothing +LIBCRTBEGIN= # nothing +LIBCRTEND= # nothing +LIBC= # nothing + +PIE_CFLAGS= +PIE_LDFLAGS= +PIE_AFLAGS= + +.include + +STRIPFLAG= # override + +SRCS?= mbr.S + +BINDIR= /usr/mdec +BINMODE= 444 + +.PATH: ${.CURDIR}/.. + +LDFLAGS+= -nostdlib -Wl,-e,start +CPPFLAGS+= -I. -I${.CURDIR}/../../lib -I${S} + +.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 + +LOADADDR= 0x8800 + +AFLAGS.mbr.S= ${${ACTIVE_CC} == "clang":?-no-integrated-as:} +AFLAGS.gpt.S= ${${ACTIVE_CC} == "clang":?-no-integrated-as:} + +${PROG}: ${OBJS} + ${_MKTARGET_LINK} + ${CC} -o ${PROG}.tmp ${LDFLAGS} -Wl,-Ttext,${LOADADDR} ${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/mbr/gpt.S b/sys/arch/i386/stand/mbr/gpt.S new file mode 100644 index 000000000..8dd53733e --- /dev/null +++ b/sys/arch/i386/stand/mbr/gpt.S @@ -0,0 +1,552 @@ +/* $NetBSD: gpt.S,v 1.1 2011/01/06 01:08:49 jakllsch Exp $ */ + +/* + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to the NetBSD Foundation + * by Mike M. Volokhov, based on the mbr.S code by Wolfgang Solfrank, + * Frank van der Linden, and David Laight. + * Development of this software was supported by the + * Google Summer of Code program. + * The GSoC project was mentored by Allen Briggs and Joerg Sonnenberger. + * + * 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. + */ + +/* + * x86 PC BIOS master boot code - GUID partition table format + */ + +/* Compile options: + * COM_PORT - do serial io to specified port number + * 0..3 => bios port, otherwise actual io_addr + * COM_BAUD - initialise serial port baud rate + * + * NO_LBA_CHECK - no check if bios supports LBA reads + * NO_CRC_CHECK - disable crc checks for GPT + * NO_BANNER - do not output title line 'banner' + */ + +#ifdef COM_PORT +#if COM_PORT < 4 +/* The first 4 items in the 40:xx segment are the serial port base addresses */ +#define COM_PORT_VAL (0x400 + (COM_PORT * 2)) +#else +#define COM_PORT_VAL $COM_PORT +#endif + +#if !defined(COM_FREQ) +#define COM_FREQ 1843200 +#endif +#endif + +#include +#include + +#define BOOTADDR 0x7c00 +#define GPTBUFADDR 0xa000 /* GPT buffer (both header & array) */ + +/* + * GPT header structure, offsets + */ +#define GPTHDR_SIG_O 0 /* header signature, 8 b */ +#define GPTHDR_REV_O 8 /* GPT revision, 4 b */ +#define GPTHDR_SIZE_O 12 /* header size, 4 b */ +#define GPTHDR_CRC_O 16 /* header CRC32, 4 b */ +#define GPTHDR_RSVD_O 20 /* reserved, 4 b */ +#define GPTHDR_MYLBA_O 24 /* this header LBA, 8 b */ +#define GPTHDR_ALTLBA_O 32 /* alternate header LBA, 8 b */ +#define GPTHDR_SLBA_O 40 /* first usable LBA, 8 b */ +#define GPTHDR_ELBA_O 48 /* last usable LBA, 8 b */ +#define GPTHDR_GUID_O 56 /* disk GUID, 16 b */ +#define GPTHDR_PTNLBA_O 72 /* ptn. entry LBA, 8 b */ +#define GPTHDR_PTNN_O 80 /* number of ptns, 4 b */ +#define GPTHDR_PTNSZ_O 84 /* partition size, 4 b */ +#define GPTHDR_PTNCRC_O 88 /* ptn. array CRC32, 4 b */ + +/* + * GPT partition entry structure, offsets + */ +#define GPTPTN_TYPE_O 0 /* ptn. type GUID, 16 b */ +#define GPTPTN_GUID_O 16 /* ptn. unique GUID, 16 b */ +#define GPTPTN_SLBA_O 32 /* ptn. starting LBA, 8 b */ +#define GPTPTN_ELBA_O 40 /* ptn. ending LBA, 8 b */ +#define GPTPTN_ATTR_O 48 /* ptn. attributes, 8 b */ +#define GPTPTN_NAME_O 56 /* ptn. name, UTF-16, 72 b */ + +/* + * Default values of generic disk partitioning + */ +#ifndef SECTOR_SIZE +#define SECTOR_SIZE 512 /* 8192 bytes max */ +#endif +#define GPTHDR_BLKNO 1 +#define GPTHDR_SIZE 92 /* size of GPT header */ +#define GPTHDR_LBASZ 1 /* default LBAs for header */ +#define GPTHDR_PTNSZ 128 /* size of a partition entry */ +#define GPTHDR_PTNN_MIN 128 /* minimum number of ptns */ +#define GPTPTN_SIZE (GPTHDR_PTNSZ * GPTHDR_PTNN_MIN) +#if GPTPTN_SIZE % SECTOR_SIZE == 0 +#define GPTPTN_LBASZ (GPTPTN_SIZE / SECTOR_SIZE) +#else +#define GPTPTN_LBASZ (GPTPTN_SIZE / SECTOR_SIZE + 1) +#endif +#define GPT_LBASZ (GPTHDR_LBASZ + GPTPTN_LBASZ) + +/* + * Minimum and maximum drive number that is considered to be valid. + */ +#define MINDRV 0x80 +#define MAXDRV 0x8f + +/* + * Error codes. Done this way to save space. + */ +#define ERR_INVPART 'P' /* Invalid partition table */ +#define ERR_READ 'R' /* Read error */ +#define ERR_NOOS 'S' /* Magic no. check failed for part. */ +#define ERR_NO_LBA 'L' /* Sector above chs limit */ + +#define set_err(err) movb $err, %al + + .text + .code16 +/* + * Move ourselves out of the way first. + * (to the address we are linked at) + * and zero our bss + */ +ENTRY(start) + xor %ax, %ax + mov %ax, %ss + movw $BOOTADDR, %sp + mov %ax, %es + mov %ax, %ds + movw $mbr, %di + mov $BOOTADDR + (mbr - start), %si + push %ax /* zero for %cs of lret */ + push %di + movw $(bss_start - mbr), %cx + rep + movsb /* relocate code (zero %cx on exit) */ + mov $(bss_end - bss_start + 511)/512, %ch + rep + stosw /* zero bss */ + lret /* Ensures %cs == 0 */ + +/* + * Sanity check the drive number passed by the BIOS. Some BIOSs may not + * do this and pass garbage. + */ +mbr: + cmpb $MAXDRV, %dl /* relies on MINDRV being 0x80 */ + jle 1f + movb $MINDRV, %dl /* garbage in, boot disk 0 */ +1: + push %dx /* save drive number */ + push %dx /* twice - for err_msg loop */ + +#if defined(COM_PORT) && defined(COM_BAUD) + mov $com_args, %si + mov $num_com_args, %cl /* %ch is zero from above */ + mov COM_PORT_VAL, %dx +1: lodsw + add %ah, %dl + outb %dx + loop 1b +#endif + +#ifndef NO_BANNER + mov $banner, %si + call message +#endif + +/* + * Read and validate GUID partition tables + * + * Register use: + * %ax temp + * %bx temp + * %cx counters (%ch was preset to zero via %cx before) + * %dx disk pointer (inherited from BIOS or the check above) + * %bp GPT header pointer + */ +#ifndef NO_LBA_CHECK +/* + * Determine whether we have int13-extensions, by calling int 13, function 41. + * Check for the magic number returned, and the disk packet capability. + * On entry %dx should contain BIOS disk number. + */ +lba_check: + movw $0x55aa, %bx + movb $0x41, %ah + int $0x13 + set_err(ERR_NO_LBA) + jc 1f /* no int13 extensions */ + cmpw $0xaa55, %bx + jnz 1f + testb $1, %cl + jnz gpt +1: jmp err_msg +#endif + +gpt: + /* + * Read GPT header + */ + movw $GPTBUFADDR, %bp /* start from primary GPT layout */ +read_gpt: + call do_lba_read /* read GPT header */ + jc try_gpt2 + + /* + * Verify GPT header + */ + movw $efihdr_sign, %si /* verify GPT signature... */ + movw %bp, %di /* ptn signature is at offset 0 */ + movb $sizeof_efihdr_sign, %cl /* signature length */ + repe + cmpsb /* compare */ + jne try_gpt2 /* if not equal - try GPT2 */ + +#ifndef NO_CRC_CHECK + mov %bp, %si /* verify CRC32 of the header... */ + mov $GPTHDR_SIZE, %di /* header boundary */ + add %bp, %di + xor %eax, %eax + xchgl %eax, GPTHDR_CRC_O(%bp) /* save and reset header CRC */ + call crc32 + cmp %eax, %ebx /* is CRC correct? */ + jne try_gpt2 +#endif + +#if 0 /* XXX: weak check - safely disabled due to space constraints */ + movw $lba_sector, %si /* verify GPT location... */ + mov $GPTHDR_MYLBA_O, %di + add %bp, %di + movb $8, %cl /* LBA size */ + repe + cmpsb /* compare */ + jne try_gpt2 /* if not equal - try GPT2 */ +#endif + + /* + * All header checks passed - now verify GPT partitions array + */ +#ifndef NO_CRC_CHECK + movl GPTHDR_PTNCRC_O(%bp), %eax /* original array checksum */ + push %bp /* save header pointer for try_gpt2 */ +#endif + + /* + * point %bp to GPT partitions array location + */ + cmp $GPTBUFADDR, %bp + je 1f + mov $GPTBUFADDR, %bp + jmp 2f +1: mov $GPTBUFADDR + GPTPTN_LBASZ * SECTOR_SIZE, %bp +2: + +#ifndef NO_CRC_CHECK + mov %bp, %si /* array location for CRC32 check */ + mov $GPTPTN_SIZE, %di /* array boundary */ + add %bp, %di + call crc32 + cmp %eax, %ebx /* is CRC correct? */ + jne 1f /* if no - try GPT2 */ + pop %ax /* restore stack consistency */ +#endif + jmp gpt_parse + +#ifndef NO_CRC_CHECK +1: pop %bp /* restore after unsucc. array check */ +#endif +try_gpt2: + cmp $GPTBUFADDR, %bp /* is this GPT1? */ + set_err(ERR_INVPART) + jne err_msg /* if no - we just tried GPT2. Stop. */ + + mov %bp, %si /* use [%bp] as tmp buffer */ + movb $0x1a, (%si) /* init buffer size (per v.1.0) */ + movb $0x48, %ah /* request extended LBA status */ + int $0x13 /* ... to get GPT2 location */ + set_err(ERR_NO_LBA) + jc err_msg /* on error - stop */ +#define LBA_DKINFO_OFFSET 16 /* interested offset in out buffer */ + addw $LBA_DKINFO_OFFSET, %si /* ... contains number of disk LBAs */ +#undef LBA_DKINFO_OFFSET + movw $lba_sector, %di + movb $8, %cl /* LBA size */ + rep + movsb /* do get */ + subl $GPT_LBASZ, lba_sector /* calculate location of GPT2 */ + sbbl $0, lba_sector + 4 /* 64-bit LBA correction */ + + movw $GPTBUFADDR + GPTPTN_LBASZ * SECTOR_SIZE, %bp + /* the GPT2 header location */ + jmp read_gpt /* try once again */ + +/* + * GPT header validation done. + * Now parse GPT partitions and try to boot from appropriate. + * Register use: + * %bx partition counter + * %bp partition entry pointer (already initialized on entry) + * %di partition entry moving pointer + * %si variables pointer + * %cx counter + */ + +gpt_parse: + movw $BOOTADDR, lba_rbuff /* from now we will read boot code */ + movb $1, lba_count /* read PBR only */ + mov $GPTHDR_PTNN_MIN, %bx /* number of GUID partitions to parse */ +do_gpt_parse: + movw $bootptn_guid, %si /* lookup the boot partition GUID */ + movb $0x10, %cl /* sizeof GUID */ + movw %bp, %di /* set pointer to partition entry */ + add %cx, %di /* partition GUID at offset 16 */ + repe + cmpsb /* do compare */ + jne try_nextptn /* doesn't seem appropriate ptn */ + + /* + * Read partition boot record + */ + mov $GPTPTN_SLBA_O, %si /* point %si to partition LBA */ + add %bp, %si + movw $lba_sector, %di + movb $8, %cl /* LBA size */ + rep + movsb /* set read pointer to LBA of PBR */ + call do_lba_read /* read PBR */ + jz try_nextptn + + /* + * Check signature for valid bootcode and try to boot + */ + movb BOOTADDR, %al /* first byte non-zero */ + testb %al, %al + jz 1f + movw BOOTADDR + MBR_MAGIC_OFFSET, %ax +1: cmp $MBR_MAGIC, %ax + jne try_nextptn +do_boot: + pop %dx /* ... %dx - drive # */ + movw $lba_sector, %sp /* ... %ecx:%ebx - boot partition LBA */ + pop %ebx + pop %ecx + movl crc32_poly, %eax /* X86_MBR_GPT_MAGIC */ + jmp BOOTADDR + /* THE END */ + +try_nextptn: + addw $GPTHDR_PTNSZ, %bp /* move to next partition */ + dec %bx /* ptncounter-- */ + jnz do_gpt_parse + set_err(ERR_NOOS) /* no bootable partitions were found */ + /* jmp err_msg */ /* stop */ + +/* Something went wrong... + * Output error code, + * reset disk subsystem - needed after read failure, + * and wait for user key + */ +err_msg: + movb %al, errcod + movw $errtxt, %si + call message + pop %dx /* drive we errored on */ + xor %ax,%ax /* only need %ah = 0 */ + int $0x13 /* reset disk subsystem */ + int $0x18 /* BIOS might ask for a key */ + /* press and retry boot seq. */ +1: sti + hlt + jmp 1b + +/* + * I hate #including source files, but the stuff below has to be at + * the correct absolute address. + * Clearly this could be done with a linker script. + */ + +#if defined(COM_PORT) && defined(COM_BAUD) +message: + pusha +message_1: + lodsb + test %al, %al + jz 3f + mov COM_PORT_VAL, %dx + outb %al, %dx + add $5, %dl +2: inb %dx + test $0x40, %al + jz 2b + jmp message_1 +3: popa + ret +#else +#include +#endif + +#if 0 +#include +#endif + +#ifndef NO_CRC_CHECK +/* + * The CRC32 calculation + * + * %si address of block to hash + * %di stop address + * %ax scratch (but restored after exit) + * %dx scratch (but restored after exit) + * %cx counter + * %ebx crc (returned) + */ +crc32: + push %dx /* preserve drive number */ + push %ax /* preserve original CRC */ + + xorl %ebx, %ebx + decl %ebx /* init value */ +1: + lodsb /* load next message byte to %al */ + movb $8, %cl /* set bit counter */ +2: + movb %al, %dl + xorb %bl, %dl /* xoring with previous result */ + shrl $1, %ebx + shrb $1, %al + testb $1, %dl + jz 3f +crc32_poly = . + 3 /* gross, but saves a few bytes */ + xorl $0xedb88320, %ebx /* EFI CRC32 Polynomial */ +3: + loop 2b /* loop over bits */ + cmp %di, %si /* do we reached end of message? */ + jne 1b + notl %ebx /* result correction */ + + pop %ax + pop %dx + ret +#endif + +do_lba_read: + movw $lba_dap, %si + movb $0x42, %ah + int $0x13 /* read */ + ret + +/* + * Data definition block + */ + +errtxt: .ascii "Error " /* runs into crlf if errcod set */ +errcod: .byte 0 +crlf: .asciz "\r\n" + +#ifndef NO_BANNER +banner: .asciz "NetBSD GPT\r\n" +#endif + +#if defined(COM_PORT) && defined(COM_BAUD) +#define COM_DIVISOR (((COM_FREQ / COM_BAUD) + 8) / 16) +com_args: + .byte 0x80 /* divisor latch enable */ + .byte +3 /* io_port + 3 */ + .byte COM_DIVISOR & 0xff + .byte -3 /* io_port */ + .byte COM_DIVISOR >> 8 /* high baud */ + .byte +1 /* io_port + 1 */ + .byte 0x03 /* 8 bit no parity */ + .byte +2 /* io_port + 3 */ +num_com_args = (. - com_args)/2 +#endif + +/* + * Control block for int-13 LBA read - Disk Address Packet + */ +lba_dap: + .byte 0x10 /* control block length */ + .byte 0 /* reserved */ +lba_count: + .word GPT_LBASZ /* sector count */ +lba_rbuff: + .word GPTBUFADDR /* offset in segment */ + .word 0 /* segment */ +lba_sector: + .quad GPTHDR_BLKNO /* sector # goes here... */ + +efihdr_sign: + .ascii "EFI PART" /* GPT header signature */ + .long 0x00010000 /* GPT header revision */ +sizeof_efihdr_sign = . - efihdr_sign + +/* + * Stuff from here on is overwritten by gpt/fdisk - the offset must not change + * + * Get amount of space to makefile can report it. + * (Unfortunately I can't seem to get the value reported when it is -ve) + */ +mbr_space = bootptn_guid - . + +/* + * GUID of the bootable partition. Patchable area. + * Default GUID used by installer for safety checks. + */ + . = start + MBR_GPT_GUID_OFFSET +bootptn_guid: + /* MBR_GPT_GUID_DEFAULT */ + .long 0xeee69d04 + .word 0x02f4 + .word 0x11e0 + .byte 0x8f,0x5d + .byte 0x00,0xe0,0x81,0x52,0x9a,0x6b + +/* space for mbr_dsn */ + . = start + MBR_DSN_OFFSET + .long 0 + +/* mbr_bootsel_magic */ + . = start + MBR_BS_MAGIC_OFFSET + .word 0 + +/* mbr partition table */ + . = start + MBR_PART_OFFSET +parttab: + .fill 0x40, 0x01, 0x00 + + . = start + MBR_MAGIC_OFFSET + .word MBR_MAGIC + +/* zeroed data space */ +bss_off = 0 +bss_start = . +#define BSS(name, size) name = bss_start + bss_off; bss_off = bss_off + size + BSS(dump_eax_buff, 16) + BSS(bss_end, 0) diff --git a/sys/arch/i386/stand/mbr/gptmbr.S b/sys/arch/i386/stand/mbr/gptmbr.S new file mode 100644 index 000000000..d808b66c8 --- /dev/null +++ b/sys/arch/i386/stand/mbr/gptmbr.S @@ -0,0 +1,330 @@ +/* ----------------------------------------------------------------------- + * + * Copyright 2007-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +#include +#include + +#ifdef CTRL_80 + .macro ADJUST_DRIVE + testb $0x04, BIOS_kbdflags + jz 1f + movb $0x80, %dl +1: + .endm +#elif defined(FORCE_80) + .macro ADJUST_DRIVE + movb $0x80, %dl + .endm +#else + .macro ADJUST_DRIVE + .endm +#endif + + .code16 + .text + + .globl bootsec +stack = 0x7c00 + +/* Partition table header here */ +phdr = stack /* Above the stack, overwritten by bootsect */ +/* Partition table sector here */ +/* To handle > 32K we need to play segment tricks... */ +psec = _phdr + 512 + +/* Where we put DS:SI */ +dssi_out = start + 0x1be + +BIOS_kbdflags = 0x417 +BIOS_page = 0x462 + + /* gas/ld has issues with doing this as absolute addresses... */ + .section ".bootsec", "a", @nobits + .globl bootsec +bootsec: + .space 512 + + .text + .globl start +start: + cli + xorw %ax, %ax + movw %ax, %ds + movw %ax, %ss + movw $stack, %sp + movw %sp, %si + pushw %es /* 4(%bp) es:di -> $PnP header */ + pushw %di /* 2(%bp) */ + movw %ax, %es + sti + cld + + /* Copy down to 0:0x600 */ + movw $start, %di + movw $(512/2), %cx + rep; movsw + + ljmpw $0, $next +next: + + ADJUST_DRIVE + pushw %dx /* 0(%bp) = %dl -> drive number */ + + /* Check to see if we have EBIOS */ + pushw %dx /* drive number */ + movb $0x41, %ah /* %al == 0 already */ + movw $0x55aa, %bx + xorw %cx, %cx + xorb %dh, %dh + stc + int $0x13 + jc 1f + cmpw $0xaa55, %bx + jne 1f + shrw %cx /* Bit 0 = fixed disk subset */ + jnc 1f + + /* We have EBIOS; patch in the following code at + read_sector_cbios: movb $0x42, %ah ; jmp read_common */ + movl $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \ + (read_sector_cbios) + +1: + popw %dx + + /* Get (C)HS geometry */ + movb $0x08, %ah + int $0x13 + andw $0x3f, %cx /* Sector count */ + movw %sp, %bp /* %bp -> frame pointer: LEAVE UNCHANGED */ + pushw %cx /* -2(%bp) Save sectors on the stack */ + movzbw %dh, %ax /* dh = max head */ + incw %ax /* From 0-based max to count */ + mulw %cx /* Heads*sectors -> sectors per cylinder */ + + /* Save sectors/cylinder on the stack */ + pushw %dx /* -4(%bp) High word */ + pushw %ax /* -6(%bp) Low word */ + + /* Load partition table header */ + xorl %eax,%eax + cltd + incw %ax /* %edx:%eax = 1 */ + movw $phdr, %bx + pushw %bx /* -8(%bp) phdr == bootsect */ + call read_sector + + /* Number of partition sectors */ + /* We assume the partition table is 32K or less, and that + the sector size is 512. */ + /* Note: phdr == 6(%bp) */ + movw (80+6)(%bp),%cx /* NumberOfPartitionEntries */ + movw (84+6)(%bp),%ax /* SizeOfPartitionEntry */ + pushw %ax + pushw %cx + mulw %cx + shrw $9,%ax + xchgw %ax,%cx + incw %cx + + /* Starting LBA of partition array */ + movl (72+6)(%bp),%eax + movl (76+6)(%bp),%edx + + pushw %bx +get_ptab: + call read_sector + call inc64 + loopw get_ptab + + /* Find the boot partition */ + xorw %si,%si /* Nothing found yet */ + popw %di /* Partition table in memory */ + popw %cx /* NumberOfPartitionEntries */ + popw %ax /* SizeOfPartitionEntry */ + +find_part: + /* If the PartitionTypeGUID is all zero, it's an empty slot */ + movl (%di),%edx + orl 4(%di),%edx + orl 8(%di),%edx + orl 12(%di),%edx + jz not_this + testb $0x04,48(%di) + jz not_this + andw %si,%si + jnz found_multiple + movw %di,%si +not_this: + addw %ax,%di + loopw find_part + + andw %si,%si + jnz found_part + +missing_os: + call error + .ascii "Missing OS\r\n" + +found_multiple: + call error + .ascii "Multiple active partitions\r\n" + +found_part: + xchgw %ax,%cx /* Set up %cx for rep movsb further down */ + + movw $dssi_out,%di + pushw %di + + /* 80 00 00 00 ee 00 00 00 + - bootable partition, type EFI (EE), no CHS information */ + xorl %eax,%eax + movb $0x80,%al + stosl + movb $0xed,%al + stosl + movl 32(%si),%eax + movl 36(%si),%edx + call saturate_stosl /* Partition start */ + + movl 40(%si),%eax + movl 44(%si),%edx + subl 32(%si),%eax + sbbl 36(%si),%edx + call inc64 + call saturate_stosl /* Partition length */ + + movzwl %cx,%eax /* Length of GPT entry */ + stosl + + rep; movsb /* GPT entry follows MBR entry */ + popw %si + +/* + * boot: invoke the actual bootstrap. %ds:%si points to the + * partition information in memory. The top word on the stack + * is phdr == 0x7c00 == the address of the boot sector. + */ +boot: + movl (32+20)(%si),%eax + movl (36+20)(%si),%edx + popw %bx + call read_sector + cmpw $0xaa55, -2(%bx) + jne missing_os /* Not a valid boot sector */ + movw %bp, %sp /* driveno == bootsec-6 */ + popw %dx /* dl -> drive number */ + popw %di /* es:di -> $PnP vector */ + popw %es + movl $0x54504721,%eax /* !GPT magic number */ + cli + jmpw *%sp /* %sp == bootsec */ + +/* + * Store the value in %eax to %di iff %edx == 0, otherwise store -1. + * Returns the value that was actually written in %eax. + */ +saturate_stosl: + andl %edx,%edx + jz 1f + orl $-1,%eax +1: stosl + ret + +/* + * Increment %edx:%eax + */ +inc64: + addl $1,%eax + adcl $0,%edx + ret + +/* + * read_sector: read a single sector pointed to by %edx:%eax to + * %es:%bx. CF is set on error. All registers saved. + */ +read_sector: + pushal + pushl %edx /* MSW of LBA */ + pushl %eax /* LSW of LBA */ + pushw %es /* Buffer segment */ + pushw %bx /* Buffer offset */ + pushw $1 /* Sector count */ + pushw $16 /* Size of packet */ + movw %sp, %si + + /* This chunk is skipped if we have ebios */ + /* Do not clobber %es:%bx or %edx:%eax before this chunk! */ +read_sector_cbios: + divl -6(%bp) /* secpercyl */ + shlb $6, %ah + movb %ah, %cl + movb %al, %ch + xchgw %dx, %ax + divb -2(%bp) /* sectors */ + movb %al, %dh + orb %ah, %cl + incw %cx /* Sectors are 1-based */ + movw $0x0201, %ax + +read_common: + movb (%bp), %dl /* driveno */ + int $0x13 + leaw 16(%si), %sp /* Drop DAPA */ + popal + jc disk_error + addb $2, %bh /* bx += 512: point to the next buffer */ + ret + +disk_error: + call error + .ascii "Disk error on boot\r\n" + +/* + * Print error messages. This is invoked with "call", with the + * error message at the return address. + */ +error: + popw %si +2: + lodsb + movb $0x0e, %ah + movb (BIOS_page), %bh + movb $0x07, %bl + int $0x10 /* May destroy %bp */ + cmpb $10, %al /* Newline? */ + jne 2b + + int $0x18 /* Boot failure */ +die: + hlt + jmp die + +mbr_space = end - . + . = MBR_DSN_OFFSET +end: diff --git a/sys/arch/i386/stand/mbr/gptmbr/Makefile b/sys/arch/i386/stand/mbr/gptmbr/Makefile new file mode 100644 index 000000000..7273c96f0 --- /dev/null +++ b/sys/arch/i386/stand/mbr/gptmbr/Makefile @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.3 2011/09/21 18:15:59 jakllsch Exp $ + +PROG= gptmbr.bin +SRCS= gptmbr.S + +AFLAGS.gptmbr.S= ${${ACTIVE_CC} == "clang":?-no-integrated-as:} + +.include <../Makefile.mbr> + +LOADADDR= 0x600 diff --git a/sys/arch/i386/stand/mbr/mbr.S b/sys/arch/i386/stand/mbr/mbr.S new file mode 100644 index 000000000..05be7aec3 --- /dev/null +++ b/sys/arch/i386/stand/mbr/mbr.S @@ -0,0 +1,663 @@ +/* $NetBSD: mbr.S,v 1.23 2010/12/08 21:56:42 jakllsch Exp $ */ + +/* + * Copyright (c) 1999-2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Frank van der Linden, based on an earlier work by Wolfgang Solfrank. + * Major surgery performed by David Laight. + * + * 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. + */ + +/* + * i386 master boot code + */ + +/* Compile options: + * BOOTSEL - bootselector code + * BOOT_EXTENDED - scan extended partition list (LBA reads) + * COM_PORT - do serial io to specified port number + * 0..3 => bios port, otherwise actual io_addr + * COM_BAUD - initialise serial port baud rate + * + * TERSE_ERROR - terse error messages + * NO_CHS - all reads are LBA + * NO_LBA_CHECK - no check if bios supports LBA reads + * NO_BANNER - do not output title line 'banner' + */ + +#ifdef BOOT_EXTENDED +#define NO_CHS 1 +#define BOOTSEL 1 +#endif + +#ifdef COM_PORT +#if COM_PORT < 4 +/* The first 4 items in the 40:xx segment are the serial port base addresses */ +#define COM_PORT_VAL (0x400 + (COM_PORT * 2)) +#else +#define COM_PORT_VAL $COM_PORT +#endif + +#if !defined(COM_FREQ) +#define COM_FREQ 1843200 +#endif +#else +#undef COM_BAUD +#endif + +#ifdef BOOTSEL +#define TERSE_ERROR 1 +#endif + +#include +#include + +#define BOOTADDR 0x7c00 /* where we get loaded to */ + +#define TABENTRYSIZE (MBR_BS_PARTNAMESIZE + 1) +#define NAMETABSIZE (MBR_PART_COUNT * TABENTRYSIZE) + +#ifdef COM_PORT +/* ASCII values for the keys */ +#define KEY_ACTIVE '\r' +#define KEY_DISK1 'a' +#define KEY_PTN1 '1' +#else +/* Scan values for the various keys we use, as returned by the BIOS */ +#define SCAN_ENTER 0x1c +#define SCAN_F1 0x3b +#define SCAN_1 0x2 + +#define KEY_ACTIVE SCAN_ENTER +#define KEY_DISK1 SCAN_F1 +#define KEY_PTN1 SCAN_1 +#endif + +/* + * Minimum and maximum drive number that is considered to be valid. + */ +#define MINDRV 0x80 +#define MAXDRV 0x8f + +#ifdef TERSE_ERROR +/* + * Error codes. Done this way to save space. + */ +#define ERR_INVPART '1' /* Invalid partition table */ +#define ERR_READ '2' /* Read error */ +#define ERR_NOOS '3' /* Magic no. check failed for part. */ +#define ERR_KEY '?' /* unknown key press */ +#define ERR_NO_LBA 'L' /* sector above chs limit */ + +#define set_err(err) movb $err, %al + +#else +#define set_err(err) mov $err, %ax +#endif + + .text + .code16 +/* + * Move ourselves out of the way first. + * (to the address we are linked at) + * and zero our bss + */ +ENTRY(start) + xor %ax, %ax + mov %ax, %ss + movw $BOOTADDR, %sp + mov %ax, %es + mov %ax, %ds + movw $mbr, %di + mov $BOOTADDR + (mbr - start), %si + push %ax /* zero for %cs of lret */ + push %di + movw $(bss_start - mbr), %cx + rep + movsb /* relocate code */ + mov $(bss_end - bss_start + 511)/512, %ch + rep + stosw /* zero bss */ + lret /* Ensures %cs == 0 */ + +/* + * Sanity check the drive number passed by the BIOS. Some BIOSs may not + * do this and pass garbage. + */ +mbr: + cmpb $MAXDRV, %dl /* relies on MINDRV being 0x80 */ + jle 1f + movb $MINDRV, %dl /* garbage in, boot disk 0 */ +1: + push %dx /* save drive number */ + push %dx /* twice - for err_msg loop */ + +#if defined(COM_BAUD) + mov $com_args, %si + mov $num_com_args, %cl /* %ch is zero from above */ + mov COM_PORT_VAL, %dx +1: lodsw + add %ah, %dl + outb %dx + loop 1b +#endif + +#ifndef NO_BANNER + mov $banner, %si + call message_crlf +#endif + +/* + * Walk through the selector (name) table printing used entries. + * + * Register use: + * %ax temp + * %bx nametab[] boot seletor menu + * %ecx base of 'extended' partition + * %edx next extended partition + * %si message ptr (etc) + * %edi sector number of this partition + * %bp parttab[] mbr partition table + */ +bootsel_menu: + movw $nametab, %bx +#ifdef BOOT_EXTENDED + xorl %ecx, %ecx /* base of extended partition */ +next_extended: + xorl %edx, %edx /* for next extended partition */ +#endif + lea parttab - nametab(%bx), %bp +next_ptn: + movb 4(%bp), %al /* partition type */ +#ifdef NO_CHS + movl 8(%bp), %edi /* partition sector number */ +#ifdef BOOT_EXTENDED + cmpb $MBR_PTYPE_EXT, %al /* Extended partition */ + je 1f + cmpb $MBR_PTYPE_EXT_LBA, %al /* Extended LBA partition */ + je 1f + cmpb $MBR_PTYPE_EXT_LNX, %al /* Linux extended partition */ + jne 2f +1: movl %edi, %edx /* save next extended ptn */ + jmp 4f +2: +#endif + addl lba_sector, %edi /* add in extended ptn base */ +#endif + test %al, %al /* undefined partition */ + je 4f + cmpb $0x80, (%bp) /* check for active partition */ + jne 3f /* jump if not... */ +#define ACTIVE (4 * ((KEY_ACTIVE - KEY_DISK1) & 0xff)) +#ifdef NO_CHS + movl %edi, ptn_list + ACTIVE /* save location of active ptn */ +#else + mov %bp, ptn_list + ACTIVE +#endif +#undef ACTIVE +3: +#ifdef BOOTSEL + cmpb $0, (%bx) /* check for prompt */ + jz 4f + /* output menu item */ + movw $prefix, %si + incb (%si) + call message /* menu number */ + mov (%si), %si /* ':' << 8 | '1' + count */ + shl $2, %si /* const + count * 4 */ +#define CONST (4 * ((':' << 8) + '1' - ((KEY_PTN1 - KEY_DISK1) & 0xff))) +#ifdef NO_CHS + movl %edi, ptn_list - CONST(%si) /* sector to read */ +#else + mov %bp, ptn_list - CONST(%si) /* partition info */ +#endif +#undef CONST + mov %bx, %si + call message_crlf /* prompt */ +#endif +4: + add $0x10, %bp + add $TABENTRYSIZE, %bx + cmpb $(nametab - start - 0x100) + 4 * TABENTRYSIZE, %bl + jne next_ptn + +#ifdef BOOT_EXTENDED +/* + * Now check extended partition chain + */ + testl %edx, %edx + je wait_key + testl %ecx, %ecx + jne 1f + xchg %ecx, %edx /* save base of ext ptn chain */ +1: addl %ecx, %edx /* sector to read */ + movl %edx, lba_sector + movw $lba_info, %si + movb $0x42, %ah + pop %dx /* recover drive # */ + push %dx /* save drive */ + int $0x13 + movw $BOOTADDR + (nametab - start), %bx + jnc next_extended /* abort menu on read fail */ +#endif + +/* + * The non-bootsel code traverses this code path, it needs the + * correct keycode to select the active partition. + */ + +#ifndef BOOTSEL + mov $(KEY_ACTIVE - KEY_DISK1) & 0xff, %ax +#else +/* + * Get the initial time value for the timeout comparison. It is returned + * by int 1a in cx:dx. We do sums modulo 2^16 so it doesn't matter if + * the counter wraps (which it does every hour) - so we can safely + * ignore 'cx'. + * + * Loop around checking for a keypress until we have one, or timeout is + * reached. + */ +wait_key: + xorb %ah, %ah + int $0x1a + mov %dx, %di /* start time to di */ +3: +#ifdef COM_PORT_VAL + mov COM_PORT_VAL, %dx + push %dx + add $5, %dx + inb %dx + pop %dx + test $1, %al + jz 1f + inb %dx + jmp check_key +#else + movb $1, %ah /* looks to see if a */ + int $0x16 /* key has been pressed */ + jz 1f +get_key: + xorb %ah, %ah + int $0x16 /* 'read key', code ah, ascii al */ + shr $8, %ax /* code in %al, %ah zero */ + jmp check_key +#endif + +1: xorb %ah, %ah + int $0x1a /* current time to cx:dx */ + sub %di, %dx + cmpw timeout, %dx /* always wait for 1 tick... */ + jbe 3b /* 0xffff means never timeout */ +def_key: + mov defkey, %al /* timedout - we need %ah to still be zero! */ + +/* + * We have a keycode, see what it means. + * If we don't know we generate error '?' and go ask again + */ +check_key: +/* + * F1-F10 -> boot disk 0-9. Check if the requested disk isn't above + * the number of disks actually in the system as stored in 0:0475 by + * the BIOS. + * If we trust loc 475, we needn't check the upper bound on the keystroke + * This is always sector 0, so always read using chs. + */ + subb $KEY_DISK1, %al + cmpb 0x0475, %al + jae boot_ptn + addb $0x80, %al + pop %dx /* dump saved drive # */ + push %ax /* replace with new */ +#ifdef NO_CHS + xorl %ebp, %ebp /* read sector number 0 */ + jmp boot_lba +#else + movw $chs_zero, %si /* chs read sector zero info */ + jmp read_chs +#endif +#endif /* BOOTSEL */ + +/* + * Boot requested partition. + * Use keycode to index the table we generated when we scanned the mbr + * while generating the menu. + * + * We very carfully saved the values in the correct part of the table. + */ + +boot_ptn: + shl $2, %ax + movw %ax, %si +#ifdef NO_CHS + movl ptn_list(%si), %ebp + testl %ebp, %ebp + jnz boot_lba +#else + mov ptn_list(%si), %si + test %si, %si + jnz boot_si +#endif +#ifdef BOOTSEL + set_err(ERR_KEY) +#else + set_err(ERR_INVPART) +#endif + /* jmp err_msg */ + +/* Something went wrong... + * Output error code, + * reset disk subsystem - needed after read failure, + * and wait for user key + */ +err_msg: +#ifdef TERSE_ERROR + movb %al, errcod + movw $errtxt, %si + call message +#else + push %ax + movw $errtxt, %si + call message + pop %si + call message_crlf +#endif + pop %dx /* drive we errored on */ + xor %ax,%ax /* only need %ah = 0 */ + int $0x13 /* reset disk subsystem */ +#ifdef BOOTSEL + pop %dx /* original drive number */ + push %dx + push %dx +#ifdef COM_PORT_VAL + jmp wait_key /* Read with timeout (again) */ +#else + jmp get_key /* Blocking read */ +#endif +#else + int $0x18 /* BIOS might ask for a key */ + /* press and retry boot seq. */ +1: sti + hlt + jmp 1b +#endif + +#ifndef NO_CHS +/* + * Active partition pointed to by si. + * Read the first sector. + * + * We can either do a CHS (Cylinder Head Sector) or an LBA (Logical + * Block Address) read. Always doing the LBA one + * would be nice - unfortunately not all systems support it. + * Also some may contain a separate (eg SCSI) bios that doesn't + * support it even when the main bios does. + * + * There is also the additional problem that the CHS values may be wrong + * (eg if fdisk was run on a different system that used different BIOS + * geometry). We convert the CHS value to a LBA sector number using + * the geometry from the BIOS, if the number matches we do a CHS read. + */ +boot_si: + movl 8(%si), %ebp /* get sector # */ + + testb $MBR_BS_READ_LBA, flags + jnz boot_lba /* fdisk forced LBA read */ + + pop %dx /* collect saved drive... */ + push %dx /* ...number to dl */ + movb $8, %ah + int $0x13 /* chs info */ + +/* + * Validate geometry, if the CHS sector number doesn't match the LBA one + * we'll do an LBA read. + * calc: (cylinder * number_of_heads + head) * number_of_sectors + sector + * and compare against LBA sector number. + * Take a slight 'flier' and assume we can just check 16bits (very likely + * to be true because the number of sectors per track is 63). + */ + movw 2(%si), %ax /* cylinder + sector */ + push %ax /* save for sector */ + shr $6, %al + xchgb %al, %ah /* 10 bit cylinder number */ + shr $8, %dx /* last head */ + inc %dx /* number of heads */ + mul %dx + mov 1(%si), %dl /* head we want */ + add %dx, %ax + and $0x3f, %cx /* number of sectors */ + mul %cx + pop %dx /* recover sector we want */ + and $0x3f, %dx + add %dx, %ax + dec %ax + + cmp %bp, %ax + je read_chs + +#ifndef NO_LBA_CHECK +/* + * Determine whether we have int13-extensions, by calling int 13, function 41. + * Check for the magic number returned, and the disk packet capability. + */ + movw $0x55aa, %bx + movb $0x41, %ah + pop %dx + push %dx + int $0x13 + set_err(ERR_NO_LBA) + jc err_msg /* no int13 extensions */ + cmpw $0xaa55, %bx + jnz err_msg + testb $1, %cl + jz err_msg +#endif /* NO_LBA_CHECK */ +#endif /* NO_CHS */ + +/* + * Save sector number (passed in %ebp) into lba parameter block, + * read the sector and leap into it. + */ +boot_lba: + movl %ebp, lba_sector /* save sector number */ + movw $lba_info, %si + movb $0x42, %ah + pop %dx /* recover drive # */ +do_read: + push %dx /* save drive */ + int $0x13 + + set_err(ERR_READ) + jc err_msg + +/* + * Check signature for valid bootcode + */ + movb BOOTADDR, %al /* first byte non-zero */ + test %al, %al + jz 1f + movw BOOTADDR + MBR_MAGIC_OFFSET, %ax +1: cmp $MBR_MAGIC, %ax + set_err(ERR_NOOS) + jnz err_msg + +/* We pass the sector number through to the next stage boot. + * It doesn't have to use it (indeed no other mbr code will generate) it, + * but it does let us have a NetBSD pbr that can identify where it was + * read from! This lets us use this code to select between two + * NetBSD system on the same physical driver. + * (If we've read the mbr of a different disk, it gets a random number + * - but it wasn't expecting anything...) +*/ + movl %ebp, %esi + pop %dx /* recover drive # */ + jmp BOOTADDR + + +#ifndef NO_CHS +/* + * Sector below CHS limit + * Do a cylinder-head-sector read instead. + */ +read_chs: + pop %dx /* recover drive # */ + movb 1(%si), %dh /* head */ + movw 2(%si), %cx /* ch=cyl, cl=sect */ + movw $BOOTADDR, %bx /* es:bx is buffer */ + movw $0x201, %ax /* command 2, 1 sector */ + jmp do_read +#endif + +/* + * Control block for int-13 LBA read. + * We need a xx, 00, 01, 00 somewhere to load chs for sector zero, + * by a complete fluke there is one here! + */ +chs_zero: +lba_info: + .word 0x10 /* control block length */ + .word 1 /* sector count */ + .word BOOTADDR /* offset in segment */ + .word 0 /* segment */ +lba_sector: + .long 0x0000 /* sector # goes here... */ + .long 0x0000 + +errtxt: .ascii "Error " /* runs into crlf if errcod set */ +errcod: .byte 0 +crlf: .asciz "\r\n" + +#ifndef NO_BANNER +#ifdef BOOTSEL +#ifdef COM_PORT_VAL +banner: .asciz "a: disk" +#else +banner: .asciz "Fn: diskn" +#endif +#else +banner: .asciz "NetBSD MBR boot" +#endif +#endif + +#ifdef BOOTSEL +prefix: .asciz "0: " +#endif + +#ifndef TERSE_ERROR +ERR_INVPART: .asciz "No active partition" +ERR_READ: .asciz "Disk read error" +ERR_NOOS: .asciz "No operating system" +#ifndef NO_LBA_CHECK +ERR_NO_LBA: .asciz "Invalid CHS read" +#endif +#ifdef BOOTSEL +ERR_KEY: .asciz "bad key" +#endif +#endif + +#if defined(COM_BAUD) +#define COM_DIVISOR (((COM_FREQ / COM_BAUD) + 8) / 16) +com_args: + .byte 0x80 /* divisor latch enable */ + .byte +3 /* io_port + 3 */ + .byte COM_DIVISOR & 0xff + .byte -3 /* io_port */ + .byte COM_DIVISOR >> 8 /* high baud */ + .byte +1 /* io_port + 1 */ + .byte 0x03 /* 8 bit no parity */ + .byte +2 /* io_port + 3 */ +num_com_args = (. - com_args)/2 +#endif + +/* + * I hate #including source files, but the stuff below has to be at + * the correct absolute address. + * Clearly this could be done with a linker script. + */ + +message_crlf: + call message + movw $crlf, %si +#include +#if 0 +#include +#endif + +/* + * Stuff from here on is overwritten by fdisk - the offset must not change... + * + * Get amount of space to makefile can report it. + * (Unfortunately I can't seem to get the value reported when it is -ve) + */ +mbr_space = defkey - . + . = start + MBR_BS_OFFSET +/* + * Default action, as a keyvalue we'd normally read from the BIOS. + */ +defkey: + .byte KEY_ACTIVE /* ps/2 code */ +#ifndef BOOTSEL_FLAGS +#define BOOTSEL_FLAGS 0 +#endif +flags: .byte MBR_BS_NEWMBR | BOOTSEL_FLAGS +/* + * Timeout value. ~65536 ticks per hour, which is ~18.2 times per second. + * 0xffff means never timeout. + */ +timeout: + .word 182 /* default to 10 seconds */ +/* + * mbr_bootsel + */ +nametab: + .fill MBR_PART_COUNT * (MBR_BS_PARTNAMESIZE + 1), 0x01, 0x00 + +/* space for mbr_dsn */ + . = start + MBR_DSN_OFFSET + .long 0 + +/* mbr_bootsel_magic */ + . = start + MBR_BS_MAGIC_OFFSET + .word MBR_BS_MAGIC + +/* + * MBR partition table + */ + . = start + MBR_PART_OFFSET +parttab: + .fill 0x40, 0x01, 0x00 + + . = start + MBR_MAGIC_OFFSET + .word MBR_MAGIC + +/* zeroed data space */ +bss_off = 0 +bss_start = . +#define BSS(name, size) name = bss_start + bss_off; bss_off = bss_off + size + BSS(ptn_list, 256 * 4) /* long[]: boot sector numbers */ + BSS(dump_eax_buff, 16) + BSS(bss_end, 0) diff --git a/sys/arch/i386/stand/mbr/mbr/Makefile b/sys/arch/i386/stand/mbr/mbr/Makefile new file mode 100644 index 000000000..eb2452def --- /dev/null +++ b/sys/arch/i386/stand/mbr/mbr/Makefile @@ -0,0 +1,5 @@ +# $NetBSD: Makefile,v 1.3 2009/11/18 21:04:12 dsl Exp $ + +PROG= mbr + +.include <../Makefile.mbr> diff --git a/sys/arch/i386/stand/mbr/mbr_bootsel/Makefile b/sys/arch/i386/stand/mbr/mbr_bootsel/Makefile new file mode 100644 index 000000000..afc6382a8 --- /dev/null +++ b/sys/arch/i386/stand/mbr/mbr_bootsel/Makefile @@ -0,0 +1,8 @@ +# $NetBSD: Makefile,v 1.3 2005/12/11 12:17:49 christos Exp $ + +PROG= mbr_bootsel +AFLAGS+= -DBOOTSEL +AFLAGS+= -DTERSE_ERROR +AFLAGS+= -DBOOTSEL_FLAGS=MBR_BS_ACTIVE + +.include <../Makefile.mbr> diff --git a/sys/arch/i386/stand/mbr/mbr_com0/Makefile b/sys/arch/i386/stand/mbr/mbr_com0/Makefile new file mode 100644 index 000000000..1f874841f --- /dev/null +++ b/sys/arch/i386/stand/mbr/mbr_com0/Makefile @@ -0,0 +1,8 @@ +# $NetBSD: Makefile,v 1.1 2008/01/19 21:01:35 dsl Exp $ + +PROG= mbr_com0 +AFLAGS+= -DBOOTSEL -DBOOT_EXTENDED -DCOM_PORT=0 +AFLAGS+= -DTERSE_ERROR -DNO_CHS +AFLAGS+= "-DBOOTSEL_FLAGS=MBR_BS_ACTIVE|MBR_BS_EXTLBA|MBR_BS_ASCII" + +.include <../Makefile.mbr> diff --git a/sys/arch/i386/stand/mbr/mbr_com0_9600/Makefile b/sys/arch/i386/stand/mbr/mbr_com0_9600/Makefile new file mode 100644 index 000000000..bb3a8a618 --- /dev/null +++ b/sys/arch/i386/stand/mbr/mbr_com0_9600/Makefile @@ -0,0 +1,8 @@ +# $NetBSD: Makefile,v 1.1 2008/01/19 21:01:35 dsl Exp $ + +PROG= mbr_com0_9600 +AFLAGS+= -DBOOTSEL -DBOOT_EXTENDED -DCOM_PORT=0 -DCOM_BAUD=9600 +AFLAGS+= -DTERSE_ERROR -DNO_CHS +AFLAGS+= "-DBOOTSEL_FLAGS=MBR_BS_ACTIVE|MBR_BS_EXTLBA|MBR_BS_ASCII" + +.include <../Makefile.mbr> diff --git a/sys/arch/i386/stand/mbr/mbr_ext/Makefile b/sys/arch/i386/stand/mbr/mbr_ext/Makefile new file mode 100644 index 000000000..5360f96da --- /dev/null +++ b/sys/arch/i386/stand/mbr/mbr_ext/Makefile @@ -0,0 +1,8 @@ +# $NetBSD: Makefile,v 1.3 2005/12/11 12:17:49 christos Exp $ + +PROG= mbr_ext +AFLAGS+= -DBOOTSEL -DBOOT_EXTENDED +AFLAGS+= -DTERSE_ERROR -DNO_CHS +AFLAGS+= "-DBOOTSEL_FLAGS=MBR_BS_ACTIVE|MBR_BS_EXTLBA" + +.include <../Makefile.mbr> diff --git a/sys/arch/i386/stand/mbr/mbr_gpt/Makefile b/sys/arch/i386/stand/mbr/mbr_gpt/Makefile new file mode 100644 index 000000000..d79f29b5d --- /dev/null +++ b/sys/arch/i386/stand/mbr/mbr_gpt/Makefile @@ -0,0 +1,6 @@ +# $NetBSD: Makefile,v 1.1 2011/01/06 01:08:49 jakllsch Exp $ + +PROG= mbr_gpt +SRCS= gpt.S + +.include <../Makefile.mbr> diff --git a/sys/arch/i386/stand/mbr/mbr_gpt_com0/Makefile b/sys/arch/i386/stand/mbr/mbr_gpt_com0/Makefile new file mode 100644 index 000000000..5e48b1ca6 --- /dev/null +++ b/sys/arch/i386/stand/mbr/mbr_gpt_com0/Makefile @@ -0,0 +1,7 @@ +# $NetBSD: Makefile,v 1.1 2011/01/06 01:08:49 jakllsch Exp $ + +PROG= mbr_gpt_com0 +SRCS= gpt.S +AFLAGS+= -DCOM_PORT=0 + +.include <../Makefile.mbr> diff --git a/tools/nbsd_ports b/tools/nbsd_ports index 9c6e5f9f7..79e451193 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/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 sys/lib/libz src/sys/lib/libz