summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrnordier <rnordier@FreeBSD.org>1998-10-12 21:16:26 +0000
committerrnordier <rnordier@FreeBSD.org>1998-10-12 21:16:26 +0000
commit0a456c31da5cce1efa65cffe5ae495ddd77f1ca0 (patch)
tree6b3b66ac0ef75e48178975e61a6920204e1cb810
parent8eaab1764cab145597a7e2574f238594639dd9ec (diff)
downloadFreeBSD-src-0a456c31da5cce1efa65cffe5ae495ddd77f1ca0.zip
FreeBSD-src-0a456c31da5cce1efa65cffe5ae495ddd77f1ca0.tar.gz
New boot blocks: support for /boot/loader; a.out & ELF; cyl > 1023;
multiple 0xa5 slices; etc.
-rw-r--r--sys/boot/i386/boot2/boot1.S250
-rw-r--r--sys/boot/i386/gptboot/Makefile51
-rw-r--r--sys/boot/i386/gptboot/gptboot.c731
3 files changed, 1032 insertions, 0 deletions
diff --git a/sys/boot/i386/boot2/boot1.S b/sys/boot/i386/boot2/boot1.S
new file mode 100644
index 0000000..b84ddf3
--- /dev/null
+++ b/sys/boot/i386/boot2/boot1.S
@@ -0,0 +1,250 @@
+#
+# Copyright (c) 1998 Robert Nordier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are freely
+# permitted provided that the above copyright notice and this
+# paragraph and the following disclaimer are duplicated in all
+# such forms.
+#
+# This software is provided "AS IS" and without any express or
+# implied warranties, including, without limitation, the implied
+# warranties of merchantability and fitness for a particular
+# purpose.
+#
+
+# $Id:$
+
+ .set MEM_REL,0x600 # Relocation address
+ .set MEM_ARG,0x800 # Arguments
+ .set MEM_PKT,0x810 # Disk packet
+ .set MEM_ORG,0x7c00 # Origin
+ .set MEM_BUF,0x8c00 # Load area
+ .set MEM_BTX,0x9000 # BTX start
+ .set MEM_JMP,0x9010 # BTX entry point
+ .set MEM_USR,0xa000 # Client start
+
+ .set PRT_OFF,0x1be # Partition offset
+ .set PRT_NUM,0x4 # Partitions
+ .set PRT_BSD,0xa5 # Partition type
+
+ .set SIZ_PAG,0x1000 # Page size
+ .set SIZ_SEC,0x200 # Sector size
+
+ .globl start
+ .globl xread
+
+start: jmp main # Start recognizably
+
+ .org 0x4,0x90
+
+xread: pushl %cs # Address
+ popl %ds # data
+xread.1: movwir(MEM_PKT,_si) # Packet
+ movbr1(_al,0x2,_si_) # Blocks to read
+ o16 # Transfer
+ movwr1(_bx,0x4,_si_) # buffer
+ o16 # LBA
+ movwr1(_cx,0x8,_si_) # address
+ callwi(read) # Read from disk
+ lret # To caller
+
+main: cld # String ops inc
+ xorl %eax,%eax # Zero
+ movl %ax,%es # Address
+ movl %ax,%ds # data
+ movl %ax,%ss # Set up
+ movwir(start,_sp) # stack
+ movl %esp,%esi # Source
+ movwir(MEM_REL,_di) # Destination
+ movwir(0x100,_cx) # Word count
+ rep # Copy
+ movsl # code
+ movb $0x10,%cl # Words to clear
+ rep # Zero
+ stosl # them
+ movbi1(0x10,-0x10,_di_) # Set packet size
+ cmpb $0x80,%dl # Hard drive?
+ jb main.4 # No
+ movwir(part4,_si) # Read master
+ movb $0x1,%al # boot
+ callwi(nread) # record
+ xorl %eax,%eax # Pass number
+main.1: movwir(MEM_BUF+PRT_OFF,_si) # Partition table
+ movb $0x1,%dh # Partition
+main.2: cmpbi1(PRT_BSD,0x4,_si_) # Our partition type?
+ jne main.3 # No
+ tstbi0(0x80,_si_) # Active?
+ jnz main.5 # Yes
+ testb %al,%al # Second pass?
+ jnz main.5 # Yes
+main.3: addl $0x10,%esi # Next entry
+ incb %dh # Partition
+ cmpb $0x1+PRT_NUM,%dh # Done?
+ jb main.2 # No
+ incl %eax # Pass
+ cmpb $0x2,%al # Done?
+ jb main.1 # No
+ movwir(msg_part,_si) # Message
+ jmp error # Error
+main.4: xorl %edx,%edx # Partition:drive
+ movwir(part4,_si) # Partition pointer
+main.5: movwrm(_dx,MEM_ARG) # Save args
+ movb $0x10,%al # Sector count
+ callwi(nread) # Read disk
+ movwir(MEM_BTX,_bx) # BTX
+ movw1r(0xa,_bx_,_si) # Point past
+ addl %ebx,%esi # it
+ movwir(MEM_USR+SIZ_PAG,_di) # Client page 1
+ movwir(MEM_BTX+0xd*SIZ_SEC,_cx) # Byte
+ subl %esi,%ecx # count
+ rep # Relocate
+ movsb # client
+ subl %edi,%ecx # Byte count
+ xorb %al,%al # Zero
+ rep # assumed
+ stosb # bss
+ callwi(seta20) # Enable A20
+ jmpnwi(start+MEM_JMP-MEM_ORG) # Start BTX
+
+# Enable A20
+
+seta20: inb $0x64,%al # Get status
+ testb $0x2,%al # Busy?
+ jnz seta20 # Yes
+ movb $0xd1,%al # Command: Write
+ outb %al,$0x64 # output port
+seta20.1: inb $0x64,%al # Get status
+ testb $0x2,%al # Busy?
+ jnz seta20.1 # Yes
+ movb $0xdf,%al # Enable
+ outb %al,$0x60 # A20
+ ret # To caller
+
+# Read from disk
+
+nread: xorw %bx,%bx # Transfer
+ movb $MEM_BUF>>0x8,%bh # buffer
+ o16 # LBA
+ movw1r(0x8,_si_,_cx) # address
+ pushl %cs # Read from
+ callwi(xread.1) # disk
+ jnc return # If success
+ movwir(msg_read,_si) # Message
+
+# Error exit
+
+error: callwi(putstr) # Display message
+ movwir(msg_boot,_si) # Display
+ callwi(putstr) # prompt
+ xorb %ah,%ah # BIOS: Get
+ int $0x16 # keypress
+ int $0x19 # BIOS: Reboot
+
+# Display string
+
+putstr.0: movwir(0x7,_bx) # Page:attribute
+ movb $0xe,%ah # BIOS: Display
+ int $0x10 # character
+putstr: lodsb # Get char
+ testb %al,%al # End of string?
+ jne putstr.0 # No
+
+return: ret # Generic return
+
+# Read from disk
+
+read: testb %dh,%dh # Try for extensions?
+ jz read.3 # No
+ movwir(0x55aa,_bx) # Magic
+ pushl %edx # Save
+ movb $0x41,%ah # BIOS: Check
+ int $0x13 # extensions present
+ popl %edx # Restore
+ jc read.3 # If error
+ cmpwir(0xaa55,_bx) # Magic?
+ jne read.3 # No
+ testb $0x1,%cl # Packet interface?
+ jz read.3 # No
+ movb $0x42,%ah # BIOS: Extended
+ int $0x13 # read
+ ret # To caller
+
+read.1: movb $0x1,%ah # Invalid
+ stc # parameter
+read.2: ret # To caller
+
+read.3: pushl %edx # Save
+ movb $0x8,%ah # BIOS: Get drive
+ int $0x13 # parameters
+ movb %dh,%ch # Max head number
+ popl %edx # Restore
+ jc read.2 # If error
+ andb $0x3f,%cl # Sectors per track
+ jz read.1 # If zero
+ o16 # Get
+ movw1r(0x8,_si_,_ax) # LBA
+ pushl %edx # Save
+ movzbw %cl,%bx # Divide by
+ xorw %dx,%dx # sectors
+ divw %bx,%ax # per track
+ movb %ch,%bl # Max head number
+ movb %dl,%ch # Sector number
+ incl %ebx # Divide by
+ xorb %dl,%dl # number of
+ divw %bx,%ax # heads
+ movb %dl,%bh # Head number
+ popl %edx # Restore
+ o16 # Cylinder number
+ cmpl $0x3ff,%eax # supportable?
+ ja read.1 # No
+ xchgb %al,%ah # Set up cylinder
+ rorb $0x2,%al # number
+ orb %ch,%al # Merge
+ incl %eax # sector
+ xchgl %eax,%ecx # number
+ movb %bh,%dh # Head number
+ subb %ah,%al # Sectors this track
+ movb1r(0x2,_si_,_ah) # Blocks to read
+ cmpb %ah,%al # To read
+ jb read.4 # this
+ movb %ah,%al # track
+read.4: movwir(0x5,_bp) # Try count
+read.5: lesw1r(0x4,_si_,_bx) # Transfer buffer
+ pushl %eax # Save
+ movb $0x2,%ah # BIOS: Conventional
+ int $0x13 # read
+ popl %ebx # Restore
+ jnc read.6 # If success
+ decl %ebp # Retry?
+ jz read.7 # No
+ xorb %ah,%ah # BIOS: Reset
+ int $0x13 # disk system
+ movl %ebx,%eax # Block count
+ jmp read.5 # Continue
+read.6: movzbw %bl,%ax # Sectors read
+ o16 # Adjust
+ addwr1(_ax,0x8,_si_) # LBA,
+ shlb %bl # buffer
+ addbr1(_bl,0x5,_si_) # pointer,
+ subbr1(_al,0x2,_si_) # block count
+ ja read.3 # If not done
+read.7: ret # To caller
+
+# Messages
+
+msg_read: .asciz "Read error"
+msg_part: .asciz "No bootable partition"
+msg_boot: .asciz "\r\nHit return to reboot: "
+
+ .org PRT_OFF,0x90
+
+# Partition table
+
+ .fill 0x30,0x1,0x0
+part4: .byte 0x80, 0x00, 0x01, 0x00
+ .byte 0xa5, 0xff, 0xff, 0xff
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x50, 0xc3, 0x00, 0x00
+
+ .word 0xaa55 # Magic number
diff --git a/sys/boot/i386/gptboot/Makefile b/sys/boot/i386/gptboot/Makefile
new file mode 100644
index 0000000..b52493f
--- /dev/null
+++ b/sys/boot/i386/gptboot/Makefile
@@ -0,0 +1,51 @@
+# $Id:$
+
+M4?= m4
+
+.if exists(${.OBJDIR}/../btx)
+BTX= ${.OBJDIR}/../btx
+.else
+BTX= ${.CURDIR}/../btx
+.endif
+
+ORG1= 0x7c00
+ORG2= 0x1000
+
+CFLAGS= -elf -I${BTX}/lib -I. -fno-builtin \
+ -O2 -malign-functions=0 -malign-jumps=0 -malign-loops=0 -mrtd \
+ -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \
+ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
+ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings
+
+LDFLAGS=-nostdlib -static -N
+
+all: boot1 boot2
+
+boot1: boot1.out
+ /usr/libexec/elf/objcopy -S -O binary boot1.out ${.TARGET}
+
+boot1.out: boot1.o
+ ${LD} ${LDFLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} boot1.o
+
+boot1.o: boot1.m4 boot1.s
+ ${M4} boot1.m4 boot1.s | ${AS} ${AFLAGS} -o ${.TARGET}
+
+boot2: boot2.ldr boot2.bin
+ btxld -v -E ${ORG2} -f bin -b ${BTX}/btx/btx -l boot2.ldr \
+ -o ${.TARGET} -P 1 boot2.bin
+ @ls -l boot2 | awk '{ x = 7680 - $$5; print x " bytes free"; \
+ if (x < 0) exit 1 }'
+
+boot2.ldr:
+ dd if=/dev/zero of=${.TARGET} bs=512 count=1 2>/dev/null
+
+boot2.bin: boot2.out
+ /usr/libexec/elf/objcopy -S -O binary boot2.out ${.TARGET}
+
+boot2.out: boot2.o
+ ${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} \
+ ${BTX}/lib/crt0.o boot2.o
+
+clean:
+ rm -f boot1 boot1.out boot1.o boot2 boot2.ldr boot2.bin \
+ boot2.out boot2.o
diff --git a/sys/boot/i386/gptboot/gptboot.c b/sys/boot/i386/gptboot/gptboot.c
new file mode 100644
index 0000000..25dd42a
--- /dev/null
+++ b/sys/boot/i386/gptboot/gptboot.c
@@ -0,0 +1,731 @@
+/*
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+/*
+ * $Id:$
+ */
+
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <sys/diskslice.h>
+#include <sys/disklabel.h>
+#include <sys/dirent.h>
+#include <machine/bootinfo.h>
+
+#include <ufs/ffs/fs.h>
+#include <ufs/ufs/dinode.h>
+
+#include <stdarg.h>
+
+#include <a.out.h>
+#include <elf.h>
+
+#include <btxv86.h>
+
+#define RBX_ASKNAME 0x0 /* -a */
+#define RBX_SINGLE 0x1 /* -s */
+#define RBX_DFLTROOT 0x5 /* -r */
+#define RBX_KDB 0x6 /* -d */
+#define RBX_CONFIG 0xa /* -c */
+#define RBX_VERBOSE 0xb /* -v */
+#define RBX_CDROM 0xd /* -C */
+#define RBX_GDB 0xf /* -g */
+
+#define PATH_CONFIG "/boot.config"
+#define PATH_BOOT3 "/boot/loader"
+#define PATH_KERNEL "/kernel"
+#define PATH_HELP "boot.help"
+
+#define ARGS 0x800
+#define NOPT 8
+#define BSIZEMAX 8192
+#define NDEV 3
+#define MEM_BASE 0x12
+#define MEM_EXT 0x15
+#define V86_CY(x) ((x) & 1)
+#define V86_ZR(x) ((x) & 0x40)
+
+extern uint32_t _end;
+
+static const char optstr[NOPT] = "aCcdgrsv";
+static const unsigned char flags[NOPT] = {
+ RBX_ASKNAME,
+ RBX_CDROM,
+ RBX_CONFIG,
+ RBX_KDB,
+ RBX_GDB,
+ RBX_DFLTROOT,
+ RBX_SINGLE,
+ RBX_VERBOSE
+};
+
+static const char *const dev_nm[] = {"fd", "wd", "da"};
+static const uint8_t dev_bios[] = {0, 0x80, 0x82};
+static const uint8_t dev_bsd[] = {2, 0, 4};
+
+static struct dsk {
+ unsigned drive;
+ unsigned type;
+ unsigned unit;
+ unsigned slice;
+ unsigned part;
+ int meta;
+} dsk;
+static char cmd[512];
+static char kname[1024];
+static char help[2048];
+static uint32_t opts;
+static struct bootinfo bootinfo;
+static int ls;
+static uint32_t fs_off;
+
+void exit(int);
+static void load(const char *);
+static int parse(char *);
+static void readfile(const char *, void *, size_t);
+static ino_t lookup(const char *);
+static int fsfind(const char *, ino_t *);
+static ssize_t fsread(ino_t, void *, size_t);
+static int dskread(void *, unsigned, unsigned);
+static int printf(const char *,...);
+static void getstr(char *, int);
+static int putchar(int);
+static int getchar(void);
+static void *memcpy(void *, const void *, size_t);
+static int strcmp(const char *, const char *);
+static void *malloc(size_t);
+static uint32_t memsize(int);
+static uint32_t drvinfo(int);
+static int drvread(void *, unsigned, unsigned);
+static int keyhit(unsigned);
+static int putch(int);
+static int getch(void);
+
+int
+main(void)
+{
+ int autoboot, helpon, i;
+
+ dsk.drive = *(uint8_t *)PTOV(ARGS);
+ for (dsk.type = NDEV - 1;
+ (i = dsk.drive - dev_bios[dsk.type]) < 0;
+ dsk.type--);
+ dsk.unit = i;
+ dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
+ bootinfo.bi_version = BOOTINFO_VERSION;
+ bootinfo.bi_size = sizeof(bootinfo);
+ bootinfo.bi_basemem = memsize(MEM_BASE);
+ bootinfo.bi_extmem = memsize(MEM_EXT);
+ bootinfo.bi_memsizes_valid++;
+ for (i = 0; i < N_BIOS_GEOM; i++)
+ bootinfo.bi_bios_geom[i] = drvinfo(i);
+ autoboot = 2;
+ helpon = 1;
+ readfile(PATH_CONFIG, cmd, sizeof(cmd));
+ if (parse(cmd))
+ autoboot = 0;
+ else if (!*kname) {
+ if (autoboot == 2) {
+ memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3));
+ if (!keyhit(0x37)) {
+ load(kname);
+ autoboot = 1;
+ }
+ }
+ if (autoboot == 1)
+ memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
+ }
+ readfile(PATH_HELP, help, sizeof(help));
+ for (;;) {
+ printf(" \n>> FreeBSD/i386 BOOT\n"
+ "Default: %u:%s(%u,%c)%s\n"
+ "%s"
+ "boot: ",
+ dsk.drive & 0x7f, dev_nm[dsk.type], dsk.unit,
+ 'a' + dsk.part, kname, helpon ? help : "");
+ if (!autoboot || keyhit(0x5a))
+ getstr(cmd, sizeof(cmd));
+ autoboot = helpon = 0;
+ if (parse(cmd))
+ helpon = 1;
+ else
+ load(kname);
+ }
+}
+
+void
+exit(int x)
+{
+}
+
+static void
+load(const char *fname)
+{
+ union {
+ struct exec ex;
+ Elf32_Ehdr eh;
+ } hdr;
+ Elf32_Phdr ep[2];
+ Elf32_Shdr es[2];
+ caddr_t p;
+ ino_t ino;
+ uint32_t addr, x;
+ int fmt, i, j;
+
+ if (!(ino = lookup(fname)) && !ls) {
+ printf("No `%s'\n", fname);
+ return;
+ }
+ if (fsread(ino, &hdr, sizeof(hdr)) != sizeof(hdr))
+ return;
+ if (N_GETMAGIC(hdr.ex) == ZMAGIC)
+ fmt = 0;
+ else if (IS_ELF(hdr.eh))
+ fmt = 1;
+ else {
+ printf("Invalid %s\n", "format");
+ return;
+ }
+ if (fmt == 0) {
+ addr = hdr.ex.a_entry & 0xffffff;
+ p = PTOV(addr);
+ printf("%s=0x%x ", "text", (unsigned)hdr.ex.a_text);
+ fs_off = PAGE_SIZE;
+ if (fsread(ino, p, hdr.ex.a_text) != hdr.ex.a_text)
+ return;
+ p += roundup2(hdr.ex.a_text, PAGE_SIZE);
+ printf("%s=0x%x ", "data", (unsigned)hdr.ex.a_data);
+ if (fsread(ino, p, hdr.ex.a_data) != hdr.ex.a_data)
+ return;
+ p += hdr.ex.a_data;
+ printf("%s=0x%x ", "bss", (unsigned)hdr.ex.a_bss);
+ p += roundup2(hdr.ex.a_bss, PAGE_SIZE);
+ bootinfo.bi_symtab = VTOP(p);
+ memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
+ p += sizeof(hdr.ex.a_syms);
+ printf("symbols=[");
+ printf("+0x%x", (unsigned)hdr.ex.a_syms);
+ if (hdr.ex.a_syms) {
+ if (fsread(ino, p, hdr.ex.a_syms) != hdr.ex.a_syms)
+ return;
+ p += hdr.ex.a_syms;
+ if (fsread(ino, p, sizeof(int)) != sizeof(int))
+ return;
+ x = *(uint32_t *)p;
+ p += sizeof(int);
+ x -= sizeof(int);
+ printf("+0x%x", x);
+ if (fsread(ino, p, x) != x)
+ return;
+ p += x;
+ }
+ } else {
+ fs_off = hdr.eh.e_phoff;
+ for (j = i = 0; i < hdr.eh.e_phoff && j < 2; i++) {
+ if (fsread(ino, ep + j, sizeof(ep[0])) != sizeof(ep[0]))
+ return;
+ if (ep[j].p_type == PT_LOAD)
+ j++;
+ }
+ for (i = 0; i < 2; i++) {
+ p = PTOV(ep[i].p_paddr & 0xffffff);
+ printf("%s=0x%x ", !i ? "text" : "data", ep[i].p_filesz);
+ fs_off = ep[i].p_offset;
+ if (fsread(ino, p, ep[i].p_filesz) != ep[i].p_filesz)
+ return;
+ }
+ printf("%s=0x%x ", "bss", ep[1].p_memsz - ep[1].p_filesz);
+ p += roundup2(ep[1].p_memsz, PAGE_SIZE);
+ bootinfo.bi_symtab = VTOP(p);
+ printf("symbols=[");
+ if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
+ fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
+ (hdr.eh.e_shstrndx + 1);
+ if (fsread(ino, &es, sizeof(es)) != sizeof(es))
+ return;
+ for (i = 0; i < 2; i++) {
+ memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size));
+ p += sizeof(es[i].sh_size);
+ printf("+0x%x", es[i].sh_size);
+ fs_off = es[i].sh_offset;
+ if (fsread(ino, p, es[i].sh_size) != es[i].sh_size)
+ return;
+ p += es[i].sh_size;
+ }
+ }
+ addr = hdr.eh.e_entry & 0xffffff;
+ }
+ bootinfo.bi_esymtab = VTOP(p);
+ printf("]\nentry=0x%x\n", addr);
+ bootinfo.bi_kernelname = VTOP(fname);
+ __exec((caddr_t)addr, RB_BOOTINFO | opts,
+ MAKEBOOTDEV(dev_bsd[dsk.type], 0, dsk.slice, dsk.unit,
+ dsk.part), 0, 0, 0, VTOP(&bootinfo));
+}
+
+static int
+parse(char *arg)
+{
+ char *p, *q;
+ int drv, c, i;
+
+ while ((c = *arg++)) {
+ if (c == ' ')
+ continue;
+ for (p = arg; *p && *p != '\n' && *p != ' '; p++);
+ if (*p)
+ *p++ = 0;
+ if (c == '-')
+ while ((c = *arg++)) {
+ for (i = 0; c != optstr[i]; i++)
+ if (i == NOPT - 1)
+ return -1;
+ opts |= 1 << flags[i];
+ }
+ else {
+ for (q = arg--; *q && *q != '('; q++);
+ if (*q) {
+ drv = -1;
+ if (arg[1] == ':') {
+ if (*arg < '0' || *arg > '9')
+ return -1;
+ drv = *arg - '0';
+ arg += 2;
+ }
+ if (q - arg != 2)
+ return -1;
+ for (i = 0; arg[0] != dev_nm[i][0] ||
+ arg[1] != dev_nm[i][1]; i++)
+ if (i == NDEV - 1)
+ return -1;
+ dsk.type = i;
+ arg += 3;
+ if (arg[1] != ',' || *arg < '0' || *arg > '9')
+ return -1;
+ dsk.unit = *arg - '0';
+ arg += 2;
+ if (arg[1] == ',') {
+ if (*arg < '0' || *arg > '4')
+ return -1;
+ if ((dsk.slice = *arg - '0'))
+ dsk.slice++;
+ arg += 2;
+ }
+ if (arg[1] != ')' || *arg < 'a' || *arg > 'p')
+ return -1;
+ dsk.part = *arg - 'a';
+ arg += 2;
+ if (drv == -1)
+ dsk.drive = dev_bios[dsk.type] + dsk.unit;
+ else
+ dsk.drive = (dsk.type ? 0x80 : 0) + drv;
+ dsk.meta = 0;
+ }
+ if ((i = p - arg - !*(p - 1))) {
+ if (i >= sizeof(kname))
+ return -1;
+ memcpy(kname, arg, i + 1);
+ }
+ }
+ arg = p;
+ }
+ return 0;
+}
+
+static void
+readfile(const char *fname, void *buf, size_t size)
+{
+ ino_t ino;
+
+ if ((ino = lookup(fname)))
+ fsread(ino, buf, size);
+}
+
+static ino_t
+lookup(const char *path)
+{
+ char name[MAXNAMLEN + 1];
+ const char *s;
+ ino_t ino;
+ ssize_t n;
+ int dt;
+
+ ino = ROOTINO;
+ dt = DT_DIR;
+ for (;;) {
+ if (*path == '/')
+ path++;
+ if (!*path)
+ break;
+ for (s = path; *s && *s != '/'; s++);
+ if ((n = s - path) > MAXNAMLEN)
+ return 0;
+ ls = *path == '?' && n == 1 && !*s;
+ memcpy(name, path, n);
+ name[n] = 0;
+ if ((dt = fsfind(name, &ino)) <= 0)
+ break;
+ path = s;
+ }
+ return dt == DT_REG ? ino : 0;
+}
+
+static int
+fsfind(const char *name, ino_t * ino)
+{
+ char buf[DEV_BSIZE];
+ struct dirent *d;
+ char *s;
+ ssize_t n;
+
+ fs_off = 0;
+ while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0)
+ for (s = buf; s < buf + DEV_BSIZE;) {
+ d = (void *)s;
+ if (ls)
+ printf("%s ", d->d_name);
+ else if (!strcmp(name, d->d_name)) {
+ *ino = d->d_fileno;
+ return d->d_type;
+ }
+ s += d->d_reclen;
+ }
+ if (n != -1 && ls)
+ putchar('\n');
+ return 0;
+}
+
+static ssize_t
+fsread(ino_t inode, void *buf, size_t nbyte)
+{
+ static struct fs fs;
+ static struct dinode din;
+ static char *blkbuf;
+ static ufs_daddr_t *indbuf;
+ static ino_t inomap;
+ static ufs_daddr_t blkmap, indmap;
+ static unsigned fsblks;
+ char *s;
+ ufs_daddr_t lbn, addr;
+ size_t n, nb, off;
+
+ if (!dsk.meta) {
+ if (!blkbuf)
+ blkbuf = malloc(BSIZEMAX);
+ inomap = 0;
+ if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE))
+ return -1;
+ memcpy(&fs, blkbuf, sizeof(fs));
+ if (fs.fs_magic != FS_MAGIC) {
+ printf("Not ufs\n");
+ return -1;
+ }
+ fsblks = fs.fs_bsize >> DEV_BSHIFT;
+ dsk.meta = 1;
+ }
+ if (inomap != inode) {
+ if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)),
+ fsblks))
+ return -1;
+ din = ((struct dinode *)blkbuf)[inode % INOPB(&fs)];
+ inomap = inode;
+ fs_off = 0;
+ blkmap = indmap = 0;
+ }
+ s = buf;
+ if (nbyte > (n = din.di_size - fs_off))
+ nbyte = n;
+ nb = nbyte;
+ while (nb) {
+ lbn = lblkno(&fs, fs_off);
+ if (lbn < NDADDR)
+ addr = din.di_db[lbn];
+ else {
+ if (indmap != din.di_ib[0]) {
+ if (!indbuf)
+ indbuf = malloc(BSIZEMAX);
+ if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]),
+ fsblks))
+ return -1;
+ indmap = din.di_ib[0];
+ }
+ addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)];
+ }
+ n = dblksize(&fs, &din, lbn);
+ if (blkmap != addr) {
+ if (dskread(blkbuf, fsbtodb(&fs, addr), n >> DEV_BSHIFT))
+ return -1;
+ blkmap = addr;
+ }
+ off = blkoff(&fs, fs_off);
+ n -= off;
+ if (n > nb)
+ n = nb;
+ memcpy(s, blkbuf + off, n);
+ s += n;
+ fs_off += n;
+ nb -= n;
+ }
+ return nbyte;
+}
+
+static int
+dskread(void *buf, unsigned lba, unsigned nblk)
+{
+ static char *sec;
+ static unsigned hidden;
+ struct dos_partition *dp;
+ struct disklabel *d;
+ unsigned sl, i;
+
+ if (!dsk.meta) {
+ if (!sec)
+ sec = malloc(DEV_BSIZE);
+ hidden = 0;
+ sl = dsk.slice;
+ if (sl != WHOLE_DISK_SLICE) {
+ if (drvread(sec, DOSBBSECTOR, 1))
+ return -1;
+ dp = (void *)(sec + DOSPARTOFF);
+ if (sl == COMPATIBILITY_SLICE)
+ for (i = 0; i < NDOSPART; i++)
+ if (dp[i].dp_typ == DOSPTYP_386BSD &&
+ (dp[i].dp_flag & 0x80 ||
+ sl == COMPATIBILITY_SLICE))
+ sl = BASE_SLICE + i;
+ if (sl != COMPATIBILITY_SLICE)
+ dp += sl - BASE_SLICE;
+ if (dp->dp_typ != DOSPTYP_386BSD) {
+ printf("Invalid %s\n", "slice");
+ return -1;
+ }
+ hidden = dp->dp_start;
+ }
+ if (dsk.part != RAW_PART) {
+ if (drvread(sec, hidden + LABELSECTOR, 1))
+ return -1;
+ d = (void *)(sec + LABELOFFSET);
+ if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
+ printf("Invalid %s\n", "label");
+ return -1;
+ }
+ if (dsk.part >= d->d_npartitions) {
+ printf("Invalid %s\n", "partition");
+ return -1;
+ }
+ hidden = d->d_partitions[dsk.part].p_offset;
+ }
+ }
+ return drvread(buf, hidden + lba, nblk);
+}
+
+static int
+printf(const char *fmt,...)
+{
+ static const char digits[16] = "0123456789abcdef";
+ va_list ap;
+ char buf[10];
+ char *s;
+ unsigned r, u;
+ int c;
+
+ va_start(ap, fmt);
+ while ((c = *fmt++)) {
+ if (c == '%') {
+ c = *fmt++;
+ switch (c) {
+ case 'c':
+ putchar(va_arg(ap, int));
+ continue;
+ case 's':
+ for (s = va_arg(ap, char *); *s; s++)
+ putchar(*s);
+ continue;
+ case 'u':
+ case 'x':
+ r = c == 'u' ? 10U : 16U;
+ u = va_arg(ap, unsigned);
+ s = buf;
+ do
+ *s++ = digits[u % r];
+ while (u /= r);
+ while (--s >= buf)
+ putchar(*s);
+ continue;
+ }
+ }
+ putchar(c);
+ }
+ va_end(ap);
+ return 0;
+}
+
+static void
+getstr(char *str, int size)
+{
+ char *s;
+ int c;
+
+ s = str;
+ do {
+ switch (c = getchar()) {
+ case '\b':
+ if (s > str)
+ s--;
+ break;
+ case '\n':
+ *s = 0;
+ break;
+ default:
+ if (s - str < size - 1)
+ *s++ = c;
+ }
+ putchar(c);
+ } while (c != '\n');
+}
+
+static int
+putchar(int c)
+{
+ if (c == '\n')
+ putch('\r');
+ return putch(c);
+}
+
+static int
+getchar(void)
+{
+ int c;
+
+ c = getch();
+ if (c == '\r')
+ c = '\n';
+ return c;
+}
+
+static void *
+memcpy(void *dst, const void *src, size_t size)
+{
+ const char *s;
+ char *d;
+
+ for (d = dst, s = src; size; size--)
+ *d++ = *s++;
+ return dst;
+}
+
+static int
+strcmp(const char *s1, const char *s2)
+{
+ for (; *s1 == *s2 && *s1; s1++, s2++);
+ return (u_char)*s1 - (u_char)*s2;
+}
+
+static void *
+malloc(size_t size)
+{
+ static uint32_t next;
+ void *p;
+
+ if (!next)
+ next = roundup2(__base + _end, 0x10000) - __base;
+ p = (void *)next;
+ next += size;
+ return p;
+}
+
+static uint32_t
+memsize(int type)
+{
+ v86.ctl = V86_FLAGS;
+ v86.addr = type;
+ v86.eax = 0x8800;
+ v86int();
+ return v86.eax;
+}
+
+static uint32_t
+drvinfo(int drive)
+{
+ v86.addr = 0x13;
+ v86.eax = 0x800;
+ v86.edx = 0x80 + drive;
+ v86int();
+ if (V86_CY(v86.efl))
+ return 0x4f010f;
+ return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) |
+ (v86.edx & 0xff00) | (v86.ecx & 0x3f);
+}
+
+static int
+drvread(void *buf, unsigned lba, unsigned nblk)
+{
+ v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
+ v86.addr = 0x604;
+ v86.eax = nblk;
+ v86.ebx = VTOPSEG(buf) << 16 | VTOPOFF(buf);
+ v86.ecx = lba;
+ v86.edx = dsk.drive;
+ v86int();
+ v86.ctl = V86_FLAGS;
+ if (V86_CY(v86.efl)) {
+ printf("Disk error 0x%x (lba=0x%x)\n", v86.eax >> 8 & 0xff,
+ lba);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+keyhit(unsigned ticks)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ v86.addr = 0x16;
+ v86.eax = 0x100;
+ v86int();
+ if (!V86_ZR(v86.efl))
+ return 1;
+ v86.addr = 0x1a;
+ v86.eax = 0;
+ v86.edx = 0;
+ v86int();
+ if (!x)
+ x = v86.edx;
+ else if (v86.edx < x || v86.edx > x + ticks)
+ return 0;
+ }
+}
+
+static int
+putch(int c)
+{
+ v86.addr = 0x10;
+ v86.eax = 0xe00 | (c & 0xff);
+ v86.ebx = 0x7;
+ v86int();
+ return c;
+}
+
+static int
+getch(void)
+{
+ v86.addr = 0x16;
+ v86.eax = 0;
+ v86int();
+ return v86.eax & 0xff;
+}
OpenPOWER on IntegriCloud