[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Booting above 1024...
Dixitur illum slash@peereboom.us scribere...
>> run OpenBSD). Now, the OpenBSD partition on this disk is the 4th primary
>> partition, and / sits above 1024. I didn't have any issues chainloading
>> NetBSD with grub, but OpenBSD just gives the ever popular "Bad magic..."
>I don't recall who made it but someone had a "working" patch for this. Search
>the archives for details
The two below are LBA-capable "mbr" and "biosboot" with appropiate
Makefiles (hand-edited right now, 15 minutes after awaking, so don't
blame me please).
They need a fairly current ELF system with the fixes to /boot by
Tobias Weingartner already applied. (ELF is necessary due to the
usage of the GNU as intel_syntax feature)
Also integrated is an updated "installboot.c" file, which has been
adapted to the changed structure of the tables within biosboot.
#----- cutting here may damage your screen surface -----#
# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# mbr.S
# Makefile.mbr
# biosboot.S
# Makefile.biosboot
# installboot.c
#
echo x - mbr.S
sed 's/^X//' >mbr.S << 'END-of-mbr.S'
X/* $MirBSD: mbr.S,v 1.5 2003/07/08 14:40:04 tg Exp $
X *-
X * Copyright (c) 2003 Thorsten Glaser <x86@ePost.de>
X *
X * Subject to these terms, everybody who obtained a copy of this work
X * is hereby permitted to deal in the work without restriction inclu-
X * ding without limitation the rights to use, distribute, sell, modi-
X * fy, publically perform, give away, merge or sublicense it provided
X * this notice is kept and the authors and contributors are given due
X * credit in derivates or accompanying documents.
X * This work is provided "as is" with no explicit or implicit warran-
X * ties whatsoever to the maximum extend permitted by applicable law;
X * in no event may an author or contributor be held liable for damage
X * that is, directly or indirectly, caused by the work, even if advi-
X * sed of the possibility of such damage.
X *-
X * Fully LBA and CHS capable Master Boot Record with enough space for
X * the partition table and the Microsoft NT® disc ID; including boot-
X * manager capable of booting the four primary partitions or from the
X * first floppy device, with a 10 second time-out going off on a key.
X */
X
X .file "mbr.S"
X .intel_syntax noprefix
X
X .text
X .code16
X .globl _start
X_start: xor eax,eax
X push eax /* assume a sane stack of 4 bytes */
X popfd /* clear eflags and interrupts */
X mov ax,0x07A0
X mov ss,ax /* set up stack and other segments */
X mov sp,0x1000
X mov ds,ax
X mov es,ax
X mov si,0x0200 /* 7A0:0200 = 0:7C00 */
X xor di,di /* 7A0:0000 = 0:7A00 */
X mov cx,0x0100
X rep movsw /* relocate ourselfes */
X jmp 0x07A0,offset Ldoit
X /* we are relocated now */
XLdoit: /*
X * a) Output "Hello" Text
X * b) if BOOTMANAGER
X * Output "Choose" Text
X * Handle input (0,1,2,3,RET,ESC)
X * else
X * Fake input RET
X * endif
X * c) load sector (RET=0x80-Partition, ESC=Floppy, 0-3=Partition)
X * d) jump to sector
X */
X mov si,offset LtHelo
X call Lotxt
X#ifdef BOOTMANAGER
X xor ax,ax /* read CMOS clock ticks since midnight */
X int 0x1A
X mov edi,183 /* 10 seconds plus one tick */
X add di,dx
X adc cl,0 /* carry over */
X shl ecx,16
X add edi,ecx
XLiloop: mov ah,1 /* check if key pressed */
X int 0x16
X jnz Lkeyp /* key was pressed */
X xor ax,ax
X int 0x1A
X shl ecx,16
X mov cx,dx /* current clock tick */
X or al,al /* past midnight? */
X jz Lnwrap
X add ecx,1573040 /* according to Ralf Brown Interrupt List */
XLnwrap: cmp ecx,edi /* time is over? */
X jbe Liloop /* not yet */
X mov al,13 /* assume user pressed RETURN (default) */
X jmp Lchose
XLkeyp: xor ah,ah /* get pressed key */
X int 0x16
X cmp al,13 /* RETURN? */
X je Lchose
X cmp al,27 /* ESCAPE? */
X je Lchose
X sub al,0x30
X cmp al,3 /* '0' .. '3' ? */
X ja Lkeyp /* if invalid key, stop 10-second timeout */
XLchose: /* al=13,27,0,1,2,3 */
X#else
X mov al,13 /* fake a RETURN keypress */
X#endif
X cmp al,27
X je Lflopp /* ESC -> floppy */
X cmp al,13
X jne Lpart /* 0..3 -> partition chosen */
X xor al,al
X mov bx,offset ptbl
XLcklp: cmp byte ptr [bx],0x80
X je Lpart /* loop over partition table, search */
X inc ax /* for active partition */
X add bl,0x10 /* sizeof ptbl-ent */
X cmp al,4
X jb Lcklp /* if none found, fail */
XLbootf: mov si,offset LtFail
X call Lotxt
X xor ah,ah /* wait for keypress */
X int 0x16
X jmp 0xF000,0xFFF0 /* reboot */
XLotxt: lodsb
X or al,al /* '\0' is end of string */
X je Ltxout
X mov ah,0x0E /* tty a character */
X mov bx,7 /* light grey on black; page 0 */
X int 0x10
X jmp Lotxt
XLtxout: ret
XLpart: mov bx,offset ptbl
X shl al,4 /* log_2 sizeof ptbl-ent */
X add bl,al /* can't overflow */
X push bx
X /* Test for LBA support */
X mov ah,0x41
X mov bx,0x55AA
X mov dl,0x80
X int 0x13
X jc L_chs /* carry -> error */
X cmp bx,0xAA55
X jne L_chs /* magic -> command known? */
X and cl,1
X je L_chs /* bitmask: supports LBA? */
XL_lba: pop bx
X /* Load the boot structure (LBA) */
X mov si,offset lbapbl
X mov eax,[bx+8] /* offset on disc */
X mov [blknum],eax
X mov ax,[bx+2] /* save CHS values, in case */
X mov [savecx],ax /* the LBA boot fails twice */
X mov dx,[bx]
X mov dl,0x80
X mov [savedx],dx
X mov ah,0x42
X jmp Lboot_loop
XL_chs: pop bx
X /* Load the boot structure (CHS) */
X mov cx,[bx+2]
X mov dx,[bx]
X mov dl,0x80
X jmp Lboot_chs
XLflopp: mov cx,1
X xor dx,dx
XLboot_chs:
X mov bx,offset bsec
X mov ax,0x0201
X jmp Lboot_loop
XLtHelo: .ascii "MirBSD mbr 1.03\r\n"
X#ifdef BOOTMANAGER
XLtBmgr: .ascii "Press 0..3 to boot partition, ESC floppy\r\n"
X .asciz "RETURN/wait 10 sec: default\r\n"
X#else
X .byte 0 /* terminate the tHelo string */
X#endif
XLtFail: .ascii "Failed!"
X /* fall through */
XLtCRLF: .asciz "\r\n"
XLboot_loop:
X xor bp,bp
XLblp1: pusha
X mov ax,0x0E2E /* print a dot */
X mov bx,7
X int 0x10
X popa
X pusha
X int 0x13 /* try to read the PBR/bootsector */
X popa
X jc Lblp2
X mov si,offset LtCRLF
X call Lotxt /* print '\n' and jump into PBR */
X jmp 0,0x7C00 /* offset flat bsec */
XLblp2: pusha
X xor ax,ax /* reset the drive */
X int 0x13
X popa
X inc bp
X cmp bp,2 /* second time it failed? */
X jne Lblp3
X xor di,di
X cmp [savedx],di /* if so, check if we were LBA */
X je Lblp3
X mov cx,[savecx] /* if so, fall back to CHS */
X mov dx,[savedx]
X mov bx,offset bsec
X mov ax,0x0201
XLblp3: cmp bp,16 /* 16 retries should be enough for everyone :) */
X jb Lblp1
X jmp Lbootf /* failed */
Xlbapbl: /* Parameter block for LBA */
X .word 0x0010 /* length, reserved */
X .word 0x0001 /* num. of sectors */
X .long 0x00007C00 /* transfer buffer */
Xblknum: .long 0,0 /* LBA block number */
Xsavecx: .word 0
Xsavedx: .word 0
X
X /* Trailer: partition table, signature */
X#if 0
X . = 0x01B8
X .long 0 /* device ID/magic */
X .word 0 /* free/reserved */
X#else
X /* In fact, we have 6 bytes of 0x00 before
X * (on the disc), and ignore/overwrite what
X * Microsoft NT writes here (on the disc),
X * so we can safely skip till here:
X */
X . = 0x01BE
X#endif
Xptbl: .long 0,0,0,0
X .long 0,0,0,0
X .long 0,0,0,0
X .long 0,0,0,0
X .word 0xAA55 /* signature */
Xbsec: /* 0x0200 is where the new boot sector is loaded */
END-of-mbr.S
echo x - Makefile.mbr
sed 's/^X//' >Makefile.mbr << 'END-of-Makefile.mbr'
X# $MirBSD: Makefile,v 1.1 2003/05/23 14:21:48 tg Exp $
X
XPROG= mbr
XSRCS= mbr.S
X
XNOMAN= yes
XINSTALL_STRIP=
XLDFLAGS= -nostdlib -Ttext 0 -N -x -Bstatic
X
X# Uncomment this to build a boot manager
XCPPFLAGS+= -DBOOTMANAGER
X
X${PROG}: $(OBJS) $(DPADD)
X $(LD) $(LDFLAGS) -o $(PROG) $(OBJS) $(LDADD)
X @size $(PROG)
X @if [ -x ${.OBJDIR}/${PROG} ]; then \
X objcopy -O binary ${PROG} ${.OBJDIR}/.tmp; \
X mv -f ${.OBJDIR}/.tmp ${.OBJDIR}/${PROG}; \
X ls -l ${.OBJDIR}/${PROG}; \
X fi
X
Xdisasm: ${PROG}
X ndisasm -b 16 ${PROG} >${.CURDIR}/disasm
X
X.include <bsd.prog.mk>
END-of-Makefile.mbr
echo x - biosboot.S
sed 's/^X//' >biosboot.S << 'END-of-biosboot.S'
X/* $MirBSD: pbr.S,v 1.20 2003/07/06 20:22:28 tg Exp $
X *-
X * Copyright (c) 2003 Thorsten Glaser <x86@ePost.de>
X * Derived from ideas and meant to be compatible to the
X * original OpenBSD first stage boot loader code from:
X * Copyright (c) 1997 Michael Shalayeff, Tobias Weingartner
X *
X * Subject to these terms, everybody who obtained a copy of this work
X * is hereby permitted to deal in the work without restriction inclu-
X * ding without limitation the rights to use, distribute, sell, modi-
X * fy, give away, merge or sublicense it provided this notice is kept
X * and the authors and contributors are given due credit in derivates
X * or accompanying documents.
X * This work is provided "as is" with no explicit or implicit warran-
X * ties whatsoever to the maximum extend permitted by applicable law;
X * in no event may an author or contributor be held liable for damage
X * that is, directly or indirectly, caused by the work, even if advi-
X * sed of the possibility of such damage.
X */
X
X#define BLKCNT (blkend - blktbl)
X
X .file "pbr.S"
X .intel_syntax noprefix
X
X .text
X .code16
X .globl _start
XLpbl: /* Parameter block for LBA, gets constructed here:
X word 0x0010 (+0,2) length, reserved
X word 0x0001 (+2,2) num. of sectors
X long 0x00007C00 (+4,4) transfer buffer
X long 0,0 (+8,8) LBA block number
X */
X_start: jmp Linit
X nop
X . = _start + 3
XLmsg: .ascii "Loading "
X .word 512 /* bytes per sector */
X .byte 1 /* sectors per cluster */
X .word 1 /* reserved sectors */
X .byte 0 /* FATs per volume */
XLldp: .word LsLBA /* root dir ents */
X .word 0 /* sectors per drive (FAT16s) */
X .byte 0xF8 /* media ID */
X .globl blkcnt /** block count in hint table */
X .type blkcnt, @function
X .globl bpbspt /** used to convert LBA -> CHS */
X .type bpbspt, @function
X .globl bpbtpc /** used to convert LBA -> CHS */
X .type bpbtpc, @function
Xblkcnt: .word BLKCNT /* sectors per FAT */
Xbpbspt: .word 18 /* sectors per track */
Xbpbtpc: .word 2 /* tracks per cylinder */
X .long 16 /* hidden sectors */
XLbmgc: .long BOOTMAGIC /* sectors per drive (FAT16B) */
XLdrv: .byte 0x80, 0 /* BIOS drive */
X .byte 0x29 /* magic (EBPB) */
X/* the following code is 0x0F bytes long:
X .long 0 // volume serial number
X .asciz "UNIX LABEL" // volume label
X */
XLotxt: lodsb
X or al,al
X je Lotxt1
X mov ah,0x0E
X mov bx,7
X int 0x10
X jmp Lotxt
XLotxt1: ret
X . = 15 + Lotxt /* ensure it fits exactly */
X .asciz "UFS 4.4" /* volume fstype */
X
XLinit: xor eax,eax
X push ax
X popf
X mov ss,ax
X mov sp,0xFFFC
X sti
X add ax,0x7C0 /* not MOV - eases debugging... */
X mov ds,ax
X mov gs,ax
X push ax
X push offset Lrun
X lret /* should read retf */
X
XLerr: .ascii "bad magic."
XLldf: .ascii " FAILED!"
XLcrlf: .asciz "\r\n"
X
XLrun: mov [Ldrv],dl /* boot device */
X /* say hello */
X mov si,offset Lmsg
X call Lotxt
X /* check for LBA */
X mov ah,0x41
X mov bx,0x55AA
X int 0x13
X jc Lr_chs /* carry -> error */
X cmp bx,0xAA55
X jne Lr_chs /* magic -> command known? */
X and cl,1
X jne Lr_lba /* bitmask: supports LBA? */
XLr_chs: call Lpaddr
XLr_lba: /* start the first stage boot loader code */
X mov ax,(LOADADDR / 16)
X mov fs,ax /* for ELFmagic check */
X push ax /* for load address and incrementing */
X mov ax,0x0010
X mov [Lpbl],eax /* high 16 bits are already cleared */
X /* initialize counters */
X mov si,offset blktbl
X mov cx,[blkcnt]
X /* --- main loop --- */
XLmlp1: lodsb
X /*
X * al contains bitmasked:
X * aaabbbbb
X * -> a=number of bytes-1 that follow (-> dl)
X * -> b=number of sectors-1 to load (-> al)
X * si, cx contain what is to be processed
X */
X
X /* decode */
X mov dl,al
X shr dl,5
X and ax,31 /* sectors */
X inc ax
X inc dx
X mov [2+Lpbl],al
X pop bx
X mov es,bx /* load segment */
X mov [6+Lpbl],bx
X shl ax,(9-4) /* number of sectors
X times their size
X divided by size of one paragraph */
X add bx,ax /* increment load addr. segment accordingly */
X push bx /* and save for next round */
X push cx /* save blkcnt */
X mov di,8+offset Lpbl
X xor ebp,ebp
X mov [di],ebp /* zero out the LBA sector number */
X mov [di+4],ebp
X mov [di-4],bp /* load offset within segment, always zero */
XLmlp2: lodsb /* copy over as many bytes as needed */
X mov [di],al
X inc di /* stos? segment override forbidden */
X dec dl
X jne Lmlp2 /* faster than loop */
X /*
X * at this point, we have the following:
X * si points to the _next_ entry to load
X * on top of stack, there is the number of
X * entries to load, including the current one
X * the _next_ load address is below that on the stack
X * the LBA parameter block is filled in.
X * ES is set up to the load segment (offset = const. 0000)
X */
X
X /* call subroutine that does the actual loading */
X mov dl,[Ldrv]
X call [Lldp]
X /* progress meter */
X mov ax,0x0E2E
X mov bx,7
X int 0x10 /* output a dot */
X /* --- main loop --- */
X pop cx
X dec cx
X jne Lmlp1
X
X /* finally /boot is loaded. compare ELFmagic */
X mov si,2
X fs lodsw
X cmp ax,0x464C /* last two bytes of "\x7FELF" */
X mov si,offset Lerr
X jne Lbarf
X /* new line, for the fine look */
X mov si,offset Lcrlf
X call Lotxt
X /* set up and jump into /boot */
X mov bp,[Ldrv] /* the byte after Ldrv is always zero */
X push ebp /* as well as the high half of ebp */
X push dword ptr [Lbmgc] /* boot magic */
X jmp (LINKADDR / 16),0
X /* CHS boot routine */
XLsCHS: push dx
X /* LBA -> CHS */
X mov edx,[8+Lpbl]
X mov ax,dx
X shr edx,16
X div word ptr [bpbspt]
X inc dx /* quotient AX, rem DX */
X push dx /* sector */
X xor dx,dx
X div word ptr [bpbtpc]
X pop cx /* cylinder AX, head DX */
X shl ah,6
X xchg ah,al
X or cx,ax
X mov dh,dl
X pop ax
X mov dl,al
X /* call the BIOS */
X mov ah,2
X mov al,[2+Lpbl]
X xor bx,bx
XLsINT: mov bp,7 /* retries */
XLsIN0: pusha
X int 0x13
X popa
X jnc Lretn
X pusha
X xor ax,ax
X int 0x13
X mov ax,0x0E40 /* say it fails */
X add ax,bp
X mov bx,7
X int 0x10
X popa
X mov si,offset Lldf
X dec bp
X jne Lnchk
XLbarf: call Lotxt
X xor ah,ah
X int 0x16
X jmp 0xF000,0xFFF0
XLnchk: cmp bp,3 /* after some failed LBA, try CHS */
X push offset LsIN0
X jna Lretn
XLpaddr: push offset LsCHS
X pop [Lldp] /* patch address of loader proc */
XLretn: ret
XLsLBA: push si /* save blktbl offset */
X mov ah,0x42 /* call BIOS */
X mov si,offset Lpbl
X call LsINT
X pop si
X ret
X /* --- end of code --- */
X
X .globl blktbl /** hint table start */
X .type blktbl, @function
Xblktbl:
X . = 0x1FE
Xblkend: .word 0xAA55
END-of-biosboot.S
echo x - Makefile.biosboot
sed 's/^X//' >Makefile.biosboot << 'END-of-Makefile.biosboot'
X# from $MirBSD: Makefile,v 1.7 2003/06/05 20:29:24 tg Exp $
X
XSADIR= ${.CURDIR}/..
X.include <../Makefile.inc>
X
XPROG= biosboot
XSRCS= biosboot.S
X
XNOMAN= yes
XINSTALL_STRIP=
XLDFLAGS= -nostdlib -Ttext 0 -N -x -Bstatic
XCPPFLAGS+= -DLOADADDR=$(LOADADDR) -DLINKADDR=$(LINKADDR) \
X -DBOOTMAGIC=$(BOOTMAGIC) ${DEBUGFLAGS}
X
X${PROG}: $(OBJS) $(DPADD)
X $(LD) $(LDFLAGS) -o $(PROG) $(OBJS) $(LDADD)
X @size $(PROG)
X
Xdisasm: ${PROG}
X objcopy -O binary ${PROG} ${.OBJDIR}/.tmp; \
X ndisasm -b 16 ${.OBJDIR}/.tmp >${.CURDIR}/disasm
XCLEANFILES+= .tmp
X
X.include <bsd.prog.mk>
END-of-Makefile.biosboot
echo x - installboot.c
sed 's/^X//' >installboot.c << 'END-of-installboot.c'
X/* $MirBSD: installboot.c,v 1.23 2003/08/31 20:54:51 tg Exp $ */
X/* $OpenBSD: installboot.c,v 1.41 2003/08/25 23:27:43 tedu Exp $ */
X/* $NetBSD: installboot.c,v 1.5 1995/11/17 23:23:50 gwr Exp $ */
X
X/*
X * Copyright (c) 2003 Thorsten Glaser
X * Copyright (c) 1997 Michael Shalayeff
X * Copyright (c) 1994 Paul Kranenburg
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X * notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X * notice, this list of conditions and the following disclaimer in the
X * documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X * must display the following acknowledgement:
X * This product includes software developed by Paul Kranenburg.
X * 4. The name of the author may not be used to endorse or promote products
X * derived from this software without specific prior written permission
X *
X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
X * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
X * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
X * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
X * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
X * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
X * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
X * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X */
X
X#include <sys/param.h>
X#include <sys/mount.h>
X#include <sys/time.h>
X#include <sys/stat.h>
X#include <sys/disklabel.h>
X#include <sys/dkio.h>
X#include <sys/ioctl.h>
X#include <ufs/ufs/dinode.h>
X#include <ufs/ufs/dir.h>
X#include <ufs/ffs/fs.h>
X#include <sys/reboot.h>
X#include <sys/errno.h>
X
X#include <uvm/uvm_extern.h>
X#include <sys/sysctl.h>
X
X#include <machine/cpu.h>
X#include <machine/biosvar.h>
X
X#include <err.h>
X#include <a.out.h>
X#include <sys/exec_elf.h>
X#include <fcntl.h>
X#include <nlist.h>
X#include <stdlib.h>
X#include <stdio.h>
X#include <string.h>
X#include <unistd.h>
X#include <util.h>
X
Xextern char *__progname;
Xint verbose, nowrite, nheads, nsectors, userspec = 0;
Xchar *boot, *proto, *dev, *realdev;
Xstruct nlist nl[] = {
X#define X_BLOCK_COUNT 0
X {{"_blkcnt"}},
X#define X_BLOCK_TABLE 1
X {{"_blktbl"}},
X#define X_NUM_SECS 2
X {{"_bpbspt"}},
X#define X_NUM_HEADS 3
X {{"_bpbtpc"}},
X {{NULL}}
X};
X
Xu_int8_t *block_count_p; /* block count var. in prototype image */
Xu_int8_t *block_table_p; /* block number array in prototype image */
Xu_int8_t *num_heads_p; /* number of tracks per cylinder */
Xu_int8_t *num_secs_p; /* number of sectors per track */
Xint maxblocklen; /* size of this array */
Xint curblocklen = 0; /* actually used up bytes */
X
Xint biosdev;
X
Xchar *loadprotoblocks(char *, long *);
Xint loadblocknums(char *, int, struct disklabel *);
Xstatic void devread(int, void *, daddr_t, size_t, char *);
Xstatic void usage(void);
Xstatic int record_block(u_int8_t *, daddr_t, u_int, struct disklabel *);
X
Xstatic const char RCSId[]="$MirBSD: installboot.c,v 1.23 2003/08/31 20:54:51 tg Exp $";
X
Xstatic int record_block(u_int8_t *bt, daddr_t blk, u_int bs,
X struct disklabel *dl);
Xstatic int do_record(u_int8_t *bt, daddr_t blk, u_int bs,
X struct disklabel *dl);
X
X
Xstatic void
Xusage(void)
X{
X fprintf(stderr, "usage: %s [-n] [-v] [-s sec-per-track] [-h track-per-cyl] "
X "boot biosboot device\n", __progname);
X exit(1);
X}
X
Xint
Xmain(int argc, char *argv[])
X{
X int c;
X int devfd;
X char *protostore;
X long protosize;
X struct stat sb;
X struct disklabel dl;
X struct dos_mbr mbr;
X struct dos_partition *dp;
X off_t startoff = 0;
X int mib[4];
X size_t size;
X dev_t devno;
X bios_diskinfo_t di;
X
X nsectors = nheads = -1;
X while ((c = getopt(argc, argv, "vnh:s:")) != -1) {
X switch (c) {
X case 'h':
X nheads = atoi(optarg);
X userspec = 1;
X break;
X case 's':
X nsectors = atoi(optarg);
X userspec = 1;
X break;
X case 'n':
X /* Do not actually write the bootblock to disk */
X nowrite = 1;
X break;
X case 'v':
X /* Chat */
X verbose = 1;
X break;
X default:
X usage();
X }
X }
X
X if (argc - optind < 3) {
X usage();
X }
X
X boot = argv[optind];
X proto = argv[optind + 1];
X realdev = dev = argv[optind + 2];
X
X /* Open and check raw disk device */
X if ((devfd = opendev(dev, (nowrite? O_RDONLY:O_RDWR),
X OPENDEV_PART, &realdev)) < 0)
X err(1, "open: %s", realdev);
X
X if (verbose) {
X fprintf(stderr, "boot: %s\n", boot);
X fprintf(stderr, "proto: %s\n", proto);
X fprintf(stderr, "device: %s\n", realdev);
X }
X
X if (ioctl(devfd, DIOCGDINFO, &dl) != 0)
X err(1, "disklabel: %s", realdev);
X
X /* check disklabel */
X if (dl.d_magic != DISKMAGIC)
X err(1, "bad disklabel magic=%0x8x", dl.d_magic);
X
X /* warn on unknown disklabel types */
X if (dl.d_type == 0)
X warnx("disklabel type unknown");
X
X /* Load proto blocks into core */
X if ((protostore = loadprotoblocks(proto, &protosize)) == NULL)
X exit(1);
X
X /* XXX - Paranoia: Make sure size is aligned! */
X if (protosize & (DEV_BSIZE - 1))
X err(1, "proto %s bad size=%ld", proto, protosize);
X
X /* Write patched proto bootblocks into the superblock */
X if (protosize > SBSIZE - DEV_BSIZE)
X errx(1, "proto bootblocks too big");
X
X if (fstat(devfd, &sb) < 0)
X err(1, "stat: %s", realdev);
X
X if (!S_ISCHR(sb.st_mode))
X errx(1, "%s: Not a character device", realdev);
X
X if (nheads == -1 || nsectors == -1) {
X mib[0] = CTL_MACHDEP;
X mib[1] = CPU_CHR2BLK;
X mib[2] = sb.st_rdev;
X size = sizeof(devno);
X if(sysctl(mib, 3, &devno, &size, NULL, 0) >= 0) {
X devno = MAKEBOOTDEV(major(devno), 0, 0,
X DISKUNIT(devno), RAW_PART);
X mib[0] = CTL_MACHDEP;
X mib[1] = CPU_BIOS;
X mib[2] = BIOS_DISKINFO;
X mib[3] = devno;
X size = sizeof(di);
X if(sysctl(mib, 4, &di, &size, NULL, 0) >= 0) {
X nheads = di.bios_heads;
X nsectors = di.bios_sectors;
X }
X }
X }
X
X if (nheads == -1 || nsectors == -1)
X fprintf(stderr, "warning: Unable to get BIOS geometry, must/should specify -h and -s\nwarning: the drive may not boot in non-LBA mode");
X
X /* Extract and load block numbers */
X if (loadblocknums(boot, devfd, &dl) != 0)
X exit(1);
X
X /* Sync filesystems (to clean in-memory superblock?) */
X sync(); sleep(1);
X
X if (dl.d_type != 0 && dl.d_type != DTYPE_FLOPPY &&
X dl.d_type != DTYPE_VND) {
X if (lseek(devfd, (off_t)DOSBBSECTOR, SEEK_SET) < 0 ||
X read(devfd, &mbr, sizeof(mbr)) < sizeof(mbr))
X err(4, "can't read master boot record");
X
X if (mbr.dmbr_sign != DOSMBR_SIGNATURE)
X errx(1, "broken MBR");
X
X /* Find MirBSD partition. */
X for (dp = mbr.dmbr_parts; dp < &mbr.dmbr_parts[NDOSPART]; dp++) {
X if (dp->dp_size && dp->dp_typ == DOSPTYP_MIRBSD) {
X startoff = (off_t)dp->dp_start * dl.d_secsize;
X fprintf(stderr, "using MBR partition %ld: "
X "type %d (0x%02x) offset %d (0x%x)\n",
X (long)(dp - mbr.dmbr_parts),
X dp->dp_typ, dp->dp_typ,
X dp->dp_start, dp->dp_start);
X break;
X }
X }
X /* Find OpenBSD partition. */
X if (dp >= &mbr.dmbr_parts[NDOSPART])
X for (dp = mbr.dmbr_parts; dp < &mbr.dmbr_parts[NDOSPART]; dp++) {
X if (dp->dp_size && dp->dp_typ == DOSPTYP_OPENBSD) {
X startoff = (off_t)dp->dp_start * dl.d_secsize;
X fprintf(stderr, "using MBR partition %ld: "
X "type %d (0x%02x) offset %d (0x%x)\n",
X (long)(dp - mbr.dmbr_parts),
X dp->dp_typ, dp->dp_typ,
X dp->dp_start, dp->dp_start);
X break;
X }
X }
X /* don't check for old part number, that is ;-p */
X if (dp >= &mbr.dmbr_parts[NDOSPART])
X errx(1, "no MirBSD or OpenBSD partition");
X }
X
X *num_heads_p = nheads;
X *num_secs_p = nsectors;
X
X if (!nowrite) {
X if (lseek(devfd, startoff, SEEK_SET) < 0 ||
X write(devfd, protostore, protosize) != protosize)
X err(1, "write bootstrap");
X }
X
X (void)close(devfd);
X
X return 0;
X}
X
Xchar *
Xloadprotoblocks(char *fname, long *size)
X{
X int fd;
X size_t tdsize; /* text+data size */
X char *bp;
X struct nlist *nlp;
X Elf_Ehdr eh;
X Elf_Word phsize;
X Elf_Phdr *ph;
X
X fd = -1;
X bp = NULL;
X
X /* Locate block number array in proto file */
X if (nlist(fname, nl) != 0) {
X warnx("nlist: %s: symbols not found", fname);
X return NULL;
X }
X /* Validate symbol types (global data). */
X for (nlp = nl; nlp->n_un.n_name; nlp++) {
X if (nlp->n_type != (N_TEXT)) {
X warnx("nlist: %s: wrong type %x", nlp->n_un.n_name,
X nlp->n_type);
X return NULL;
X }
X }
X
X if ((fd = open(fname, O_RDONLY)) < 0) {
X warn("open: %s", fname);
X return NULL;
X }
X if (read(fd, &eh, sizeof(eh)) != sizeof(eh)) {
X warn("read: %s", fname);
X goto bad;
X }
X if (!IS_ELF(eh)) {
X errx(1, "%s: bad magic: 0x%02x%02x%02x%02x",
X boot,
X eh.e_ident[EI_MAG0], eh.e_ident[EI_MAG1],
X eh.e_ident[EI_MAG2], eh.e_ident[EI_MAG3]);
X }
X
X /*
X * We have to include the exec header in the beginning of
X * the buffer, and leave extra space at the end in case
X * the actual write to disk wants to skip the header.
X */
X
X /* program load header */
X if (eh.e_phnum != 1) {
X errx(1, "%s: only supports one ELF load section", boot);
X }
X phsize = eh.e_phnum * sizeof(Elf_Phdr);
X ph = malloc(phsize);
X if (ph == NULL) {
X errx(1, "%s: unable to allocate program header space",
X boot);
X }
X lseek(fd, eh.e_phoff, SEEK_SET);
X
X if (read(fd, ph, phsize) != phsize) {
X errx(1, "%s: unable to read program header space", boot);
X }
X
X tdsize = ph->p_filesz;
X
X /*
X * Allocate extra space here because the caller may copy
X * the boot block starting at the end of the exec header.
X * This prevents reading beyond the end of the buffer.
X */
X if ((bp = calloc(tdsize, 1)) == NULL) {
X warnx("malloc: %s: no memory", fname);
X goto bad;
X }
X /* Read the rest of the file. */
X lseek(fd, ph->p_offset, SEEK_SET);
X if (read(fd, bp, tdsize) != tdsize) {
X warn("read: %s", fname);
X goto bad;
X }
X
X *size = tdsize; /* not aligned to DEV_BSIZE */
X
X /* Calculate the symbols' locations within the proto file */
X block_count_p = (u_int8_t *) (bp + nl[X_BLOCK_COUNT].n_value);
X block_table_p = (u_int8_t *) (bp + nl[X_BLOCK_TABLE].n_value);
X num_heads_p = (u_int8_t *) (bp + nl[X_NUM_HEADS].n_value);
X num_secs_p = (u_int8_t *) (bp + nl[X_NUM_SECS].n_value);
X maxblocklen = *block_count_p;
X
X if (verbose) {
X fprintf(stderr, "%s: entry point %#x\n", fname, eh.e_entry);
X fprintf(stderr, "proto bootblock size %ld\n", *size);
X fprintf(stderr,
X "room for average %d filesystem blocks (%d bytes) at %#lx\n",
X (int)(((double)maxblocklen)/4.5), maxblocklen,
X nl[X_BLOCK_TABLE].n_value);
X }
X
X close(fd);
X return bp;
X
X bad:
X if (bp)
X free(bp);
X if (fd >= 0)
X close(fd);
X return NULL;
X}
X
Xstatic void
Xdevread(int fd, void *buf, daddr_t blk, size_t size, char *msg)
X{
X if (lseek(fd, dbtob((off_t)blk), SEEK_SET) != dbtob((off_t)blk))
X err(1, "%s: devread: lseek", msg);
X
X if (read(fd, buf, size) != size)
X err(1, "%s: devread: read", msg);
X}
X
Xstatic char sblock[SBSIZE];
X
Xint
Xloadblocknums(char *boot, int devfd, struct disklabel *dl)
X{
X int i, fd;
X struct stat statbuf, sb;
X struct statfs statfsbuf;
X struct partition *pl;
X struct fs *fs;
X char *buf;
X daddr_t blk, *ap;
X struct ufs1_dinode *ip;
X int ndb;
X u_int8_t *bt;
X int mib[4];
X size_t size;
X dev_t dev;
X
X /*
X * Open 2nd-level boot program and record the block numbers
X * it occupies on the filesystem represented by 'devfd'.
X */
X
X /* Make sure the (probably new) boot file is on disk. */
X sync(); sleep(1);
X
X if ((fd = open(boot, O_RDONLY)) < 0)
X err(1, "open: %s", boot);
X
X if (fstatfs(fd, &statfsbuf) != 0)
X err(1, "statfs: %s", boot);
X
X if (strncmp(statfsbuf.f_fstypename, "ffs", MFSNAMELEN) &&
X strncmp(statfsbuf.f_fstypename, "ufs", MFSNAMELEN) ) {
X errx(1, "%s: must be on an FFS filesystem", boot);
X }
X
X#if 0
X if (read(fd, &eh, sizeof(eh)) != sizeof(eh)) {
X errx(1, "read: %s", boot);
X }
X
X if (!IS_ELF(eh)) {
X errx(1, "%s: bad magic: 0x%02x%02x%02x%02x",
X boot,
X eh.e_ident[EI_MAG0], eh.e_ident[EI_MAG1],
X eh.e_ident[EI_MAG2], eh.e_ident[EI_MAG3]);
X }
X#endif
X
X if (fsync(fd) != 0)
X err(1, "fsync: %s", boot);
X
X if (fstat(fd, &statbuf) != 0)
X err(1, "fstat: %s", boot);
X
X if (fstat(devfd, &sb) != 0)
X err(1, "fstat: %s", realdev);
X
X /* check devices */
X mib[0] = CTL_MACHDEP;
X mib[1] = CPU_CHR2BLK;
X mib[2] = sb.st_rdev;
X size = sizeof(dev);
X if (sysctl(mib, 3, &dev, &size, NULL, 0) >= 0)
X if (statbuf.st_dev / MAXPARTITIONS != dev / MAXPARTITIONS)
X errx(1, "cross-device install");
X
X pl = &dl->d_partitions[DISKPART(statbuf.st_dev)];
X close(fd);
X
X /* Read superblock */
X devread(devfd, sblock, pl->p_offset + SBLOCK, SBSIZE, "superblock");
X fs = (struct fs *)sblock;
X
X /* Sanity-check super-block. */
X if (fs->fs_magic != FS_MAGIC)
X errx(1, "Bad magic number in superblock");
X if (fs->fs_inopb <= 0)
X err(1, "Bad inopb=%d in superblock", fs->fs_inopb);
X
X /* Read inode */
X if ((buf = malloc(fs->fs_bsize)) == NULL)
X errx(1, "No memory for filesystem block");
X
X blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino));
X devread(devfd, buf, pl->p_offset + blk, fs->fs_bsize, "inode");
X ip = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs, statbuf.st_ino);
X
X /*
X * Have the inode. Figure out how many blocks we need.
X */
X ndb = howmany(ip->di_size, fs->fs_bsize);
X if (ndb <= 0)
X errx(1, "No blocks to load");
X if (verbose)
X fprintf(stderr, "Will load %d blocks of size %d each.\n",
X ndb, fs->fs_bsize);
X
X if ((dl->d_type != 0 && dl->d_type != DTYPE_FLOPPY &&
X dl->d_type != DTYPE_VND) || userspec ) {
X /* adjust disklabel w/ synthetic geometry */
X dl->d_nsectors = nsectors;
X dl->d_secpercyl = dl->d_nsectors * nheads;
X }
X
X if (verbose)
X fprintf(stderr, "Using disk geometry of %u sectors and %u heads.\n",
X dl->d_nsectors, dl->d_secpercyl/dl->d_nsectors);
X
X /*
X * Get the block numbers; we don't handle fragments
X */
X ap = ip->di_db;
X bt = block_table_p;
X for (i = 0; i < NDADDR && *ap && ndb; i++, ap++, ndb--)
X bt += record_block(bt, pl->p_offset + fsbtodb(fs, *ap),
X fs->fs_bsize / 512, dl);
X if (ndb != 0) {
X
X /*
X * Just one level of indirections; there isn't much room
X * for more in the 2nd-level /boot anyway.
X */
X blk = fsbtodb(fs, ip->di_ib[0]);
X devread(devfd, buf, pl->p_offset + blk, fs->fs_bsize,
X "indirect block");
X ap = (daddr_t *)buf;
X for (; i < NINDIR(fs) && *ap && ndb; i++, ap++, ndb--)
X bt += record_block(bt, pl->p_offset + fsbtodb(fs, *ap),
X fs->fs_bsize / 512, dl);
X }
X
X bt += record_block(bt, 0, 0, dl);
X
X if (bt > (block_table_p + maxblocklen))
X errx(1, "Too many blocks");
X
X if (verbose)
X fprintf(stderr, "%s: %d entries total (%d bytes)\n",
X boot, block_count_p[0], curblocklen);
X
X return 0;
X}
X
Xstatic int
Xrecord_block(u_int8_t *bt, daddr_t blk, u_int bs, struct disklabel *dl)
X{
X static u_int W_num = 0;
X static daddr_t W_ofs = 0;
X
X int flush = 0, cache = 0, retval = 0;
X int i;
X
X if (!blk) {
X ++flush;
X } else if (!W_ofs) {
X ++cache;
X } else if (blk == (W_ofs+W_num)) {
X ++cache;
X } else {
X ++flush;
X ++cache;
X }
X
X if (flush) {
X /*
X * Flush the blocks cached to the disc.
X * Obey the track boundaries if possible.
X */
X if (!W_num) goto flush_end;
X if ((nheads == -1) || (nsectors == -1)) {
X retval += do_record(bt+retval, W_ofs, W_num, dl);
X goto flush_end;
X }
X
X i = W_ofs % nsectors; /* sector within track -1 */
X if (i < (nsectors-1)) {
X i = nsectors - i;
X if (i > W_num) i=W_num;
X retval += do_record(bt+retval, W_ofs, i, dl);
X W_ofs += i;
X W_num -= i;
X }
X
X while (W_num > nsectors) {
X retval += do_record(bt+retval, W_ofs, nsectors, dl);
X W_ofs += nsectors;
X W_num -= nsectors;
X }
X
X if (W_num)
X retval += do_record(bt+retval, W_ofs, W_num, dl);
X
X flush_end:
X W_ofs=0; W_num=0;
X }
X
X if (cache) {
X if (!W_ofs) W_ofs = blk;
X W_num += bs;
X }
X
X return (retval);
X}
X
Xstatic int
Xdo_record(u_int8_t *bt, daddr_t blk, u_int bs, struct disklabel *dl)
X{
X static u_int i = 0;
X u_int8_t tv, len;
X u_int64_t bk, wbk;
X u_int j;
X int wbs, retval = 0;
X u_int8_t *wbt;
X
X if ((!blk) || (!bt))
X return 0;
X
X if (bs > 768) /* after that there's VGA memory */
X errx(1, "Too many blocks in a chunk!");
X
X wbs = bs;
X wbt = bt;
X bk = blk;
X if (verbose)
X fprintf(stderr, "%2d: %2d @%lld (0x%08llX)\n",
X i, bs, bk, bk);
X
X do {
X ++i;
X
X if (bk < 0x0000000000000100ULL)
X len = 0;
X else if (bk < 0x0000000000010000ULL)
X len = 1;
X else if (bk < 0x0000000001000000ULL)
X len = 2;
X else if (bk < 0x0000000100000000ULL)
X len = 3;
X else if (bk < 0x0000010000000000ULL)
X len = 4;
X else if (bk < 0x0001000000000000ULL)
X len = 5;
X else if (bk < 0x0100000000000000ULL)
X len = 6;
X else len = 7;
X
X if (wbs < 33)
X tv = (len << 5) | (wbs - 1);
X else tv = (len << 5) | 31;
X
X *(wbt++) = tv;
X wbk = bk;
X bk += 1 + (tv & 31);
X for (j = 0; j <= len; ++j) {
X *(wbt++) = (wbk & 0xFF);
X wbk >>= 8;
X }
X
X wbs -= 32;
X retval += (len+2);
X } while (wbs > 0);
X
X *block_count_p = i;
X curblocklen += retval;
X return (retval);
X}
END-of-installboot.c
exit
#----- cutting here may damage your screen surface -----#
HTH&HAND,
//Thorsten
--
[...] if maybe ext3fs wasn't a better pick, or jfs, or maybe reiserfs, oh but
what about xfs, and if only i had waited until reiser4 was ready... in the be-
ginning, there was ffs, and in the middle, there was ffs, and at the end, there
was still ffs, and the sys admins knew it was good. :) -- Ted Unangst über *fs