diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 2004-02-03 12:09:48 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 2004-02-03 12:09:48 +0000 |
commit | ee64ff9774a8a97d8ac9159076e5aa096f4b0465 (patch) | |
tree | 56c0a44d5a11182f89b55b68c79f750f9a093bc6 | |
parent | 74d9ef0d94f422fd01f5c329723d4a06537c0884 (diff) |
das boot; das cloned das from das i386
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 |