summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Shalayeff <mickey@cvs.openbsd.org>2004-02-03 12:09:48 +0000
committerMichael Shalayeff <mickey@cvs.openbsd.org>2004-02-03 12:09:48 +0000
commitee64ff9774a8a97d8ac9159076e5aa096f4b0465 (patch)
tree56c0a44d5a11182f89b55b68c79f750f9a093bc6
parent74d9ef0d94f422fd01f5c329723d4a06537c0884 (diff)
das boot; das cloned das from das i386
-rw-r--r--sys/arch/amd64/amd64/autoconf.c78
-rw-r--r--sys/arch/amd64/amd64/conf.c4
-rw-r--r--sys/arch/amd64/amd64/consinit.c3
-rw-r--r--sys/arch/amd64/amd64/locore.S89
-rw-r--r--sys/arch/amd64/amd64/machdep.c151
-rw-r--r--sys/arch/amd64/include/biosvar.h4
-rw-r--r--sys/arch/amd64/include/bootinfo.h159
-rw-r--r--sys/arch/amd64/include/types.h3
-rw-r--r--sys/arch/amd64/stand/Makefile8
-rw-r--r--sys/arch/amd64/stand/Makefile.inc55
-rw-r--r--sys/arch/amd64/stand/biosboot/Makefile26
-rw-r--r--sys/arch/amd64/stand/biosboot/biosboot.8273
-rw-r--r--sys/arch/amd64/stand/biosboot/biosboot.S896
-rw-r--r--sys/arch/amd64/stand/boot/Makefile60
-rw-r--r--sys/arch/amd64/stand/boot/boot.8375
-rw-r--r--sys/arch/amd64/stand/boot/conf.c77
-rw-r--r--sys/arch/amd64/stand/boot/srt0.S92
-rw-r--r--sys/arch/amd64/stand/etc/Makefile20
-rw-r--r--sys/arch/amd64/stand/etc/genassym.cf30
-rw-r--r--sys/arch/amd64/stand/installboot/Makefile19
-rw-r--r--sys/arch/amd64/stand/installboot/installboot.8135
-rw-r--r--sys/arch/amd64/stand/installboot/installboot.c535
-rw-r--r--sys/arch/amd64/stand/installboot/nlist.c547
-rw-r--r--sys/arch/amd64/stand/libsa/alloca.S54
-rw-r--r--sys/arch/amd64/stand/libsa/bioscons.c213
-rw-r--r--sys/arch/amd64/stand/libsa/biosdev.c610
-rw-r--r--sys/arch/amd64/stand/libsa/biosdev.h70
-rw-r--r--sys/arch/amd64/stand/libsa/biosprobe.c80
-rw-r--r--sys/arch/amd64/stand/libsa/cmd_i386.c181
-rw-r--r--sys/arch/amd64/stand/libsa/dev_i386.c191
-rw-r--r--sys/arch/amd64/stand/libsa/disk.h52
-rw-r--r--sys/arch/amd64/stand/libsa/diskprobe.c294
-rw-r--r--sys/arch/amd64/stand/libsa/exec_i386.c73
-rw-r--r--sys/arch/amd64/stand/libsa/gateA20.c82
-rw-r--r--sys/arch/amd64/stand/libsa/gidt.S415
-rw-r--r--sys/arch/amd64/stand/libsa/libsa.h62
-rw-r--r--sys/arch/amd64/stand/libsa/machdep.c56
-rw-r--r--sys/arch/amd64/stand/libsa/memprobe.c473
-rw-r--r--sys/arch/amd64/stand/libsa/time.c147
-rw-r--r--sys/arch/amd64/stand/mbr/Makefile29
-rw-r--r--sys/arch/amd64/stand/mbr/mbr.S570
41 files changed, 6832 insertions, 459 deletions
diff --git a/sys/arch/amd64/amd64/autoconf.c b/sys/arch/amd64/amd64/autoconf.c
index d4eed4a1134..38a5d4bcc0d 100644
--- a/sys/arch/amd64/amd64/autoconf.c
+++ b/sys/arch/amd64/amd64/autoconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: autoconf.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */
+/* $OpenBSD: autoconf.c,v 1.2 2004/02/03 12:09:47 mickey Exp $ */
/* $NetBSD: autoconf.c,v 1.1 2003/04/26 18:39:26 fvdl Exp $ */
/*-
@@ -63,7 +63,6 @@
#include <machine/pte.h>
#include <machine/cpu.h>
-#include <machine/bootinfo.h>
#include <dev/cons.h>
@@ -100,6 +99,7 @@ extern int x86_64_ndisks;
int cold = 1; /* if 1, still working on cold-start */
struct device *booted_device;
int booted_partition;
+dev_t bootdev;
/*
* Determine i/o configuration for a machine.
@@ -139,11 +139,8 @@ cpu_configure(void)
void
diskconf(void)
{
-printf("setroot\n");
setroot();
-printf("swapconf\n");
swapconf();
-printf("dumpconf\n");
dumpconf();
}
@@ -500,77 +497,6 @@ getstr(cp, size)
}
}
-#include "pci.h"
-
-#include <dev/isa/isavar.h>
-#if NPCI > 0
-#include <dev/pci/pcivar.h>
-#endif
-
-void
-device_register(struct device *dev, void *aux)
-{
- /*
- * Handle network interfaces here, the attachment information is
- * not available driver independantly later.
- * For disks, there is nothing useful available at attach time.
- */
- if (dev->dv_class == DV_IFNET) {
- struct btinfo_netif *bin = lookup_bootinfo(BTINFO_NETIF);
- if (bin == NULL)
- return;
-
- /*
- * We don't check the driver name against the device name
- * passed by the boot ROM. The ROM should stay usable
- * if the driver gets obsoleted.
- * The physical attachment information (checked below)
- * must be sufficient to identify the device.
- */
-
- if (bin->bus == BI_BUS_ISA &&
- !strcmp(dev->dv_parent->dv_cfdata->cf_driver->cd_name,
- "isa")) {
- struct isa_attach_args *iaa = aux;
-
- /* compare IO base address */
- /* XXXJRT what about multiple I/O addrs? */
- if (iaa->ipa_nio > 0 &&
- bin->addr.iobase == iaa->ipa_io[0].base)
- goto found;
- }
-#if NPCI > 0
- if (bin->bus == BI_BUS_PCI &&
- !strcmp(dev->dv_parent->dv_cfdata->cf_driver->cd_name,
- "pci")) {
- struct pci_attach_args *paa = aux;
- int b, d, f;
-
- /*
- * Calculate BIOS representation of:
- *
- * <bus,device,function>
- *
- * and compare.
- */
- pci_decompose_tag(paa->pa_pc, paa->pa_tag, &b, &d, &f);
- if (bin->addr.tag == ((b << 8) | (d << 3) | f))
- goto found;
- }
-#endif
- }
- return;
-
-found:
- if (booted_device) {
- /* XXX should be a "panic()" */
- printf("warning: double match for boot device (%s, %s)\n",
- booted_device->dv_xname, dev->dv_xname);
- return;
- }
- booted_device = dev;
-}
-
/* XXX */
static struct nam2blk {
char *name;
diff --git a/sys/arch/amd64/amd64/conf.c b/sys/arch/amd64/amd64/conf.c
index cb6c91516c1..ac1fb00010e 100644
--- a/sys/arch/amd64/amd64/conf.c
+++ b/sys/arch/amd64/amd64/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */
+/* $OpenBSD: conf.c,v 1.2 2004/02/03 12:09:47 mickey Exp $ */
/*
* Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
@@ -439,7 +439,6 @@ dev_rawpart(dv)
*/
#include <dev/cons.h>
-cons_decl(pc);
cons_decl(com);
cons_decl(ws);
@@ -452,4 +451,3 @@ struct consdev constab[] = {
#endif
{ 0 },
};
-
diff --git a/sys/arch/amd64/amd64/consinit.c b/sys/arch/amd64/amd64/consinit.c
index 2a167480017..4a28d3d5aa7 100644
--- a/sys/arch/amd64/amd64/consinit.c
+++ b/sys/arch/amd64/amd64/consinit.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: consinit.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */
+/* $OpenBSD: consinit.c,v 1.2 2004/02/03 12:09:47 mickey Exp $ */
/* $NetBSD: consinit.c,v 1.2 2003/03/02 18:27:14 fvdl Exp $ */
/*
@@ -31,7 +31,6 @@
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/bus.h>
-#include <machine/bootinfo.h>
#include <dev/cons.h>
diff --git a/sys/arch/amd64/amd64/locore.S b/sys/arch/amd64/amd64/locore.S
index 2ec08feec31..1d9d74be9cb 100644
--- a/sys/arch/amd64/amd64/locore.S
+++ b/sys/arch/amd64/amd64/locore.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: locore.S,v 1.1 2004/01/28 01:39:38 mickey Exp $ */
+/* $OpenBSD: locore.S,v 1.2 2004/02/03 12:09:47 mickey Exp $ */
/* $NetBSD: locore.S,v 1.2 2003/04/26 19:34:45 fvdl Exp $ */
/*
@@ -129,7 +129,6 @@
#include <machine/segments.h>
#include <machine/specialreg.h>
#include <machine/trap.h>
-#include <machine/bootinfo.h>
#include <machine/frameasm.h>
#if NLAPIC > 0
@@ -191,7 +190,7 @@ _C_LABEL(lapic_isr):
.globl _C_LABEL(cpu_id),_C_LABEL(cpu_vendor), _C_LABEL(cpu_brand_id)
.globl _C_LABEL(cpuid_level),_C_LABEL(cpu_feature)
- .globl _C_LABEL(esym),_C_LABEL(boothowto)
+ .globl _C_LABEL(esym),_C_LABEL(boothowto),_C_LABEL(bootdev)
.globl _C_LABEL(bootinfo),_C_LABEL(atdevbase)
.globl _C_LABEL(proc0paddr),_C_LABEL(PTDpaddr)
.globl _C_LABEL(biosbasemem),_C_LABEL(biosextmem)
@@ -257,80 +256,32 @@ tmpstk:
.globl _C_LABEL(kernel_text)
.set _C_LABEL(kernel_text),KERNTEXTOFF
-.code32
+ .code32
.globl start
start: movw $0x1234,0x472 # warm boot
/*
* Load parameters from stack
- * (howto, [bootdev], bootinfo, esym, basemem, extmem).
+ * (howto, bootdev, bootapiver, esym, cnvmem, extmem, ac, av)
*/
movl 4(%esp),%eax
- movl %eax,RELOC(boothowto)
- movl 12(%esp),%eax
- testl %eax, %eax
- jz 1f
- movl (%eax), %ebx /* number of entries */
- movl $RELOC(bootinfo),%ebp
- movl %ebp, %edx
- addl $BOOTINFO_MAXSIZE,%ebp
- movl %ebx, (%edx)
- addl $4, %edx
-2:
- testl %ebx, %ebx
- jz 1f
- addl $4, %eax
- movl (%eax), %ecx /* address of entry */
- pushl %edi
- pushl %esi
- pushl %eax
-
- movl (%ecx),%eax /* len */
- movl %edx,%edi
- addl (%ecx), %edx /* update dest pointer */
- cmpl %ebp, %edx
- jg 2f
- movl %ecx,%esi
- movl %eax,%ecx
- rep
- movsb
- popl %eax
- popl %esi
- popl %edi
- subl $1, %ebx
- jmp 2b
-2: /* cleanup for overflow case */
- popl %eax
- popl %esi
- popl %edi
- movl $RELOC(bootinfo),%ebp
- movl %ebp, %edx
- subl %ebx, (%edx) /* correct number of entries */
-1:
-
- movl 16(%esp),%eax
- testl %eax,%eax
- jz 1f
- addl $KERNBASE_LO,%eax
-1: movl $RELOC(esym),%ebp
- movl %eax,(%ebp)
- movl $KERNBASE_HI,4(%ebp)
-
- movl $RELOC(biosextmem),%ebp
- movl (%ebp),%eax
- testl %eax,%eax
- jnz 1f
- movl 20(%esp),%eax
- movl %eax,(%ebp)
-1:
- movl $RELOC(biosbasemem),%ebp
- movl (%ebp),%eax
- testl %eax,%eax
- jnz 1f
- movl 24(%esp),%eax
- movl %eax,(%ebp)
+ movl %eax,RELOC(_C_LABEL(boothowto))
+ movl 8(%esp),%eax
+ movl %eax,RELOC(_C_LABEL(bootdev))
+
+ movl 16(%esp), %eax
+ testl %eax,%eax
+ jz 1f
+ addl $KERNBASE_LO,%eax
+ movl $RELOC(esym),%ebp
+ movl %eax,(%ebp)
+ movl $KERNBASE_HI,4(%ebp)
1:
+ movl 20(%esp), %eax
+ movl %eax, RELOC(biosextmem)
+ movl 24(%esp), %eax
+ movl %eax, RELOC(biosbasemem)
/* First, reset the PSL. */
pushl $PSL_MBO
@@ -573,7 +524,7 @@ compat:
movl $RELOC(farjmp64),%eax
ljmp *(%eax)
-.code64
+ .code64
longmode:
/*
* 6.
diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
index 56ba54d60da..bf82df6856a 100644
--- a/sys/arch/amd64/amd64/machdep.c
+++ b/sys/arch/amd64/amd64/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.2 2004/01/29 13:21:10 mickey Exp $ */
+/* $OpenBSD: machdep.c,v 1.3 2004/02/03 12:09:47 mickey Exp $ */
/* $NetBSD: machdep.c,v 1.3 2003/05/07 22:58:18 fvdl Exp $ */
/*-
@@ -120,7 +120,6 @@
#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/specialreg.h>
-#include <machine/bootinfo.h>
#include <machine/fpu.h>
#include <machine/mtrr.h>
#include <machine/mpbiosvar.h>
@@ -143,9 +142,6 @@
char machine[] = "amd64"; /* cpu "architecture" */
char machine_arch[] = "x86_64"; /* machine == machine_arch */
-char bootinfo[BOOTINFO_MAXSIZE];
-
-struct bi_devmatch *x86_64_alldisks = NULL;
int x86_64_ndisks = 0;
#ifdef CPURESET_DELAY
@@ -541,7 +537,6 @@ cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
struct proc *p;
{
dev_t consdev;
- struct btinfo_bootpath *bibp;
/* all sysctl names at this level are terminal */
if (namelen != 1)
@@ -556,6 +551,7 @@ cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev,
sizeof consdev));
+#ifdef notyet
case CPU_BOOTED_KERNEL:
bibp = lookup_bootinfo(BTINFO_BOOTPATH);
if(!bibp)
@@ -567,6 +563,7 @@ cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
return (sysctl_rdstruct(oldp, oldlenp, newp, x86_64_alldisks,
sizeof (struct disklist) +
(x86_64_ndisks - 1) * sizeof (struct nativedisk_info)));
+#endif
default:
return (EOPNOTSUPP);
}
@@ -1174,10 +1171,6 @@ init_x86_64(first_avail)
int x, first16q, ist;
u_int64_t seg_start, seg_end;
u_int64_t seg_start1, seg_end1;
-#if !defined(REALEXTMEM) && !defined(REALBASEMEM)
- struct btinfo_memmap *bim;
- u_int64_t addr, size, io_end;
-#endif
cpu_init_msrs(&cpu_info_primary);
@@ -1213,104 +1206,6 @@ init_x86_64(first_avail)
if (avail_start != PAGE_SIZE)
pmap_prealloc_lowmem_ptps();
-#if !defined(REALBASEMEM) && !defined(REALEXTMEM)
-
- /*
- * Check to see if we have a memory map from the BIOS (passed
- * to us by the boot program.
- */
- bim = lookup_bootinfo(BTINFO_MEMMAP);
- if (bim != NULL && bim->num > 0) {
-#if DEBUG_MEMLOAD
- printf("BIOS MEMORY MAP (%d ENTRIES):\n", bim->num);
-#endif
- for (x = 0; x < bim->num; x++) {
- addr = bim->entry[x].addr;
- size = bim->entry[x].size;
-#if DEBUG_MEMLOAD
- printf(" addr 0x%lx size 0x%lx type 0x%x\n",
- addr, size, bim->entry[x].type);
-#endif
-
- /*
- * If the segment is not memory, skip it.
- */
- switch (bim->entry[x].type) {
- case BIM_Memory:
- case BIM_ACPI:
- case BIM_NVS:
- break;
- default:
- continue;
- }
-
- seg_start = addr;
- seg_end = addr + size;
-
- if (seg_end > 0x100000000000ULL) {
- printf("WARNING: skipping large "
- "memory map entry: "
- "0x%lx/0x%lx/0x%x\n",
- addr, size,
- bim->entry[x].type);
- continue;
- }
-
- /*
- * Allocate the physical addresses used by RAM
- * from the iomem extent map. This is done before
- * the addresses are page rounded just to make
- * sure we get them all.
- */
- if (seg_start < 0x100000000UL) {
- if (seg_end > 0x100000000UL)
- io_end = 0x100000000UL;
- else
- io_end = seg_end;
- if (extent_alloc_region(iomem_ex, seg_start,
- io_end - seg_start, EX_NOWAIT)) {
- /* XXX What should we do? */
- printf("WARNING: CAN'T ALLOCATE "
- "MEMORY SEGMENT %d "
- "(0x%lx/0x%lx/0l%x) FROM "
- "IOMEM EXTENT MAP!\n",
- x, seg_start, io_end - seg_start,
- bim->entry[x].type);
- }
- }
-
- /*
- * If it's not free memory, skip it.
- */
- if (bim->entry[x].type != BIM_Memory)
- continue;
-
- /* XXX XXX XXX */
- if (mem_cluster_cnt >= VM_PHYSSEG_MAX)
- panic("init386: too many memory segments");
-
- seg_start = round_page(seg_start);
- seg_end = trunc_page(seg_end);
-
- if (seg_start == seg_end)
- continue;
-
- mem_clusters[mem_cluster_cnt].start = seg_start;
- mem_clusters[mem_cluster_cnt].size =
- seg_end - seg_start;
-
- if (avail_end < seg_end)
- avail_end = seg_end;
- physmem += atop(mem_clusters[mem_cluster_cnt].size);
- mem_cluster_cnt++;
- }
- }
-#endif /* ! REALBASEMEM && ! REALEXTMEM */
-
- /*
- * If the loop above didn't find any valid segment, fall back to
- * former code.
- */
if (mem_cluster_cnt == 0) {
/*
* Allocate the physical addresses used by RAM from the iomem
@@ -1631,20 +1526,8 @@ init_x86_64(first_avail)
cpu_init_idt();
#ifdef DDB
- {
- extern caddr_t esym;
- struct btinfo_symtab *symtab;
-
- symtab = lookup_bootinfo(BTINFO_SYMTAB);
- if (symtab) {
- ssym = (char *)((vaddr_t)symtab->ssym + KERNBASE);
- esym = (caddr_t)((vaddr_t)symtab->esym + KERNBASE);
- }
-
- db_machine_init();
- ddb_init();
- }
-
+ db_machine_init();
+ ddb_init();
if (boothowto & RB_KDB)
Debugger();
#endif
@@ -1667,30 +1550,6 @@ init_x86_64(first_avail)
maxproc = cpu_maxproc();
}
-void *
-lookup_bootinfo(type)
- int type;
-{
- struct btinfo_common *help;
- int n = *(int*)bootinfo;
- help = (struct btinfo_common *)(bootinfo + sizeof(int));
- while(n--) {
- if(help->type == type) {
-#if 0
- if (type == BTINFO_CONSOLE) {
- struct btinfo_console *consinfo = (struct btinfo_console *)help;
- snprintf(consinfo->devname, 16, "com");
- consinfo->speed = 9600;
- consinfo->addr = 0x3f8;
- }
-#endif
- return(help);
- }
- help = (struct btinfo_common *)((char*)help + help->len);
- }
- return(0);
-}
-
void
cpu_reset()
{
diff --git a/sys/arch/amd64/include/biosvar.h b/sys/arch/amd64/include/biosvar.h
index 55922d4e002..ff959054c5d 100644
--- a/sys/arch/amd64/include/biosvar.h
+++ b/sys/arch/amd64/include/biosvar.h
@@ -1,5 +1,5 @@
/* XXX - DSR */
-/* $OpenBSD: biosvar.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */
+/* $OpenBSD: biosvar.h,v 1.2 2004/02/03 12:09:47 mickey Exp $ */
/*
* Copyright (c) 1997-1999 Michael Shalayeff
@@ -205,7 +205,7 @@ typedef struct _bios_consdev {
#else
#define DOINT(n) "int $0x20+(" #n ")"
-extern struct BIOS_regs {
+extern volatile struct BIOS_regs {
u_int32_t biosr_ax;
u_int32_t biosr_cx;
u_int32_t biosr_dx;
diff --git a/sys/arch/amd64/include/bootinfo.h b/sys/arch/amd64/include/bootinfo.h
deleted file mode 100644
index 8751e66a3be..00000000000
--- a/sys/arch/amd64/include/bootinfo.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/* $OpenBSD: bootinfo.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */
-/* $NetBSD: bootinfo.h,v 1.2 2003/04/16 19:16:42 dsl Exp $ */
-
-/*
- * Copyright (c) 1997
- * Matthias Drochner. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed for the NetBSD Project
- * by Matthias Drochner.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- *
- */
-
-#ifndef _LOCORE
-
-struct btinfo_common {
- int len;
- int type;
-};
-
-#define BTINFO_BOOTPATH 0
-#define BTINFO_BOOTDISK 3
-#define BTINFO_NETIF 4
-#define BTINFO_CONSOLE 6
-#define BTINFO_BIOSGEOM 7
-#define BTINFO_SYMTAB 8
-#define BTINFO_MEMMAP 9
-
-struct btinfo_bootpath {
- struct btinfo_common common;
- char bootpath[80];
-};
-
-struct btinfo_bootdisk {
- struct btinfo_common common;
- int labelsector; /* label valid if != -1 */
- struct {
- u_int16_t type, checksum;
- char packname[16];
- } label;
- int biosdev;
- int partition;
-};
-
-struct btinfo_netif {
- struct btinfo_common common;
- char ifname[16];
- int bus;
-#define BI_BUS_ISA 0
-#define BI_BUS_PCI 1
- union {
- unsigned int iobase; /* ISA */
- unsigned int tag; /* PCI, BIOS format */
- } addr;
-};
-
-struct btinfo_console {
- struct btinfo_common common;
- char devname[16];
- int addr;
- int speed;
-};
-
-struct btinfo_symtab {
- struct btinfo_common common;
- int nsym;
- int ssym;
- int esym;
-};
-
-struct bi_memmap_entry {
- u_int64_t addr; /* beginning of block */ /* 8 */
- u_int64_t size; /* size of block */ /* 8 */
- u_int32_t type; /* type of block */ /* 4 */
-} __attribute__((packed)); /* == 20 */
-
-#define BIM_Memory 1 /* available RAM usable by OS */
-#define BIM_Reserved 2 /* in use or reserved by the system */
-#define BIM_ACPI 3 /* ACPI Reclaim memory */
-#define BIM_NVS 4 /* ACPI NVS memory */
-
-struct btinfo_memmap {
- struct btinfo_common common;
- int num;
- struct bi_memmap_entry entry[1]; /* var len */
-};
-
-#include <machine/disklabel.h>
-
-/*
- * Structure describing disk info as seen by the BIOS.
- */
-struct bi_biosgeom_entry {
- int sec, head, cyl; /* geometry */
- u_int64_t totsec; /* LBA sectors from ext int13 */
- int flags, dev; /* flags, BIOS device # */
-#define BI_GEOM_INVALID 0x000001
-#define BI_GEOM_EXTINT13 0x000002
-#ifdef BIOSDISK_EXT13INFO_V3
-#define BI_GEOM_BADCKSUM 0x000004 /* v3.x checksum invalid */
-#define BI_GEOM_BUS_MASK 0x00ff00 /* connecting bus type */
-#define BI_GEOM_BUS_ISA 0x000100
-#define BI_GEOM_BUS_PCI 0x000200
-#define BI_GEOM_BUS_OTHER 0x00ff00
-#define BI_GEOM_IFACE_MASK 0xff0000 /* interface type */
-#define BI_GEOM_IFACE_ATA 0x010000
-#define BI_GEOM_IFACE_ATAPI 0x020000
-#define BI_GEOM_IFACE_SCSI 0x030000
-#define BI_GEOM_IFACE_USB 0x040000
-#define BI_GEOM_IFACE_1394 0x050000 /* Firewire */
-#define BI_GEOM_IFACE_FIBRE 0x060000 /* Fibre channel */
-#define BI_GEOM_IFACE_OTHER 0xff0000
- unsigned int cksum; /* MBR checksum */
- u_int interface_path; /* ISA iobase PCI bus/dev/fun */
- u_int64_t device_path;
- int res0; /* future expansion; 0 now */
-#else
- unsigned int cksum; /* MBR checksum */
- int res0, res1, res2, res3; /* future expansion; 0 now */
-#endif
- struct dos_partition dosparts[NDOSPART]; /* MBR itself */
-} __attribute__((packed));
-
-struct btinfo_biosgeom {
- struct btinfo_common common;
- int num;
- struct bi_biosgeom_entry disk[1]; /* var len */
-};
-
-#ifdef _KERNEL
-void *lookup_bootinfo __P((int));
-#endif
-#endif /* _LOCORE */
-
-#ifdef _KERNEL
-#define BOOTINFO_MAXSIZE 4096
-#endif
diff --git a/sys/arch/amd64/include/types.h b/sys/arch/amd64/include/types.h
index dc95c7e0a4e..29db1c37d00 100644
--- a/sys/arch/amd64/include/types.h
+++ b/sys/arch/amd64/include/types.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: types.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */
+/* $OpenBSD: types.h,v 1.2 2004/02/03 12:09:47 mickey Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@@ -70,7 +70,6 @@ typedef long register_t;
/* The amd64 does not have strict alignment requirements. */
#define __NO_STRICT_ALIGNMENT
-#define __HAVE_DEVICE_REGISTER
#define __HAVE_NWSCONS
#define __HAVE_CPU_COUNTER
#define __HAVE_SYSCALL_INTERN
diff --git a/sys/arch/amd64/stand/Makefile b/sys/arch/amd64/stand/Makefile
new file mode 100644
index 00000000000..54cfd25fcab
--- /dev/null
+++ b/sys/arch/amd64/stand/Makefile
@@ -0,0 +1,8 @@
+# $OpenBSD: Makefile,v 1.1 2004/02/03 12:09:47 mickey Exp $
+
+.if ${MACHINE} == "amd64"
+SUBDIR= etc mbr
+.endif
+SUBDIR+= biosboot installboot boot
+
+.include <bsd.subdir.mk>
diff --git a/sys/arch/amd64/stand/Makefile.inc b/sys/arch/amd64/stand/Makefile.inc
new file mode 100644
index 00000000000..8a995ebab4a
--- /dev/null
+++ b/sys/arch/amd64/stand/Makefile.inc
@@ -0,0 +1,55 @@
+# $OpenBSD: Makefile.inc,v 1.1 2004/02/03 12:09:47 mickey Exp $
+
+CFLAGS=${DEBUG} ${COPTS} -Os -Wall -Werror
+CFLAGS+= -fno-stack-protector
+CPPFLAGS+=-I${S} -I${SADIR}/libsa -I. -I${.CURDIR}
+SACFLAGS=-D_STANDALONE
+DEBUGLIBS=no
+DEBUGFLAGS=
+# DEBUGFLAGS+=-DDEBUG
+# DEBUGFLAGS+=-DGIDT_DEBUG
+# DEBUGFLAGS+=-DBIOS_DEBUG
+# DEBUGFLAGS+=-DEXEC_DEBUG
+# DEBUGFLAGS+=-DALLOC_TRACE
+# DEBUGFLAGS+=-g -D_TEST
+# DEBUGFLAGS+=-DUNIX_DEBUG
+# DEBUGFLAGS+=-DBOOTP_DEBUG -DNETIF_DEBUG -DETHER_DEBUG
+# DEBUGFLAGS+=-DNFS_DEBUG -DRPC_DEBUG -DRARP_DEBUG
+LINKADDR=0x40120
+LOADADDR=0x40000
+HEAP_LIMIT=0x90000
+BOOTREL=0x60000
+BOOTMAGIC=0xc001d00d
+#ROM_SIZE=32768
+CLEANFILES+= machine
+
+.if empty(DEBUGFLAGS:M-D_TEST)
+SACFLAGS+=-nostdinc -fno-builtin -fpack-struct
+.endif
+
+.if !make(libdep) && !make(sadep) && !make(salibdir) && !make(kernlibdir) && !make(obj)
+.BEGIN:
+ @([ X$(S) == X -o -h machine ] || ln -s $(S)/arch/amd64/include machine)
+.endif
+
+
+.if exists(${SADIR}/etc/assym.h)
+CPPFLAGS+=-I${SADIR}/etc
+.else
+CPPFLAGS+=-I${SADIR}/etc/${__objdir}
+.endif
+.if exists(${SADIR}/libsa/libsa.a)
+LIBSA=${SADIR}/libsa/libsa.a
+.else
+LIBSA=${SADIR}/libsa/${__objdir}/libsa.a
+.endif
+.if exists(${SADIR}/libz/libz.a)
+LIBZ=${SADIR}/libz/libz.a
+.else
+LIBZ=${SADIR}/libz/${__objdir}/libz.a
+.endif
+
+# NO_NET=no_net
+BINDIR= /usr/mdec
+
+MANSUBDIR=amd64
diff --git a/sys/arch/amd64/stand/biosboot/Makefile b/sys/arch/amd64/stand/biosboot/Makefile
new file mode 100644
index 00000000000..37f201d9f77
--- /dev/null
+++ b/sys/arch/amd64/stand/biosboot/Makefile
@@ -0,0 +1,26 @@
+# $OpenBSD: Makefile,v 1.1 2004/02/03 12:09:47 mickey Exp $
+
+MAN= biosboot.8
+
+.if ${MACHINE} == "amd64"
+PROG= biosboot
+SRCS= biosboot.S
+LD=ld
+LDFLAGS=-melf_i386 -nostdlib -Ttext 0 -N -x -Bstatic
+INSTALL_STRIP=
+SADIR= ${.CURDIR}/..
+
+${PROG}: $(OBJS) $(DPADD)
+ @rm -f $(PROG)
+ $(LD) $(LDFLAGS) -o $(PROG) $(OBJS) $(LDADD)
+ #@size $(PROG)
+
+CPPFLAGS+=-DLOADADDR=$(LOADADDR) -DLINKADDR=$(LINKADDR) -DBOOTMAGIC=$(BOOTMAGIC)
+CPPFLAGS+=${DEBUGFLAGS}
+AFLAGS+=-m32 # -Wa,-a
+.else
+NOPROG=
+.endif
+
+.include <bsd.prog.mk>
+
diff --git a/sys/arch/amd64/stand/biosboot/biosboot.8 b/sys/arch/amd64/stand/biosboot/biosboot.8
new file mode 100644
index 00000000000..55ccc710ffe
--- /dev/null
+++ b/sys/arch/amd64/stand/biosboot/biosboot.8
@@ -0,0 +1,273 @@
+.\" $OpenBSD: biosboot.8,v 1.1 2004/02/03 12:09:47 mickey Exp $
+.\"
+.\" Copyright (c) 2003 Tom Cosgrove <tom.cosgrove@arches-consulting.com>
+.\" Copyright (c) 1997 Michael Shalayeff
+.\" All rights reserved.
+.\"
+.\" 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 AUTHOR ``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 REGENTS 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 MIND, 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.
+.\"
+.Dd December 23, 2003
+.Dt BIOSBOOT 8 i386
+.Os
+.Sh NAME
+.Nm biosboot
+.Nd
+i386-specific first-stage system bootstrap
+.Sh DESCRIPTION
+This small program (roughly 512 bytes of code) is responsible for
+loading the second-stage
+.Xr boot 8
+program (typically /boot), which in turn will load the kernel.
+.Pp
+.Nm
+must be installed by
+.Xr installboot 8 .
+As part of the installation,
+.Xr installboot 8
+patches
+.Nm
+with information about the location of
+.Xr boot 8
+on disk.
+Specifically, it writes the filesystem block number of
+.Xr boot 8 's
+inode,
+the offset within this block of the inode,
+and various filesystem parameters (taken from the superblock)
+required to convert filesystem blocks to disk sectors.
+.Pp
+You must re-run
+.Xr installboot 8
+whenever
+.Xr boot 8
+is changed, as its inode may change.
+While it should not be necessary,
+it may also be advisable to re-run
+.Xr installboot 8
+if you move your disk between machines and/or controllers.
+.Pp
+When
+.Nm
+receives control from either the BIOS or the
+master boot record (MBR) it will print the message:
+.Pp
+.Dl Loading
+.Pp
+followed by a dot for every filesystem block it attempts to load.
+If /boot is loaded successfully,
+.Nm
+will put the cursor on the next line just before
+transferring control to the newly-loaded program.
+.Pp
+If possible,
+.Nm
+will read disk sectors using calls detailed in the Phoenix
+Enhanced Disk Drive Specification (EDD, sometimes known as LBA, reads).
+It will fall back to CHS reads only if EDD calls are not available.
+However, to allow users to boot on hardware that claims LBA capability,
+but which requires CHS reads in order to boot,
+the user may hold down either Shift key during boot.
+If
+.Nm
+detects this, it will force itself to use CHS calls, ignoring
+any LBA capability.
+This will of course prevent booting if /boot lies above the 8 GB
+CHS limit.
+There is an exported symbol
+.Dq force_chs
+of type u_int8_t
+which may be set to 1 to force CHS reads always.
+(However, no tool is currently provided to set this flag.)
+.Sh DIAGNOSTICS
+.Nm
+prints a
+.Sq !\&
+before the
+.Dq Loading
+message if it is being forced to use CHS rather than LBA reads
+(by the user holding down either Shift key during boot,
+or having set the
+.Dq force_chs
+flag in the boot sector).
+.Pp
+.Nm
+prints a
+.Sq ;\&
+after the
+.Dq Loading
+message if it is going to use CHS reads for any reason.
+For example, when booting from floppy or CD-ROM.
+.Pp
+.Nm
+may fail with any of the following error messages:
+.Bl -tag -width ERR_X__
+.It Er ERR I
+Too many indirect blocks.
+.Nm
+is capable of reading the direct blocks in
+.Xr boot 8 's
+inode (the location of which is patched into
+.Nm
+by
+.Xr installboot 8 )
+and the first indirect block,
+but it is not capable of reading further indirect blocks.
+This error indicates that further such indirect blocks were found.
+The system will not be able to boot.
+.Pp
+This is unlikely to ever happen in practice, as
+.Xr boot 8
+has to be quite large for this to be an issue.
+The smallest possible filesystem block size is 512 bytes
+(one sector per filesystem block).
+On such a system, there are 140 filesystem blocks that
+.Nm
+can read, so
+.Xr boot 8
+can be up to 70 KB.
+.Pp
+However, even on floppy disks the filesystem block size is 1024 bytes.
+This allows
+.Xr boot 8
+to occupy up to 268 disk blocks,
+i.e. to be 268 KB.
+On hard disks (default filesystem block size 16 KB)
+4,108 disk blocks are available, to allow
+.Xr boot 8
+to be over 64 MB in size!
+(Only direct blocks are required for
+.Xr boot 8 s
+of up to 192 KB.)
+.It Er ERR M
+Bad magic.
+The ELF
+.Dq magic number
+\e7fELF in
+.Xr boot 8 's
+header was not found.
+This indicates that the first block of
+.Xr boot 8
+was not read correctly.
+This could be due to disk corruption,
+failing to run
+.Xr installboot 8 ,
+giving an invalid
+.Xr boot 8
+program as the
+.Ar boot
+argument to
+.Xr installboot 8 ,
+or
+incorrect geometry translation.
+.It Er ERR R
+Read error.
+The BIOS returned an error indication when
+.Nm
+attempted to read a disk sector.
+This might be any media error, including bad sectors (common on floppy disks),
+and invalid sectors (can occur with bad geometry translations).
+.Pp
+If this error occurs during an LBA boot (no
+.Sq ;\&
+after
+.Dq Loading ) ,
+then a CHS boot may succeed.
+To do this, you should reboot, then hold down either Shift key
+before
+.Nm
+starts.
+You should see a
+.Sq !\&
+before
+.Dq Loading
+as confirmation that your
+override was accepted.
+.It Er ERR X
+Can't boot.
+Issued when trying to read sectors in CHS mode,
+but the BIOS call
+.Em get\ drive\ parameters
+failed or gave a value of 0 for the number of sectors per track.
+In either case, it is not possible for
+.Nm
+to calculate the (cylinder, head, sector) values required to
+read any sectors.
+.Sh NOTES
+Using
+.Nm
+as the MBR,
+as has been done in the past,
+is not recommended, and is not supported.
+Instead, create a single
+.Xr fdisk 8
+partition that spans the entire disk.
+.Pp
+Despite the support for
+.Xr boot 8
+over the 8 GB boundary,
+good
+.Xr disklabel 8
+partitioning practices should still be followed.
+.Sh FILES
+.Bl -tag -width /usr/mdec/biosbootxx -compact
+.It Pa /usr/mdec/mbr
+Master Boot Record block
+.It Pa /usr/mdec/biosboot
+primary bootstrap
+.It Pa /boot
+secondary bootstrap
+.It Pa /bsd
+.Ox
+kernel
+.El
+.Sh SEE ALSO
+.Xr boot 8 ,
+.Xr boot_i386 8 ,
+.Xr disklabel 8 ,
+.Xr fdisk 8 ,
+.Xr installboot 8
+.Sh HISTORY
+.Nm
+was originally written by Michael Shalayeff for
+.Ox 2.1 .
+However it was based on bootstrap code from older versions of this
+operating system, other operating systems, other programs, and
+other people's work.
+.Pp
+It was significantly revised in December 2003 by Tom Cosgrove,
+in order to support LBA disk access (via the Phoenix Enhanced Disk
+Drive Specification API).
+At that time the internal table of disk blocks was removed, and
+.Nm
+modified to read filesystem block numbers from the inode.
+.Sh BUGS
+.Nm
+should perform and verify a checksum across the entire loaded
+.Xr boot 8
+image,
+rather than just checking the magic number in the first block.
+.Pp
+There is no BIOS error number reported nor is the location of the error
+reported.
+.Pp
+You can pick your motherboard, and you can pick your BIOS,
+but you can't pick your motherboard's BIOS.
diff --git a/sys/arch/amd64/stand/biosboot/biosboot.S b/sys/arch/amd64/stand/biosboot/biosboot.S
new file mode 100644
index 00000000000..a5d31bb4217
--- /dev/null
+++ b/sys/arch/amd64/stand/biosboot/biosboot.S
@@ -0,0 +1,896 @@
+/* $OpenBSD: biosboot.S,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 2003 Tobias Weingartner
+ * Copyright (c) 2003 Tom Cosgrove <tom.cosgrove@arches-consulting.com>
+ * Copyright (c) 1997 Michael Shalayeff, Tobias Weingartner
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 REGENTS 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.
+ *
+ */
+ .file "biosboot.S"
+
+#include <machine/asm.h>
+#include <assym.h>
+
+/* Error indicators */
+#define PBR_READ_ERROR 'R'
+#define PBR_CANT_BOOT 'X'
+#define PBR_BAD_MAGIC 'M'
+#define PBR_TOO_MANY_INDIRECTS 'I'
+
+#define CHAR_BLOCK_READ '.'
+#define CHAR_CHS_READ ';'
+
+/*
+ * Memory layout:
+ *
+ * 0x00000 -> 0x079FF our stack (to 30k5)
+ * 0x07A00 -> 0x07BFF typical MBR loc (at 30k5)
+ * 0x07C00 -> 0x07DFF our code (at 31k)
+ * 0x07E00 -> ... /boot inode block (at 31k5)
+ * 0x07E00 -> ... (indirect block if nec)
+ * 0x40000 -> ... /boot (at 256k)
+ *
+ * The BIOS loads the MBR at physical address 0x07C00. It then relocates
+ * itself to (typically) 0x07A00.
+ *
+ * The MBR then loads us at physical address 0x07C00.
+ *
+ * We use a long jmp to normalise our address to seg:offset 07C0:0000.
+ * (In real mode on x86, segment registers contain a base address in
+ * paragraphs (16 bytes). 0000:00010 is the same as 0001:0000.)
+ *
+ * We set the stack to start at 0000:79FC (grows down on i386)
+ *
+ * We then read the inode for /boot into memory just above us at
+ * 07E0:0000, and run through the direct block table (and the first
+ * indirect block table, if necessary).
+ *
+ * We load /boot at seg:offset 4000:0000.
+ *
+ * Previous versions limited the size of /boot to 64k (loaded in a single
+ * segment). This version does not have this limitation.
+ */
+#define INODESEG 0x07e0 /* where we put /boot's inode's block */
+#define INDIRECTSEG 0x07e0 /* where we put indirect table, if nec */
+#define BOOTSEG 0x07c0 /* biosboot loaded here */
+#define BOOTSTACKOFF ((BOOTSEG << 4) - 4) /* stack starts here, grows down */
+#define LFMAGIC 0x464c /* LFMAGIC (last two bytes of \7fELF) */
+#define ELFMAGIC 0x464c457f /* ELFMAGIC ("\7fELF") */
+
+#define INODEOFF ((INODESEG-BOOTSEG) << 4)
+
+/*
+ * The data passed by installboot is:
+ *
+ * inodeblk uint32 the filesystem block that holds /boot's inode
+ * inodedbl uint32 the memory offset to the beginning of the
+ * direct block list (di_db[]). (This is the
+ * offset within the block + $INODEOFF, which is
+ * where we load the block to.)
+ * fs_bsize_p uint16 the filesystem block size _in paragraphs_
+ * (i.e. fs_bsize / 16)
+ * fs_bsize_s uint16 the number of 512-byte sectors in a filesystem
+ * block (i.e. fs_bsize / 512). Directly written
+ * into the LBA command block, at lba_count.
+ * XXX LIMITED TO 127 BY PHOENIX EDD SPEC.
+ * fsbtodb uint8 shift count to convert filesystem blocks to
+ * disk blocks (sectors). Note that this is NOT
+ * log2 fs_bsize, since fragmentation allows
+ * the trailing part of a file to use part of a
+ * filesystem block. In other words, filesystem
+ * block numbers can point into the middle of
+ * filesystem blocks.
+ * p_offset uint32 the starting disk block (sector) of the
+ * filesystem
+ * nblocks uint16 the number of filesystem blocks to read.
+ * While this can be calculated as
+ * howmany(di_size, fs_bsize) it takes us too
+ * many code bytes to do it.
+ *
+ * All of these are patched directly into the code where they are used
+ * (once only, each), to save space.
+ *
+ * One more symbol is exported, in anticipation of a "-c" flag in
+ * installboot to force CHS reads:
+ *
+ * force_chs uint8 set to the value 1 to force biosboot to use CHS
+ * reads (this will of course cause the boot sequence
+ * to fail if /boot is above 8 GB).
+ */
+
+ .globl inodeblk, inodedbl, fs_bsize_p, fsbtodb, p_offset, nblocks
+ .globl fs_bsize_s, force_chs
+ .type inodeblk, @function
+ .type inodedbl, @function
+ .type fs_bsize_p, @function
+ .type fs_bsize_s, @function
+ .type fsbtodb, @function
+ .type p_offset, @function
+ .type nblocks, @function
+ .type force_chs, @function
+
+
+/* Clobbers %ax, maybe more */
+#define putc(c) movb $c, %al; call Lchr
+
+/* Clobbers %ax, %si, maybe more */
+#define puts(s) movw $s, %si; call Lmessage
+
+
+ .text
+ .code16
+ .globl _start
+_start:
+ jmp begin
+ nop
+
+ /*
+ * BIOS Parameter Block. Read by many disk utilities.
+ *
+ * We would have liked biosboot to go from the superblock to
+ * the root directory to the inode for /boot, thence to read
+ * its blocks into memory.
+ *
+ * As code and data space is quite tight in the 512-byte
+ * partition boot sector, we instead get installboot to pass
+ * us some pre-processed fields.
+ *
+ * We would have liked to put these in the BIOS parameter block,
+ * as that seems to be the right place to put them (it's really
+ * the equivalent of the superblock for FAT filesystems), but
+ * caution prevents us.
+ *
+ * For now, these fields are either directly in the code (when they
+ * are used once only) or at the end of this sector.
+ */
+
+ . = _start + 3
+
+ .asciz "OpenBSD"
+
+ /* BPB */
+ . = _start + 0x0b
+bpb: .word DEV_BSIZE /* sector size */
+ .byte 2 /* sectors/cluster */
+ .word 0 /* reserved sectors */
+ .byte 0 /* # of FAT */
+ .word 0 /* root entries */
+ .word 0 /* small sectors */
+ .byte 0xf8 /* media type (hd) */
+ .word 0 /* sectors/fat */
+ .word 0 /* sectors per track */
+ .word 0 /* # of heads */
+
+ /* EBPB */
+ . = _start + 0x1c
+ebpb: .long 16 /* hidden sectors */
+ .long 0 /* large sectors */
+ .word 0 /* physical disk */
+ .byte 0x29 /* signature, needed by NT */
+ .space 4, 0 /* volume serial number */
+ .ascii "UNIX LABEL"
+ .asciz "UFS 4.4"
+
+ /* boot code */
+ . = _start + 0x3e
+
+begin:
+ /* Fix up %cs just in case */
+ ljmp $BOOTSEG, $main
+
+ /*
+ * Come here if we have to do a CHS boot, but we get an error from
+ * BIOS get drive parameters, or it returns nsectors == 0 (in which
+ * case we can't do the division we need to convert LBA sector
+ * number to CHS).
+ */
+cant_boot:
+ movb $PBR_CANT_BOOT, %al
+ jmp err_print_crlf
+
+main:
+ /* Set up stack */
+ xorw %ax, %ax
+ movw %ax, %ss
+ movw $BOOTSTACKOFF, %sp
+
+ /* Set up needed data segment reg */
+ pushw %cs
+ popw %ds /* Now %cs == %ds, != %ss (%ss == 0) */
+
+#ifdef SERIAL
+ /* Initialize the serial port to 9600 baud, 8N1 */
+ push %dx
+ movw $0x00e3, %ax
+ movw SERIAL, %dx
+ int $0x14
+ pop %dx
+#endif
+
+#ifdef BDEBUG
+ putc('R')
+#endif
+
+ /*
+ * We're going to print our sign-on message.
+ *
+ * We're now LBA-aware, and will use LBA to load /boot if the
+ * BIOS says it's available. However, we have seen machines
+ * where CHS is required even when LBA is available. Therefore
+ * we provide a way to force CHS use:
+ *
+ * If the SHIFT key is held down on entry, force CHS reads.
+ */
+ movw $load_msg+1, %si /* "Loading" */
+ movb %dl, %dh
+
+ /*
+ * BIOS call "INT 0x16 Get Keyboard Shift Flags
+ * Call with %ah = 0x02
+ * Return:
+ * %al = shift flags
+ * %ah - undefined by many BIOSes
+ */
+ movb $0x02, %ah
+ int $0x16
+
+ /*
+ * We provide the ability to force CHS use without having to hold
+ * down the SHIFT key each boot. Just set the byte at force_chs
+ * to 1 (more accurately any value with either of the bottom two
+ * bits set, but the use of 1 is recommended).
+ */
+force_chs = .+1
+ orb $0, %al
+
+ testb $0x3, %al /* Either shift key down? */
+ jz no_force_chs
+
+ decw %si /* "!Loading" indicates forced CHS */
+ xorb %dh, %dh /* Pretend a floppy, so no LBA use */
+
+no_force_chs:
+ /* Print pretty message */
+ call Lmessage
+
+ /*
+ * We will use LBA reads if we have LBA support, so find out.
+ */
+
+ /*
+ * But don't even try on floppies, OR if forcing to CHS.
+ *
+ * (We're really testing %dl, but use %dh so we can force the
+ * top bit to zero to force CHS boot.)
+ */
+ testb $0x80, %dh
+ jz no_lba
+
+ /*
+ * BIOS call "INT 0x13 Extensions Installation Check"
+ * Call with %ah = 0x41
+ * %bx = 0x55AA
+ * %dl = drive (0x80 for 1st hd, 0x81 for 2nd, etc)
+ * Return:
+ * carry set: failure
+ * %ah = error code (0x01, invalid func)
+ * carry clear: success
+ * %bx = 0xAA55 (must verify)
+ * %ah = major version of extensions
+ * %al (internal use)
+ * %cx = capabilities bitmap
+ * 0x0001 - extnd disk access funcs
+ * 0x0002 - rem. drive ctrl funcs
+ * 0x0004 - EDD functions with EBP
+ * %dx (extension version?)
+ */
+
+ pushw %dx /* Save the drive number (%dl) */
+ movw $0x55AA, %bx
+ movb $0x41, %ah
+ int $0x13
+ popw %dx /* Retrieve drive number */
+
+ jc no_lba /* Did the command work? Jump if not */
+ cmpw $0xAA55, %bx /* Check that bl, bh exchanged */
+ jne no_lba /* If not, don't have EDD extensions */
+ testb $0x01, %cl /* And do we have "read" available? */
+ jz no_lba /* Again, use CHS if not */
+
+ /* We have LBA support, so that's the vector to use */
+
+ movw $load_lba, load_fsblock
+ jmp get_going
+
+no_lba:
+ pushw %dx
+
+ /*
+ * BIOS call "INT 0x13 Function 0x08" to get drive parameters
+ * Call with %ah = 0x08
+ * %dl = drive (0x80 for 1st hd, 0x81 for 2nd...)
+ * Return:
+ * carry set: failure
+ * %ah = err code
+ * carry clear: success
+ * %ah = 0x00
+ * %al = 0x00 (some BIOSes)
+ * %ch = 0x00 (some BIOSes)
+ * %ch = max-cylinder & 0xFF
+ * %cl = max sector | rest of max-cyl bits
+ * %dh = max head number
+ * %dl = number of drives
+ * (according to Ralph Brown Int List)
+ */
+ movb $0x08, %ah
+ int $0x13 /* We need to know heads & sectors */
+
+ jc cant_boot /* If error, can't boot */
+
+ movb %dh, maxheads /* Remember this */
+
+ andb $0x3F, %cl
+ jz cant_boot
+ movb %cl, nsectors
+
+ putc(CHAR_CHS_READ) /* Indicate (subtly) CHS reads */
+
+ popw %dx /* Retrieve the drive number */
+
+get_going:
+ /*
+ * Older versions of biosboot used to set up the destination
+ * segment, and increase the target offset every time a number
+ * of blocks was read. That limits /boot to 64k.
+ *
+ * In order to support /boots > 64k, we always read to offset
+ * 0000 in the target segment, and just increase the target segment
+ * each time.
+ */
+
+ /*
+ * We would do movl inodeblk, %eax here, but that instruction
+ * is 4 bytes long; add 4 bytes for data takes 8 bytes. Using
+ * a load immediate takes 6 bytes, and we just get installboot
+ * to patch here, rather than data anywhere else.
+ */
+inodeblk = .+2
+ movl $0x90909090, %eax /* mov $inodeblk, %eax */
+
+ movw $INODESEG, %bx /* Where to put /boot's inode */
+
+ /*
+ * %eax - filesystem block to read
+ * %bx - target segment (target offset is 0000)
+ * %dl - BIOS drive number
+ */
+ call *load_fsblock /* This will crash'n'burn on errs */
+
+ /*
+ * We now have /boot's inode in memory.
+ *
+ * /usr/include/ufs/ufs/dinode.h for the details:
+ *
+ * Offset 8 (decimal): 64-bit file size (only use low 32 bits)
+ * Offset 40 (decimal): list of NDADDR (12) direct disk blocks
+ * Offset 88 (decimal): list of NIADDR (3) indirect disk blocks
+ *
+ * NOTE: list of indirect blocks immediately follows list of
+ * direct blocks. We use this fact in the code.
+ *
+ * We only support loading from direct blocks plus the first
+ * indirect block. This is the same as the previous biosboot/
+ * installboot limit. Note that, with default 16,384-bytes
+ * filesystem blocks, the direct block list supports files up
+ * to 192 KB. /boot is currently around 60 KB.
+ *
+ * The on-disk format can't change (filesystems with this format
+ * already exist) so okay to hardcode offsets here.
+ *
+ * The nice thing about doing things with filesystem blocks
+ * rather than sectors is that filesystem blocks numbers have
+ * 32 bits, so fit into a single register (even if "e"d).
+ *
+ * Note that this code does need updating if booting from a new
+ * filesystem is required.
+ */
+#define NDADDR 12
+#define di_db 40 /* Not used; addr put in by instboot */
+#define di_ib 88 /* Not used; run on from direct blks */
+
+ /*
+ * Register usage:
+ *
+ * %eax - block number for load_fsblock
+ * %bx - target segment (target offset is 0000) for load_fsblock
+ * %dl - BIOS drive number for load_fsblock
+ * %esi - points to block table in inode/indirect block
+ * %cx - number of blocks to load within loop (i.e. from current
+ * block list, which is either the direct block list di_db[]
+ * or the indirect block list)
+ * %di - total number of blocks to load
+ */
+
+ /*
+ * We would do movl inodedbl, %esi here, but that instruction
+ * is 4 bytes long; add 4 bytes for data takes 8 bytes. Using
+ * a load immediate takes 6 bytes, and we just get installboot
+ * to patch here, rather than in data anywhere else.
+ */
+inodedbl = .+2
+ movl $0x90909090, %esi /* mov $inodedbl, %esi */
+ /* Now esi -> di_db[] */
+
+nblocks = .+1
+ movw $0x9090, %di /* mov nblocks, %di */
+ movw %di, %cx
+ cmpw $NDADDR, %cx
+ jc 1f
+ movw $NDADDR, %cx
+1: /* %cx = min(nblocks, $NADDR) */
+
+ movw $(LOADADDR >> 4), %bx /* Target segment for /boot */
+
+load_blocks:
+ putc(CHAR_BLOCK_READ) /* Show progress indicator */
+
+ cld
+
+ /* Get the next filesystem block number into %eax */
+ lodsl /* %eax = *(%si++), make sure 0x66 0xad */
+
+ pushal /* Save all 32-bit registers */
+
+ /*
+ * Read a single filesystem block (will almost certainly be multiple
+ * disk sectors)
+ *
+ * %eax - filesystem block to read
+ * %bx - target segment (target offset is 0000)
+ * %dl - BIOS drive number
+ */
+ call *load_fsblock /* This will crash'n'burn on errs */
+
+ popal /* Restore 32-bit registers */
+
+ /*
+ * We want to put addw fs_bsize_p, %bx, which takes 4 bytes
+ * of code and two bytes of data.
+ *
+ * Instead, use an immediate load, and have installboot patch
+ * here directly.
+ */
+ /* Move on one filesystem block */
+fs_bsize_p = .+2
+ addw $0x9090, %bx /* addw $fs_bsize_p, %bx */
+
+ decw %di
+ loop load_blocks
+
+ /* %cx == 0 ... important it stays this way (used later) */
+
+ /*
+ * Finished reading a set of blocks.
+ *
+ * This was either the direct blocks, and there may or may not
+ * be indirect blocks to read, or it was the indirect blocks,
+ * and we may or may not have read in all of /boot. (Ideally
+ * will have read in all of /boot.)
+ */
+ orw %di, %di
+ jz done_load /* No more sectors to read */
+
+ /* We have more blocks to load */
+
+ /* We only support a single indirect block (the same as previous
+ * versions of installboot. This is required for the boot floppies.
+ *
+ * We use a bit of the code to store a flag that indicates
+ * whether we have read the first indirect block or not.
+ *
+ * If we've already read the indirect list, we can't load this /boot.
+ *
+ * indirect uint8 0 => running through load_blocks loop reading
+ * direct blocks. If != 0, we're reading the
+ * indirect blocks. Must use a field that is
+ * initialised to 0.
+ */
+indirect = .+2
+ movw $PBR_TOO_MANY_INDIRECTS, %ax /* movb $PRB_TOO..., %al */
+ /* movb indirect, %ah */
+ orb %ah, %ah
+ jnz err_print_crlf
+
+ incb indirect /* No need to worry about wrap */
+ /* around, as this will only be done */
+ /* once before we fail */
+
+ /* Okay, let's read in the indirect block */
+
+ lodsl /* Get blk num of 1st indirect blk */
+
+ pushw %bx /* Remember where we got to */
+ movw $INODESEG, %bx
+ call *load_fsblock /* This will crash'n'burn on errs */
+ popw %bx /* Indirect blocks get added on to */
+ /* just after where we got to */
+ movl $INODEOFF, %esi
+ movw %di, %cx /* How many blocks left to read */
+
+ jmp load_blocks
+
+done_load:
+ puts(crlf)
+
+ /* %cx == 0 from loop above... keep it that way */
+
+ /*
+ * Check the magic signature at the beginning of /boot.
+ * Since /boot is now ELF, this should be 0xFF E L F.
+ */
+ movw $(LOADADDR >> 4), %ax /* Target segment */
+ movw %ax, %es
+
+ /*
+ * We cheat a little here, and only check the L and F.
+ *
+ * (Saves 3 bytes of code... the two signature bytes we
+ * don't check, and the operand size prefix that's not
+ * needed.)
+ */
+ cmpw $LFMAGIC, %es:2(,1)
+ je exec_boot
+
+ movb $PBR_BAD_MAGIC, %al
+
+err_print:
+ movw $err_txt, %si
+err_print2:
+ movb %al, err_id
+err_stop:
+ call Lmessage
+stay_stopped:
+ cli
+ hlt
+ jmp stay_stopped /* Just to make sure :-) */
+
+exec_boot:
+ /* At this point we could try to use the entry point in
+ * the image we just loaded. But if we do that, we also
+ * have to potentially support loading that image where it
+ * is supposed to go. Screw it, just assume that the image
+ * is sane.
+ */
+#ifdef BDEBUG
+ putc('P')
+#endif
+
+ /* %cx == 0 from loop above... keep it that way */
+
+ /*
+ * We want to do movzbl %dl, %eax ; pushl %eax to zero-extend the
+ * drive number to 32 bits and pass it to /boot. However, this
+ * takes 6 bytes.
+ *
+ * Doing it this way saves 2 bytes.
+ */
+ pushw %cx
+ movb %dl, %cl
+ pushw %cx
+
+ pushl $BOOTMAGIC /* use some magic */
+
+ /* jmp /boot */
+ ljmp $(LINKADDR >> 4), $0
+ /* not reached */
+
+
+/*
+ * Load a single filesystem block into memory using CHS calls.
+ *
+ * Input: %eax - 32-bit filesystem block number
+ * %bx - target segment (target offset is 0000)
+ * %dl - BIOS drive number
+ *
+ * Output: block successfully read in (panics if not)
+ * all general purpose registers may have been trashed
+ */
+load_chs:
+ /*
+ * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into
+ * memory.
+ * Call with %ah = 0x42
+ * %ah = 0x2
+ * %al = number of sectors
+ * %ch = cylinder & 0xFF
+ * %cl = sector (0-63) | rest of cylinder bits
+ * %dh = head
+ * %dl = drive (0x80 for 1st hd, 0x81 for 2nd...)
+ * %es:%bx = segment:offset of buffer
+ * Return:
+ * carry set: failure
+ * %ah = err code
+ * %al = number of sectors transferred
+ * carry clear: success
+ * %al = 0x0 OR number of sectors transferred
+ * (depends on BIOS!)
+ * (according to Ralph Brown Int List)
+ */
+
+ /* Convert the filesystem block into a sector value */
+ call fsbtosector
+ movl lba_sector, %eax /* we can only use 24 bits, really */
+
+ movw fs_bsize_s, %cx /* sectors per filesystem block */
+
+ /*
+ * Some BIOSes require that reads don't cross track boundaries.
+ * Therefore we do all CHS reads single-sector.
+ */
+calc_chs:
+ pushal
+ movw %bx, %es /* Set up target segment */
+
+ pushw %dx /* Save drive number (in %dl) */
+ xorl %edx, %edx
+ movl %edx, %ecx
+
+nsectors = .+1
+ movb $0x90, %cl /* movb $nsectors, %cl */
+ /* Doing it this way saves 4-2 = 2 bytes code */
+ /* bytes (no data, since we would overload) */
+
+ divl %ecx, %eax
+ /* Now have sector number in %dl */
+ pushw %dx /* Remember for later */
+
+ xorl %edx, %edx
+
+maxheads = .+1
+ movb $0x90, %cl /* movb $maxheads, %cl; 0 <= maxheads <= 255 */
+ /* Doing it this way saves 4-2 = 2 code */
+ /* bytes (no data, since we would overload */
+
+ incw %cx /* Number of heads is 1..256, no "/0" worries */
+
+ divl %ecx, %eax
+ /* Have head number in %dl */
+ /* Cylinder number in %ax */
+ movb %al, %ch /* Bottom 8 bits of cyl number */
+ shlb $6, %ah /* Move up top 2 bits of cyl number */
+ movb %ah, %cl /* Top 2 bits of cyl number in here */
+
+ popw %bx /* (pushed %dx, but need %dl for now */
+ incb %bl /* Sector numbers run from 1, not 0 */
+ orb %bl, %cl /* Or the sector number into top bits cyl */
+
+ /* Remember, %dl has head number */
+ popw %ax
+ /* %al has BIOS drive number -> %dl */
+
+ movb %dl, %dh /* Now %dh has head number (from 0) */
+ movb %al, %dl /* Now %dl has BIOS drive number */
+
+ xorw %bx, %bx /* Set up target offset */
+
+ movw $0x0201, %ax /* %al = 1 - read one sector at a time */
+ /* %ah = 2 - int 0x13 function for CHS read */
+
+ call do_int_13 /* saves us 1 byte :-) */
+
+ /* Get the next sector */
+
+ popal
+ incl %eax
+ addw $32, %bx /* Number of segments/paras in a sector */
+ loop calc_chs
+
+ ret
+
+ /* read error */
+read_error:
+ movb $PBR_READ_ERROR, %al
+err_print_crlf:
+ movw $err_txt_crlf, %si
+ jmp err_print2
+
+
+/*
+ * Load a single filesystem block into memory using LBA calls.
+ *
+ * Input: %eax - 32-bit filesystem block number
+ * %bx - target segment (target offset is 0000)
+ * %dl - BIOS drive number
+ *
+ * Output: block successfully read in (panics if not)
+ * all general purpose registers may have been trashed
+ */
+load_lba:
+ /*
+ * BIOS call "INT 0x13 Extensions Extended Read"
+ * Call with %ah = 0x42
+ * %dl = drive (0x80 for 1st hd, 0x81 for 2nd, etc)
+ * %ds:%si = segment:offset of command packet
+ * Return:
+ * carry set: failure
+ * %ah = error code (0x01, invalid func)
+ * command packet's sector count field set
+ * to the number of sectors successfully
+ * transferred
+ * carry clear: success
+ * %ah = 0 (success)
+ * Command Packet:
+ * 0x0000 BYTE packet size (0x10 or 0x18)
+ * 0x0001 BYTE reserved (should be 0)
+ * 0x0002 WORD sectors to transfer (max 127)
+ * 0x0004 DWORD seg:offset of transfer buffer
+ * 0x0008 QWORD starting sector number
+ */
+ call fsbtosector /* Set up lba_sector & lba_sector+4 */
+
+ /* movb %dh, lba_count <- XXX done by installboot */
+ movw %bx, lba_seg
+ movw $lba_command, %si
+ movb $0x42, %ah
+do_int_13:
+ int $0x13
+ jc read_error
+
+ ret
+
+
+/*
+ * Converts a given filesystem block number into a disk sector
+ * at lba_sector and lba_sector+4.
+ *
+ * Input: %eax - 32-bit filesystem block number
+ *
+ * Output: lba_sector and lba_sector+4 set up
+ * XXX
+ */
+fsbtosector:
+ /*
+ * We want to do
+ *
+ * movb fsbtodb, %ch /# Shift counts we'll need #/
+ * movb $32, %cl
+ *
+ * which is 6 bytes of code + 1 byte of data.
+ *
+ * We'll actually code it with an immediate 16-bit load into %cx,
+ * which is just 3 bytes of data (saves 4 bytes).
+ */
+fsbtodb = .+2
+ movw $0x9020, %cx /* %ch = fsbtodb, %cl = 0x20 */
+
+ pushl %eax
+ subb %ch, %cl
+ shrl %cl, %eax
+ movl %eax, lba_sector+4
+ popl %eax
+
+ movb %ch, %cl
+ shll %cl, %eax
+
+ /*
+ * And add p_offset, which is the block offset to the start
+ * of the filesystem.
+ *
+ * We would do addl p_offset, %eax, which is 5 bytes of code
+ * and 4 bytes of data, but it's more efficient to have
+ * installboot patch directly in the code (this variable is
+ * only used here) for 6 bytes of code (but no data).
+ */
+p_offset = .+2
+ addl $0x90909090, %eax /* addl $p_offset, %eax */
+
+ movl %eax, lba_sector
+ jnc 1f
+
+ incl lba_sector+4
+1:
+ ret
+
+
+/*
+ * Display string
+ */
+Lmessage:
+ cld
+1:
+ lodsb /* load a byte into %al */
+ orb %al, %al
+ jz 1f
+ call Lchr
+ jmp 1b
+
+/*
+ * Lchr: write the character in %al to console
+ */
+Lchr:
+#ifdef SERIAL
+ pushw %dx
+ movb $0x01, %ah
+ xorw %dx, %dx
+ movb SERIAL, %dl
+ int $0x14
+ popw %dx
+#else
+ pushw %bx
+ movb $0x0e, %ah
+ xorw %bx, %bx
+ incw %bx /* movw $0x01, %bx */
+ int $0x10
+ popw %bx
+#endif
+1:
+ ret
+
+ /* .data */
+
+/* vector to the routine to read a particular filesystem block for us */
+load_fsblock:
+ .word load_chs
+
+
+/* This next block is used for the EDD command packet used to read /boot
+ * sectors.
+ *
+ * lba_count is set up for us by installboot. It is the number of sectors
+ * in a filesystem block. (Max value 127.)
+ *
+ * XXX The EDD limit of 127 sectors in one read means that we currently
+ * restrict filesystem blocks to 127 sectors, or < 64 KB. That is
+ * effectively a 32 KB block limit, as filesystem block sizes are
+ * powers of two. The default filesystem block size is 16 KB.
+ *
+ * I say we run with this limitation and see where it bites us...
+ */
+
+lba_command:
+ .byte 0x10 /* size of command packet */
+ .byte 0x00 /* reserved */
+fs_bsize_s:
+lba_count:
+ .word 0 /* sectors to transfer, max 127 */
+ .word 0 /* target buffer, offset */
+lba_seg:
+ .word 0 /* target buffer, segment */
+lba_sector:
+ .long 0, 0 /* sector number */
+
+load_msg:
+ .asciz "!Loading"
+err_txt_crlf:
+ .ascii "\r\n"
+err_txt:
+ .ascii "ERR "
+err_id:
+ .ascii "?"
+crlf: .asciz "\r\n"
+
+ . = 0x200 - 2
+ /* a little signature */
+ .word DOSMBR_SIGNATURE
diff --git a/sys/arch/amd64/stand/boot/Makefile b/sys/arch/amd64/stand/boot/Makefile
new file mode 100644
index 00000000000..82eb17fdc51
--- /dev/null
+++ b/sys/arch/amd64/stand/boot/Makefile
@@ -0,0 +1,60 @@
+# $OpenBSD: Makefile,v 1.1 2004/02/03 12:09:47 mickey Exp $
+
+.include "${.CURDIR}/../Makefile.inc"
+
+MAN= boot.8
+MLINKS= boot.8 boot.conf.8
+
+.if ${MACHINE} == "amd64"
+S =${.CURDIR}/../../../..
+SADIR= ${.CURDIR}/..
+
+PROG= boot
+SRCS= srt0.S conf.c
+LD?= ld
+SIZE?= size
+LDFLAGS+=-melf_i386 -nostdlib -Bstatic -Ttext $(LINKADDR) -N -x -noinhibit-exec
+
+.PATH: ${SADIR}/libsa
+# i386 stuff (so, it will possibly load in the same 64k)
+SRCS+= machdep.c dev_i386.c exec_i386.c cmd_i386.c
+SRCS+= gidt.S alloca.S biosdev.c bioscons.c gateA20.c \
+ memprobe.c diskprobe.c time.c biosprobe.c
+
+.PATH: ${S}/stand/boot
+SRCS+= boot.c cmd.c vars.c bootarg.c
+
+.PATH: ${S}/lib/libsa
+.PATH: ${S}/lib/libkern # for strl*
+# stand routines
+SRCS+= alloc.c exit.c getfile.c gets.c globals.c strcmp.c strlen.c \
+ strncmp.c memcmp.c memcpy.c memset.c printf.c snprintf.c \
+ strerror.c strncpy.c strtol.c ctime.c strlcpy.c strlcat.c
+# io routines
+SRCS+= close.c closeall.c dev.c disklabel.c dkcksum.c fstat.c ioctl.c lseek.c \
+ open.c read.c stat.c write.c cread.c readdir.c cons.c loadfile.c
+# boot filesystems
+SRCS+= ufs.c
+
+.PATH: ${S}/lib/libz
+SRCS+= adler32.c crc32.c inflate.c inftrees.c
+
+boot.bin: boot
+ objcopy -v -O binary ${PROG} boot.bin
+
+${PROG}: $(OBJS)
+ $(LD) $(LDFLAGS) -o ${PROG} $(OBJS)
+ #@$(SIZE) ${PROG}
+
+.else
+NOPROG=
+.endif
+
+.include <bsd.prog.mk>
+
+CPPFLAGS+=-DBOOTMAGIC=$(BOOTMAGIC) ${DEBUGFLAGS} -DLINKADDR=${LINKADDR}
+CPPFLAGS+=-DSLOW -DSMALL -DNOBYFOUR -DNO_GZIP -DDYNAMIC_CRC_TABLE
+CPPFLAGS+=-DHEAP_LIMIT=${HEAP_LIMIT} -I${S}/stand/boot #-DCOMPAT_UFS
+CFLAGS+=-m32 $(SACFLAGS) -D__INTERNAL_LIBSA_CREAD
+AFLAGS+=-m32 # -Wa,-R
+# AFLAGS+=-Wa,-a
diff --git a/sys/arch/amd64/stand/boot/boot.8 b/sys/arch/amd64/stand/boot/boot.8
new file mode 100644
index 00000000000..d9085add665
--- /dev/null
+++ b/sys/arch/amd64/stand/boot/boot.8
@@ -0,0 +1,375 @@
+.\" $OpenBSD: boot.8,v 1.1 2004/02/03 12:09:47 mickey Exp $
+.\"
+.\" Copyright (c) 1997-2001 Michael Shalayeff
+.\" All rights reserved.
+.\"
+.\" 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 AUTHOR ``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 AUTHOR OR HIS RELATIVES 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 MIND, 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.
+.\"
+.\"
+.Dd September 1, 1997
+.Dt BOOT 8 i386
+.Os
+.Sh NAME
+.Nm boot ,
+.Nm boot.conf
+.Nd
+i386-specific second-stage bootstrap
+.Sh DESCRIPTION
+The main purpose of this program is to load the system kernel while dealing
+with the downfalls of the PC BIOS architecture.
+.Pp
+As described in
+.Xr boot_i386 8 ,
+this program is loaded by the
+.Xr biosboot 8
+primary bootstrap loader and provides a convenient way to load the kernel.
+This program acts as an enhanced boot monitor for PC systems, providing
+a common interface for the kernel to start from.
+.Pp
+Basic operations include:
+.Pp
+.Bl -bullet -compact
+.It
+Detecting and switching between multiple consoles.
+.It
+Loading kernels from any device supported by your system BIOS.
+.It
+Loading kernels compressed by
+.Xr gzip 1 .
+.It
+Passing system parameters queried from the BIOS to the kernel.
+.It
+Providing an interactive command line.
+.El
+.Pp
+The sequence of its operation is as follows: initialization,
+parsing the configuration file, then an interactive command line.
+While at the command line you have 5 seconds to type any commands, if needed.
+If time expires, the kernel will be loaded according to
+the current variable settings (see the
+.Nm set
+command).
+Each time a kernel load fails, the timeout is increased by one second.
+The sequence of
+.Nm
+operations is as follows:
+.Bl -enum
+.It
+Set up a protected mode environment which catches and reports processor
+exceptions and provides a simple protected-mode BIOS interface.
+.It
+Probe for console devices, which includes the (default) PC VGA+Keyboard
+console
+.Pq Li pc0
+and up to four serial consoles
+.Pf ( Li com0
+through
+.Li com3 )
+connected to the serial ports.
+Display messages to the default console about the devices found.
+.It
+Detect memory.
+Conventional memory is detected by querying the BIOS.
+Extended memory is detected by probing page-by-page through the address
+space, rather than asking the BIOS; many BIOS's cannot report larger than
+64M of memory.
+All memory found is reported to the default console device.
+.It
+Probe for APM support in the BIOS.
+Display a message if support is present.
+.It
+If the file
+.Pa /etc/boot.conf
+exists on the filesystem
+.Nm
+was loaded from, open and parse it.
+This file may contain any commands
+.Nm
+accepts at the interactive prompt.
+Though default settings usually suffice, they can be changed here.
+.It
+The header line
+.Pp
+.Dl >> OpenBSD/i386 BOOT [x.xx]
+.Pp
+is displayed to the active console, where
+.Ar x.xx
+is the version number of the
+.Nm
+program, followed by the
+.Pp
+.Dl boot>
+.Pp
+prompt, which means you are in interactive mode and may enter commands.
+If you do not,
+.Nm
+will proceed to load the kernel with the current parameters after the
+timeout period has expired.
+.El
+.Pp
+By default,
+.Nm
+attempts to load the kernel executable
+.Pa /bsd .
+If that fails, it will attempt to load
+.Pa /obsd
+and then
+.Pa /bsd.old .
+If it fails to find any of these files,
+and no alternative kernel image has been specified,
+the system will be unable to boot.
+.Sh COMMANDS
+The following commands are accepted at the
+.Nm
+prompt:
+.Bl -tag -width shorten
+.It boot Op Ar image Op Fl acds
+Boots the kernel image specified by
+.Ar image
+with any options given.
+Image specification consists of a pair
+.Ar device : Ns Ar filename ;
+either or both can be omitted (`:' is not needed if both are omitted),
+in which case values from
+.Nm
+variables will be used.
+.Pp
+When selecting the
+.Ar device
+to boot from,
+.Nm
+makes no distinction between SCSI and IDE type drives;
+they are detected as
+.Sq hd
+devices.
+Therefore, to boot kernel
+.Pa /bsd
+from slice
+.Sq a
+on the first hard drive
+.Pq irrespective of device type ,
+specify
+.Dq boot hd0a:/bsd .
+.Bl -tag -width _a_
+.It Fl a
+Causes the kernel to ask for the
+.Nm root
+device to use.
+.It Fl c
+Causes the kernel to go into
+.Xr boot_config 8
+before performing
+.Xr autoconf 4
+procedures.
+.It Fl d
+Causes the kernel to drop into
+.Xr ddb 4
+at the earliest convenient point.
+.It Fl s
+Causes the kernel to boot single-user.
+.El
+.It echo Op Ar args
+Displays
+.Ar args
+on the console device.
+.It help
+Prints a list of available commands and machine dependent
+commands, if any.
+.It machine Op Ar command
+Issues machine-dependent commands.
+These are defined for i386 architecture:
+.Bl -tag -width diskinfo
+.It Nm diskinfo
+Prints a list of hard disks installed on your system including:
+BIOS device number, and the BIOS geometry.
+.It Nm memory
+If used without any arguments this command will print out
+the memory configuration as determined through BIOS routines.
+Otherwise the arguments would specify the expressions to modify the
+memory configuration.
+The expression would have a form of:
+.Pp
+.Dl [+-]<size>@<address>
+.Pp
+Meaning to add(+) or exempt(-) the specified by the
+.Ar <size>
+amount of memory at the location specified by the
+.Ar <address>
+argument.
+Both size and base address could be specified as octal,
+decimal, or hexadecimal numbers, as accepted by the
+.Xr strtoul 3
+routine.
+Memory segments are not required to be adjacent to each other,
+the only requirement is that there is real physical memory under
+the range added.
+For example:
+.Bd -unfilled -offset indent
+machine mem +0x2000000@0x1000000
+.Ed
+.Pp
+would add 32M of memory right after the first 16M.
+The other useful command would be to withdraw a range
+of memory from OS usage (might be wrongfully reported as
+useful by the BIOS).
+.Bd -unfilled -offset indent
+machine mem -0x100000@0xf00000
+.Ed
+.Pp
+which effectively excludes 15-16M range from the map of useful memory.
+.It Nm regs
+Prints contents of processor registers if compiled with
+.Em DEBUG .
+.El
+.It ls Op Ar directory
+Prints contents of the specified
+.Ar directory
+in long format including: attributes and file type, owner, group,
+size, filename.
+.It reboot
+Reboots the machine by initiating a warm boot procedure.
+.It set Op Ar varname Op Ar value
+If invoked without arguments, prints a list of variables and their values.
+If only
+.Ar varname
+is specified, displays contents of that variable.
+If
+.Ar varname
+and
+.Ar value
+are both specified, sets that variable to the given value.
+Variables include:
+.Pp
+.Bl -tag -compact -width boothow
+.It Nm addr
+Address at which to load the kernel.
+.It Nm debug
+Debug flag if
+.Nm
+was compiled with DEBUG defined.
+.It Nm device
+Boot device name (e.g.,
+.Li fd0a ,
+.Li hd0a ) .
+.It Nm howto
+Options to pass to the loaded kernel.
+.It Nm image
+File name containing the kernel image.
+.It Nm timeout
+Number of seconds boot will wait for human intervention before
+booting the default kernel image.
+.It Nm tty
+Active console device name (e.g.,
+.Li com0 ,
+.Li com1 ,
+.Li pc0 ) .
+Currently, only the first serial port
+.Pq Li com0
+is supported for console on i386.
+.El
+.It stty Op Ar device Op Ar speed
+Displays or sets the
+.Ar speed
+for a console
+.Ar device .
+If changing the baudrate for the currently active console,
+.Nm
+offers you five seconds of grace time before committing the change
+to allow you to change your terminal's speed to match.
+If changing speed
+.Em not
+for the active console, the baudrate is set for the
+.Em next
+time you switch to a serial console.
+The baudrate value is not used for the
+.Li pc0
+console.
+.Pp
+The default baudrate is 9600bps.
+.It time
+Displays system time and date.
+.El
+.Sh FILES
+.Bl -tag -width /usr/mdec/biosbootxx -compact
+.It Pa /usr/mdec/biosboot
+first stage bootstrap
+.It Pa /boot
+system bootstrap
+.It Pa /etc/boot.conf
+system bootstrap's startup file
+.It Pa /bsd
+kernel image
+.El
+.Sh EXAMPLES
+Boot the default kernel:
+.Pp
+.Dl boot> boot
+.Pp
+Remove the 5 second pause at boot-time permanently, causing
+.Nm
+to load the kernel immediately without prompting:
+.Pp
+.Dl # echo \&"boot\&" > /etc/boot.conf
+.Pp
+Use serial console.
+A null modem cable should connect the specified serial port to a terminal.
+Useful for debugging.
+.Pp
+.Dl boot> set tty com0
+.Pp
+Invoke the serial console at every boot:
+.Pp
+.Dl # echo \&"set tty com0\&" > /etc/boot.conf
+.Pp
+Boot the kernel named
+.Pa /bsd
+from the second hard disk in
+.Dq User Kernel Configuration
+mode (see
+.Xr boot_config 8 ) .
+This mechanism allows for the explicit enabling and disabling of devices
+during the current boot sequence, as well as the modification
+of device parameters.
+Once booted, such changes can be made permanent by using
+.Xr config 8 Ns 's
+.Fl e
+option.
+.Pp
+.Dl boot> boot hd1a:/bsd -c
+.Sh SEE ALSO
+.Xr gzip 1 ,
+.Xr autoconf 4 ,
+.Xr ddb 4 ,
+.Xr biosboot 8 ,
+.Xr boot_config 8 ,
+.Xr boot_i386 8 ,
+.Xr fdisk 8 ,
+.Xr installboot 8 ,
+.Xr reboot 8
+.Pp
+RFC 1950 describes the zlib library interface.
+.Pp
+The official home page for the version of zlib used in this
+operating system is at http://quest.jpl.nasa.gov/zlib/.
+.Sh HISTORY
+This program was written by Michael Shalayeff for
+.Ox 2.1 .
diff --git a/sys/arch/amd64/stand/boot/conf.c b/sys/arch/amd64/stand/boot/conf.c
new file mode 100644
index 00000000000..9464b92e512
--- /dev/null
+++ b/sys/arch/amd64/stand/boot/conf.c
@@ -0,0 +1,77 @@
+/* $OpenBSD: conf.c,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1996 Michael Shalayeff
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 REGENTS 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.
+ *
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <libsa.h>
+#include <lib/libsa/ufs.h>
+#ifdef notdef
+#include <lib/libsa/cd9660.h>
+#include <lib/libsa/fat.h>
+#include <lib/libsa/nfs.h>
+#include <lib/libsa/tftp.h>
+#include <lib/libsa/netif.h>
+#endif
+#include <lib/libsa/unixdev.h>
+#include <biosdev.h>
+#include <dev/cons.h>
+
+const char version[] = "2.05";
+int debug = 1;
+
+
+struct fs_ops file_system[] = {
+ { ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek,
+ ufs_stat, ufs_readdir },
+#ifdef notdef
+ { fat_open, fat_close, fat_read, fat_write, fat_seek,
+ fat_stat, fat_readdir },
+ { nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek,
+ nfs_stat, nfs_readdir },
+ { cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek,
+ cd9660_stat, cd9660_readdir },
+#endif
+};
+int nfsys = NENTS(file_system);
+
+struct devsw devsw[] = {
+ { "BIOS", biosstrategy, biosopen, biosclose, biosioctl },
+#if 0
+ { "TFTP", tftpstrategy, tftpopen, tftpclose, tftpioctl },
+#endif
+};
+int ndevs = NENTS(devsw);
+
+struct consdev constab[] = {
+ { pc_probe, pc_init, pc_getc, pc_putc },
+ { com_probe, com_init, com_getc, com_putc },
+ { NULL }
+};
+struct consdev *cn_tab = constab;
+
diff --git a/sys/arch/amd64/stand/boot/srt0.S b/sys/arch/amd64/stand/boot/srt0.S
new file mode 100644
index 00000000000..ccd3eff0ed2
--- /dev/null
+++ b/sys/arch/amd64/stand/boot/srt0.S
@@ -0,0 +1,92 @@
+/* $OpenBSD: srt0.S,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1997 Michael Shalayeff
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 REGENTS 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.
+ *
+ */
+#include <machine/asm.h>
+#include <assym.h>
+
+#define BOOTSTACK 0xfffc
+
+ .globl _C_LABEL(end)
+ .globl _C_LABEL(edata)
+ .globl _C_LABEL(boot)
+ .globl _C_LABEL(_rtt)
+ .globl _C_LABEL(bios_bootdev)
+ .globl _ASM_LABEL(pmm_init)
+ .globl Gdtr
+
+ .text
+ .code16
+ .globl _start
+_start:
+ popl %eax
+ cmpl $BOOTMAGIC, %eax
+ je 1f
+#ifdef DEBUG
+ movl $0xb80a0, %ebx
+ addr32 movl $0x07420742, (%ebx)
+#endif
+1:
+ popl %edx
+ cli
+ pushl %cs
+ popl %ds
+ addr32 data32 lgdt (Gdtr - LINKADDR)
+ movl %cr0, %eax
+ orl $CR0_PE, %eax
+ data32 movl %eax, %cr0
+ data32 ljmp $8, $1f
+1:
+ .code32
+ movl $0x10,%eax
+ mov %ax,%ds
+ mov %ax,%ss
+ mov %ax,%es
+ mov %ax,%fs
+ mov %ax,%gs
+ movl $BOOTSTACK,%esp
+ pushl %edx
+ movl %edx, _C_LABEL(bios_bootdev)
+
+ /* Now do it all */
+ call _ASM_LABEL(pmm_init)
+#ifdef DEBUG
+ movl $0xb80a4, %ebx
+ movl $0x07520752, (%ebx)
+#endif
+ /* zero .bss */
+ xorl %eax, %eax
+ movl $_C_LABEL(end), %ecx
+ subl $_C_LABEL(edata),%ecx
+ movl $_C_LABEL(edata), %edi
+ cld
+ rep; stosb
+
+ call _C_LABEL(boot)
+
+ jmp _C_LABEL(_rtt)
+
diff --git a/sys/arch/amd64/stand/etc/Makefile b/sys/arch/amd64/stand/etc/Makefile
new file mode 100644
index 00000000000..37aebe4337e
--- /dev/null
+++ b/sys/arch/amd64/stand/etc/Makefile
@@ -0,0 +1,20 @@
+# $OpenBSD: Makefile,v 1.1 2004/02/03 12:09:47 mickey Exp $
+
+S= ${.CURDIR}/../../../..
+
+all depend:: assym.h
+
+assym.h: $S/kern/genassym.sh ${.CURDIR}/genassym.cf
+ sh $S/kern/genassym.sh ${CC} ${CFLAGS} ${CPPFLAGS} \
+ ${PARAM} < ${.CURDIR}/genassym.cf > assym.h.tmp && \
+ mv -f assym.h.tmp assym.h
+
+cleandir: clean
+
+clean:
+ @rm -f isa.h apm.h assym.h machine
+
+.include <bsd.obj.mk>
+.include <bsd.subdir.mk>
+.include "../Makefile.inc"
+CFLAGS+=${SACFLAGS}
diff --git a/sys/arch/amd64/stand/etc/genassym.cf b/sys/arch/amd64/stand/etc/genassym.cf
new file mode 100644
index 00000000000..f4fb63490bf
--- /dev/null
+++ b/sys/arch/amd64/stand/etc/genassym.cf
@@ -0,0 +1,30 @@
+# $OpenBSD: genassym.cf,v 1.1 2004/02/03 12:09:47 mickey Exp $
+
+include <sys/param.h>
+
+include <machine/specialreg.h>
+include <machine/segments.h>
+include <machine/biosvar.h>
+include <machine/disklabel.h>
+
+export DOSPARTOFF
+export DOSACTIVE
+export DOSPTYP_OPENBSD
+export NDOSPART
+export DOSMBR_SIGNATURE
+export DEV_BSIZE
+export CR0_PE
+export SDT_MEMERAC
+export SDT_MEMERA
+export SDT_MEMRWA
+export SDT_SYS386TGT
+struct BIOS_regs
+member biosr_ax
+member biosr_cx
+member biosr_dx
+member biosr_bx
+member biosr_bp
+member biosr_si
+member biosr_di
+member biosr_ds
+member biosr_es
diff --git a/sys/arch/amd64/stand/installboot/Makefile b/sys/arch/amd64/stand/installboot/Makefile
new file mode 100644
index 00000000000..400dd87b217
--- /dev/null
+++ b/sys/arch/amd64/stand/installboot/Makefile
@@ -0,0 +1,19 @@
+# $OpenBSD: Makefile,v 1.1 2004/02/03 12:09:47 mickey Exp $
+
+MAN= installboot.8
+
+.if ${MACHINE} == "amd64"
+PROG= installboot
+CPPFLAGFS+=-I${.CURDIR}
+
+LDADD= -lutil
+DPADD= ${LIBUTIL}
+# Need this to work in the miniroot
+LDSTATIC= -static
+
+SADIR= ${.CURDIR}/..
+.else
+NOPROG=
+.endif
+
+.include <bsd.prog.mk>
diff --git a/sys/arch/amd64/stand/installboot/installboot.8 b/sys/arch/amd64/stand/installboot/installboot.8
new file mode 100644
index 00000000000..fc1836b2ac7
--- /dev/null
+++ b/sys/arch/amd64/stand/installboot/installboot.8
@@ -0,0 +1,135 @@
+.\" $OpenBSD: installboot.8,v 1.1 2004/02/03 12:09:47 mickey Exp $
+.\"
+.\" Copyright (c) 1997 Michael Shalayeff
+.\" All rights reserved.
+.\"
+.\" 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 AUTHOR ``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 REGENTS 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.
+.\"
+.\"
+.Dd December 23, 2003
+.Dt INSTALLBOOT 8 i386
+.Os
+.Sh NAME
+.Nm installboot
+.Nd installs a bootstrap on an FFS disk or partition
+.Sh SYNOPSIS
+.Nm installboot
+.Op Fl nv
+.Ar boot
+.Ar biosboot
+.Ar disk
+.Sh DESCRIPTION
+.Nm
+is used to install a
+.Dq first-stage
+boot program into the boot area of an FFS disk partition.
+It inserts the block number and offset of the inode of
+the second-stage boot program
+.Xr boot 8
+so that the
+.Xr biosboot 8
+program can load it.
+Various filesystem parameters are also patched into the boot block.
+.Pp
+The options are as follows:
+.Bl -tag -width flag_opt
+.It Fl n
+Do not actually write anything on the disk.
+.It Fl v
+Be verbose, printing out the data that are stored in
+.Ar biosboot
+along with lots of other information.
+.El
+.Pp
+The arguments are:
+.Bl -tag -width biosboot
+.It Ar boot
+The name of the second-stage boot program in the mounted file system
+where the first-stage boot program is to be installed.
+This should be a full pathname.
+.It Ar biosboot
+The name of the prototype file for the first stage boot program,
+usually
+.Pa /usr/mdec/biosboot .
+.It Ar disk
+The name of the disk containing the partition in which the second-stage
+boot program resides and the first-stage boot program is to be installed.
+This can either be specified in short form (e.g.,
+.Sq sd0
+or
+.Sq wd0 ) ,
+or as the explicit device node, such as
+.Pa /dev/rsd0c
+or
+.Pa /dev/rwd0c .
+.Pp
+Note that you must be in single-user mode or have your kernel in
+insecure mode (see the
+.Xr sysctl 8
+.Va kern.securelevel
+variable or
+.Pa /etc/rc.securelevel )
+to enable access to the raw partition of a mounted disk.
+.Pp
+The
+.Sq c
+partition is always used to represent the
+.Dq entire
+disk on i386.
+.El
+.Sh EXAMPLES
+The typical use is
+.Bd -literal -offset indent
+# cp /usr/mdec/boot /boot
+# /usr/mdec/installboot -n -v /boot /usr/mdec/biosboot sd0
+.Ed
+.Pp
+And if the information supplied looks right, run the above without the
+.Fl n
+flag.
+If you are upgrading an old system, you may need to perform
+some additional steps first.
+For example:
+.Bd -literal -offset indent
+boot the floppy.fs filesystem floppy
+# fsck /dev/rsd0a
+# mount /dev/sd0a /mnt
+# cp /usr/mdec/boot /mnt/boot
+# /usr/mdec/installboot -v /mnt/boot /usr/mdec/biosboot sd0
+.Ed
+.Sh SEE ALSO
+.Xr biosboot 8 ,
+.Xr boot 8 ,
+.Xr disklabel 8 ,
+.Xr fdisk 8 ,
+.Xr init 8
+.Sh CAVEATS
+The disklabel
+.Va d_type
+field must be set to a value other than
+.Dq unknown .
+.Pp
+.Pa /boot
+must be on the drive/partition specified by
+.Pa disk ;
+you cannot perform cross-device
+.Nm Ns s .
diff --git a/sys/arch/amd64/stand/installboot/installboot.c b/sys/arch/amd64/stand/installboot/installboot.c
new file mode 100644
index 00000000000..f834d769143
--- /dev/null
+++ b/sys/arch/amd64/stand/installboot/installboot.c
@@ -0,0 +1,535 @@
+/* $OpenBSD: installboot.c,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+/* $NetBSD: installboot.c,v 1.5 1995/11/17 23:23:50 gwr Exp $ */
+
+/*
+ * Copyright (c) 2003 Tom Cosgrove <tom.cosgrove@arches-consulting.com>
+ * Copyright (c) 1997 Michael Shalayeff
+ * Copyright (c) 1994 Paul Kranenburg
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#define ELFSIZE 32
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/disklabel.h>
+#include <sys/dkio.h>
+#include <sys/ioctl.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ufs/dir.h>
+#include <ufs/ffs/fs.h>
+#include <sys/reboot.h>
+
+#include <uvm/uvm_extern.h>
+#include <sys/sysctl.h>
+
+#include <machine/cpu.h>
+#include <machine/biosvar.h>
+
+#include <err.h>
+#include <a.out.h>
+#include <sys/exec_elf.h>
+#include <fcntl.h>
+#include <nlist.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+
+#include "nlist.c"
+
+struct sym_data {
+ char *sym_name; /* Must be initialised */
+ int sym_size; /* And this one */
+ int sym_set; /* Rest set at runtime */
+ u_int32_t sym_value;
+};
+
+extern char *__progname;
+int verbose, nowrite = 0;
+char *boot, *proto, *dev, *realdev;
+struct sym_data pbr_symbols[] = {
+ {"_fs_bsize_p", 2},
+ {"_fs_bsize_s", 2},
+ {"_fsbtodb", 1},
+ {"_p_offset", 4},
+ {"_inodeblk", 4},
+ {"_inodedbl", 4},
+ {"_nblocks", 2},
+ {NULL}
+};
+
+#define INODESEG 0x07e0 /* where we will put /boot's inode's block */
+#define BOOTSEG 0x07c0 /* biosboot loaded here */
+
+#define INODEOFF ((INODESEG-BOOTSEG) << 4)
+
+static char *loadproto(char *, long *);
+static int getbootparams(char *, int, struct disklabel *);
+static void devread(int, void *, daddr_t, size_t, char *);
+static void sym_set_value(struct sym_data *, char *, u_int32_t);
+static void pbr_set_symbols(char *, char *, struct sym_data *);
+static void usage(void);
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-nv] boot biosboot device\n", __progname);
+ exit(1);
+}
+
+/*
+ * Read information about /boot's inode and filesystem parameters, then
+ * put biosboot (partition boot record) on the target drive with these
+ * parameters patched in.
+ */
+int
+main(int argc, char *argv[])
+{
+ int c;
+ int devfd;
+ char *protostore;
+ long protosize;
+ struct stat sb;
+ struct disklabel dl;
+ struct dos_mbr mbr;
+ struct dos_partition *dp;
+ off_t startoff = 0;
+
+ while ((c = getopt(argc, argv, "vn")) != -1) {
+ switch (c) {
+ case 'n':
+ /* Do not actually write the bootblock to disk. */
+ nowrite = 1;
+ break;
+ case 'v':
+ /* Give more information. */
+ verbose = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (argc - optind < 3)
+ usage();
+
+ boot = argv[optind];
+ proto = argv[optind + 1];
+ realdev = dev = argv[optind + 2];
+
+ /* Open and check raw disk device. */
+ if ((devfd = opendev(dev, (nowrite? O_RDONLY:O_RDWR),
+ OPENDEV_PART, &realdev)) < 0)
+ err(1, "open: %s", realdev);
+
+ if (verbose) {
+ fprintf(stderr, "boot: %s\n", boot);
+ fprintf(stderr, "proto: %s\n", proto);
+ fprintf(stderr, "device: %s\n", realdev);
+ }
+
+ if (ioctl(devfd, DIOCGDINFO, &dl) != 0)
+ err(1, "disklabel: %s", realdev);
+
+ /* Check disklabel. */
+ if (dl.d_magic != DISKMAGIC)
+ err(1, "bad disklabel magic=%0x8x", dl.d_magic);
+
+ /* Warn on unknown disklabel types. */
+ if (dl.d_type == 0)
+ warnx("disklabel type unknown");
+
+ /* Load proto blocks into core. */
+ if ((protostore = loadproto(proto, &protosize)) == NULL)
+ exit(1);
+
+ /* XXX - Paranoia: Make sure size is aligned! */
+ if (protosize & (DEV_BSIZE - 1))
+ err(1, "proto %s bad size=%ld", proto, protosize);
+
+ /* Write patched proto bootblock(s) into the superblock. */
+ if (protosize > SBSIZE - DEV_BSIZE)
+ errx(1, "proto bootblocks too big");
+
+ if (fstat(devfd, &sb) < 0)
+ err(1, "stat: %s", realdev);
+
+ if (!S_ISCHR(sb.st_mode))
+ errx(1, "%s: not a character device", realdev);
+
+ /* Get bootstrap parameters that are to be patched into proto. */
+ if (getbootparams(boot, devfd, &dl) != 0)
+ exit(1);
+
+ /* Patch the parameters into the proto bootstrap sector. */
+ pbr_set_symbols(proto, protostore, pbr_symbols);
+
+ if (!nowrite) {
+ /* Sync filesystems (to clean in-memory superblock?). */
+ sync(); sleep(1);
+ }
+
+ if (dl.d_type != 0 && dl.d_type != DTYPE_FLOPPY &&
+ dl.d_type != DTYPE_VND) {
+ if (lseek(devfd, (off_t)DOSBBSECTOR, SEEK_SET) < 0 ||
+ read(devfd, &mbr, sizeof(mbr)) < sizeof(mbr))
+ err(4, "can't read master boot record");
+
+ if (mbr.dmbr_sign != DOSMBR_SIGNATURE)
+ errx(1, "broken MBR");
+
+ /* Find OpenBSD partition. */
+ for (dp = mbr.dmbr_parts; dp < &mbr.dmbr_parts[NDOSPART];
+ dp++) {
+ if (dp->dp_size && dp->dp_typ == DOSPTYP_OPENBSD) {
+ startoff = (off_t)dp->dp_start * dl.d_secsize;
+ fprintf(stderr, "using MBR partition %ld: "
+ "type %d (0x%02x) offset %d (0x%x)\n",
+ (long)(dp - mbr.dmbr_parts),
+ dp->dp_typ, dp->dp_typ,
+ dp->dp_start, dp->dp_start);
+ break;
+ }
+ }
+ /* Don't check for old part number, that is ;-p */
+ if (dp >= &mbr.dmbr_parts[NDOSPART])
+ errx(1, "no OpenBSD partition");
+ }
+
+ if (!nowrite) {
+ if (lseek(devfd, startoff, SEEK_SET) < 0 ||
+ write(devfd, protostore, protosize) != protosize)
+ err(1, "write bootstrap");
+ }
+
+ (void)close(devfd);
+
+ return 0;
+}
+
+/*
+ * Load the prototype boot sector (biosboot) into memory.
+ */
+static char *
+loadproto(char *fname, long *size)
+{
+ int fd;
+ size_t tdsize; /* text+data size */
+ char *bp;
+ Elf_Ehdr eh;
+ Elf_Word phsize;
+ Elf_Phdr *ph;
+
+ if ((fd = open(fname, O_RDONLY)) < 0)
+ err(1, "%s", fname);
+
+ if (read(fd, &eh, sizeof(eh)) != sizeof(eh))
+ errx(1, "%s: read failed", fname);
+
+ if (!IS_ELF(eh))
+ errx(1, "%s: bad magic: 0x%02x%02x%02x%02x",
+ boot,
+ eh.e_ident[EI_MAG0], eh.e_ident[EI_MAG1],
+ eh.e_ident[EI_MAG2], eh.e_ident[EI_MAG3]);
+
+ /*
+ * We have to include the exec header in the beginning of
+ * the buffer, and leave extra space at the end in case
+ * the actual write to disk wants to skip the header.
+ */
+
+ /* Program load header. */
+ if (eh.e_phnum != 1)
+ errx(1, "%s: %u ELF load sections (only support 1)",
+ boot, eh.e_phnum);
+
+ phsize = eh.e_phnum * sizeof(Elf_Phdr);
+ ph = malloc(phsize);
+ if (ph == NULL)
+ err(1, NULL);
+
+ lseek(fd, eh.e_phoff, SEEK_SET);
+
+ if (read(fd, ph, phsize) != phsize)
+ errx(1, "%s: can't read header", boot);
+
+ tdsize = ph->p_filesz;
+
+ /*
+ * Allocate extra space here because the caller may copy
+ * the boot block starting at the end of the exec header.
+ * This prevents reading beyond the end of the buffer.
+ */
+ if ((bp = calloc(tdsize, 1)) == NULL) {
+ err(1, NULL);
+ }
+
+ /* Read the rest of the file. */
+ lseek(fd, ph->p_offset, SEEK_SET);
+ if (read(fd, bp, tdsize) != tdsize) {
+ errx(1, "%s: read failed", fname);
+ }
+
+ *size = tdsize; /* not aligned to DEV_BSIZE */
+
+ if (verbose) {
+ fprintf(stderr, "%s: entry point %#x\n", fname, eh.e_entry);
+ fprintf(stderr, "proto bootblock size %ld\n", *size);
+ }
+
+ close(fd);
+ return bp;
+}
+
+static void
+devread(int fd, void *buf, daddr_t blk, size_t size, char *msg)
+{
+ if (lseek(fd, dbtob((off_t)blk), SEEK_SET) != dbtob((off_t)blk))
+ err(1, "%s: devread: lseek", msg);
+
+ if (read(fd, buf, size) != size)
+ err(1, "%s: devread: read", msg);
+}
+
+static char sblock[SBSIZE];
+
+/*
+ * Read information about /boot's inode, then put this and filesystem
+ * parameters from the superblock into pbr_symbols.
+ */
+static int
+getbootparams(char *boot, int devfd, struct disklabel *dl)
+{
+ int fd;
+ struct stat statbuf, sb;
+ struct statfs statfsbuf;
+ struct partition *pl;
+ struct fs *fs;
+ char *buf;
+ daddr_t blk, *ap;
+ struct ufs1_dinode *ip;
+ int ndb;
+ int mib[4];
+ size_t size;
+ dev_t dev;
+
+ /*
+ * Open 2nd-level boot program and record enough details about
+ * where it is on the filesystem represented by `devfd'
+ * (inode block, offset within that block, and various filesystem
+ * parameters essentially taken from the superblock) for biosboot
+ * to be able to load it later.
+ */
+
+ /* Make sure the (probably new) boot file is on disk. */
+ sync(); sleep(1);
+
+ if ((fd = open(boot, O_RDONLY)) < 0)
+ err(1, "open: %s", boot);
+
+ if (fstatfs(fd, &statfsbuf) != 0)
+ err(1, "statfs: %s", boot);
+
+ if (strncmp(statfsbuf.f_fstypename, "ffs", MFSNAMELEN) &&
+ strncmp(statfsbuf.f_fstypename, "ufs", MFSNAMELEN) )
+ errx(1, "%s: not on an FFS filesystem", boot);
+
+#if 0
+ if (read(fd, &eh, sizeof(eh)) != sizeof(eh))
+ errx(1, "read: %s", boot);
+
+ if (!IS_ELF(eh)) {
+ errx(1, "%s: bad magic: 0x%02x%02x%02x%02x",
+ boot,
+ eh.e_ident[EI_MAG0], eh.e_ident[EI_MAG1],
+ eh.e_ident[EI_MAG2], eh.e_ident[EI_MAG3]);
+ }
+#endif
+
+ if (fsync(fd) != 0)
+ err(1, "fsync: %s", boot);
+
+ if (fstat(fd, &statbuf) != 0)
+ err(1, "fstat: %s", boot);
+
+ if (fstat(devfd, &sb) != 0)
+ err(1, "fstat: %s", realdev);
+
+ /* Check devices. */
+ mib[0] = CTL_MACHDEP;
+ mib[1] = CPU_CHR2BLK;
+ mib[2] = sb.st_rdev;
+ size = sizeof(dev);
+ if (sysctl(mib, 3, &dev, &size, NULL, 0) >= 0) {
+ if (statbuf.st_dev / MAXPARTITIONS != dev / MAXPARTITIONS)
+ errx(1, "cross-device install");
+ }
+
+ pl = &dl->d_partitions[DISKPART(statbuf.st_dev)];
+ close(fd);
+
+ /* Read superblock. */
+ devread(devfd, sblock, pl->p_offset + SBLOCK, SBSIZE, "superblock");
+ fs = (struct fs *)sblock;
+
+ /* Sanity-check super-block. */
+ if (fs->fs_magic != FS_MAGIC)
+ errx(1, "Bad magic number in superblock");
+ if (fs->fs_inopb <= 0)
+ err(1, "Bad inopb=%d in superblock", fs->fs_inopb);
+
+ /* Read inode. */
+ if ((buf = malloc(fs->fs_bsize)) == NULL)
+ err(1, NULL);
+
+ blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino));
+
+ devread(devfd, buf, pl->p_offset + blk, fs->fs_bsize, "inode");
+ ip = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs, statbuf.st_ino);
+
+ /*
+ * Have the inode. Figure out how many filesystem blocks (not disk
+ * sectors) there are for biosboot to load.
+ */
+ ndb = howmany(ip->di_size, fs->fs_bsize);
+ if (ndb <= 0)
+ errx(1, "No blocks to load");
+ if (verbose)
+ fprintf(stderr, "%s is %d blocks x %d bytes\n",
+ boot, ndb, fs->fs_bsize);
+
+ /*
+ * Now set the values that will need to go into biosboot
+ * (the partition boot record, a.k.a. the PBR).
+ */
+ sym_set_value(pbr_symbols, "_fs_bsize_p", (fs->fs_bsize / 16));
+ sym_set_value(pbr_symbols, "_fs_bsize_s", (fs->fs_bsize / 512));
+ sym_set_value(pbr_symbols, "_fsbtodb", fs->fs_fsbtodb);
+ sym_set_value(pbr_symbols, "_p_offset", pl->p_offset);
+ sym_set_value(pbr_symbols, "_inodeblk",
+ ino_to_fsba(fs, statbuf.st_ino));
+ ap = ip->di_db;
+ sym_set_value(pbr_symbols, "_inodedbl",
+ ((((char *)ap) - buf) + INODEOFF));
+ sym_set_value(pbr_symbols, "_nblocks", ndb);
+
+ return 0;
+}
+
+static void
+sym_set_value(struct sym_data *sym_list, char *sym, u_int32_t value)
+{
+ struct sym_data *p;
+
+ for (p = sym_list; p->sym_name != NULL; p++) {
+ if (strcmp(p->sym_name, sym) == 0)
+ break;
+ }
+
+ if (p->sym_name == NULL)
+ errx(1, "%s: no such symbol", sym);
+
+ if (p->sym_set)
+ errx(1, "%s already set", p->sym_name);
+
+ p->sym_value = value;
+ p->sym_set = 1;
+}
+
+/*
+ * Write the parameters stored in sym_list into the in-memory copy of
+ * the prototype biosboot (proto), ready for it to be written to disk.
+ */
+static void
+pbr_set_symbols(char *fname, char *proto, struct sym_data *sym_list)
+{
+ struct sym_data *sym;
+ struct nlist *nl;
+ char *vp;
+ u_int32_t *lp;
+ u_int16_t *wp;
+ u_int8_t *bp;
+
+ for (sym = sym_list; sym->sym_name != NULL; sym++) {
+ if (!sym->sym_set)
+ errx(1, "%s not set", sym->sym_name);
+
+ /* Allocate space for 2; second is null-terminator for list. */
+ nl = calloc(2, sizeof(struct nlist));
+ if (nl == NULL)
+ err(1, NULL);
+
+ nl->n_un.n_name = sym->sym_name;
+
+ if (nlist(fname, nl) != 0)
+ errx(1, "%s: symbol %s not found",
+ fname, sym->sym_name);
+
+ if (nl->n_type != (N_TEXT))
+ errx(1, "%s: %s: wrong type (%x)",
+ fname, sym->sym_name, nl->n_type);
+
+ /* Get a pointer to where the symbol's value needs to go. */
+ vp = proto + nl->n_value;
+
+ switch (sym->sym_size) {
+ case 4: /* u_int32_t */
+ lp = (u_int32_t *) vp;
+ *lp = sym->sym_value;
+ break;
+ case 2: /* u_int16_t */
+ if (sym->sym_value >= 0x10000) /* out of range */
+ errx(1, "%s: symbol out of range (%u)",
+ sym->sym_name, sym->sym_value);
+ wp = (u_int16_t *) vp;
+ *wp = (u_int16_t) sym->sym_value;
+ break;
+ case 1: /* u_int16_t */
+ if (sym->sym_value >= 0x100) /* out of range */
+ errx(1, "%s: symbol out of range (%u)",
+ sym->sym_name, sym->sym_value);
+ bp = (u_int8_t *) vp;
+ *bp = (u_int8_t) sym->sym_value;
+ break;
+ default:
+ errx(1, "%s: bad symbol size %d",
+ sym->sym_name, sym->sym_size);
+ /* NOTREACHED */
+ }
+
+ free(nl);
+
+ if (verbose)
+ fprintf(stderr, "%s = %u\n",
+ sym->sym_name, sym->sym_value);
+ }
+}
diff --git a/sys/arch/amd64/stand/installboot/nlist.c b/sys/arch/amd64/stand/installboot/nlist.c
new file mode 100644
index 00000000000..477c6c0f738
--- /dev/null
+++ b/sys/arch/amd64/stand/installboot/nlist.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: nlist.c,v 1.1 2004/02/03 12:09:47 mickey Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <a.out.h> /* pulls in nlist.h */
+
+#ifdef _NLIST_DO_ELF
+#include <elf_abi.h>
+#include <olf_abi.h>
+#endif
+
+#ifdef _NLIST_DO_ECOFF
+#include <sys/exec_ecoff.h>
+#endif
+
+int __fdnlist(int, struct nlist *);
+int __aout_fdnlist(int, struct nlist *);
+int __ecoff_fdnlist(int, struct nlist *);
+int __elf_fdnlist(int, struct nlist *);
+#ifdef _NLIST_DO_ELF
+int __elf_is_okay__(register Elf_Ehdr *ehdr);
+#endif
+
+#define ISLAST(p) (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
+
+#ifdef _NLIST_DO_AOUT
+int
+__aout_fdnlist(fd, list)
+ register int fd;
+ register struct nlist *list;
+{
+ register struct nlist *p, *s;
+ register char *strtab;
+ register off_t symoff, stroff;
+ register u_long symsize;
+ register int nent, cc;
+ int strsize, usemalloc = 0;
+ struct nlist nbuf[1024];
+ struct exec exec;
+
+ if (pread(fd, &exec, sizeof(exec), (off_t)0) != sizeof(exec) ||
+ N_BADMAG(exec) || exec.a_syms == NULL)
+ return (-1);
+
+ stroff = N_STROFF(exec);
+ symoff = N_SYMOFF(exec);
+ symsize = exec.a_syms;
+
+ /* Read in the size of the string table. */
+ if (pread(fd, (void *)&strsize, sizeof(strsize), stroff) !=
+ sizeof(strsize))
+ return (-1);
+ else
+ stroff += sizeof(strsize);
+
+ /*
+ * Read in the string table. We try mmap, but that will fail
+ * for /dev/ksyms so fall back on malloc. Since OpenBSD's malloc(3)
+ * returns memory to the system on free this does not cause bloat.
+ */
+ strsize -= sizeof(strsize);
+ strtab = mmap(NULL, (size_t)strsize, PROT_READ, MAP_SHARED|MAP_FILE,
+ fd, stroff);
+ if (strtab == MAP_FAILED) {
+ usemalloc = 1;
+ if ((strtab = (char *)malloc(strsize)) == NULL)
+ return (-1);
+ errno = EIO;
+ if (pread(fd, strtab, strsize, stroff) != strsize) {
+ nent = -1;
+ goto aout_done;
+ }
+ }
+
+ /*
+ * clean out any left-over information for all valid entries.
+ * Type and value defined to be 0 if not found; historical
+ * versions cleared other and desc as well. Also figure out
+ * the largest string length so don't read any more of the
+ * string table than we have to.
+ *
+ * XXX clearing anything other than n_type and n_value violates
+ * the semantics given in the man page.
+ */
+ nent = 0;
+ for (p = list; !ISLAST(p); ++p) {
+ p->n_type = 0;
+ p->n_other = 0;
+ p->n_desc = 0;
+ p->n_value = 0;
+ ++nent;
+ }
+
+ while (symsize > 0) {
+ cc = MIN(symsize, sizeof(nbuf));
+ if (pread(fd, nbuf, cc, symoff) != cc)
+ break;
+ symsize -= cc;
+ symoff += cc;
+ for (s = nbuf; cc > 0; ++s, cc -= sizeof(*s)) {
+ char *sname = strtab + s->n_un.n_strx - sizeof(int);
+
+ if (s->n_un.n_strx == 0 || (s->n_type & N_STAB) != 0)
+ continue;
+ for (p = list; !ISLAST(p); p++) {
+ char *pname = p->n_un.n_name;
+
+ if (*sname != '_' && *pname == '_')
+ pname++;
+ if (!strcmp(sname, pname)) {
+ p->n_value = s->n_value;
+ p->n_type = s->n_type;
+ p->n_desc = s->n_desc;
+ p->n_other = s->n_other;
+ if (--nent <= 0)
+ break;
+ }
+ }
+ }
+ }
+aout_done:
+ if (usemalloc)
+ free(strtab);
+ else
+ munmap(strtab, strsize);
+ return (nent);
+}
+#endif /* _NLIST_DO_AOUT */
+
+#ifdef _NLIST_DO_ECOFF
+#define check(off, size) ((off < 0) || (off + size > mappedsize))
+#define BAD do { rv = -1; goto out; } while (0)
+#define BADUNMAP do { rv = -1; goto unmap; } while (0)
+
+int
+__ecoff_fdnlist(fd, list)
+ register int fd;
+ register struct nlist *list;
+{
+ struct nlist *p;
+ struct ecoff_exechdr *exechdrp;
+ struct ecoff_symhdr *symhdrp;
+ struct ecoff_extsym *esyms;
+ struct stat st;
+ char *mappedfile;
+ size_t mappedsize;
+ u_long symhdroff, extstroff;
+ u_int symhdrsize;
+ int rv, nent;
+ long i, nesyms;
+
+ rv = -3;
+
+ if (fstat(fd, &st) < 0)
+ BAD;
+ if (st.st_size > SIZE_T_MAX) {
+ errno = EFBIG;
+ BAD;
+ }
+ mappedsize = st.st_size;
+ mappedfile = mmap(NULL, mappedsize, PROT_READ, MAP_SHARED|MAP_FILE,
+ fd, 0);
+ if (mappedfile == MAP_FAILED)
+ BAD;
+
+ if (check(0, sizeof *exechdrp))
+ BADUNMAP;
+ exechdrp = (struct ecoff_exechdr *)&mappedfile[0];
+
+ if (ECOFF_BADMAG(exechdrp))
+ BADUNMAP;
+
+ symhdroff = exechdrp->f.f_symptr;
+ symhdrsize = exechdrp->f.f_nsyms;
+
+ if (check(symhdroff, sizeof *symhdrp) ||
+ sizeof *symhdrp != symhdrsize)
+ BADUNMAP;
+ symhdrp = (struct ecoff_symhdr *)&mappedfile[symhdroff];
+
+ nesyms = symhdrp->esymMax;
+ if (check(symhdrp->cbExtOffset, nesyms * sizeof *esyms))
+ BADUNMAP;
+ esyms = (struct ecoff_extsym *)&mappedfile[symhdrp->cbExtOffset];
+ extstroff = symhdrp->cbSsExtOffset;
+
+ /*
+ * clean out any left-over information for all valid entries.
+ * Type and value defined to be 0 if not found; historical
+ * versions cleared other and desc as well.
+ *
+ * XXX clearing anything other than n_type and n_value violates
+ * the semantics given in the man page.
+ */
+ nent = 0;
+ for (p = list; !ISLAST(p); ++p) {
+ p->n_type = 0;
+ p->n_other = 0;
+ p->n_desc = 0;
+ p->n_value = 0;
+ ++nent;
+ }
+
+ for (i = 0; i < nesyms; i++) {
+ for (p = list; !ISLAST(p); p++) {
+ char *nlistname;
+ char *symtabname;
+
+ nlistname = p->n_un.n_name;
+ if (*nlistname == '_')
+ nlistname++;
+ symtabname =
+ &mappedfile[extstroff + esyms[i].es_strindex];
+
+ if (!strcmp(symtabname, nlistname)) {
+ p->n_value = esyms[i].es_value;
+ p->n_type = N_EXT; /* XXX */
+ p->n_desc = 0; /* XXX */
+ p->n_other = 0; /* XXX */
+ if (--nent <= 0)
+ break;
+ }
+ }
+ }
+ rv = nent;
+
+unmap:
+ munmap(mappedfile, mappedsize);
+out:
+ return (rv);
+}
+#endif /* _NLIST_DO_ECOFF */
+
+#ifdef _NLIST_DO_ELF
+/*
+ * __elf_is_okay__ - Determine if ehdr really
+ * is ELF and valid for the target platform.
+ *
+ * WARNING: This is NOT a ELF ABI function and
+ * as such it's use should be restricted.
+ */
+int
+__elf_is_okay__(ehdr)
+ register Elf_Ehdr *ehdr;
+{
+ register int retval = 0;
+ /*
+ * We need to check magic, class size, endianess,
+ * and version before we look at the rest of the
+ * Elf_Ehdr structure. These few elements are
+ * represented in a machine independent fashion.
+ */
+ if ((IS_ELF(*ehdr) || IS_OLF(*ehdr)) &&
+ ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS &&
+ ehdr->e_ident[EI_DATA] == ELF_TARG_DATA &&
+ ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) {
+
+ /* Now check the machine dependant header */
+ if (ehdr->e_machine == ELF_TARG_MACH &&
+ ehdr->e_version == ELF_TARG_VER)
+ retval = 1;
+ }
+
+ return retval;
+}
+
+int
+__elf_fdnlist(fd, list)
+ register int fd;
+ register struct nlist *list;
+{
+ register struct nlist *p;
+ register caddr_t strtab;
+ register Elf_Off symoff = 0, symstroff = 0;
+ register Elf_Word symsize = 0, symstrsize = 0;
+ register Elf_Sword nent, cc, i;
+ Elf_Sym sbuf[1024];
+ Elf_Sym *s;
+ Elf_Ehdr ehdr;
+ Elf_Shdr *shdr = NULL;
+ Elf_Word shdr_size;
+ struct stat st;
+ int usemalloc = 0;
+
+ /* Make sure obj is OK */
+ if (pread(fd, &ehdr, sizeof(Elf_Ehdr), (off_t)0) != sizeof(Elf_Ehdr) ||
+ /* !__elf_is_okay__(&ehdr) || */ fstat(fd, &st) < 0)
+ return (-1);
+
+ /* calculate section header table size */
+ shdr_size = ehdr.e_shentsize * ehdr.e_shnum;
+
+ /* Make sure it's not too big to mmap */
+ if (shdr_size > SIZE_T_MAX) {
+ errno = EFBIG;
+ return (-1);
+ }
+
+ /* mmap section header table */
+ shdr = (Elf_Shdr *)mmap(NULL, (size_t)shdr_size, PROT_READ,
+ MAP_SHARED|MAP_FILE, fd, (off_t) ehdr.e_shoff);
+ if (shdr == MAP_FAILED) {
+ usemalloc = 1;
+ if ((shdr = malloc(shdr_size)) == NULL)
+ return (-1);
+ if (pread(fd, shdr, shdr_size, ehdr.e_shoff) != shdr_size) {
+ free(shdr);
+ return (-1);
+ }
+ }
+
+ /*
+ * Find the symbol table entry and it's corresponding
+ * string table entry. Version 1.1 of the ABI states
+ * that there is only one symbol table but that this
+ * could change in the future.
+ */
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ if (shdr[i].sh_type == SHT_SYMTAB) {
+ symoff = shdr[i].sh_offset;
+ symsize = shdr[i].sh_size;
+ symstroff = shdr[shdr[i].sh_link].sh_offset;
+ symstrsize = shdr[shdr[i].sh_link].sh_size;
+ break;
+ }
+ }
+
+ /* Flush the section header table */
+ if (usemalloc)
+ free(shdr);
+ else
+ munmap((caddr_t)shdr, shdr_size);
+
+ /* Check for files too large to mmap. */
+ /* XXX is this really possible? */
+ if (symstrsize > SIZE_T_MAX) {
+ errno = EFBIG;
+ return (-1);
+ }
+ /*
+ * Map string table into our address space. This gives us
+ * an easy way to randomly access all the strings, without
+ * making the memory allocation permanent as with malloc/free
+ * (i.e., munmap will return it to the system).
+ */
+ if (usemalloc) {
+ if ((strtab = malloc(symstrsize)) == NULL)
+ return (-1);
+ if (pread(fd, strtab, symstrsize, symstroff) != symstrsize) {
+ free(strtab);
+ return (-1);
+ }
+ } else {
+ strtab = mmap(NULL, (size_t)symstrsize, PROT_READ,
+ MAP_SHARED|MAP_FILE, fd, (off_t) symstroff);
+ if (strtab == MAP_FAILED)
+ return (-1);
+ }
+ /*
+ * clean out any left-over information for all valid entries.
+ * Type and value defined to be 0 if not found; historical
+ * versions cleared other and desc as well. Also figure out
+ * the largest string length so don't read any more of the
+ * string table than we have to.
+ *
+ * XXX clearing anything other than n_type and n_value violates
+ * the semantics given in the man page.
+ */
+ nent = 0;
+ for (p = list; !ISLAST(p); ++p) {
+ p->n_type = 0;
+ p->n_other = 0;
+ p->n_desc = 0;
+ p->n_value = 0;
+ ++nent;
+ }
+
+ /* Don't process any further if object is stripped. */
+ /* ELFism - dunno if stripped by looking at header */
+ if (symoff == 0)
+ goto elf_done;
+
+ while (symsize > 0) {
+ cc = MIN(symsize, sizeof(sbuf));
+ if (pread(fd, sbuf, cc, symoff) != cc)
+ break;
+ symsize -= cc;
+ symoff += cc;
+ for (s = sbuf; cc > 0; ++s, cc -= sizeof(*s)) {
+ int soff = s->st_name;
+
+ if (soff == 0)
+ continue;
+ for (p = list; !ISLAST(p); p++) {
+ char *sym;
+
+ /*
+ * First we check for the symbol as it was
+ * provided by the user. If that fails,
+ * skip the first char if it's an '_' and
+ * try again.
+ * XXX - What do we do when the user really
+ * wants '_foo' and the are symbols
+ * for both 'foo' and '_foo' in the
+ * table and 'foo' is first?
+ */
+ sym = p->n_un.n_name;
+ if (strcmp(&strtab[soff], sym) != 0 &&
+ ((sym[0] == '_') &&
+ strcmp(&strtab[soff], sym + 1) != 0))
+ continue;
+
+ p->n_value = s->st_value;
+
+ /* XXX - type conversion */
+ /* is pretty rude. */
+ switch(ELF_ST_TYPE(s->st_info)) {
+ case STT_NOTYPE:
+ switch (s->st_shndx) {
+ case SHN_UNDEF:
+ p->n_type = N_UNDF;
+ break;
+ case SHN_ABS:
+ p->n_type = N_ABS;
+ break;
+ case SHN_COMMON:
+ p->n_type = N_COMM;
+ break;
+ default:
+ p->n_type = N_COMM | N_EXT;
+ break;
+ }
+ break;
+ case STT_OBJECT:
+ p->n_type = N_DATA;
+ break;
+ case STT_FUNC:
+ p->n_type = N_TEXT;
+ break;
+ case STT_FILE:
+ p->n_type = N_FN;
+ break;
+ }
+ if (ELF_ST_BIND(s->st_info) ==
+ STB_LOCAL)
+ p->n_type = N_EXT;
+ p->n_desc = 0;
+ p->n_other = 0;
+ if (--nent <= 0)
+ break;
+ }
+ }
+ }
+elf_done:
+ if (usemalloc)
+ free(strtab);
+ else
+ munmap(strtab, symstrsize);
+ return (nent);
+}
+#endif /* _NLIST_DO_ELF */
+
+
+static struct nlist_handlers {
+ int (*fn)(int fd, struct nlist *list);
+} nlist_fn[] = {
+#ifdef _NLIST_DO_AOUT
+ { __aout_fdnlist },
+#endif
+#ifdef _NLIST_DO_ELF
+ { __elf_fdnlist },
+#endif
+#ifdef _NLIST_DO_ECOFF
+ { __ecoff_fdnlist },
+#endif
+};
+
+int
+__fdnlist(fd, list)
+ register int fd;
+ register struct nlist *list;
+{
+ int n = -1, i;
+
+ for (i = 0; i < sizeof(nlist_fn)/sizeof(nlist_fn[0]); i++) {
+ n = (nlist_fn[i].fn)(fd, list);
+ if (n != -1)
+ break;
+ }
+ return (n);
+}
+
+
+int
+nlist(name, list)
+ const char *name;
+ struct nlist *list;
+{
+ int fd, n;
+
+ fd = open(name, O_RDONLY, 0);
+ if (fd < 0)
+ return (-1);
+ n = __fdnlist(fd, list);
+ (void)close(fd);
+ return (n);
+}
diff --git a/sys/arch/amd64/stand/libsa/alloca.S b/sys/arch/amd64/stand/libsa/alloca.S
new file mode 100644
index 00000000000..d8b4b241575
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/alloca.S
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#include <machine/asm.h>
+
+#if defined(LIBC_SCCS)
+ .text
+ .asciz "$OpenBSD: alloca.S,v 1.1 2004/02/03 12:09:47 mickey Exp $"
+#endif
+
+/* like alloc, but automatic free in return */
+
+ENTRY(alloca)
+ popl %edx /* pop return addr */
+ popl %eax /* pop amount to allocate */
+ movl %esp,%ecx
+ addl $3,%eax /* round up to next word */
+ andl $-4,%eax
+ subl %eax,%esp
+ movl %esp,%eax /* base of newly allocated space */
+ pushl 8(%ecx) /* copy possible saved registers */
+ pushl 4(%ecx)
+ pushl 0(%ecx)
+ pushl %eax /* dummy to pop at callsite */
+ jmp *%edx /* "return" */
diff --git a/sys/arch/amd64/stand/libsa/bioscons.c b/sys/arch/amd64/stand/libsa/bioscons.c
new file mode 100644
index 00000000000..5668b06ba19
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/bioscons.c
@@ -0,0 +1,213 @@
+/* $OpenBSD: bioscons.c,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1997-1999 Michael Shalayeff
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 AUTHOR OR HIS RELATIVES 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 MIND, 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.
+ */
+
+#include <sys/types.h>
+#include <machine/biosvar.h>
+#include <machine/pio.h>
+#include <dev/isa/isareg.h>
+#include <dev/ic/mc146818reg.h>
+#include <dev/ic/comreg.h>
+#include <dev/ic/ns16450reg.h>
+/* #include <i386/isa/nvram.h> */
+#include <dev/cons.h>
+#include <lib/libsa/stand.h>
+#include "biosdev.h"
+
+/* XXX cannot trust NVRAM on this. Maybe later we make a real probe. */
+#if 0
+#define PRESENT_MASK (NVRAM_EQUIPMENT_KBD|NVRAM_EQUIPMENT_DISPLAY)
+#else
+#define PRESENT_MASK 0
+#endif
+
+void
+pc_probe(struct consdev *cn)
+{
+ cn->cn_pri = CN_INTERNAL;
+ cn->cn_dev = makedev(12, 0);
+ printf(" pc%d", minor(cn->cn_dev));
+
+#if 0
+ outb(IO_RTC, NVRAM_EQUIPMENT);
+ if ((inb(IO_RTC+1) & PRESENT_MASK) == PRESENT_MASK) {
+ cn->cn_pri = CN_INTERNAL;
+ /* XXX from i386/conf.c */
+ cn->cn_dev = makedev(12, 0);
+ printf(" pc%d", minor(cn->cn_dev));
+ }
+#endif
+}
+
+void
+pc_init(struct consdev *cn)
+{
+}
+
+int
+pc_getc(dev_t dev)
+{
+ register int rv;
+
+ if (dev & 0x80) {
+ __asm __volatile(DOINT(0x16) "; setnz %b0" : "=a" (rv) :
+ "0" (0x100) : "%ecx", "%edx", "cc" );
+ return (rv & 0xff);
+ }
+
+ __asm __volatile(DOINT(0x16) : "=a" (rv) : "0" (0x000) :
+ "%ecx", "%edx", "cc" );
+ return (rv & 0xff);
+}
+
+void
+pc_putc(dev_t dev, int c)
+{
+ __asm __volatile(DOINT(0x10) : : "a" (c | 0xe00), "b" (1) :
+ "%ecx", "%edx", "cc" );
+}
+
+const int comports[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+
+void
+com_probe(struct consdev *cn)
+{
+ register int i, n;
+
+ /* get equip. (9-11 # of coms) */
+ __asm __volatile(DOINT(0x11) : "=a" (n) : : "%ecx", "%edx", "cc");
+ n >>= 9;
+ n &= 7;
+ for (i = 0; i < n; i++)
+ printf(" com%d", i);
+ if (n) {
+ cn->cn_pri = CN_NORMAL;
+ /* XXX from i386/conf.c */
+ cn->cn_dev = makedev(8, 0);
+ }
+}
+
+void
+com_init(struct consdev *cn)
+{
+ register int unit = minor(cn->cn_dev);
+
+ /* let bios do necessary init first, 9600-N-1 */
+ __asm __volatile(DOINT(0x14) : : "a" (0xe3), "d" (unit) :
+ "%ecx", "cc" );
+}
+
+int
+com_getc(dev_t dev)
+{
+ register int rv;
+
+ if (dev & 0x80) {
+ __asm __volatile(DOINT(0x14) : "=a" (rv) :
+ "0" (0x300), "d" (minor(dev&0x7f)) : "%ecx", "cc" );
+ return ((rv & 0x100) == 0x100);
+ }
+
+ do
+ __asm __volatile(DOINT(0x14) : "=a" (rv) :
+ "0" (0x200), "d" (minor(dev)) : "%ecx", "cc" );
+ while (rv & 0x8000);
+
+ return (rv & 0xff);
+}
+
+/* call with sp == 0 to query the current speed */
+int com_speed = 9600; /* default speed is 9600 baud */
+int
+comspeed(dev_t dev, int sp)
+{
+ int i, newsp;
+ int err;
+
+ if (sp <= 0)
+ return com_speed;
+ /* valid baud rate? */
+ if (115200 < sp || sp < 75)
+ return -1;
+
+ /*
+ * Accepted speeds:
+ * 75 150 300 600 1200 2400 4800 9600 19200 38400 76800 and
+ * 14400 28800 57600 115200
+ */
+ for (i = sp; i != 75 && i != 14400; i >>= 1)
+ if (i & 1)
+ return -1;
+
+/* ripped screaming from dev/ic/com.c */
+#define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
+ newsp = divrnd((COM_FREQ / 16), sp);
+ if (newsp <= 0)
+ return -1;
+ err = divrnd((COM_FREQ / 16) * 1000, sp * newsp) - 1000;
+ if (err < 0)
+ err = -err;
+ if (err > COM_TOLERANCE)
+ return -1;
+#undef divrnd
+
+ if (cn_tab && cn_tab->cn_dev == dev && com_speed != sp) {
+ printf("com%d: changing speed to %d baud in 5 seconds, "
+ "change your terminal to match!\n\a",
+ minor(dev), sp);
+ sleep(5);
+ }
+
+ outb(comports[minor(dev)] + com_cfcr, LCR_DLAB);
+ outb(comports[minor(dev)] + com_dlbl, newsp);
+ outb(comports[minor(dev)] + com_dlbh, newsp>>8);
+ outb(comports[minor(dev)] + com_cfcr, LCR_8BITS);
+ printf("\ncom%d: %d baud\n", minor(dev), sp);
+
+ newsp = com_speed;
+ com_speed = sp;
+ return newsp;
+}
+
+void
+com_putc(dev_t dev, int c)
+{
+ register int rv;
+
+ dev = minor(dev) & 0x7f;
+
+ /* check online (DSR) */
+ __asm __volatile(DOINT(0x14) : "=a" (rv) :
+ "0" (0x300), "d" (dev) : "%ecx", "cc" );
+ if ( !(rv & 0x20) )
+ return;
+
+ /* send character */
+ __asm __volatile(DOINT(0x14) : "=a" (rv) :
+ "0" (c | 0x100), "d" (dev) : "%ecx", "cc" );
+}
+
diff --git a/sys/arch/amd64/stand/libsa/biosdev.c b/sys/arch/amd64/stand/libsa/biosdev.c
new file mode 100644
index 00000000000..f0c86450879
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/biosdev.c
@@ -0,0 +1,610 @@
+/* $OpenBSD: biosdev.c,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1996 Michael Shalayeff
+ * Copyright (c) 2003 Tobias Weingartner
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 REGENTS 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.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <sys/disklabel.h>
+#include <machine/tss.h>
+#include <machine/biosvar.h>
+#include <lib/libsa/saerrno.h>
+#include "disk.h"
+#include "libsa.h"
+#include "biosdev.h"
+
+static const char *biosdisk_err(u_int);
+static int biosdisk_errno(u_int);
+
+static int CHS_rw (int, int, int, int, int, int, void *);
+static int EDD_rw (int, int, u_int64_t, u_int32_t, void *);
+
+extern int debug;
+int bios_bootdev;
+
+#if 0
+struct biosdisk {
+ bios_diskinfo_t *bios_info;
+ dev_t bsddev;
+ struct disklabel disklabel;
+};
+#endif
+
+struct EDD_CB {
+ u_int8_t edd_len; /* size of packet */
+ u_int8_t edd_res1; /* reserved */
+ u_int8_t edd_nblk; /* # of blocks to transfer */
+ u_int8_t edd_res2; /* reserved */
+ u_int16_t edd_off; /* address of buffer (offset) */
+ u_int16_t edd_seg; /* address of buffer (segment) */
+ u_int64_t edd_daddr; /* starting block */
+};
+
+/*
+ * reset disk system
+ */
+static int
+biosdreset(int dev)
+{
+ int rv;
+ __asm __volatile (DOINT(0x13) "; setc %b0" : "=a" (rv)
+ : "0" (0), "d" (dev) : "%ecx", "cc");
+ return (rv & 0xff)? rv >> 8 : 0;
+}
+
+/*
+ * Fill out a bios_diskinfo_t for this device.
+ * Return 0 if all ok.
+ * Return 1 if not ok.
+ */
+int
+bios_getdiskinfo(int dev, bios_diskinfo_t *pdi)
+{
+ u_int rv;
+
+ /* Just reset, don't check return code */
+ rv = biosdreset(dev);
+
+#ifdef BIOS_DEBUG
+ if (debug)
+ printf("getinfo: try #8, 0x%x, %p\n", dev, pdi);
+#endif
+ __asm __volatile (DOINT(0x13) "\n\t"
+ "setc %b0; movzbl %h1, %1\n\t"
+ "movzbl %%cl, %3; andb $0x3f, %b3\n\t"
+ "xchgb %%cl, %%ch; rolb $2, %%ch"
+ : "=a" (rv), "=d" (pdi->bios_heads),
+ "=c" (pdi->bios_cylinders),
+ "=b" (pdi->bios_sectors)
+ : "0" (0x0800), "1" (dev) : "cc");
+
+#ifdef BIOS_DEBUG
+ if (debug) {
+ printf("getinfo: got #8\n");
+ printf("disk 0x%x: %d,%d,%d\n", dev, pdi->bios_cylinders,
+ pdi->bios_heads, pdi->bios_sectors);
+ }
+#endif
+ if (rv & 0xff)
+ return (1);
+
+ /* Fix up info */
+ pdi->bios_number = dev;
+ pdi->bios_heads++;
+ pdi->bios_cylinders &= 0x3ff;
+ pdi->bios_cylinders++;
+
+ /* Sanity check */
+ if (!pdi->bios_cylinders || !pdi->bios_heads || !pdi->bios_sectors)
+ return(1);
+
+ /* CD-ROMs sometimes return heads == 1 */
+ if (pdi->bios_heads < 2)
+ return(1);
+
+ /* NOTE:
+ * This currently hangs/reboots some machines
+ * The IBM Thinkpad 750ED for one.
+ *
+ * Funny that an IBM/MS extension would not be
+ * implemented by an IBM system...
+ *
+ * Future hangs (when reported) can be "fixed"
+ * with getSYSCONFaddr() and an exceptions list.
+ */
+ if (dev & 0x80 && (dev == 0x80 || dev == 0x81 || dev == bios_bootdev)) {
+ int bm;
+
+#ifdef BIOS_DEBUG
+ if (debug)
+ printf("getinfo: try #41, 0x%x\n", dev);
+#endif
+ /* EDD support check */
+ __asm __volatile(DOINT(0x13) "; setc %b0"
+ : "=a" (rv), "=c" (bm)
+ : "0" (0x4100), "b" (0x55aa), "d" (dev) : "cc");
+ if (!(rv & 0xff) && (BIOS_regs.biosr_bx & 0xffff) == 0xaa55)
+ pdi->bios_edd = (bm & 0xffff) | ((rv & 0xff) << 16);
+ else
+ pdi->bios_edd = -1;
+
+#ifdef BIOS_DEBUG
+ if (debug) {
+ printf("getinfo: got #41\n");
+ printf("disk 0x%x: 0x%x\n", dev, bm);
+ }
+#endif
+ /*
+ * If extended disk access functions are not supported
+ * there is not much point on doing EDD.
+ */
+ if (!(pdi->bios_edd & EXT_BM_EDA))
+ pdi->bios_edd = -1;
+ } else
+ pdi->bios_edd = -1;
+
+ return(0);
+}
+
+/*
+ * Read/Write a block from given place using the BIOS.
+ */
+static __inline int
+CHS_rw(int rw, int dev, int cyl, int head, int sect, int nsect, void *buf)
+{
+ int rv;
+
+ rw = rw == F_READ ? 2 : 3;
+ BIOS_regs.biosr_es = (u_int32_t)buf >> 4;
+ __asm __volatile ("movb %b7, %h1\n\t"
+ "movb %b6, %%dh\n\t"
+ "andl $0xf, %4\n\t"
+ /* cylinder; the highest 2 bits of cyl is in %cl */
+ "xchgb %%ch, %%cl\n\t"
+ "rorb $2, %%cl\n\t"
+ "orb %b5, %%cl\n\t"
+ "inc %%cx\n\t"
+ DOINT(0x13) "\n\t"
+ "setc %b0"
+ : "=a" (rv)
+ : "0" (nsect), "d" (dev), "c" (cyl),
+ "b" (buf), "m" (sect), "m" (head),
+ "m" (rw)
+ : "cc", "memory");
+
+ return (rv & 0xff)? rv >> 8 : 0;
+}
+
+static __inline int
+EDD_rw(int rw, int dev, u_int64_t daddr, u_int32_t nblk, void *buf)
+{
+ int rv;
+ volatile static struct EDD_CB cb;
+
+ /* Zero out reserved stuff */
+ cb.edd_res1 = 0;
+ cb.edd_res2 = 0;
+
+ /* Fill in parameters */
+ cb.edd_len = sizeof(cb);
+ cb.edd_nblk = nblk;
+ cb.edd_seg = ((u_int32_t)buf >> 4) & 0xffff;
+ cb.edd_off = (u_int32_t)buf & 0xf;
+ cb.edd_daddr = daddr;
+
+ /* if offset/segment are zero, punt */
+ if (!cb.edd_seg && !cb.edd_off)
+ return (1);
+
+ /* Call extended read/write (with disk packet) */
+ BIOS_regs.biosr_ds = (u_int32_t)&cb >> 4;
+ __asm __volatile (DOINT(0x13) "; setc %b0" : "=a" (rv)
+ : "0" ((rw == F_READ)? 0x4200: 0x4300),
+ "d" (dev), "S" ((int) (&cb) & 0xf) : "%ecx", "cc");
+ return (rv & 0xff)? rv >> 8 : 0;
+}
+
+/*
+ * Read given sector, handling retry/errors/etc.
+ */
+int
+biosd_io(int rw, bios_diskinfo_t *bd, daddr_t off, int nsect, void *buf)
+{
+ int dev = bd->bios_number;
+ int j, error;
+ void *bb;
+
+ /* use a bounce buffer to not cross 64k DMA boundary */
+ if ((((u_int32_t)buf) & ~0xffff) !=
+ (((u_int32_t)buf + nsect * DEV_BSIZE) & ~0xffff)) {
+ /*
+ * XXX we believe that all the io is buffered
+ * by fs routines, so no big reads anyway
+ */
+ bb = alloca(nsect * DEV_BSIZE);
+ if (rw != F_READ)
+ bcopy (buf, bb, nsect * DEV_BSIZE);
+ } else
+ bb = buf;
+
+ /* Try to do operation up to 5 times */
+ for (error = 1, j = 5; j-- && error;) {
+ /* CHS or LBA access? */
+ if (bd->bios_edd != -1) {
+ error = EDD_rw(rw, dev, off, nsect, bb);
+ } else {
+ int cyl, head, sect;
+ size_t i, n;
+ char *p = bb;
+
+ /* Handle track boundaries */
+ for (error = i = 0; error == 0 && i < nsect;
+ i += n, off += n, p += n * DEV_BSIZE) {
+
+ btochs(off, cyl, head, sect, bd->bios_heads, bd->bios_sectors);
+ if ((sect + (nsect - i)) >= bd->bios_sectors)
+ n = bd->bios_sectors - sect;
+ else
+ n = nsect - i;
+
+ error = CHS_rw(rw, dev, cyl, head, sect, n, p);
+
+ /* ECC corrected */
+ if (error == 0x11)
+ error = 0;
+ }
+ }
+ switch (error) {
+ case 0x00: /* No errors */
+ case 0x11: /* ECC corrected */
+ error = 0;
+ break;
+
+ default: /* All other errors */
+#ifdef BIOS_DEBUG
+ if (debug)
+ printf("\nBIOS error 0x%x (%s)\n",
+ error, biosdisk_err(error));
+#endif
+ biosdreset(dev);
+ break;
+ }
+ }
+
+ if (bb != buf && rw == F_READ)
+ bcopy (bb, buf, nsect * DEV_BSIZE);
+
+#ifdef BIOS_DEBUG
+ if (debug) {
+ if (error != 0)
+ printf("=0x%x(%s)", error, biosdisk_err(error));
+ putchar('\n');
+ }
+#endif
+
+ return (error);
+}
+
+/*
+ * Try to read the bsd label on the given BIOS device
+ */
+const char *
+bios_getdisklabel(bios_diskinfo_t *bd, struct disklabel *label)
+{
+ daddr_t off = LABELSECTOR;
+ char *buf;
+ struct dos_mbr mbr;
+ int error, i;
+
+ /* Sanity check */
+ if(bd->bios_heads == 0 || bd->bios_sectors == 0)
+ return("failed to read disklabel");
+
+ /* MBR is a harddisk thing */
+ if (bd->bios_number & 0x80) {
+ /* Read MBR */
+ error = biosd_io(F_READ, bd, DOSBBSECTOR, 1, &mbr);
+ if (error)
+ return(biosdisk_err(error));
+
+ /* check mbr signature */
+ if (mbr.dmbr_sign != DOSMBR_SIGNATURE)
+ return("bad MBR signature\n");
+
+ /* Search for OpenBSD partition */
+ for (off = 0, i = 0; off == 0 && i < NDOSPART; i++)
+ if (mbr.dmbr_parts[i].dp_typ == DOSPTYP_OPENBSD)
+ off = mbr.dmbr_parts[i].dp_start + LABELSECTOR;
+
+ /* just in case */
+ if (off == 0)
+ for (off = 0, i = 0; off == 0 && i < NDOSPART; i++)
+ if (mbr.dmbr_parts[i].dp_typ == DOSPTYP_NETBSD)
+ off = mbr.dmbr_parts[i].dp_start + LABELSECTOR;
+
+ if (off == 0)
+ return("no BSD partition\n");
+ } else
+ off = LABELSECTOR;
+
+ /* Load BSD disklabel */
+ buf = alloca(DEV_BSIZE);
+#ifdef BIOS_DEBUG
+ if (debug)
+ printf("loading disklabel @ %u\n", off);
+#endif
+ /* read disklabel */
+ error = biosd_io(F_READ, bd, off, 1, buf);
+
+ if(error)
+ return("failed to read disklabel");
+
+ /* Fill in disklabel */
+ return (getdisklabel(buf, label));
+}
+
+int
+biosopen(struct open_file *f, ...)
+{
+ va_list ap;
+ register char *cp, **file;
+ dev_t maj, unit, part;
+ struct diskinfo *dip;
+ int biosdev;
+
+ va_start(ap, f);
+ cp = *(file = va_arg(ap, char **));
+ va_end(ap);
+
+#ifdef BIOS_DEBUG
+ if (debug)
+ printf("%s\n", cp);
+#endif
+
+ f->f_devdata = NULL;
+ /* search for device specification */
+ cp += 2;
+ if (cp[2] != ':') {
+ if (cp[3] != ':')
+ return ENOENT;
+ else
+ cp++;
+ }
+
+ for (maj = 0; maj < nbdevs &&
+ strncmp(*file, bdevs[maj], cp - *file); maj++);
+ if (maj >= nbdevs) {
+ printf("Unknown device: ");
+ for (cp = *file; *cp != ':'; cp++)
+ putchar(*cp);
+ putchar('\n');
+ return EADAPT;
+ }
+
+ /* get unit */
+ if ('0' <= *cp && *cp <= '9')
+ unit = *cp++ - '0';
+ else {
+ printf("Bad unit number\n");
+ return EUNIT;
+ }
+ /* get partition */
+ if ('a' <= *cp && *cp <= 'p')
+ part = *cp++ - 'a';
+ else {
+ printf("Bad partition id\n");
+ return EPART;
+ }
+
+ cp++; /* skip ':' */
+ if (*cp != 0)
+ *file = cp;
+ else
+ f->f_flags |= F_RAW;
+
+ biosdev = unit;
+ switch (maj) {
+ case 0: /* wd */
+ case 4: /* sd */
+ case 17: /* hd */
+ biosdev |= 0x80;
+ break;
+ case 2: /* fd */
+ break;
+ default:
+ return ENXIO;
+ }
+
+ /* Find device */
+ bootdev_dip = dip = dklookup(biosdev);
+
+ /* Fix up bootdev */
+ { dev_t bsd_dev;
+ bsd_dev = dip->bios_info.bsd_dev;
+ dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
+ B_CONTROLLER(bsd_dev), unit, part);
+ dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
+ B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part);
+ }
+
+#if 0
+ dip->bios_info.bsd_dev = dip->bootdev;
+ bootdev = dip->bootdev;
+#endif
+
+#ifdef BIOS_DEBUG
+ if (debug) {
+ printf("BIOS geometry: heads=%u, s/t=%u; EDD=%d\n",
+ dip->bios_info.bios_heads, dip->bios_info.bios_sectors,
+ dip->bios_info.bios_edd);
+ }
+#endif
+
+ /* Try for disklabel again (might be removable media) */
+ if(dip->bios_info.flags & BDI_BADLABEL){
+ const char *st = bios_getdisklabel(&dip->bios_info,
+ &dip->disklabel);
+#ifdef BIOS_DEBUG
+ if (debug && st)
+ printf("%s\n", st);
+#endif
+ if (!st) {
+ dip->bios_info.flags &= ~BDI_BADLABEL;
+ dip->bios_info.flags |= BDI_GOODLABEL;
+ } else
+ return (ERDLAB);
+ }
+
+ f->f_devdata = dip;
+
+ return 0;
+}
+
+const u_char bidos_errs[] =
+/* ignored "\x00" "successful completion\0" */
+ "\x01" "invalid function/parameter\0"
+ "\x02" "address mark not found\0"
+ "\x03" "write-protected\0"
+ "\x04" "sector not found\0"
+ "\x05" "reset failed\0"
+ "\x06" "disk changed\0"
+ "\x07" "drive parameter activity failed\0"
+ "\x08" "DMA overrun\0"
+ "\x09" "data boundary error\0"
+ "\x0A" "bad sector detected\0"
+ "\x0B" "bad track detected\0"
+ "\x0C" "invalid media\0"
+ "\x0E" "control data address mark detected\0"
+ "\x0F" "DMA arbitration level out of range\0"
+ "\x10" "uncorrectable CRC or ECC error on read\0"
+/* ignored "\x11" "data ECC corrected\0" */
+ "\x20" "controller failure\0"
+ "\x31" "no media in drive\0"
+ "\x32" "incorrect drive type in CMOS\0"
+ "\x40" "seek failed\0"
+ "\x80" "operation timed out\0"
+ "\xAA" "drive not ready\0"
+ "\xB0" "volume not locked in drive\0"
+ "\xB1" "volume locked in drive\0"
+ "\xB2" "volume not removable\0"
+ "\xB3" "volume in use\0"
+ "\xB4" "lock count exceeded\0"
+ "\xB5" "valid eject request failed\0"
+ "\xBB" "undefined error\0"
+ "\xCC" "write fault\0"
+ "\xE0" "status register error\0"
+ "\xFF" "sense operation failed\0"
+ "\x00" "\0";
+
+static const char *
+biosdisk_err(u_int error)
+{
+ register const u_char *p = bidos_errs;
+
+ while (*p && *p != error)
+ while(*p++);
+
+ return ++p;
+}
+
+const struct biosdisk_errors {
+ u_char error;
+ u_char errno;
+} tab[] = {
+ { 0x01, EINVAL },
+ { 0x03, EROFS },
+ { 0x08, EINVAL },
+ { 0x09, EINVAL },
+ { 0x0A, EBSE },
+ { 0x0B, EBSE },
+ { 0x0C, ENXIO },
+ { 0x0D, EINVAL },
+ { 0x10, EECC },
+ { 0x20, EHER },
+ { 0x31, ENXIO },
+ { 0x32, ENXIO },
+ { 0x00, EIO }
+};
+
+static int
+biosdisk_errno(u_int error)
+{
+ register const struct biosdisk_errors *p;
+
+ if (!error)
+ return 0;
+
+ for (p = tab; p->error && p->error != error; p++);
+
+ return p->errno;
+}
+
+int
+biosstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf,
+ size_t *rsize)
+{
+ struct diskinfo *dip = (struct diskinfo *)devdata;
+ bios_diskinfo_t *bd = &dip->bios_info;
+ u_int8_t error = 0;
+ size_t nsect;
+
+ nsect = (size + DEV_BSIZE-1) / DEV_BSIZE;
+ if (rsize != NULL)
+ blk += dip->disklabel.
+ d_partitions[B_PARTITION(dip->bsddev)].p_offset;
+
+ /* Read all, sub-functions handle track boundaries */
+ error = biosd_io(rw, bd, blk, nsect, buf);
+
+#ifdef BIOS_DEBUG
+ if (debug) {
+ if (error != 0)
+ printf("=0x%x(%s)", error, biosdisk_err(error));
+ putchar('\n');
+ }
+#endif
+
+ if (rsize != NULL)
+ *rsize = nsect * DEV_BSIZE;
+
+ return biosdisk_errno(error);
+}
+
+int
+biosclose(struct open_file *f)
+{
+ f->f_devdata = NULL;
+ return 0;
+}
+
+int
+biosioctl(struct open_file *f, u_long cmd, void *data)
+{
+ return 0;
+}
+
diff --git a/sys/arch/amd64/stand/libsa/biosdev.h b/sys/arch/amd64/stand/libsa/biosdev.h
new file mode 100644
index 00000000000..3c00bc6d9a1
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/biosdev.h
@@ -0,0 +1,70 @@
+/* $OpenBSD: biosdev.h,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1996 Michael Shalayeff
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 REGENTS 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.
+ *
+ */
+
+/*
+ * Extension support bitmap definition (returned by 41h)
+ */
+#define EXT_BM_EDA 0x01 /* Extended disk access functions */
+ /* (42h-44h, 47h and 48h) supported. */
+#define EXT_BM_RDC 0x02 /* Removable drive controller functions */
+ /* (45h, 46h, 48h, 49h and INT 15 52h) */
+ /* supported. */
+#define EXT_BM_EDD 0x04 /* Enhanced disk drive functions */
+ /* (48h and 4eh) supported. */
+#define EXT_BM_RSV 0xf8 /* Reserved (0) */
+
+struct consdev;
+struct open_file;
+
+/* biosdev.c */
+extern const char *biosdevs[];
+int biosstrategy(void *, int, daddr_t, size_t, void *, size_t *);
+int biosopen(struct open_file *, ...);
+int biosclose(struct open_file *);
+int biosioctl(struct open_file *, u_long, void *);
+int bios_getdiskinfo(int, bios_diskinfo_t *);
+int biosd_io(int, bios_diskinfo_t *, daddr_t, int, void *);
+const char * bios_getdisklabel(bios_diskinfo_t *, struct disklabel *);
+
+/* diskprobe.c */
+struct diskinfo *dklookup(int);
+bios_diskinfo_t *bios_dklookup(int);
+
+/* bioscons.c */
+void pc_probe(struct consdev *);
+void pc_init(struct consdev *);
+int pc_getc(dev_t);
+void pc_putc(dev_t, int);
+void pc_pollc(dev_t, int);
+void com_probe(struct consdev *);
+void com_init(struct consdev *);
+int comspeed(dev_t, int);
+int com_getc(dev_t);
+void com_putc(dev_t, int);
+void com_pollc(dev_t, int);
diff --git a/sys/arch/amd64/stand/libsa/biosprobe.c b/sys/arch/amd64/stand/libsa/biosprobe.c
new file mode 100644
index 00000000000..8e57907ffb8
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/biosprobe.c
@@ -0,0 +1,80 @@
+/* $OpenBSD: biosprobe.c,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 2002 Tobias Weingartner
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/param.h>
+#include <machine/biosvar.h>
+#include <machine/pio.h>
+#include <dev/cons.h>
+#include <sys/disklabel.h>
+#include "disk.h"
+#include "libsa.h"
+#include "biosdev.h"
+
+
+void *
+getSYSCONFaddr(void)
+{
+ u_int32_t status;
+ u_int8_t *vers;
+
+ __asm __volatile(DOINT(0x15) "\n\t"
+ "setc %%al\n\t"
+ : "=a" (status)
+ : "0" (0xC000)
+ : "%ebx", "%ecx", "%edx", "%esi", "%edi", "cc");
+
+ /* On failure we go for a NULL */
+ if(status)
+ return(NULL);
+
+ /* Calculate where the version bytes are */
+ vers = (void*)((BIOS_regs.biosr_es << 4) | BIOS_regs.biosr_bx);
+ return(vers);
+}
+
+void *
+getEBDAaddr(void)
+{
+ u_int32_t status;
+ u_int8_t *info;
+
+ info = getSYSCONFaddr();
+ if(!info) return(NULL);
+
+ __asm __volatile(DOINT(0x15) "\n\t"
+ "setc %%al"
+ : "=a" (status)
+ : "0" (0xC100)
+ : "%ebx", "%ecx", "%edx", "%esi", "%edi", "cc");
+
+ if(status) return(NULL);
+
+ info = (void *)(BIOS_regs.biosr_es << 4);
+
+ return(info);
+}
+
diff --git a/sys/arch/amd64/stand/libsa/cmd_i386.c b/sys/arch/amd64/stand/libsa/cmd_i386.c
new file mode 100644
index 00000000000..03f495350dd
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/cmd_i386.c
@@ -0,0 +1,181 @@
+/* $OpenBSD: cmd_i386.c,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1997-1999 Michael Shalayeff
+ * Copyright (c) 1997 Tobias Weingartner
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 REGENTS 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.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <machine/biosvar.h>
+#include <sys/disklabel.h>
+#include "disk.h"
+#include "biosdev.h"
+#include "libsa.h"
+#include <cmd.h>
+
+
+extern const char version[];
+
+int Xboot(void);
+int Xdiskinfo(void);
+int Xmemory(void);
+int Xregs(void);
+
+/* From gidt.S */
+int bootbuf(void *, int);
+
+const struct cmd_table cmd_machine[] = {
+ { "boot", CMDT_CMD, Xboot },
+ { "diskinfo", CMDT_CMD, Xdiskinfo },
+ { "memory", CMDT_CMD, Xmemory },
+#ifdef DEBUG
+ { "regs", CMDT_CMD, Xregs },
+#endif
+ { NULL, 0 }
+};
+
+int
+Xdiskinfo(void)
+{
+#ifndef _TEST
+ dump_diskinfo();
+#endif
+ return 0;
+}
+
+#ifdef DEBUG
+int
+Xregs(void)
+{
+ DUMP_REGS;
+ return 0;
+}
+#endif
+
+int
+Xboot(void)
+{
+#ifndef _TEST
+ int dev, part, st;
+ bios_diskinfo_t *bd = NULL;
+ char buf[DEV_BSIZE], *dest = (void *)BOOTBIOS_ADDR;
+
+ if(cmd.argc != 2) {
+ printf("machine boot {fd,hd}<0123>[abcd]\n");
+ printf("Where [0123] is the disk number,"
+ " and [abcd] is the partition.\n");
+ return 0;
+ }
+
+ /* Check arg */
+ if(cmd.argv[1][0] != 'f' && cmd.argv[1][0] != 'h')
+ goto bad;
+ if(cmd.argv[1][1] != 'd')
+ goto bad;
+ if(cmd.argv[1][2] < '0' || cmd.argv[1][2] > '3')
+ goto bad;
+ if((cmd.argv[1][3] < 'a' || cmd.argv[1][3] > 'd') && cmd.argv[1][3] != '\0')
+ goto bad;
+
+ printf("Booting from %s ", cmd.argv[1]);
+
+ dev = (cmd.argv[1][0] == 'h')?0x80:0;
+ dev += (cmd.argv[1][2] - '0');
+ part = (cmd.argv[1][3] - 'a');
+
+ if (part > 0)
+ printf("[%x,%d]\n", dev, part);
+ else
+ printf("[%x]\n", dev);
+
+ /* Read boot sector from device */
+ bd = bios_dklookup(dev);
+ st = biosd_io(F_READ, bd, 0, 1, buf);
+ if(st) goto bad;
+
+ /* Frob boot flag in buffer from HD */
+ if((dev & 0x80) && (part > 0)){
+ int i, j;
+
+ for(i = 0, j = DOSPARTOFF; i < 4; i++, j += 16)
+ if(part == i)
+ buf[j] |= 0x80;
+ else
+ buf[j] &= ~0x80;
+ }
+
+ /* Load %dl, ljmp */
+ bcopy(buf, dest, DEV_BSIZE);
+ bootbuf(dest, dev);
+
+bad:
+ printf("Invalid device!\n");
+#endif
+ return 0;
+}
+
+int
+Xmemory(void)
+{
+ if (cmd.argc >= 2) {
+ int i;
+ /* parse the memory specs */
+
+ for (i = 1; i < cmd.argc; i++) {
+ char *p;
+ long addr, size;
+
+ p = cmd.argv[i];
+
+ size = strtol(p + 1, &p, 0);
+ if (*p && *p == '@')
+ addr = strtol(p + 1, NULL, 0);
+ else
+ addr = 0;
+ if (addr == 0 && (*p != '@' || size == 0)) {
+ printf ("bad language\n");
+ return 0;
+ } else {
+ switch (cmd.argv[i][0]) {
+ case '-':
+ mem_delete(addr, addr + size);
+ break;
+ case '+':
+ mem_add(addr, addr + size);
+ break;
+ default :
+ printf ("bad OP\n");
+ return 0;
+ }
+ }
+ }
+ }
+
+ dump_biosmem(NULL);
+
+ return 0;
+}
diff --git a/sys/arch/amd64/stand/libsa/dev_i386.c b/sys/arch/amd64/stand/libsa/dev_i386.c
new file mode 100644
index 00000000000..c2bd950ebaa
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/dev_i386.c
@@ -0,0 +1,191 @@
+/* $OpenBSD: dev_i386.c,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1996-1999 Michael Shalayeff
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 AUTHOR OR HIS RELATIVES 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 MIND, 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.
+ */
+
+#include "libsa.h"
+#include "biosdev.h"
+#include <sys/param.h>
+#include <dev/cons.h>
+
+extern int debug;
+
+/* XXX use slot for 'rd' for 'hd' pseudo-device */
+const char bdevs[][4] = {
+ "wd", "", "fd", "wt", "sd", "st", "cd", "mcd",
+ "", "", "", "", "", "", "", "scd", "", "hd", ""
+};
+const int nbdevs = NENTS(bdevs);
+
+const char cdevs[][4] = {
+ "cn", "", "", "", "", "", "", "",
+ "com", "", "", "", "pc"
+};
+const int ncdevs = NENTS(cdevs);
+
+/* pass dev_t to the open routines */
+int
+devopen(struct open_file *f, const char *fname, char **file)
+{
+ struct devsw *dp = devsw;
+ register int i, rc = 1;
+
+ *file = (char *)fname;
+
+#ifdef DEBUG
+ if (debug)
+ printf("devopen:");
+#endif
+
+ for (i = 0; i < ndevs && rc != 0; dp++, i++) {
+#ifdef DEBUG
+ if (debug)
+ printf(" %s: ", dp->dv_name);
+#endif
+ if ((rc = (*dp->dv_open)(f, file)) == 0) {
+ f->f_dev = dp;
+ return 0;
+ }
+#ifdef DEBUG
+ else if (debug)
+ printf("%d", rc);
+#endif
+
+ }
+#ifdef DEBUG
+ if (debug)
+ putchar('\n');
+#endif
+
+ if ((f->f_flags & F_NODEV) == 0)
+ f->f_dev = dp;
+
+ return rc;
+}
+
+void
+devboot(dev_t bootdev, char *p)
+{
+#ifdef _TEST
+ *p++ = '/';
+ *p++ = 'd';
+ *p++ = 'e';
+ *p++ = 'v';
+ *p++ = '/';
+ *p++ = 'r';
+#endif
+ if (bootdev & 0x80)
+ *p++ = 'h';
+ else
+ *p++ = 'f';
+ *p++ = 'd';
+ *p++ = '0' + (bootdev & 0x7f);
+ *p++ = 'a';
+ *p = '\0';
+}
+
+int pch_pos = 0;
+
+void
+putchar(int c)
+{
+ switch(c) {
+ case '\177': /* DEL erases */
+ cnputc('\b');
+ cnputc(' ');
+ case '\b':
+ cnputc('\b');
+ if (pch_pos)
+ pch_pos--;
+ break;
+ case '\t':
+ do
+ cnputc(' ');
+ while(++pch_pos % 8);
+ break;
+ case '\n':
+ case '\r':
+ cnputc(c);
+ pch_pos=0;
+ break;
+ default:
+ cnputc(c);
+ pch_pos++;
+ break;
+ }
+}
+
+int
+getchar(void)
+{
+ register int c = cngetc();
+
+ if (c == '\r')
+ c = '\n';
+
+ if ((c < ' ' && c != '\n') || c == '\177')
+ return(c);
+
+ putchar(c);
+
+ return(c);
+}
+
+char ttyname_buf[8];
+
+char *
+ttyname(int fd)
+{
+ snprintf(ttyname_buf, sizeof ttyname_buf, "%s%d",
+ cdevs[major(cn_tab->cn_dev)],
+ minor(cn_tab->cn_dev));
+ return (ttyname_buf);
+}
+
+dev_t
+ttydev(char *name)
+{
+ int i, unit = -1;
+ char *no = name + strlen(name) - 1;
+
+ while (no >= name && *no >= '0' && *no <= '9')
+ unit = (unit < 0 ? 0 : (unit * 10)) + *no-- - '0';
+ if (no < name || unit < 0)
+ return (NODEV);
+ for (i = 0; i < ncdevs; i++)
+ if (strncmp(name, cdevs[i], no - name + 1) == 0)
+ return (makedev(i, unit));
+ return (NODEV);
+}
+
+int
+cnspeed(dev_t dev, int sp)
+{
+ if (major(dev) == 8) /* comN */
+ return comspeed(dev, sp);
+ /* pc0 and anything else */
+ return 9600;
+}
diff --git a/sys/arch/amd64/stand/libsa/disk.h b/sys/arch/amd64/stand/libsa/disk.h
new file mode 100644
index 00000000000..e95a3642924
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/disk.h
@@ -0,0 +1,52 @@
+/* $OpenBSD: disk.h,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 REGENTS 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.
+ *
+ */
+
+#ifndef _DISKPROBE_H
+#define _DISKPROBE_H
+
+#include <sys/queue.h>
+
+/* All the info on a disk we've found */
+struct diskinfo {
+ bios_diskinfo_t bios_info;
+ struct disklabel disklabel;
+
+ dev_t bsddev, bootdev;
+
+ TAILQ_ENTRY(diskinfo) list;
+};
+TAILQ_HEAD(disklist_lh, diskinfo);
+
+/* Head of this list */
+extern struct diskinfo *bootdev_dip;
+
+void dump_diskinfo(void);
+
+#endif /* _DISKPROBE_H */
+
diff --git a/sys/arch/amd64/stand/libsa/diskprobe.c b/sys/arch/amd64/stand/libsa/diskprobe.c
new file mode 100644
index 00000000000..117e1ebad98
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/diskprobe.c
@@ -0,0 +1,294 @@
+/* $OpenBSD: diskprobe.c,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 REGENTS 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.
+ *
+ */
+
+/* We want the disk type names from disklabel.h */
+#undef DKTYPENAMES
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/reboot.h>
+#include <sys/disklabel.h>
+#include <stand/boot/bootarg.h>
+#include <machine/biosvar.h>
+#include <lib/libz/zlib.h>
+#include "disk.h"
+#include "biosdev.h"
+#include "libsa.h"
+
+#define MAX_CKSUMLEN MAXBSIZE / DEV_BSIZE /* Max # of blks to cksum */
+
+/* Local Prototypes */
+static int disksum(int);
+
+/* List of disk devices we found/probed */
+struct disklist_lh disklist;
+
+/* Pointer to boot device */
+struct diskinfo *bootdev_dip;
+
+extern int debug;
+
+/* Probe for all BIOS floppies */
+static void
+floppyprobe(void)
+{
+ struct diskinfo *dip;
+ int i;
+
+ /* Floppies */
+ for(i = 0; i < 4; i++) {
+ dip = alloc(sizeof(struct diskinfo));
+ bzero(dip, sizeof(*dip));
+
+ if(bios_getdiskinfo(i, &dip->bios_info)) {
+#ifdef BIOS_DEBUG
+ if (debug)
+ printf(" <!fd%u>", i);
+#endif
+ free(dip, 0);
+ break;
+ }
+
+ printf(" fd%u", i);
+
+ /* Fill out best we can - (fd?) */
+ dip->bios_info.bsd_dev = MAKEBOOTDEV(2, 0, 0, i, RAW_PART);
+
+ /*
+ * Delay reading the disklabel until we're sure we want
+ * to boot from the floppy. Doing this avoids a delay
+ * (sometimes very long) when trying to read the label
+ * and the drive is unplugged.
+ */
+ dip->bios_info.flags |= BDI_BADLABEL;
+
+ /* Add to queue of disks */
+ TAILQ_INSERT_TAIL(&disklist, dip, list);
+ }
+}
+
+
+/* Probe for all BIOS hard disks */
+static void
+hardprobe(void)
+{
+ struct diskinfo *dip;
+ int i;
+ u_int bsdunit, type;
+ u_int scsi = 0, ide = 0;
+ const char *dc = (const char *)((0x40 << 4) + 0x75);
+
+ /* Hard disks */
+ for (i = 0x80; i < (0x80 + *dc); i++) {
+ dip = alloc(sizeof(struct diskinfo));
+ bzero(dip, sizeof(*dip));
+
+ if(bios_getdiskinfo(i, &dip->bios_info)) {
+#ifdef BIOS_DEBUG
+ if (debug)
+ printf(" <!hd%u>", i&0x7f);
+#endif
+ free(dip, 0);
+ break;
+ }
+
+ printf(" hd%u%s", i&0x7f, (dip->bios_info.bios_edd > 0?"+":""));
+
+ /* Try to find the label, to figure out device type */
+ if((bios_getdisklabel(&dip->bios_info, &dip->disklabel)) ) {
+ printf("*");
+ bsdunit = ide++;
+ type = 0; /* XXX let it be IDE */
+ } else {
+ /* Best guess */
+ switch (dip->disklabel.d_type) {
+ case DTYPE_SCSI:
+ type = 4;
+ bsdunit = scsi++;
+ dip->bios_info.flags |= BDI_GOODLABEL;
+ break;
+
+ case DTYPE_ESDI:
+ case DTYPE_ST506:
+ type = 0;
+ bsdunit = ide++;
+ dip->bios_info.flags |= BDI_GOODLABEL;
+ break;
+
+ default:
+ dip->bios_info.flags |= BDI_BADLABEL;
+ type = 0; /* XXX Suggest IDE */
+ bsdunit = ide++;
+ }
+ }
+
+ dip->bios_info.checksum = 0; /* just in case */
+ /* Fill out best we can */
+ dip->bios_info.bsd_dev = MAKEBOOTDEV(type, 0, 0, bsdunit, RAW_PART);
+
+ /* Add to queue of disks */
+ TAILQ_INSERT_TAIL(&disklist, dip, list);
+ }
+}
+
+
+/* Probe for all BIOS supported disks */
+u_int32_t bios_cksumlen;
+void
+diskprobe(void)
+{
+ struct diskinfo *dip;
+ int i;
+
+ /* These get passed to kernel */
+ bios_diskinfo_t *bios_diskinfo;
+
+ /* Init stuff */
+ printf("disk:");
+ TAILQ_INIT(&disklist);
+
+ /* Do probes */
+ floppyprobe();
+#ifdef BIOS_DEBUG
+ if (debug)
+ printf(";");
+#endif
+ hardprobe();
+
+ /* Checksumming of hard disks */
+ for (i = 0; disksum(i++) && i < MAX_CKSUMLEN; )
+ ;
+ bios_cksumlen = i;
+
+ /* Get space for passing bios_diskinfo stuff to kernel */
+ for(i = 0, dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list))
+ i++;
+ bios_diskinfo = alloc(++i * sizeof(bios_diskinfo_t));
+
+ /* Copy out the bios_diskinfo stuff */
+ for(i = 0, dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list))
+ bios_diskinfo[i++] = dip->bios_info;
+
+ bios_diskinfo[i++].bios_number = -1;
+ /* Register for kernel use */
+ addbootarg(BOOTARG_CKSUMLEN, sizeof(u_int32_t), &bios_cksumlen);
+ addbootarg(BOOTARG_DISKINFO, i * sizeof(bios_diskinfo_t), bios_diskinfo);
+
+ printf("\n");
+}
+
+
+/* Find info on given BIOS disk */
+struct diskinfo *
+dklookup(int dev)
+{
+ struct diskinfo *dip;
+
+ for(dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list))
+ if(dip->bios_info.bios_number == dev)
+ return(dip);
+
+ return(NULL);
+}
+
+void
+dump_diskinfo(void)
+{
+ struct diskinfo *dip;
+
+ printf("Disk\tBIOS#\tType\tCyls\tHeads\tSecs\tFlags\tChecksum\n");
+ for(dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list)){
+ bios_diskinfo_t *bdi = &dip->bios_info;
+ int d = bdi->bios_number;
+
+ printf("%cd%d\t0x%x\t%s\t%d\t%d\t%d\t0x%x\t0x%x\n",
+ (d & 0x80)?'h':'f', d & 0x7F, d,
+ (bdi->flags & BDI_BADLABEL)?"*none*":"label",
+ bdi->bios_cylinders, bdi->bios_heads, bdi->bios_sectors,
+ bdi->flags, bdi->checksum);
+ }
+}
+
+/* Find BIOS portion on given BIOS disk
+ * XXX - Use dklookup() instead.
+ */
+bios_diskinfo_t *
+bios_dklookup(int dev)
+{
+ struct diskinfo *dip;
+
+ dip = dklookup(dev);
+ if(dip)
+ return(&dip->bios_info);
+
+ return(NULL);
+}
+
+/*
+ * Checksum one more block on all harddrives
+ *
+ * Use the adler32() function from libz,
+ * as it is quick, small, and available.
+ */
+int
+disksum(int blk)
+{
+ struct diskinfo *dip, *dip2;
+ int st, reprobe = 0;
+ char *buf;
+
+ buf = alloca(DEV_BSIZE);
+ for(dip = TAILQ_FIRST(&disklist); dip; dip = TAILQ_NEXT(dip, list)){
+ bios_diskinfo_t *bdi = &dip->bios_info;
+
+ /* Skip this disk if it is not a HD or has had an I/O error */
+ if (!(bdi->bios_number & 0x80) || bdi->flags & BDI_INVALID)
+ continue;
+
+ /* Adler32 checksum */
+ st = biosd_io(F_READ, bdi, blk, 1, buf);
+ if (st) {
+ bdi->flags |= BDI_INVALID;
+ continue;
+ }
+ bdi->checksum = adler32(bdi->checksum, buf, DEV_BSIZE);
+
+ for(dip2 = TAILQ_FIRST(&disklist); dip2 != dip;
+ dip2 = TAILQ_NEXT(dip2, list)){
+ bios_diskinfo_t *bd = &dip2->bios_info;
+ if ((bd->bios_number & 0x80) &&
+ !(bd->flags & BDI_INVALID) &&
+ bdi->checksum == bd->checksum)
+ reprobe = 1;
+ }
+ }
+
+ return (reprobe);
+}
+
diff --git a/sys/arch/amd64/stand/libsa/exec_i386.c b/sys/arch/amd64/stand/libsa/exec_i386.c
new file mode 100644
index 00000000000..0b814d9d3db
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/exec_i386.c
@@ -0,0 +1,73 @@
+/* $OpenBSD: exec_i386.c,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1997-1998 Michael Shalayeff
+ * Copyright (c) 1997 Tobias Weingartner
+ * All rights reserved.
+ *
+ * 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 AUTHORS ``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 REGENTS 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.
+ *
+ */
+
+#include <sys/param.h>
+#include <dev/cons.h>
+#include <stand/boot/bootarg.h>
+#include <machine/biosvar.h>
+#include <sys/disklabel.h>
+#include "disk.h"
+#include "libsa.h"
+#include <lib/libsa/loadfile.h>
+
+typedef void (*startfuncp)(int, int, int, int, int, int, int, int)
+ __attribute__ ((noreturn));
+
+void
+run_loadfile(u_long *marks, int howto)
+{
+ u_long entry;
+#ifdef EXEC_DEBUG
+ extern int debug;
+#endif
+ dev_t bootdev = bootdev_dip->bootdev;
+ size_t ac = BOOTARG_LEN;
+ caddr_t av = (caddr_t)BOOTARG_OFF;
+ bios_consdev_t cd;
+ extern int com_speed; /* from bioscons.c */
+
+ cd.consdev = cn_tab->cn_dev;
+ cd.conspeed = com_speed;
+ addbootarg(BOOTARG_CONSDEV, sizeof(cd), &cd);
+
+ /* Pass memory map to the kernel */
+ mem_pass();
+
+ makebootargs(av, &ac);
+
+ entry = marks[MARK_ENTRY] & 0x0fffffff;
+
+ printf("entry point at 0x%lx [%x, %x, %x, %x]\n", entry,
+ ((int *)entry)[0], ((int *)entry)[1], ((int *)entry)[2], ((int *)entry)[3]);
+ /* stack and the gung is ok at this point, so, no need for asm setup */
+ (*(startfuncp)entry)(howto, bootdev, BOOTARG_APIVER,
+ marks[MARK_END], extmem, cnvmem, ac, (int)av);
+ /* not reached */
+}
diff --git a/sys/arch/amd64/stand/libsa/gateA20.c b/sys/arch/amd64/stand/libsa/gateA20.c
new file mode 100644
index 00000000000..26cfb3539cb
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/gateA20.c
@@ -0,0 +1,82 @@
+/* $OpenBSD: gateA20.c,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <machine/pio.h>
+#include <dev/ic/i8042reg.h>
+#include <dev/isa/isareg.h>
+
+#include "libsa.h"
+
+#define KB_A20 0xdf /* enable A20,
+ enable output buffer full interrupt
+ enable data line
+ enable clock line */
+
+
+/*
+ * Gate A20 for high memory
+ */
+void
+gateA20(int on)
+{
+ if (ps2model == 0xf82 ||
+ (inb(IO_KBD + KBSTATP) == 0xff && inb(IO_KBD + KBDATAP) == 0xff)) {
+ int data;
+
+ /* Try to use 0x92 to turn on A20 */
+ if (on) {
+ data = inb(0x92);
+ outb(0x92, data | 0x2);
+ } else {
+ data = inb(0x92);
+ outb(0x92, data & ~0x2);
+ }
+ } else {
+
+ while (inb(IO_KBD + KBSTATP) & KBS_IBF);
+
+ while (inb(IO_KBD + KBSTATP) & KBS_DIB)
+ (void)inb(IO_KBD + KBDATAP);
+
+ outb(IO_KBD + KBCMDP, KBC_CMDWOUT);
+ while (inb(IO_KBD + KBSTATP) & KBS_IBF);
+
+ if (on)
+ outb(IO_KBD + KBDATAP, KB_A20);
+ else
+ outb(IO_KBD + KBDATAP, 0xcd);
+ while (inb(IO_KBD + KBSTATP) & KBS_IBF);
+
+ while (inb(IO_KBD + KBSTATP) & KBS_DIB)
+ (void)inb(IO_KBD + KBDATAP);
+ }
+}
diff --git a/sys/arch/amd64/stand/libsa/gidt.S b/sys/arch/amd64/stand/libsa/gidt.S
new file mode 100644
index 00000000000..c280c64a9ab
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/gidt.S
@@ -0,0 +1,415 @@
+/* $OpenBSD: gidt.S,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1997 Michael Shalayeff
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 REGENTS 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.
+ *
+ */
+
+ .file "gidt.S"
+
+#include <machine/asm.h>
+#define _LOCORE
+#include <machine/trap.h>
+#undef _LOCORE
+#include <assym.h>
+
+#define SNULL 0x00
+#define S32TEXT 0x08
+#define S32DATA 0x10
+#define S16TEXT 0x18
+#define S16DATA 0x20
+
+#ifdef GIDT_DEBUG
+#define gidt_debug0 ; \
+ mov $0xb8000, %eax ; \
+ mov $0x47314730, (%eax)
+#define gidt_debug1 ; \
+ mov $(0xb8000 - LINKADDR), %eax ; \
+ mov $0x4f314f30, (%eax)
+#define gidt_debug2 ; \
+ mov $0xb8004, %eax ; \
+ mov $0x47334732, (%eax)
+#define gidt_debug3 ; \
+ mov $0xb8004, %eax ; \
+ mov $0x4f334f32, (%eax)
+#define gidt_debug4 ; \
+ movl $0xb8008, %eax ; \
+ movl $0x47344733, (%eax)
+#else
+#define gidt_debug0 /* gidt_debug0 */
+#define gidt_debug1 /* gidt_debug1 */
+#define gidt_debug2 /* gidt_debug2 */
+#define gidt_debug3 /* gidt_debug3 */
+#define gidt_debug4 /* gidt_debug4 */
+#endif
+
+#define prot2real \
+ gidt_debug0; \
+ \
+ ljmp $S16TEXT, $1f - LINKADDR; \
+1: \
+ .code16; \
+ movw $S16DATA, %ax; \
+ mov %ax, %ds; \
+ mov %ax, %es; \
+ gidt_debug1; \
+ \
+ movl %cr0, %eax; /* disable pmmm */ \
+ andl $~CR0_PE, %eax; \
+ movl %eax, %cr0; \
+ \
+ /* reload real cs:ip */ \
+ data32 ljmp $(LINKADDR >> 4), $1f - LINKADDR; \
+1: \
+ xor %ax, %ax; /* setup: %ds, %es, %ss */ \
+ mov %ax, %ds; \
+ mov %ax, %es; \
+ mov %ax, %ss; \
+ \
+ gidt_debug2; \
+ \
+ data32 addr32 lidt Idtr_real; /* load idtr for real mode */
+
+#define real2prot \
+ gidt_debug3; \
+ \
+ data32 addr32 lgdt Gdtr; /* load the gdtr */ \
+ \
+ movl %cr0, %eax; /* enable pmmm */ \
+ orl $CR0_PE, %eax; \
+ movl %eax, %cr0; \
+ \
+ data32 ljmp $S32TEXT, $1f; /* reload %cs,flush pipeline */\
+1: \
+ .code32; \
+ /* reload 32bit %ds, %ss, %es */ \
+ mov $S32DATA, %eax; \
+ mov %ax, %ds; \
+ mov %ax, %ss; \
+ mov %ax, %es; \
+ \
+ gidt_debug4; \
+ \
+ /* load idtr for debugger and DOS/BIOS iface */ \
+ lidt Idtr;
+
+
+ .globl _C_LABEL(BIOS_regs)
+
+ .text
+ .code32
+ .globl _ASM_LABEL(pmm_init)
+ .globl _C_LABEL(_rtt)
+
+ENTRY(_rtt)
+#ifdef GIDT_DEBUG
+ movl $0xb8000, %ebx
+ movl $0x4f514f51, (%ebx)
+#endif
+ movw $0x1234, %ax
+ movw %ax, 0x472 /* warm boot */
+
+ /* Try to use the KBD to reboot system */
+ movb $0xfe, %al
+ outb %al, $0x64
+
+ movl $0x5000, %ecx
+1: inb $0x84, %al
+ loop 1b
+
+ movb $0xfe, %al
+ outb %al, $0x64
+
+#ifdef GIDT_DEBUG
+ movl $0xb8000, %ebx
+ movl $0x07310731, (%ebx)
+#endif
+
+ /* Try to cause a tripple fault... */
+ lidt Idtr_reset
+ xorl %eax, %eax
+ divl %eax, %eax
+
+ /* Again... */
+ int $0x8
+
+ /* Again... */
+ movl $0, %esp /* segment violation */
+ ret
+
+ .align 8, 0x90
+pmm_init:
+ /* load idtr for interrupts */
+ lidt Idtr
+ ret
+
+
+#ifdef __STDC__
+#define IPROC(n) X##n
+#define IEMU(n) IPROC(emu##n)
+#else
+#define IPROC(n) X/**/n
+#define IEMU(n) IPROC(emu/**/n)
+#endif
+ .align 8, 0x90
+idt:
+#define idte(e) \
+ .short IPROC(e); .short (S32TEXT); \
+ .short ((0x80|SDT_SYS386TGT) << 8); .short (LINKADDR >> 16)
+/* internal (0-31) */
+ idte(de); idte(db); idte(nmi); idte(bp); idte(of); idte(br)
+ idte(ud); idte(nm); idte(df); idte(fo); idte(ts); idte(np)
+ idte(ss); idte(gp); idte(pf); idte(xx); idte(mf); idte(ac)
+ idte(xx)
+ idte(xx); idte(xx); idte(xx); idte(xx); idte(xx); idte(xx)
+ idte(xx); idte(xx); idte(xx); idte(xx); idte(xx); idte(xx)
+ idte(xx)
+ /* Maskable interrupts (32-255) */
+ /* BIOS entry points (32-63) */
+ /* DOS entry points (64-80) */
+#ifdef __STDC__
+#define idtb(b) idte(emu##b)
+#else
+#define idtb(b) idte(emu/**/b)
+#endif
+ idtb(0); idtb(1); idtb(2); idtb(3); idtb(4); idtb(5)
+ idtb(6); idtb(7); idtb(8); idtb(9); idtb(10); idtb(11)
+ idtb(12); idtb(13); idtb(14); idtb(15); idtb(16); idtb(17)
+ idtb(18); idtb(19); idtb(20); idtb(21); idtb(22); idtb(23)
+ idtb(24); idtb(25); idtb(26); idtb(27); idtb(28); idtb(29)
+ idtb(30); idtb(31); idtb(32); idtb(33); idtb(34); idtb(35)
+ idtb(36); idtb(37); idtb(38); idtb(39); idtb(40); idtb(41)
+ idtb(42); idtb(43); idtb(44); idtb(45); idtb(46); idtb(47)
+#undef idte
+Idtr: .word . - idt - 1
+ .long idt
+ .word 0
+
+ .align 8
+Idtr_real: .word 1023
+ .long 0
+ .word 0
+
+ .align 8
+Idtr_reset: .long 0, 0
+
+ .align 8
+gdt:
+ /* 0x00 : null */
+ .space 8
+ /* 0x08 : flat code */
+ .word 0xFFFF # lolimit
+ .word 0 # lobase
+ .byte 0 # midbase
+ .byte SDT_MEMERAC | 0 | 0x80 # RXAC, dpl = 0, present
+ .byte 0xf | 0 | 0x40 | 0x80 # hilimit, xx, 32bit, 4k granularity
+ .byte 0 # hibase
+ /* 0x10 : flat data */
+ .word 0xFFFF # lolimit
+ .word 0 # lobase
+ .byte 0 # midbase
+ .byte SDT_MEMRWA | 0 | 0x80 # RWA, dpl = 0, present
+ .byte 0xf | 0 | 0x40 | 0x80 # hilimit, xx, 32bit, 4k granularity
+ .byte 0 # hibase
+ /* 0x18 : 16 bit code */
+ .word 0xFFFF # lolimit
+ .word (LINKADDR & 0xffff) # lobase
+ .byte (LINKADDR >> 16) & 0xff # midbase
+ .byte SDT_MEMERAC | 0 | 0x80 # RXAC, dpl = 0, present
+ .byte 0xf | 0 | 0 | 0 # hilimit, xx, 16bit, byte granularity
+ .byte (LINKADDR >> 20) & 0xff # hibase
+ /* 0x20 : 16 bit data */
+ .word 0xFFFF # lolimit
+ .word (LINKADDR & 0xffff) # lobase
+ .byte (LINKADDR >> 16) & 0xff # midbase
+ .byte SDT_MEMRWA | 0 | 0x80 # RWA, dpl = 0, present
+ .byte 0xf | 0 | 0 | 0 # hilimit, xx, 16bit, byte granularity
+ .byte (LINKADDR >> 20) & 0xff # hibase
+
+.globl Gdtr
+Gdtr: .word . - gdt - 1
+ .long gdt
+ .word 0
+
+#define IENTRY(name,type) \
+IPROC(name): \
+ pushl $type ; \
+ jmp 1f
+#define IENTRY_ERR(name,err,type) \
+IPROC(name): \
+ pushl $err ; \
+ pushl $type ; \
+ jmp 1f
+
+IPROC(xx):
+ pushl $1
+ pushl $T_RESERVED
+ jmp 1f
+
+IENTRY_ERR(de,0,T_DIVIDE) /* #DE divide by zero */
+IENTRY_ERR(db,0,T_TRCTRAP) /* #DB debug */
+IENTRY_ERR(nmi,0,T_NMI) /* NMI */
+IENTRY_ERR(bp,0,T_BPTFLT) /* #BP breakpoint */
+IENTRY_ERR(of,0,T_OFLOW) /* #OF overflow */
+IENTRY_ERR(br,0,T_BOUND) /* #BR BOUND range exceeded */
+IENTRY_ERR(ud,0,T_PRIVINFLT) /* #UD invalid opcode */
+IENTRY_ERR(nm,0,T_DNA) /* #NM device not available */
+IENTRY(df,T_DOUBLEFLT) /* #DF double fault */
+IENTRY_ERR(fo,0,T_FPOPFLT) /* #FO coprocessor segment overrun */
+IENTRY(ts,T_TSSFLT) /* #TS innvalid TSS */
+IENTRY(np,T_SEGNPFLT) /* #NP segmant not present */
+IENTRY(ss,T_STKFLT) /* #SS stack fault */
+IENTRY(gp,T_PROTFLT) /* #GP general protection */
+IENTRY(pf,T_PAGEFLT) /* #PF page fault */
+IENTRY_ERR(mf,0,T_ARITHTRAP) /* #MF floating point error */
+IENTRY(ac,T_ALIGNFLT) /* #AC alignment check */
+
+1:
+ cli
+ hlt
+
+#define IEMUENT(n) IEMU(n): pushl $n; jmp 1f
+
+IEMUENT(0); IEMUENT(1); IEMUENT(2); IEMUENT(3)
+IEMUENT(4); IEMUENT(5); IEMUENT(6); IEMUENT(7)
+IEMUENT(8); IEMUENT(9); IEMUENT(10); IEMUENT(11)
+IEMUENT(12); IEMUENT(13); IEMUENT(14); IEMUENT(15)
+IEMUENT(16); IEMUENT(17); IEMUENT(18); IEMUENT(19)
+IEMUENT(20); IEMUENT(21); IEMUENT(22); IEMUENT(23)
+IEMUENT(24); IEMUENT(25); IEMUENT(26); IEMUENT(27)
+IEMUENT(28); IEMUENT(29); IEMUENT(30); IEMUENT(31)
+1: jmp EMUh /* redirect for short jumps */
+IEMUENT(32); IEMUENT(33); IEMUENT(34); IEMUENT(35)
+IEMUENT(36); IEMUENT(37); IEMUENT(38); IEMUENT(39)
+IEMUENT(40); IEMUENT(41); IEMUENT(42); IEMUENT(43)
+IEMUENT(44); IEMUENT(45); IEMUENT(46); IEMUENT(47)
+1: jmp EMUh
+
+/*
+ * entry point for BIOS real-mode interface
+ * all the magic for real-prot mode switching is here
+ *
+ * Call: %eax, %ecx, %edx, %ebx, %ebp, %esi, %edi, %es, %ds
+ * Return: %eax, %edx, %ecx, %eflags (as returned from BIOS)
+ *
+ */
+ .globl EMUh
+ .align 8, 0x90
+EMUh:
+ /* save %eax */
+ mov %eax, 3f
+ pop %eax
+
+ pusha
+ push %ds
+ push %es
+ push %fs
+ push %gs
+
+ /* save BIOS int vector */
+ mov %al, intno
+
+ prot2real
+
+ push %ds
+
+ addr32 mov _C_LABEL(BIOS_regs)+(BIOSR_ES), %eax
+ mov %ax, %es
+ addr32 mov _C_LABEL(BIOS_regs)+(BIOSR_DS), %eax
+ mov %ax, %ds
+
+ # data32 movl $Leax, %eax
+ .byte 0x66, 0xb8
+3: .long 0x90909090
+
+ ;sti
+ int $0
+intno = . - 1
+ ;cli
+
+ pop %ds
+
+ addr32 mov %ebx, _C_LABEL(BIOS_regs)+(BIOSR_BX)
+ mov %es, %bx
+ addr32 mov %ebx, _C_LABEL(BIOS_regs)+(BIOSR_ES)
+ movb %ah, %bh
+ lahf
+ xchgb %ah, %bh
+
+ addr32 mov %eax, 2f
+
+ real2prot
+
+ # movl $Leax, %eax
+ .byte 0xb8
+2: .long 0x90909090
+
+ /* pass BIOS return values back to caller */
+ mov %eax, 0xb*4(%esp)
+ mov %ecx, 0xa*4(%esp)
+ mov %edx, 0x9*4(%esp)
+ movb %bh , 0xe*4(%esp)
+
+ /* clear NT flag in eflags */
+ /* Martin Fredriksson <martin@gbg.netman.se> */
+ pushf
+ pop %eax
+ and $0xffffbfff, %eax
+ push %eax
+ popf
+
+ /* save registers into save area */
+ mov %eax, _C_LABEL(BIOS_regs)+BIOSR_AX
+ mov %ecx, _C_LABEL(BIOS_regs)+BIOSR_CX
+ mov %edx, _C_LABEL(BIOS_regs)+BIOSR_DX
+ mov %ebp, _C_LABEL(BIOS_regs)+BIOSR_BP
+ mov %esi, _C_LABEL(BIOS_regs)+BIOSR_SI
+ mov %edi, _C_LABEL(BIOS_regs)+BIOSR_DI
+
+ pop %gs
+ pop %fs
+ pop %es
+ pop %ds
+ popa
+ iret
+
+/* Call buffer at 07c0:0000 in real mode to simulate a BIOS boot */
+ENTRY(bootbuf)
+ pop %eax /* Don't need return address */
+ pop %esi /* Buffer */
+ pop %edx /* Device */
+ prot2real /* Switch */
+
+ /* Set up stack */
+ cli
+ xor %ax, %ax
+ mov %ax, %ss
+ mov $0xfffc, %esp
+ sti
+
+ /* Jump to buffer */
+ ljmp $0x0, $0x7c00
+
+ .end
diff --git a/sys/arch/amd64/stand/libsa/libsa.h b/sys/arch/amd64/stand/libsa/libsa.h
new file mode 100644
index 00000000000..4c587852017
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/libsa.h
@@ -0,0 +1,62 @@
+/* $OpenBSD: libsa.h,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1996-1999 Michael Shalayeff
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 AUTHOR OR HIS RELATIVES 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 MIND, 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.
+ */
+
+#include <lib/libsa/stand.h>
+#include <machine/biosvar.h>
+
+#define DEFAULT_KERNEL_ADDRESS 0
+
+void gateA20(int);
+
+void smpprobe(void);
+void pciprobe(void);
+void memprobe(void);
+void diskprobe(void);
+void apmprobe(void);
+void apmfixmem(void);
+void dump_biosmem(bios_memmap_t *);
+int mem_add(long, long);
+int mem_delete(long, long);
+void mem_pass(void);
+
+void devboot(dev_t, char *);
+void machdep(void);
+
+void *getSYSCONFaddr(void);
+void *getEBDAaddr(void);
+
+extern const char bdevs[][4];
+extern const int nbdevs;
+extern u_int cnvmem, extmem; /* XXX global pass memprobe()->machdep_start() */
+extern int ps2model;
+
+/* diskprobe.c */
+extern bios_diskinfo_t bios_diskinfo[];
+extern u_int32_t bios_cksumlen;
+
+#define MACHINE_CMD cmd_machine /* we have i386 specific sommands */
diff --git a/sys/arch/amd64/stand/libsa/machdep.c b/sys/arch/amd64/stand/libsa/machdep.c
new file mode 100644
index 00000000000..440a14c09bd
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/machdep.c
@@ -0,0 +1,56 @@
+/* $OpenBSD: machdep.c,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1997-1999 Michael Shalayeff
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 AUTHOR OR HIS RELATIVES 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 MIND, 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.
+ */
+
+#include "libsa.h"
+#include <machine/apmvar.h>
+#include <machine/biosvar.h>
+
+volatile struct BIOS_regs BIOS_regs;
+
+#if defined(DEBUG) && !defined(_TEST)
+#define CKPT(c) (*(u_int16_t*)0xb8148 = 0x4700 + (c))
+#else
+#define CKPT(c) /* c */
+#endif
+
+extern int debug;
+int ps2model;
+
+void
+machdep(void)
+{
+ /* here */ CKPT('0');
+ printf("probing:");
+ /* probe for a model number, gateA20() neds ps2model */
+ gateA20(1); CKPT('1');
+ memprobe(); CKPT('2');
+ printf("\n");
+
+ diskprobe(); CKPT('3');
+ CKPT('Z');
+}
diff --git a/sys/arch/amd64/stand/libsa/memprobe.c b/sys/arch/amd64/stand/libsa/memprobe.c
new file mode 100644
index 00000000000..58543d1da6b
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/memprobe.c
@@ -0,0 +1,473 @@
+/* $OpenBSD: memprobe.c,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1997-1999 Michael Shalayeff
+ * Copyright (c) 1997-1999 Tobias Weingartner
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 REGENTS 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.
+ *
+ */
+
+#include <sys/param.h>
+#include <machine/biosvar.h>
+#include <dev/isa/isareg.h>
+#include <stand/boot/bootarg.h>
+#include "libsa.h"
+
+u_int cnvmem, extmem; /* XXX - compatibility */
+
+
+/* Check gateA20
+ *
+ * A sanity check.
+ */
+static __inline int
+checkA20(void)
+{
+ register char *p = (char *)0x100000;
+ register char *q = (char *)0x000000;
+ int st;
+
+ /* Simple check */
+ if(*p != *q)
+ return(1);
+
+ /* Complex check */
+ *p = ~(*p);
+ st = (*p != *q);
+ *p = ~(*p);
+
+ return(st);
+}
+
+/* BIOS int 15, AX=E820
+ *
+ * This is the "preferred" method.
+ */
+static __inline bios_memmap_t *
+bios_E820(bios_memmap_t *mp)
+{
+ void *info;
+ int rc, off = 0, sig, gotcha = 0;
+ info = getEBDAaddr();
+
+ do {
+ BIOS_regs.biosr_es = ((u_int)(mp) >> 4);
+ __asm __volatile(DOINT(0x15) "; setc %b1"
+ : "=a" (sig), "=d" (rc), "=b" (off)
+ : "0" (0xE820), "1" (0x534d4150), "b" (off),
+ "c" (sizeof(*mp)), "D" (((u_int)mp) & 0xF)
+ : "cc", "memory");
+ off = BIOS_regs.biosr_bx;
+
+ if (rc & 0xff || sig != 0x534d4150)
+ break;
+ gotcha++;
+ if (!mp->type)
+ mp->type = BIOS_MAP_RES;
+ mp++;
+ } while (off);
+
+ if (!gotcha)
+ return (NULL);
+#ifdef DEBUG
+ printf("0x15[E820] ");
+#endif
+ return (mp);
+}
+
+#if 0
+/* BIOS int 15, AX=E801
+ *
+ * Only used if int 15, AX=E820 does not work.
+ * This should work for more than 64MB on most
+ * modern machines. However, there is always
+ * an exception, the older IBM machine do not
+ * like this call.
+ */
+static __inline bios_memmap_t *
+bios_E801(bios_memmap_t *mp)
+{
+ int rc, m1, m2, m3, m4;
+ u_int8_t *info;
+
+ /* Test for possibility of 0xE801 */
+ info = getSYSCONFaddr();
+ if(!info) return(NULL);
+ /* XXX - Should test model/submodel/rev here */
+ printf("model(%d,%d,%d)", info[2], info[3], info[4]);
+
+ /* Check for 94 or later bios */
+ info = (void *)0xFFFFB;
+ if(info[0] == '9' && info[1] <= '3') return(NULL);
+
+ /* We might have this call */
+ __asm __volatile(DOINT(0x15) "; mov %%ax, %%si; setc %b0"
+ : "=a" (rc), "=S" (m1), "=b" (m2), "=c" (m3), "=d" (m4)
+ : "0" (0xE801));
+
+ /* Test for failure */
+ if(rc & 0xff)
+ return (NULL);
+
+ /* Fixup for screwed up machines */
+ if(m1 == 0){
+ m1 = m3;
+ m2 = m4;
+ }
+#ifdef DEBUG
+ printf("0x15[E801] ");
+#endif
+ /* Fill out BIOS map */
+ mp->addr = (1024 * 1024); /* 1MB */
+ mp->size = (m1 & 0xffff) * 1024;
+ mp->type = BIOS_MAP_FREE;
+
+ mp++;
+ mp->addr = (1024 * 1024) * 16; /* 16MB */
+ mp->size = (m2 & 0xffff) * 64L * 1024;
+ mp->type = BIOS_MAP_FREE;
+
+ return ++mp;
+}
+#endif
+
+/* BIOS int 15, AX=8800
+ *
+ * Only used if int 15, AX=E801 does not work.
+ * Machines with this are restricted to 64MB.
+ */
+static __inline bios_memmap_t *
+bios_8800(bios_memmap_t *mp)
+{
+ int rc, mem;
+
+ __asm __volatile(DOINT(0x15) "; setc %b0"
+ : "=c" (rc), "=a" (mem) : "a" (0x8800));
+
+ if(rc & 0xff)
+ return (NULL);
+#ifdef DEBUG
+ printf("0x15[8800] ");
+#endif
+ /* Fill out a BIOS_MAP */
+ mp->addr = 1024 * 1024; /* 1MB */
+ mp->size = (mem & 0xffff) * 1024;
+ mp->type = BIOS_MAP_FREE;
+
+ return ++mp;
+}
+
+/* BIOS int 0x12 Get Conventional Memory
+ *
+ * Only used if int 15, AX=E820 does not work.
+ */
+static __inline bios_memmap_t *
+bios_int12(bios_memmap_t *mp)
+{
+ int mem;
+#ifdef DEBUG
+ printf("0x12 ");
+#endif
+ __asm __volatile(DOINT(0x12) : "=a" (mem) :: "%ecx", "%edx", "cc");
+
+ /* Fill out a bios_memmap_t */
+ mp->addr = 0;
+ mp->size = (mem & 0xffff) * 1024;
+ mp->type = BIOS_MAP_FREE;
+
+ return ++mp;
+}
+
+
+/* addrprobe(kloc): Probe memory at address kloc * 1024.
+ *
+ * This is a hack, but it seems to work ok. Maybe this is
+ * the *real* way that you are supposed to do probing???
+ *
+ * Modify the original a bit. We write everything first, and
+ * then test for the values. This should croak on machines that
+ * return values just written on non-existent memory...
+ *
+ * BTW: These machines are pretty broken IMHO.
+ *
+ * XXX - Does not detect aliased memory.
+ */
+const u_int addrprobe_pat[] = {
+ 0x00000000, 0xFFFFFFFF,
+ 0x01010101, 0x10101010,
+ 0x55555555, 0xCCCCCCCC
+};
+static int
+addrprobe(u_int kloc)
+{
+ __volatile u_int *loc;
+ register u_int i, ret = 0;
+ u_int save[NENTS(addrprobe_pat)];
+
+ /* Get location */
+ loc = (int *)(kloc * 1024);
+
+ save[0] = *loc;
+ /* Probe address */
+ for(i = 0; i < NENTS(addrprobe_pat); i++){
+ *loc = addrprobe_pat[i];
+ if(*loc != addrprobe_pat[i])
+ ret++;
+ }
+ *loc = save[0];
+
+ if (!ret) {
+ /* Write address */
+ for(i = 0; i < NENTS(addrprobe_pat); i++) {
+ save[i] = loc[i];
+ loc[i] = addrprobe_pat[i];
+ }
+
+ /* Read address */
+ for(i = 0; i < NENTS(addrprobe_pat); i++) {
+ if(loc[i] != addrprobe_pat[i])
+ ret++;
+ loc[i] = save[i];
+ }
+ }
+
+ return ret;
+}
+
+/* Probe for all extended memory.
+ *
+ * This is only used as a last resort. If we resort to this
+ * routine, we are getting pretty desperate. Hopefully nobody
+ * has to rely on this after all the work above.
+ *
+ * XXX - Does not detect aliased memory.
+ * XXX - Could be destructive, as it does write.
+ */
+static __inline bios_memmap_t *
+badprobe(bios_memmap_t *mp)
+{
+ u_int64_t ram;
+#ifdef DEBUG
+ printf("scan ");
+#endif
+ /* probe extended memory
+ *
+ * There is no need to do this in assembly language. This is
+ * much easier to debug in C anyways.
+ */
+ for(ram = 1024; ram < 512 * 1024; ram += 4)
+ if(addrprobe(ram))
+ break;
+
+ mp->addr = 1024 * 1024;
+ mp->size = (ram - 1024) * 1024;
+ mp->type = BIOS_MAP_FREE;
+
+ return ++mp;
+}
+
+bios_memmap_t bios_memmap[32]; /* This is easier */
+#ifndef _TEST
+void
+memprobe(void)
+{
+ bios_memmap_t *pm = bios_memmap, *im;
+
+#ifdef DEBUG
+ printf(" mem(");
+#else
+ printf(" mem[");
+#endif
+
+ if(!(pm = bios_E820(bios_memmap))) {
+ im = bios_int12(bios_memmap);
+#if 0
+ pm = bios_E801(im);
+ if (!pm)
+#endif
+ pm = bios_8800(im);
+ if (!pm)
+ pm = badprobe(im);
+ if (!pm) {
+ printf (" No Extended memory detected.");
+ pm = im;
+ }
+ }
+ pm->type = BIOS_MAP_END;
+
+ /* XXX - gotta peephole optimize the list */
+
+#ifdef DEBUG
+ printf(")[");
+#endif
+
+ /* XXX - Compatibility, remove later (smpprobe() relies on it) */
+ extmem = cnvmem = 0;
+ for(im = bios_memmap; im->type != BIOS_MAP_END; im++) {
+ /* Count only "good" memory chunks 12K and up in size */
+ if ((im->type == BIOS_MAP_FREE) && (im->size >= 12*1024)) {
+ if (im->size > 1024 * 1024)
+ printf("%uM ", (u_int)im->size / (1024 * 1024));
+ else
+ printf("%uK ", (u_int)im->size / 1024);
+
+ /*
+ * Compute compatibility values:
+ * cnvmem -- is the upper boundary of conventional
+ * memory (below IOM_BEGIN (=640k))
+ * extmem -- is the size of the contignous extended
+ * memory segment starting at 1M
+ *
+ * We ignore "good" memory in the 640K-1M hole.
+ * We drop "machine {cnvmem,extmem}" commands.
+ */
+ if(im->addr < IOM_BEGIN)
+ cnvmem = max(cnvmem,
+ im->addr + im->size) / 1024;
+ if(im->addr >= IOM_END)
+ extmem += im->size / 1024;
+ }
+ }
+
+ /* Check if gate A20 is on */
+ printf("a20=o%s] ", checkA20()? "n" : "ff!");
+}
+#endif
+
+void
+dump_biosmem(bios_memmap_t *tm)
+{
+ register bios_memmap_t *p;
+ register u_int total = 0;
+
+ if (!tm)
+ tm = bios_memmap;
+
+ /* libsa printf does not handle quad args, so we use long
+ * instead. Note, since we're unlikely to support more than
+ * 4G of RAM on a x86 box, this not likely to cause a problem.
+ * If/when we do, libsa may need to be updated some...
+ */
+ for(p = tm; p->type != BIOS_MAP_END; p++) {
+ printf("Region %ld: type %u at 0x%x for %uKB\n",
+ (long)(p - tm), p->type, (u_int)p->addr,
+ (u_int)(p->size / 1024));
+
+ if(p->type == BIOS_MAP_FREE)
+ total += p->size / 1024;
+ }
+
+ printf("Low ram: %dKB High ram: %dKB\n", cnvmem, extmem);
+ printf("Total free memory: %uKB\n", total);
+}
+
+int
+mem_delete(long sa, long ea)
+{
+ register bios_memmap_t *p;
+
+ for (p = bios_memmap; p->type != BIOS_MAP_END; p++) {
+ if (p->type == BIOS_MAP_FREE) {
+ register int64_t sp = p->addr, ep = p->addr + p->size;
+
+ /* can we eat it as a whole? */
+ if ((sa - sp) <= NBPG && (ep - ea) <= NBPG) {
+ bcopy (p + 1, p, (char *)bios_memmap +
+ sizeof(bios_memmap) - (char *)p);
+ break;
+ /* eat head or legs */
+ } else if (sa <= sp && sp < ea) {
+ p->addr = ea;
+ p->size = ep - ea;
+ break;
+ } else if (sa < ep && ep <= ea) {
+ p->size = sa - sp;
+ break;
+ } else if (sp < sa && ea < ep) {
+ /* bite in half */
+ bcopy (p, p + 1, (char *)bios_memmap +
+ sizeof(bios_memmap) - (char *)p -
+ sizeof(bios_memmap[0]));
+ p[1].addr = ea;
+ p[1].size = ep - ea;
+ p->size = sa - sp;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+int
+mem_add(long sa, long ea)
+{
+ register bios_memmap_t *p;
+
+ for (p = bios_memmap; p->type != BIOS_MAP_END; p++) {
+ if (p->type == BIOS_MAP_FREE) {
+ register int64_t sp = p->addr, ep = p->addr + p->size;
+
+ /* is it already there? */
+ if (sp <= sa && ea <= ep) {
+ break;
+ /* join head or legs */
+ } else if (sa < sp && sp <= ea) {
+ p->addr = sa;
+ p->size = ep - sa;
+ break;
+ } else if (sa <= ep && ep < ea) {
+ p->size = ea - sp;
+ break;
+ } else if (ea < sp) {
+ /* insert before */
+ bcopy (p, p + 1, (char *)bios_memmap +
+ sizeof(bios_memmap) - (char *)(p - 1));
+ p->addr = sa;
+ p->size = ea - sa;
+ break;
+ }
+ }
+ }
+
+ /* meaning add new item at the end of the list */
+ if (p->type == BIOS_MAP_END) {
+ p[1] = p[0];
+ p->type = BIOS_MAP_FREE;
+ p->addr = sa;
+ p->size = ea - sa;
+ }
+
+ return 0;
+}
+
+void
+mem_pass(void)
+{
+ bios_memmap_t *p;
+
+ for (p = bios_memmap; p->type != BIOS_MAP_END; p++)
+ ;
+ addbootarg(BOOTARG_MEMMAP, (p - bios_memmap + 1) * sizeof *bios_memmap,
+ bios_memmap);
+}
diff --git a/sys/arch/amd64/stand/libsa/time.c b/sys/arch/amd64/stand/libsa/time.c
new file mode 100644
index 00000000000..e79698f1fac
--- /dev/null
+++ b/sys/arch/amd64/stand/libsa/time.c
@@ -0,0 +1,147 @@
+/* $OpenBSD: time.c,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1997 Michael Shalayeff
+ * Copyright (c) 1997 Tobias Weingartner
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 REGENTS 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.
+ *
+ */
+
+#include <sys/time.h>
+#include <machine/biosvar.h>
+#include <machine/pio.h>
+#include "libsa.h"
+#include "biosdev.h"
+
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
+/*
+ * Convert from bcd (packed) to int
+ */
+static __inline u_int8_t
+bcdtoint(u_int8_t c)
+{
+
+ return ((c & 0xf0) / 8) * 5 + (c & 0x0f);
+}
+
+/*
+ * Quick compute of time in seconds since the Epoch
+ */
+const u_short monthcount[] = {
+ 0, 0, 31, 59, 90, 120, 151, 181,
+ 212, 243, 273, 304, 334, 365
+};
+
+static __inline time_t
+compute(int year, u_int8_t month, u_int8_t day, u_int8_t hour,
+ u_int8_t min, u_int8_t sec)
+{
+ /* Number of days per month */
+ register time_t tt;
+
+ /* Compute days */
+ tt = (year - 1970) * 365 + monthcount[month] + day;
+
+ /* Compute for leap year */
+ for(month <= 2? year--:0;year >= 1970;year--)
+ if(isleap(year))
+ tt++;
+
+ /* Plus the time */
+ tt = sec + 60 * (min + 60 * (tt * 24 + hour));
+
+ return tt;
+}
+
+static int
+bios_time_date(int f, u_int8_t *b)
+{
+ __asm __volatile(DOINT(0x1a) "\n\t"
+ "setc %b0\n\t"
+ "movb %%ch, 0(%2)\n\t"
+ "movb %%cl, 1(%2)\n\t"
+ "movb %%dh, 2(%2)\n\t"
+ "movb %%dl, 3(%2)\n\t"
+ : "=a" (f)
+ : "0" (f), "p" (b) : "%ecx", "%edx", "cc");
+ if (f & 0xff)
+ return -1;
+ else {
+ b[0] = bcdtoint(b[0]);
+ b[1] = bcdtoint(b[1]);
+ b[2] = bcdtoint(b[2]);
+ b[3] = bcdtoint(b[3]);
+ return 0;
+ }
+}
+
+static __inline int
+biosdate(u_int8_t *b)
+{
+ return bios_time_date(4 << 8, b);
+}
+
+static __inline int
+biostime(u_int8_t *b)
+{
+ return bios_time_date(2 << 8, b);
+}
+
+/*
+ * Return time since epoch
+ */
+time_t
+getsecs(void)
+{
+ u_int8_t timebuf[4], datebuf[4];
+
+ /* Query BIOS for time & date */
+ if(!biostime(timebuf) && !biosdate(datebuf)) {
+#ifdef notdef
+ int dst;
+
+ dst = timebuf[3];
+#endif
+ /* Convert to seconds since Epoch */
+ return compute(datebuf[0] * 100 + datebuf[1],
+ datebuf[2], datebuf[3],
+ timebuf[0], timebuf[1], timebuf[2]);
+ } else
+ errno = EIO;
+
+ return(1);
+}
+
+u_int
+sleep(u_int i)
+{
+ register time_t t;
+
+ /* loop for that number of seconds, polling BIOS,
+ so that it may handle interrupts */
+ for (t = getsecs() + i; getsecs() < t; cnischar());
+
+ return 0;
+}
diff --git a/sys/arch/amd64/stand/mbr/Makefile b/sys/arch/amd64/stand/mbr/Makefile
new file mode 100644
index 00000000000..670c731871c
--- /dev/null
+++ b/sys/arch/amd64/stand/mbr/Makefile
@@ -0,0 +1,29 @@
+# $OpenBSD: Makefile,v 1.1 2004/02/03 12:09:47 mickey Exp $
+#
+
+PROG= mbr
+SRCS= mbr.S
+AFLAGS+=-m32 -I${.CURDIR} -I${.CURDIR}/../../.. #-Wa,-a
+LD=ld
+LDFLAGS=-melf_i386 -nostdlib -Ttext 0 -x -N -s -Bstatic -e start
+
+NOMAN=
+#MAN+= mbr.8
+
+INSTALL_STRIP=
+SADIR=${.CURDIR}/..
+S= ${.CURDIR}/../../../..
+
+# Uncomment this to make mbr talk to a serial port.
+#CPPFLAGS+=-DSERIAL=0
+
+${PROG}: $(OBJS) $(DPADD)
+ $(LD) $(LDFLAGS) -o $(PROG) $(OBJS) $(LDADD)
+ #@size $(PROG)
+ @if [ -x ${.OBJDIR}/${PROG} ]; then \
+ objcopy -O binary ${PROG} ${.OBJDIR}/.tmp;\
+ mv -f ${.OBJDIR}/.tmp ${.OBJDIR}/${PROG}; \
+ ls -l ${.OBJDIR}/${PROG}; \
+ fi
+
+.include <bsd.prog.mk>
diff --git a/sys/arch/amd64/stand/mbr/mbr.S b/sys/arch/amd64/stand/mbr/mbr.S
new file mode 100644
index 00000000000..b7553ead71a
--- /dev/null
+++ b/sys/arch/amd64/stand/mbr/mbr.S
@@ -0,0 +1,570 @@
+/* $OpenBSD: mbr.S,v 1.1 2004/02/03 12:09:47 mickey Exp $ */
+
+/*
+ * Copyright (c) 1997 Michael Shalayeff and Tobias Weingartner
+ * Copyright (c) 2003 Tom Cosgrove <tom.cosgrove@arches-consulting.com>
+ * All rights reserved.
+ *
+ * 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 AUTHOR ``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 REGENTS 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.
+ *
+ */
+/* Copyright (c) 1996 VaX#n8 (vax@linkdead.paranoia.com)
+ * last edited 9 July 1996
+ * many thanks to Erich Boleyn (erich@uruk.org) for putting up with
+ * all my questions, and for his work on GRUB
+ * You may use this code or fragments thereof in a manner consistent
+ * with the other copyrights as long as you retain my pseudonym and
+ * this copyright notice in the file.
+ */
+
+ .file "mbr.S"
+
+#include <machine/asm.h>
+#include <assym.h>
+
+/*
+ * Memory layout:
+ *
+ * 0x07C00 -> 0x07DFF BIOS loads us here (at 31k)
+ * 0x07E00 -> 0x17BFC our stack (to 95k)
+ *
+ * 0x07A00 -> 0x07BFF we relocate to here (at 30k5)
+ *
+ * 0x07C00 -> 0x07DFF we load PBR here (at 31k)
+ *
+ * The BIOS loads us at physical address 0x07C00. We use a long jmp to
+ * normalise our address to seg:offset 07C0:0000. We then relocate to
+ * 0x07A00, seg:offset 07A0:0000.
+ *
+ * We use a long jmp to normalise our address to seg:offset 07A0:0000
+ * We set the stack to start at 07C0:FFFC (grows down on i386)
+ * We load the partition boot record (PBR) /boot at seg:offset 4000:0000
+ */
+#define BOOTSEG 0x7c0 /* segment where we are loaded */
+#define BOOTRELOCSEG 0x7a0 /* segment where we relocate to */
+#define BOOTSTACKOFF 0xfffc /* stack starts here, grows down */
+#define PARTSZ 16 /* each partition table entry is 16 bytes */
+
+#define CHAR_LBA_READ '.'
+#define CHAR_CHS_READ ';'
+#define CHAR_CHS_FORCE '!'
+#define CHAR_SHIFT_SEEN 0x07 /* Use BEL */
+
+#define MBR_FLAGS_FORCE_CHS 0x0001
+
+#ifdef DEBUG
+#define CHAR_S 'S' /* started */
+#define CHAR_R 'R' /* relocated */
+#define CHAR_L 'L' /* looking for bootable partition */
+#define CHAR_B 'B' /* loading boot */
+#define CHAR_G 'G' /* jumping to boot */
+
+#define DBGMSG(c) movb $c, %al; call Lchr
+#else /* !DEBUG */
+#define DBGMSG(c)
+#endif /* !DEBUG */
+
+/* Clobbers %al - maybe more */
+#define putc(c) movb $c, %al; call Lchr
+
+/* Clobbers %esi - maybe more */
+#define puts(s) movw $s, %si; call Lmessage
+
+
+ .text
+ .code16
+
+ .globl start
+start:
+ /* Adjust %cs to be right */
+ ljmp $BOOTSEG, $1f
+1:
+ /* Set up stack */
+ movw %cs, %ax
+
+ /*
+ * We don't need to disable and re-enable interrupts around the
+ * the load of ss and sp.
+ *
+ * From 80386 Programmer's Reference Manual:
+ * "A MOV into SS inhibits all interrupts until after the execution
+ * of the next instruction (which is presumably a MOV into eSP)"
+ *
+ * According to Hamarsoft's 86BUGS list (which is distributed with
+ * Ralph Brown's Interrupt List), some early 8086/88 processors
+ * failed to disable interrupts following a load into a segment
+ * register, but this was fixed with later steppings.
+ *
+ * Accordingly, this code will fail on very early 8086/88s, but
+ * nick@ will just have to live with it. Others will note that
+ * we require an 80386 (or compatible) or above processor, anyway.
+ */
+ /* cli */
+ movw %ax, %ss
+ movw $BOOTSTACKOFF, %sp
+ /* sti */ /* XXX not necessary; see above */
+
+ /* Set up data segment */
+ movw %ax, %ds
+ DBGMSG(CHAR_S)
+
+ /*
+ * On the PC architecture, the boot record (originally on a floppy
+ * disk) is loaded at 0000:7C00 (hex) and execution starts at the
+ * beginning.
+ *
+ * When hard disk support was added, a scheme to partition disks into
+ * four separate partitions was used, to allow multiple operating
+ * systems to be installed on the one disk. The boot sectors of the
+ * operating systems on each partition would of course expect to be
+ * loaded at 0000:7C00.
+ *
+ * The first sector of the hard disk is the master boot record (MBR).
+ * It is this which defines the partitions and says which one is
+ * bootable. Of course, the BIOS loads the MBR at 0000:7C00, the
+ * same location where the MBR needs to load the partition boot
+ * record (PBR, called biosboot in OpenBSD).
+ *
+ * Therefore, the MBR needs to relocate itself before loading the PBR.
+ *
+ * Make it so.
+ */
+ movw $BOOTRELOCSEG, %ax
+ movw %ax, %es
+ xorw %si, %si
+ xorw %di, %di
+ movw $0x200, %cx /* Bytes in MBR, relocate it all */
+ cld
+ rep
+ movsb
+
+ /* Jump to relocated self */
+ ljmp $BOOTRELOCSEG, $reloc
+reloc:
+ DBGMSG(CHAR_R)
+
+ /* Set up %es and %ds */
+ pushw %ds
+ popw %es /* next boot is at the same place as we were loaded */
+ pushw %cs
+ popw %ds /* and %ds is at the %cs */
+
+#ifdef SERIAL
+ /* Initialize the serial port to 9600 baud, 8N1.
+ */
+ xorw %ax, %ax
+ movb $0xe3, %ax
+ movw $SERIAL, %dx
+ int $0x14
+#endif
+
+ /*
+ * If the SHIFT key is held down on entry, force CHS read
+ */
+
+ /*
+ * BIOS call "INT 0x16 Get Keyboard Shift Flags
+ * Call with %ah = 0x02
+ * Return:
+ * %al = shift flags
+ * %ah - undefined by many BIOSes
+ */
+ movb $0x02, %ah
+ int $0x16
+ testb $0x3, %al /* Either shift key down? */
+ jz no_shift
+
+ putc(CHAR_SHIFT_SEEN) /* Signal that shift key was seen */
+
+ orb $MBR_FLAGS_FORCE_CHS, flags
+
+no_shift:
+ /* BIOS passes us drive number in %dl
+ *
+ * XXX - This is not always true. We currently check if %dl
+ * points to a HD, and if not we complain, and set it to point
+ * to the first HDD. Note, this is not 100% correct, since
+ * there is a possibility that you boot of of HD #2, and still
+ * get (%dl & 0x80) == 0x00, these type of systems will lose.
+ */
+ testb $0x80, %dl
+ jnz drive_ok
+
+ /* MBR on floppy or old BIOS
+ * Note: MBR (this code) should never be on a floppy. It does
+ * not belong there, so %dl should never be 0x00.
+ *
+ * Here we simply complain (should we?), and then hardcode the
+ * boot drive to 0x80.
+ */
+ puts(efdmbr)
+
+ /* If we are passed bogus data, set it to HD #1
+ */
+ movb $0x80, %dl
+
+drive_ok:
+ /* Find the first active partition.
+ * Note: this should be the only active partition. We currently
+ * don't check for that.
+ */
+ movw $pt, %si
+
+ movw $NDOSPART, %cx
+find_active:
+ DBGMSG(CHAR_L)
+ movb (%si), %al
+
+ cmpb $DOSACTIVE, %al
+ je found
+
+ addw $PARTSZ, %si
+ loop find_active
+
+ /* No bootable partition */
+no_part:
+ movw $enoboot, %si
+
+err_stop:
+ call Lmessage
+
+stay_stopped:
+ cli
+ hlt
+ /* Just to make sure */
+ jmp stay_stopped
+
+found:
+ /*
+ * Found bootable partition
+ */
+
+ DBGMSG(CHAR_B)
+
+ /* Store the drive number (from %dl) in decimal */
+ movb %dl, %al
+ andb $0x0F, %al
+ addb $'0', %al
+ movb %al, drive_num
+
+ /*
+ * Store the partition number, in decimal.
+ *
+ * We started with cx = 4; if found we want part '0'
+ * cx = 3; part '1'
+ * cx = 2; part '2'
+ * cx = 1; part '3'
+ *
+ * We'll come into this with no other values for cl.
+ */
+ movb $'0'+4, %al
+ subb %cl, %al
+ movb %al, part_num
+
+ /*
+ * Tell operator what partition we're trying to boot.
+ *
+ * Using drive X, partition Y
+ * - this used to be printed out after successfully loading the
+ * partition boot record; we now print it out before
+ */
+ pushw %si
+ movw $info, %si
+ testb $MBR_FLAGS_FORCE_CHS, flags
+ jnz 1f
+ incw %si
+1:
+ call Lmessage
+ popw %si
+
+ /*
+ * Partition table entry format:
+ *
+ * 0x00 BYTE boot indicator (0x80 = active, 0x00 = inactive)
+ * 0x01 BYTE start head
+ * 0x02 WORD start cylinder, sector
+ * 0x04 BYTE system type (0xA6 = OpenBSD)
+ * 0x05 BYTE end head
+ * 0x06 WORD end cylinder, sector
+ * 0x08 LONG start LBA sector
+ * 0x0C LONG number of sectors in partition
+ *
+ * In the case of a partition that extends beyond the 8GB boundary,
+ * the LBA values will be correct, the CHS values will have their
+ * maximums (typically (C,H,S) = (1023,255,63)).
+ *
+ * %ds:%si points to the active partition table entry.
+ */
+
+ /* We will load the partition boot sector (biosboot) where we
+ * were originally loaded. We'll check to make sure something
+ * valid comes in. So that we don't find ourselves, zero out
+ * the signature at the end.
+ */
+ movw $0, %es:signature(,1)
+
+ /*
+ * Have we been instructed to ignore LBA?
+ */
+ testb $MBR_FLAGS_FORCE_CHS, flags
+ jnz do_chs
+
+ /*
+ * We will use the LBA sector number if we have LBA support,
+ * so find out.
+ */
+
+ /*
+ * BIOS call "INT 0x13 Extensions Installation Check"
+ * Call with %ah = 0x41
+ * %bx = 0x55AA
+ * %dl = drive (0x80 for 1st hd, 0x81 for 2nd, etc)
+ * Return:
+ * carry set: failure
+ * %ah = error code (0x01, invalid func)
+ * carry clear: success
+ * %bx = 0xAA55 (must verify)
+ * %ah = major version of extensions
+ * %al (internal use)
+ * %cx = capabilities bitmap
+ * 0x0001 - extnd disk access funcs
+ * 0x0002 - rem. drive ctrl funcs
+ * 0x0004 - EDD functions with EBP
+ * %dx (extension version?)
+ */
+
+ movb %dl, (%si) /* Store drive here temporarily */
+ /* (This call trashes %dl) */
+ /*
+ * XXX This is actually the correct
+ * place to store this. The 0x80
+ * value used to indicate the
+ * active partition is by intention
+ * the same as the BIOS drive value
+ * for the first hard disk (0x80).
+ * At one point, 0x81 would go here
+ * for the second hard disk; the
+ * 0x80 value is often used as a
+ * bit flag for testing, rather
+ * than an exact byte value.
+ */
+ movw $0x55AA, %bx
+ movb $0x41, %ah
+ int $0x13
+
+ movb (%si), %dl /* Get back drive number */
+
+ jc do_chs /* Did the command work? Jump if not */
+ cmpw $0xAA55, %bx /* Check that bl, bh exchanged */
+ jne do_chs /* If not, don't have EDD extensions */
+ testb $0x01, %cl /* And do we have "read" available? */
+ jz do_chs /* Again, use CHS if not */
+
+do_lba:
+ /*
+ * BIOS call "INT 0x13 Extensions Extended Read"
+ * Call with %ah = 0x42
+ * %dl = drive (0x80 for 1st hd, 0x81 for 2nd, etc)
+ * %ds:%si = segment:offset of command packet
+ * Return:
+ * carry set: failure
+ * %ah = error code (0x01, invalid func)
+ * command packet's sector count field set
+ * to the number of sectors successfully
+ * transferred
+ * carry clear: success
+ * %ah = 0 (success)
+ * Command Packet:
+ * 0x0000 BYTE packet size (0x10 or 0x18)
+ * 0x0001 BYTE reserved (should be 0)
+ * 0x0002 WORD sectors to transfer (max 127)
+ * 0x0004 DWORD seg:offset of transfer buffer
+ * 0x0008 QWORD starting sector number
+ */
+ movb $CHAR_LBA_READ, %al
+ call Lchr
+
+ /* Load LBA sector number from active partition table entry */
+ movl 8(%si), %ecx
+ movl %ecx, lba_sector
+
+ pushw %si /* We'll need %si later */
+
+ movb $0x42, %ah
+ movw $lba_command, %si
+ int $0x13
+
+ popw %si /* (get back %si) flags unchanged */
+
+ jnc booting_os /* If it worked, run the pbr we got */
+
+ /*
+ * LBA read failed, fall through to try CHS read
+ */
+
+do_chs:
+ /*
+ * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into
+ * memory
+ * Call with %ah = 0x2
+ * %al = number of sectors
+ * %ch = cylinder & 0xFF
+ * %cl = sector (0-63) | rest of cylinder bits
+ * %dh = head
+ * %dl = drive (0x80 for hard disk)
+ * %es:%bx = segment:offset of buffer
+ * Return:
+ * carry set: failure
+ * %ah = err code
+ * %al = number of sectors transferred
+ * carry clear: success
+ * %al = 0x0 OR number of sectors transferred
+ * (depends on BIOS!)
+ * (according to Ralph Brown Int List)
+ */
+ movb $CHAR_CHS_READ, %al
+ call Lchr
+
+ /* Load values from active partition table entry */
+ movb 1(%si), %dh /* head */
+ movw 2(%si), %cx /* sect, cyl */
+ movw $0x201, %ax /* function and number of blocks */
+ xorw %bx, %bx /* put it at %es:0 */
+ int $0x13
+ jnc booting_os
+
+read_error:
+ movw $eread, %si
+ jmp err_stop
+
+booting_os:
+ puts(crlf)
+ DBGMSG(CHAR_G)
+
+ /*
+ * Make sure the pbr we loaded has a valid signature at the end.
+ * This also ensures that something did load where we were expecting
+ * it, as there's still a copy of our code there...
+ */
+ cmpw $DOSMBR_SIGNATURE, %es:signature(,1)
+ jne missing_os
+
+ /* jump to the new code (%ds:%si is at the right point) */
+ ljmp $0, $BOOTSEG << 4
+ /* not reached */
+
+missing_os:
+ movw $enoos, %si
+ jmp err_stop
+
+/*
+ * Display string
+ */
+Lmessage:
+ pushw %ax
+ cld
+1:
+ lodsb /* %al = *%si++ */
+ testb %al, %al
+ jz 1f
+ call Lchr
+ jmp 1b
+
+/*
+ * Lchr: write the error message in %ds:%si to console
+ */
+Lchr:
+ pushw %ax
+
+#ifdef SERIAL
+ pushw %dx
+ movb $0x01, %ah
+ movw SERIAL, %dx
+ int $0x14
+ popw %dx
+#else
+ pushw %bx
+ movb $0x0e, %ah
+ movw $1, %bx
+ int $0x10
+ popw %bx
+#endif
+1: popw %ax
+ ret
+
+/* command packet for LBA read of boot sector */
+lba_command:
+ .byte 0x10 /* size of command packet */
+ .byte 0x00 /* reserved */
+ .word 0x0001 /* sectors to transfer, just 1 */
+ .word 0 /* target buffer, offset */
+ .word BOOTSEG /* target buffer, segment */
+lba_sector:
+ .long 0, 0 /* sector number */
+
+/* Info messages */
+info: .ascii "!Using drive "
+drive_num:
+ .byte 'X'
+ .ascii ", partition "
+part_num:
+ .asciz "Y"
+
+/* Error messages */
+efdmbr: .asciz "MBR on floppy or old BIOS\r\n"
+eread: .asciz "\r\nRead error\r\n"
+enoos: .asciz "No O/S\r\n"
+enoboot: .ascii "No active partition" /* runs into crlf... */
+crlf: .asciz "\r\n"
+
+endofcode:
+ nop
+
+/* We're going to store a flags word here */
+
+ . = 0x1b4
+flags:
+ .word 0x0000
+ .ascii "Ox" /* Indicate that the two bytes */
+ /* before us are the flags word */
+
+/* (MBR) NT disk signature offset */
+ . = 0x1b8
+ .space 4, 0
+
+/* partition table */
+/* flag, head, sec, cyl, type, ehead, esect, ecyl, start, len */
+ . = DOSPARTOFF /* starting address of partition table */
+pt:
+ .byte 0x0,0,0,0,0,0,0,0
+ .long 0,0
+ .byte 0x0,0,0,0,0,0,0,0
+ .long 0,0
+ .byte 0x0,0,0,0,0,0,0,0
+ .long 0,0
+ .byte DOSACTIVE,0,1,0,DOSPTYP_OPENBSD,255,255,255
+ .long 0,0x7FFFFFFF
+/* the last 2 bytes in the sector 0 contain the signature */
+ . = 0x1fe
+signature:
+ .short DOSMBR_SIGNATURE
+ . = 0x200