summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordfr <dfr@FreeBSD.org>2011-06-30 16:08:56 +0000
committerdfr <dfr@FreeBSD.org>2011-06-30 16:08:56 +0000
commit2b9b009195e403f0f2fc9bf0d9eeefc2297d94b8 (patch)
treea32b66abbdbc4e1ab303ad37461df4652cb74043
parent4d4c5b3285343962855e4ac2e891fc6711595b64 (diff)
downloadFreeBSD-src-2b9b009195e403f0f2fc9bf0d9eeefc2297d94b8.zip
FreeBSD-src-2b9b009195e403f0f2fc9bf0d9eeefc2297d94b8.tar.gz
Add a version of the FreeBSD bootloader which can run in userland, packaged
as a shared library. This is intended to be used by BHyVe to load FreeBSD kernels into new virtual machines.
-rw-r--r--sys/boot/Makefile.amd641
-rw-r--r--sys/boot/common/Makefile.inc2
-rw-r--r--sys/boot/common/disk.c788
-rw-r--r--sys/boot/common/disk.h99
-rw-r--r--sys/boot/common/load_elf.c2
-rw-r--r--sys/boot/common/reloc_elf.c2
-rw-r--r--sys/boot/ficl/amd64/sysdep.c101
-rw-r--r--sys/boot/ficl/amd64/sysdep.h434
-rw-r--r--sys/boot/i386/libi386/bioscd.c6
-rw-r--r--sys/boot/userboot/Makefile8
-rw-r--r--sys/boot/userboot/ficl/Makefile73
-rw-r--r--sys/boot/userboot/libstand/Makefile161
-rw-r--r--sys/boot/userboot/libstand/amd64/_setjmp.S93
-rw-r--r--sys/boot/userboot/test/Makefile15
-rw-r--r--sys/boot/userboot/test/test.c428
-rw-r--r--sys/boot/userboot/userboot.h178
-rw-r--r--sys/boot/userboot/userboot/Makefile61
-rw-r--r--sys/boot/userboot/userboot/autoload.c35
-rw-r--r--sys/boot/userboot/userboot/bootinfo.c192
-rw-r--r--sys/boot/userboot/userboot/bootinfo32.c264
-rw-r--r--sys/boot/userboot/userboot/bootinfo64.c304
-rw-r--r--sys/boot/userboot/userboot/conf.c93
-rw-r--r--sys/boot/userboot/userboot/copy.c74
-rw-r--r--sys/boot/userboot/userboot/devicename.c274
-rw-r--r--sys/boot/userboot/userboot/elf32_freebsd.c99
-rw-r--r--sys/boot/userboot/userboot/elf64_freebsd.c172
-rw-r--r--sys/boot/userboot/userboot/host.c198
-rw-r--r--sys/boot/userboot/userboot/libuserboot.h67
-rw-r--r--sys/boot/userboot/userboot/main.c177
-rw-r--r--sys/boot/userboot/userboot/userboot_cons.c86
-rw-r--r--sys/boot/userboot/userboot/userboot_disk.c146
-rw-r--r--sys/boot/userboot/userboot/version4
32 files changed, 4633 insertions, 4 deletions
diff --git a/sys/boot/Makefile.amd64 b/sys/boot/Makefile.amd64
index 256201d..b9e1609 100644
--- a/sys/boot/Makefile.amd64
+++ b/sys/boot/Makefile.amd64
@@ -2,3 +2,4 @@
SUBDIR+= efi
SUBDIR+= zfs
+SUBDIR+= userboot
diff --git a/sys/boot/common/Makefile.inc b/sys/boot/common/Makefile.inc
index be6c3301..ad9535c 100644
--- a/sys/boot/common/Makefile.inc
+++ b/sys/boot/common/Makefile.inc
@@ -1,6 +1,6 @@
# $FreeBSD$
-SRCS+= boot.c commands.c console.c devopen.c interp.c
+SRCS+= boot.c commands.c console.c devopen.c disk.c interp.c
SRCS+= interp_backslash.c interp_parse.c ls.c misc.c
SRCS+= module.c panic.c
diff --git a/sys/boot/common/disk.c b/sys/boot/common/disk.c
new file mode 100644
index 0000000..40dbc8a
--- /dev/null
+++ b/sys/boot/common/disk.c
@@ -0,0 +1,788 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * 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 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 AUTHOR 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * MBR/GPT partitioned disk device handling.
+ *
+ * Ideas and algorithms from:
+ *
+ * - NetBSD libi386/biosdisk.c
+ * - FreeBSD biosboot/disk.c
+ *
+ */
+
+#include <stand.h>
+
+#include <sys/diskmbr.h>
+#include <sys/disklabel.h>
+#include <sys/gpt.h>
+
+#include <stdarg.h>
+#include <uuid.h>
+
+#include <bootstrap.h>
+
+#include "disk.h"
+
+#ifdef DISK_DEBUG
+# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args)
+#else
+# define DEBUG(fmt, args...)
+#endif
+
+/*
+ * Search for a slice with the following preferences:
+ *
+ * 1: Active FreeBSD slice
+ * 2: Non-active FreeBSD slice
+ * 3: Active Linux slice
+ * 4: non-active Linux slice
+ * 5: Active FAT/FAT32 slice
+ * 6: non-active FAT/FAT32 slice
+ */
+#define PREF_RAWDISK 0
+#define PREF_FBSD_ACT 1
+#define PREF_FBSD 2
+#define PREF_LINUX_ACT 3
+#define PREF_LINUX 4
+#define PREF_DOS_ACT 5
+#define PREF_DOS 6
+#define PREF_NONE 7
+
+#ifdef LOADER_GPT_SUPPORT
+
+struct gpt_part {
+ int gp_index;
+ uuid_t gp_type;
+ uint64_t gp_start;
+ uint64_t gp_end;
+};
+
+static uuid_t efi = GPT_ENT_TYPE_EFI;
+static uuid_t freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
+static uuid_t freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
+static uuid_t freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
+static uuid_t freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
+static uuid_t ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA;
+
+#endif
+
+/* Given a size in 512 byte sectors, convert it to a human-readable number. */
+static char *
+display_size(uint64_t size)
+{
+ static char buf[80];
+ char unit;
+
+ size /= 2;
+ unit = 'K';
+ if (size >= 10485760000LL) {
+ size /= 1073741824;
+ unit = 'T';
+ } else if (size >= 10240000) {
+ size /= 1048576;
+ unit = 'G';
+ } else if (size >= 10000) {
+ size /= 1024;
+ unit = 'M';
+ }
+ sprintf(buf, "%.6ld%cB", (long)size, unit);
+ return (buf);
+}
+
+static void
+disk_checkextended(struct disk_devdesc *dev,
+ struct dos_partition *slicetab, int slicenum, int *nslicesp)
+{
+ uint8_t buf[DISK_SECSIZE];
+ struct dos_partition *dp;
+ uint32_t base;
+ int rc, i, start, end;
+
+ dp = &slicetab[slicenum];
+ start = *nslicesp;
+
+ if (dp->dp_size == 0)
+ goto done;
+ if (dp->dp_typ != DOSPTYP_EXT)
+ goto done;
+ rc = dev->d_dev->dv_strategy(dev, F_READ, dp->dp_start, DISK_SECSIZE,
+ (char *) buf, NULL);
+ if (rc)
+ goto done;
+ if (buf[0x1fe] != 0x55 || buf[0x1ff] != 0xaa) {
+ DEBUG("no magic in extended table");
+ goto done;
+ }
+ base = dp->dp_start;
+ dp = (struct dos_partition *) &buf[DOSPARTOFF];
+ for (i = 0; i < NDOSPART; i++, dp++) {
+ if (dp->dp_size == 0)
+ continue;
+ if (*nslicesp == NEXTDOSPART)
+ goto done;
+ dp->dp_start += base;
+ bcopy(dp, &slicetab[*nslicesp], sizeof(*dp));
+ (*nslicesp)++;
+ }
+ end = *nslicesp;
+
+ /*
+ * now, recursively check the slices we just added
+ */
+ for (i = start; i < end; i++)
+ disk_checkextended(dev, slicetab, i, nslicesp);
+done:
+ return;
+}
+
+static int
+disk_readslicetab(struct disk_devdesc *dev,
+ struct dos_partition **slicetabp, int *nslicesp)
+{
+ struct dos_partition *slicetab = NULL;
+ int nslices, i;
+ int rc;
+ uint8_t buf[DISK_SECSIZE];
+
+ /*
+ * Find the slice in the DOS slice table.
+ */
+ rc = dev->d_dev->dv_strategy(dev, F_READ, 0, DISK_SECSIZE,
+ (char *) buf, NULL);
+ if (rc) {
+ DEBUG("error reading MBR");
+ return (rc);
+ }
+
+ /*
+ * Check the slice table magic.
+ */
+ if (buf[0x1fe] != 0x55 || buf[0x1ff] != 0xaa) {
+ DEBUG("no slice table/MBR (no magic)");
+ return (rc);
+ }
+
+ /*
+ * copy the partition table, then pick up any extended partitions.
+ */
+ slicetab = malloc(NEXTDOSPART * sizeof(struct dos_partition));
+ bcopy(buf + DOSPARTOFF, slicetab,
+ sizeof(struct dos_partition) * NDOSPART);
+ nslices = NDOSPART; /* extended slices start here */
+ for (i = 0; i < NDOSPART; i++)
+ disk_checkextended(dev, slicetab, i, &nslices);
+
+ *slicetabp = slicetab;
+ *nslicesp = nslices;
+ return (0);
+}
+
+/*
+ * Search for the best MBR slice (typically the first FreeBSD slice).
+ */
+static int
+disk_bestslice(struct dos_partition *slicetab, int nslices)
+{
+ struct dos_partition *dp;
+ int pref, preflevel;
+ int i, prefslice;
+
+ prefslice = 0;
+ preflevel = PREF_NONE;
+
+ dp = &slicetab[0];
+ for (i = 0; i < nslices; i++, dp++) {
+ switch (dp->dp_typ) {
+ case DOSPTYP_386BSD: /* FreeBSD */
+ pref = dp->dp_flag & 0x80 ? PREF_FBSD_ACT : PREF_FBSD;
+ break;
+
+ case DOSPTYP_LINUX:
+ pref = dp->dp_flag & 0x80 ? PREF_LINUX_ACT : PREF_LINUX;
+ break;
+
+ case 0x01: /* DOS/Windows */
+ case 0x04:
+ case 0x06:
+ case 0x0b:
+ case 0x0c:
+ case 0x0e:
+ pref = dp->dp_flag & 0x80 ? PREF_DOS_ACT : PREF_DOS;
+ break;
+
+ default:
+ pref = PREF_NONE;
+ }
+ if (pref < preflevel) {
+ preflevel = pref;
+ prefslice = i + 1;
+ }
+ }
+ return (prefslice);
+}
+
+static int
+disk_openmbr(struct disk_devdesc *dev)
+{
+ struct dos_partition *slicetab = NULL, *dptr;
+ int nslices, sector, slice;
+ int rc;
+ uint8_t buf[DISK_SECSIZE];
+ struct disklabel *lp;
+
+ /*
+ * Following calculations attempt to determine the correct value
+ * for dev->d_offset by looking for the slice and partition specified,
+ * or searching for reasonable defaults.
+ */
+ rc = disk_readslicetab(dev, &slicetab, &nslices);
+ if (rc)
+ return (rc);
+
+ /*
+ * if a slice number was supplied but not found, this is an error.
+ */
+ if (dev->d_slice > 0) {
+ slice = dev->d_slice - 1;
+ if (slice >= nslices) {
+ DEBUG("slice %d not found", slice);
+ rc = EPART;
+ goto out;
+ }
+ }
+
+ /*
+ * Check for the historically bogus MBR found on true dedicated disks
+ */
+ if (slicetab[3].dp_typ == DOSPTYP_386BSD &&
+ slicetab[3].dp_start == 0 && slicetab[3].dp_size == 50000) {
+ sector = 0;
+ goto unsliced;
+ }
+
+ /*
+ * Try to auto-detect the best slice; this should always give
+ * a slice number
+ */
+ if (dev->d_slice == 0) {
+ slice = disk_bestslice(slicetab, nslices);
+ if (slice == -1) {
+ rc = ENOENT;
+ goto out;
+ }
+ dev->d_slice = slice;
+ }
+
+ /*
+ * Accept the supplied slice number unequivocally (we may be looking
+ * at a DOS partition).
+ * Note: we number 1-4, offsets are 0-3
+ */
+ dptr = &slicetab[dev->d_slice - 1];
+ sector = dptr->dp_start;
+ DEBUG("slice entry %d at %d, %d sectors",
+ dev->d_slice - 1, sector, dptr->dp_size);
+
+unsliced:
+ /*
+ * Now we have the slice offset, look for the partition in the
+ * disklabel if we have a partition to start with.
+ *
+ * XXX we might want to check the label checksum.
+ */
+ if (dev->d_partition < 0) {
+ /* no partition, must be after the slice */
+ DEBUG("opening raw slice");
+ dev->d_offset = sector;
+ rc = 0;
+ goto out;
+ }
+
+ rc = dev->d_dev->dv_strategy(dev, F_READ, sector + LABELSECTOR,
+ DISK_SECSIZE, (char *) buf, NULL);
+ if (rc) {
+ DEBUG("error reading disklabel");
+ goto out;
+ }
+
+ lp = (struct disklabel *) buf;
+
+ if (lp->d_magic != DISKMAGIC) {
+ DEBUG("no disklabel");
+ rc = ENOENT;
+ goto out;
+ }
+ if (dev->d_partition >= lp->d_npartitions) {
+ DEBUG("partition '%c' exceeds partitions in table (a-'%c')",
+ 'a' + dev->d_partition,
+ 'a' + lp->d_npartitions);
+ rc = EPART;
+ goto out;
+ }
+
+ dev->d_offset =
+ lp->d_partitions[dev->d_partition].p_offset -
+ lp->d_partitions[RAW_PART].p_offset +
+ sector;
+ rc = 0;
+
+out:
+ if (slicetab)
+ free(slicetab);
+ return (rc);
+}
+
+/*
+ * Print out each valid partition in the disklabel of a FreeBSD slice.
+ * For size calculations, we assume a 512 byte sector size.
+ */
+static void
+disk_printbsdslice(struct disk_devdesc *dev, daddr_t offset,
+ char *prefix, int verbose)
+{
+ char line[80];
+ char buf[DISK_SECSIZE];
+ struct disklabel *lp;
+ int i, rc, fstype;
+
+ /* read disklabel */
+ rc = dev->d_dev->dv_strategy(dev, F_READ, offset + LABELSECTOR,
+ DISK_SECSIZE, (char *) buf, NULL);
+ if (rc)
+ return;
+ lp =(struct disklabel *)(&buf[0]);
+ if (lp->d_magic != DISKMAGIC) {
+ sprintf(line, "%s: FFS bad disklabel\n", prefix);
+ pager_output(line);
+ return;
+ }
+
+ /* Print partitions */
+ for (i = 0; i < lp->d_npartitions; i++) {
+ /*
+ * For each partition, make sure we know what type of fs it
+ * is. If not, then skip it.
+ */
+ fstype = lp->d_partitions[i].p_fstype;
+ if (fstype != FS_BSDFFS &&
+ fstype != FS_SWAP &&
+ fstype != FS_VINUM)
+ continue;
+
+ /* Only print out statistics in verbose mode */
+ if (verbose)
+ sprintf(line, " %s%c: %s %s (%d - %d)\n",
+ prefix, 'a' + i,
+ (fstype == FS_SWAP) ? "swap " :
+ (fstype == FS_VINUM) ? "vinum" :
+ "FFS ",
+ display_size(lp->d_partitions[i].p_size),
+ lp->d_partitions[i].p_offset,
+ (lp->d_partitions[i].p_offset
+ + lp->d_partitions[i].p_size));
+ else
+ sprintf(line, " %s%c: %s\n", prefix, 'a' + i,
+ (fstype == FS_SWAP) ? "swap" :
+ (fstype == FS_VINUM) ? "vinum" :
+ "FFS");
+ pager_output(line);
+ }
+}
+
+static void
+disk_printslice(struct disk_devdesc *dev, int slice,
+ struct dos_partition *dp, char *prefix, int verbose)
+{
+ char stats[80];
+ char line[80];
+
+ if (verbose)
+ sprintf(stats, " %s (%d - %d)", display_size(dp->dp_size),
+ dp->dp_start, dp->dp_start + dp->dp_size);
+ else
+ stats[0] = '\0';
+
+ switch (dp->dp_typ) {
+ case DOSPTYP_386BSD:
+ disk_printbsdslice(dev, (daddr_t)dp->dp_start,
+ prefix, verbose);
+ return;
+ case DOSPTYP_LINSWP:
+ sprintf(line, "%s: Linux swap%s\n", prefix, stats);
+ break;
+ case DOSPTYP_LINUX:
+ /*
+ * XXX
+ * read the superblock to confirm this is an ext2fs partition?
+ */
+ sprintf(line, "%s: ext2fs%s\n", prefix, stats);
+ break;
+ case 0x00: /* unused partition */
+ case DOSPTYP_EXT:
+ return;
+ case 0x01:
+ sprintf(line, "%s: FAT-12%s\n", prefix, stats);
+ break;
+ case 0x04:
+ case 0x06:
+ case 0x0e:
+ sprintf(line, "%s: FAT-16%s\n", prefix, stats);
+ break;
+ case 0x07:
+ sprintf(line, "%s: NTFS/HPFS%s\n", prefix, stats);
+ break;
+ case 0x0b:
+ case 0x0c:
+ sprintf(line, "%s: FAT-32%s\n", prefix, stats);
+ break;
+ default:
+ sprintf(line, "%s: Unknown fs: 0x%x %s\n", prefix, dp->dp_typ,
+ stats);
+ }
+ pager_output(line);
+}
+
+int
+disk_printmbr(struct disk_devdesc *dev, char *prefix, int verbose)
+{
+ struct dos_partition *slicetab;
+ int nslices, i;
+ int rc;
+ char line[80];
+
+ rc = disk_readslicetab(dev, &slicetab, &nslices);
+ if (rc)
+ return (rc);
+ for (i = 0; i < nslices; i++) {
+ sprintf(line, "%ss%d", prefix, i + 1);
+ disk_printslice(dev, i, &slicetab[i], line, verbose);
+ }
+ free(slicetab);
+ return (0);
+}
+
+#ifdef LOADER_GPT_SUPPORT
+
+static int
+disk_readgpt(struct disk_devdesc *dev, struct gpt_part **gptp, int *ngptp)
+{
+ struct dos_partition *dp;
+ struct gpt_hdr *hdr;
+ struct gpt_ent *ent;
+ struct gpt_part *gptab = NULL;
+ int entries_per_sec, rc, i, part;
+ daddr_t lba, elba;
+ uint8_t gpt[DISK_SECSIZE], tbl[DISK_SECSIZE];
+
+ /*
+ * Following calculations attempt to determine the correct value
+ * for dev->d_offset by looking for the slice and partition specified,
+ * or searching for reasonable defaults.
+ */
+ rc = 0;
+
+ /* First, read the MBR and see if we have a PMBR. */
+ rc = dev->d_dev->dv_strategy(dev, F_READ, 0, DISK_SECSIZE,
+ (char *) tbl, NULL);
+ if (rc) {
+ DEBUG("error reading MBR");
+ return (EIO);
+ }
+
+ /* Check the slice table magic. */
+ if (tbl[0x1fe] != 0x55 || tbl[0x1ff] != 0xaa)
+ return (ENXIO);
+
+ /* Check for GPT slice. */
+ part = 0;
+ dp = (struct dos_partition *)(tbl + DOSPARTOFF);
+ for (i = 0; i < NDOSPART; i++) {
+ if (dp[i].dp_typ == 0xee)
+ part++;
+ else if ((part != 1) && (dp[i].dp_typ != 0x00))
+ return (EINVAL);
+ }
+ if (part != 1)
+ return (EINVAL);
+
+ /* Read primary GPT table header. */
+ rc = dev->d_dev->dv_strategy(dev, F_READ, 1, DISK_SECSIZE,
+ (char *) gpt, NULL);
+ if (rc) {
+ DEBUG("error reading GPT header");
+ return (EIO);
+ }
+ hdr = (struct gpt_hdr *)gpt;
+ if (bcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0 ||
+ hdr->hdr_lba_self != 1 || hdr->hdr_revision < 0x00010000 ||
+ hdr->hdr_entsz < sizeof(*ent) ||
+ DISK_SECSIZE % hdr->hdr_entsz != 0) {
+ DEBUG("Invalid GPT header\n");
+ return (EINVAL);
+ }
+
+ /* Walk the partition table to count valid partitions. */
+ part = 0;
+ entries_per_sec = DISK_SECSIZE / hdr->hdr_entsz;
+ elba = hdr->hdr_lba_table + hdr->hdr_entries / entries_per_sec;
+ for (lba = hdr->hdr_lba_table; lba < elba; lba++) {
+ rc = dev->d_dev->dv_strategy(dev, F_READ, lba, DISK_SECSIZE,
+ (char *) tbl, NULL);
+ if (rc) {
+ DEBUG("error reading GPT table");
+ return (EIO);
+ }
+ for (i = 0; i < entries_per_sec; i++) {
+ ent = (struct gpt_ent *)(tbl + i * hdr->hdr_entsz);
+ if (uuid_is_nil(&ent->ent_type, NULL) ||
+ ent->ent_lba_start == 0 ||
+ ent->ent_lba_end < ent->ent_lba_start)
+ continue;
+ part++;
+ }
+ }
+
+ /* Save the important information about all the valid partitions. */
+ if (part != 0) {
+ gptab = malloc(part * sizeof(struct gpt_part));
+ part = 0;
+ for (lba = hdr->hdr_lba_table; lba < elba; lba++) {
+ rc = dev->d_dev->dv_strategy(dev, F_READ, lba, DISK_SECSIZE,
+ (char *) tbl, NULL);
+ if (rc) {
+ DEBUG("error reading GPT table");
+ free(gptab);
+ return (EIO);
+ }
+ for (i = 0; i < entries_per_sec; i++) {
+ ent = (struct gpt_ent *)(tbl + i * hdr->hdr_entsz);
+ if (uuid_is_nil(&ent->ent_type, NULL) ||
+ ent->ent_lba_start == 0 ||
+ ent->ent_lba_end < ent->ent_lba_start)
+ continue;
+ gptab[part].gp_index = (lba - hdr->hdr_lba_table) *
+ entries_per_sec + i + 1;
+ gptab[part].gp_type = ent->ent_type;
+ gptab[part].gp_start = ent->ent_lba_start;
+ gptab[part].gp_end = ent->ent_lba_end;
+ part++;
+ }
+ }
+ }
+
+ *gptp = gptab;
+ *ngptp = part;
+ return (0);
+}
+
+static struct gpt_part *
+disk_bestgpt(struct gpt_part *gpt, int ngpt)
+{
+ struct gpt_part *gp, *prefpart;
+ int i, pref, preflevel;
+
+ prefpart = NULL;
+ preflevel = PREF_NONE;
+
+ gp = gpt;
+ for (i = 0; i < ngpt; i++, gp++) {
+ /* Windows. XXX: Also Linux. */
+ if (uuid_equal(&gp->gp_type, &ms_basic_data, NULL))
+ pref = PREF_DOS;
+ /* FreeBSD */
+ else if (uuid_equal(&gp->gp_type, &freebsd_ufs, NULL) ||
+ uuid_equal(&gp->gp_type, &freebsd_zfs, NULL))
+ pref = PREF_FBSD;
+ else
+ pref = PREF_NONE;
+ if (pref < preflevel) {
+ preflevel = pref;
+ prefpart = gp;
+ }
+ }
+ return (prefpart);
+}
+
+int
+disk_opengpt(struct disk_devdesc *dev)
+{
+ struct gpt_part *gpt = NULL, *gp;
+ int rc, ngpt, i;
+
+ rc = disk_readgpt(dev, &gpt, &ngpt);
+ if (rc)
+ return (rc);
+
+ /* Is this a request for the whole disk? */
+ if (dev->d_slice < 0) {
+ dev->d_offset = 0;
+ rc = 0;
+ goto out;
+ }
+
+ /*
+ * If a partition number was supplied, then the user is trying to use
+ * an MBR address rather than a GPT address, so fail.
+ */
+ if (dev->d_partition != 0xff) {
+ rc = ENOENT;
+ goto out;
+ }
+
+ /* If a slice number was supplied but not found, this is an error. */
+ gp = NULL;
+ if (dev->d_slice > 0) {
+ for (i = 0; i < ngpt; i++) {
+ if (gpt[i].gp_index == dev->d_slice) {
+ gp = &gpt[i];
+ break;
+ }
+ }
+ if (gp == NULL) {
+ DEBUG("partition %d not found", dev->d_slice);
+ rc = ENOENT;
+ goto out;
+ }
+ }
+
+ /* Try to auto-detect the best partition. */
+ if (dev->d_slice == 0) {
+ gp = disk_bestgpt(gpt, ngpt);
+ if (gp == NULL) {
+ rc = ENOENT;
+ goto out;
+ }
+ dev->d_slice = gp->gp_index;
+ }
+
+ dev->d_offset = gp->gp_start;
+ rc = 0;
+
+out:
+ if (gpt)
+ free(gpt);
+ return (rc);
+}
+
+static void
+disk_printgptpart(struct disk_devdesc *dev, struct gpt_part *gp,
+ char *prefix, int verbose)
+{
+ char stats[80];
+ char line[96];
+
+ if (verbose)
+ sprintf(stats, " %s",
+ display_size(gp->gp_end + 1 - gp->gp_start));
+ else
+ stats[0] = '\0';
+
+ if (uuid_equal(&gp->gp_type, &efi, NULL))
+ sprintf(line, "%s: EFI %s\n", prefix, stats);
+ else if (uuid_equal(&gp->gp_type, &ms_basic_data, NULL))
+ sprintf(line, "%s: FAT/NTFS %s\n", prefix, stats);
+ else if (uuid_equal(&gp->gp_type, &freebsd_boot, NULL))
+ sprintf(line, "%s: FreeBSD boot%s\n", prefix, stats);
+ else if (uuid_equal(&gp->gp_type, &freebsd_ufs, NULL))
+ sprintf(line, "%s: FreeBSD UFS %s\n", prefix, stats);
+ else if (uuid_equal(&gp->gp_type, &freebsd_zfs, NULL))
+ sprintf(line, "%s: FreeBSD ZFS %s\n", prefix, stats);
+ else if (uuid_equal(&gp->gp_type, &freebsd_swap, NULL))
+ sprintf(line, "%s: FreeBSD swap%s\n", prefix, stats);
+ else
+ sprintf(line,
+ "%s: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x%s\n",
+ prefix,
+ gp->gp_type.time_low, gp->gp_type.time_mid,
+ gp->gp_type.time_hi_and_version,
+ gp->gp_type.clock_seq_hi_and_reserved,
+ gp->gp_type.clock_seq_low,
+ gp->gp_type.node[0],
+ gp->gp_type.node[1],
+ gp->gp_type.node[2],
+ gp->gp_type.node[3],
+ gp->gp_type.node[4],
+ gp->gp_type.node[5],
+ stats);
+ pager_output(line);
+}
+
+static int
+disk_printgpt(struct disk_devdesc *dev, char *prefix, int verbose)
+{
+ struct gpt_part *gpt = NULL;
+ int rc, ngpt, i;
+ char line[80];
+
+ rc = disk_readgpt(dev, &gpt, &ngpt);
+ if (rc)
+ return (rc);
+ for (i = 0; i < ngpt; i++) {
+ sprintf(line, "%sp%d", prefix, i + 1);
+ disk_printgptpart(dev, &gpt[i], line, verbose);
+ }
+ free(gpt);
+ return (0);
+}
+
+#endif
+
+int
+disk_open(struct disk_devdesc *dev)
+{
+ int rc;
+
+ /*
+ * While we are reading disk metadata, make sure we do it relative
+ * to the start of the disk
+ */
+ dev->d_offset = 0;
+
+#ifdef LOADER_GPT_SUPPORT
+ rc = disk_opengpt(dev);
+ if (rc)
+#endif
+ rc = disk_openmbr(dev);
+
+ return (rc);
+}
+
+void
+disk_print(struct disk_devdesc *dev, char *prefix, int verbose)
+{
+ int rc;
+
+#ifdef LOADER_GPT_SUPPORT
+ rc = disk_printgpt(dev, prefix, verbose);
+ if (rc == 0)
+ return;
+#endif
+ disk_printmbr(dev, prefix, verbose);
+}
diff --git a/sys/boot/common/disk.h b/sys/boot/common/disk.h
new file mode 100644
index 0000000..0fc7e91
--- /dev/null
+++ b/sys/boot/common/disk.h
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 2011 Google, Inc.
+ * 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 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Device descriptor for partitioned disks. We assume that all disk addresses
+ * are 512 byte block offsets from the start of the disk. To use, set the
+ * d_slice and d_partition variables as follows:
+ *
+ * Whole disk access:
+ *
+ * d_slice = -1
+ * d_partition = -1
+ *
+ * Whole MBR slice:
+ *
+ * d_slice = MBR slice number (typically 1..4)
+ * d_partition = -1
+ *
+ * BSD disklabel partition within an MBR slice:
+ *
+ * d_slice = MBR slice number (typically 1..4)
+ * d_partition = disklabel partition (typically 0..7)
+ *
+ * GPT partition:
+ *
+ * d_slice = GPT partition number (typically 1..N)
+ * d_partition = 255
+ *
+ * For both MBR and GPT, to automatically find the 'best' slice or partition,
+ * set d_slice to zero. This uses the partition type to decide which partition
+ * to use according to the following list of preferences:
+ *
+ * FreeBSD (active)
+ * FreeBSD (inactive)
+ * Linux (active)
+ * Linux (inactive)
+ * DOS/Windows (active)
+ * DOS/Windows (inactive)
+ *
+ * Active MBR slices (marked as bootable) are preferred over inactive. GPT
+ * doesn't have the concept of active/inactive partitions. In both MBR and GPT,
+ * if there are multiple slices/partitions of a given type, the first one
+ * is chosen.
+ *
+ * The low-level disk device will typically call slice_open() from its open
+ * method to interpret the disk partition tables according to the rules above.
+ * This will initialize d_offset to the block offset of the start of the
+ * selected partition - this offset should be added to the offset passed to
+ * the device's strategy method.
+ */
+
+#define DISK_SECSIZE 512
+
+struct disk_devdesc
+{
+ struct devsw *d_dev;
+ int d_type;
+ int d_unit;
+ void *d_opendata;
+ int d_slice;
+ int d_partition;
+ int d_offset;
+};
+
+/*
+ * Parse disk metadata and initialise dev->d_offset.
+ */
+extern int disk_open(struct disk_devdesc * dev);
+
+/*
+ * Print information about slices on a disk. For the size calculations we
+ * assume a 512 byte sector.
+ */
+extern void disk_print(struct disk_devdesc *dev, char *prefix, int verbose);
diff --git a/sys/boot/common/load_elf.c b/sys/boot/common/load_elf.c
index ee6389f..bf095bb 100644
--- a/sys/boot/common/load_elf.c
+++ b/sys/boot/common/load_elf.c
@@ -260,7 +260,7 @@ __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
firstaddr = lastaddr = 0;
ehdr = ef->ehdr;
if (ef->kernel) {
-#ifdef __i386__
+#if defined(__i386__) || defined(__amd64__)
#if __ELF_WORD_SIZE == 64
off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */
#else
diff --git a/sys/boot/common/reloc_elf.c b/sys/boot/common/reloc_elf.c
index 43b7cbf..b614091 100644
--- a/sys/boot/common/reloc_elf.c
+++ b/sys/boot/common/reloc_elf.c
@@ -78,7 +78,7 @@ __elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr, const void *reldata,
}
return (0);
-#elif defined(__i386__) && __ELF_WORD_SIZE == 64
+#elif (defined(__i386__) || defined(__amd64__)) && __ELF_WORD_SIZE == 64
Elf64_Addr *where, val;
Elf_Addr addend, addr;
Elf_Size rtype, symidx;
diff --git a/sys/boot/ficl/amd64/sysdep.c b/sys/boot/ficl/amd64/sysdep.c
new file mode 100644
index 0000000..00b0d4a
--- /dev/null
+++ b/sys/boot/ficl/amd64/sysdep.c
@@ -0,0 +1,101 @@
+/*******************************************************************
+** s y s d e p . c
+** Forth Inspired Command Language
+** Author: John Sadler (john_sadler@alum.mit.edu)
+** Created: 16 Oct 1997
+** Implementations of FICL external interface functions...
+**
+*******************************************************************/
+
+/* $FreeBSD$ */
+
+#ifdef TESTMAIN
+#include <stdio.h>
+#include <stdlib.h>
+#else
+#include <stand.h>
+#endif
+#include "ficl.h"
+
+/*
+******************* FreeBSD P O R T B E G I N S H E R E ******************** Michael Smith
+*/
+
+#if PORTABLE_LONGMULDIV == 0
+DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y)
+{
+ DPUNS q;
+ u_int64_t qx;
+
+ qx = (u_int64_t)x * (u_int64_t) y;
+
+ q.hi = (u_int32_t)( qx >> 32 );
+ q.lo = (u_int32_t)( qx & 0xFFFFFFFFL);
+
+ return q;
+}
+
+UNSQR ficlLongDiv(DPUNS q, FICL_UNS y)
+{
+ UNSQR result;
+ u_int64_t qx, qh;
+
+ qh = q.hi;
+ qx = (qh << 32) | q.lo;
+
+ result.quot = qx / y;
+ result.rem = qx % y;
+
+ return result;
+}
+#endif
+
+void ficlTextOut(FICL_VM *pVM, char *msg, int fNewline)
+{
+ IGNORE(pVM);
+
+ while(*msg != 0)
+ putchar(*(msg++));
+ if (fNewline)
+ putchar('\n');
+
+ return;
+}
+
+void *ficlMalloc (size_t size)
+{
+ return malloc(size);
+}
+
+void *ficlRealloc (void *p, size_t size)
+{
+ return realloc(p, size);
+}
+
+void ficlFree (void *p)
+{
+ free(p);
+}
+
+
+/*
+** Stub function for dictionary access control - does nothing
+** by default, user can redefine to guarantee exclusive dict
+** access to a single thread for updates. All dict update code
+** is guaranteed to be bracketed as follows:
+** ficlLockDictionary(TRUE);
+** <code that updates dictionary>
+** ficlLockDictionary(FALSE);
+**
+** Returns zero if successful, nonzero if unable to acquire lock
+** befor timeout (optional - could also block forever)
+*/
+#if FICL_MULTITHREAD
+int ficlLockDictionary(short fLock)
+{
+ IGNORE(fLock);
+ return 0;
+}
+#endif /* FICL_MULTITHREAD */
+
+
diff --git a/sys/boot/ficl/amd64/sysdep.h b/sys/boot/ficl/amd64/sysdep.h
new file mode 100644
index 0000000..08bc0e1
--- /dev/null
+++ b/sys/boot/ficl/amd64/sysdep.h
@@ -0,0 +1,434 @@
+/*******************************************************************
+ s y s d e p . h
+** Forth Inspired Command Language
+** Author: John Sadler (john_sadler@alum.mit.edu)
+** Created: 16 Oct 1997
+** Ficl system dependent types and prototypes...
+**
+** Note: Ficl also depends on the use of "assert" when
+** FICL_ROBUST is enabled. This may require some consideration
+** in firmware systems since assert often
+** assumes stderr/stdout.
+** $Id: sysdep.h,v 1.11 2001/12/05 07:21:34 jsadler Exp $
+*******************************************************************/
+/*
+** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
+** All rights reserved.
+**
+** Get the latest Ficl release at http://ficl.sourceforge.net
+**
+** I am interested in hearing from anyone who uses ficl. If you have
+** a problem, a success story, a defect, an enhancement request, or
+** if you would like to contribute to the ficl release, please
+** contact me by email at the address above.
+**
+** L I C E N S E and D I S C L A I M E R
+**
+** 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 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 AUTHOR 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.
+**
+** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $
+*/
+
+/* $FreeBSD$ */
+
+#if !defined (__SYSDEP_H__)
+#define __SYSDEP_H__
+
+#include <sys/types.h>
+
+#include <stddef.h> /* size_t, NULL */
+#include <setjmp.h>
+#include <assert.h>
+
+#if !defined IGNORE /* Macro to silence unused param warnings */
+#define IGNORE(x) &x
+#endif
+
+/*
+** TRUE and FALSE for C boolean operations, and
+** portable 32 bit types for CELLs
+**
+*/
+#if !defined TRUE
+#define TRUE 1
+#endif
+#if !defined FALSE
+#define FALSE 0
+#endif
+
+/*
+** System dependent data type declarations...
+*/
+#if !defined INT32
+#define INT32 int
+#endif
+
+#if !defined UNS32
+#define UNS32 unsigned int
+#endif
+
+#if !defined UNS16
+#define UNS16 unsigned short
+#endif
+
+#if !defined UNS8
+#define UNS8 unsigned char
+#endif
+
+#if !defined NULL
+#define NULL ((void *)0)
+#endif
+
+/*
+** FICL_UNS and FICL_INT must have the same size as a void* on
+** the target system. A CELL is a union of void*, FICL_UNS, and
+** FICL_INT.
+** (11/2000: same for FICL_FLOAT)
+*/
+#if !defined FICL_INT
+#define FICL_INT long
+#endif
+
+#if !defined FICL_UNS
+#define FICL_UNS unsigned long
+#endif
+
+#if !defined FICL_FLOAT
+#define FICL_FLOAT float
+#endif
+
+/*
+** Ficl presently supports values of 32 and 64 for BITS_PER_CELL
+*/
+#if !defined BITS_PER_CELL
+#define BITS_PER_CELL 64
+#endif
+
+#if ((BITS_PER_CELL != 32) && (BITS_PER_CELL != 64))
+ Error!
+#endif
+
+typedef struct
+{
+ FICL_UNS hi;
+ FICL_UNS lo;
+} DPUNS;
+
+typedef struct
+{
+ FICL_UNS quot;
+ FICL_UNS rem;
+} UNSQR;
+
+typedef struct
+{
+ FICL_INT hi;
+ FICL_INT lo;
+} DPINT;
+
+typedef struct
+{
+ FICL_INT quot;
+ FICL_INT rem;
+} INTQR;
+
+
+/*
+** B U I L D C O N T R O L S
+*/
+
+#if !defined (FICL_MINIMAL)
+#define FICL_MINIMAL 0
+#endif
+#if (FICL_MINIMAL)
+#define FICL_WANT_SOFTWORDS 0
+#define FICL_WANT_FILE 0
+#define FICL_WANT_FLOAT 0
+#define FICL_WANT_USER 0
+#define FICL_WANT_LOCALS 0
+#define FICL_WANT_DEBUGGER 0
+#define FICL_WANT_OOP 0
+#define FICL_PLATFORM_EXTEND 0
+#define FICL_MULTITHREAD 0
+#define FICL_ROBUST 0
+#define FICL_EXTENDED_PREFIX 0
+#endif
+
+/*
+** FICL_PLATFORM_EXTEND
+** Includes words defined in ficlCompilePlatform
+*/
+#if !defined (FICL_PLATFORM_EXTEND)
+#define FICL_PLATFORM_EXTEND 1
+#endif
+
+
+/*
+** FICL_WANT_FILE
+** Includes the FILE and FILE-EXT wordset and associated code. Turn this off if you do not
+** have a filesystem!
+** Contributed by Larry Hastings
+*/
+#if !defined (FICL_WANT_FILE)
+#define FICL_WANT_FILE 0
+#endif
+
+/*
+** FICL_WANT_FLOAT
+** Includes a floating point stack for the VM, and words to do float operations.
+** Contributed by Guy Carver
+*/
+#if !defined (FICL_WANT_FLOAT)
+#define FICL_WANT_FLOAT 0
+#endif
+
+/*
+** FICL_WANT_DEBUGGER
+** Inludes a simple source level debugger
+*/
+#if !defined (FICL_WANT_DEBUGGER)
+#define FICL_WANT_DEBUGGER 1
+#endif
+
+/*
+** FICL_EXTENDED_PREFIX enables a bunch of extra prefixes in prefix.c and prefix.fr (if
+** included as part of softcore.c)
+*/
+#if !defined FICL_EXTENDED_PREFIX
+#define FICL_EXTENDED_PREFIX 0
+#endif
+
+/*
+** User variables: per-instance variables bound to the VM.
+** Kinda like thread-local storage. Could be implemented in a
+** VM private dictionary, but I've chosen the lower overhead
+** approach of an array of CELLs instead.
+*/
+#if !defined FICL_WANT_USER
+#define FICL_WANT_USER 1
+#endif
+
+#if !defined FICL_USER_CELLS
+#define FICL_USER_CELLS 16
+#endif
+
+/*
+** FICL_WANT_LOCALS controls the creation of the LOCALS wordset and
+** a private dictionary for local variable compilation.
+*/
+#if !defined FICL_WANT_LOCALS
+#define FICL_WANT_LOCALS 1
+#endif
+
+/* Max number of local variables per definition */
+#if !defined FICL_MAX_LOCALS
+#define FICL_MAX_LOCALS 16
+#endif
+
+/*
+** FICL_WANT_OOP
+** Inludes object oriented programming support (in softwords)
+** OOP support requires locals and user variables!
+*/
+#if !(FICL_WANT_LOCALS) || !(FICL_WANT_USER)
+#if !defined (FICL_WANT_OOP)
+#define FICL_WANT_OOP 0
+#endif
+#endif
+
+#if !defined (FICL_WANT_OOP)
+#define FICL_WANT_OOP 1
+#endif
+
+/*
+** FICL_WANT_SOFTWORDS
+** Controls inclusion of all softwords in softcore.c
+*/
+#if !defined (FICL_WANT_SOFTWORDS)
+#define FICL_WANT_SOFTWORDS 1
+#endif
+
+/*
+** FICL_MULTITHREAD enables dictionary mutual exclusion
+** wia the ficlLockDictionary system dependent function.
+** Note: this implementation is experimental and poorly
+** tested. Further, it's unnecessary unless you really
+** intend to have multiple SESSIONS (poor choice of name
+** on my part) - that is, threads that modify the dictionary
+** at the same time.
+*/
+#if !defined FICL_MULTITHREAD
+#define FICL_MULTITHREAD 0
+#endif
+
+/*
+** PORTABLE_LONGMULDIV causes ficlLongMul and ficlLongDiv to be
+** defined in C in sysdep.c. Use this if you cannot easily
+** generate an inline asm definition
+*/
+#if !defined (PORTABLE_LONGMULDIV)
+#define PORTABLE_LONGMULDIV 0
+#endif
+
+/*
+** INLINE_INNER_LOOP causes the inner interpreter to be inline code
+** instead of a function call. This is mainly because MS VC++ 5
+** chokes with an internal compiler error on the function version.
+** in release mode. Sheesh.
+*/
+#if !defined INLINE_INNER_LOOP
+#if defined _DEBUG
+#define INLINE_INNER_LOOP 0
+#else
+#define INLINE_INNER_LOOP 1
+#endif
+#endif
+
+/*
+** FICL_ROBUST enables bounds checking of stacks and the dictionary.
+** This will detect stack over and underflows and dictionary overflows.
+** Any exceptional condition will result in an assertion failure.
+** (As generated by the ANSI assert macro)
+** FICL_ROBUST == 1 --> stack checking in the outer interpreter
+** FICL_ROBUST == 2 also enables checking in many primitives
+*/
+
+#if !defined FICL_ROBUST
+#define FICL_ROBUST 2
+#endif
+
+/*
+** FICL_DEFAULT_STACK Specifies the default size (in CELLs) of
+** a new virtual machine's stacks, unless overridden at
+** create time.
+*/
+#if !defined FICL_DEFAULT_STACK
+#define FICL_DEFAULT_STACK 128
+#endif
+
+/*
+** FICL_DEFAULT_DICT specifies the number of CELLs to allocate
+** for the system dictionary by default. The value
+** can be overridden at startup time as well.
+** FICL_DEFAULT_ENV specifies the number of cells to allot
+** for the environment-query dictionary.
+*/
+#if !defined FICL_DEFAULT_DICT
+#define FICL_DEFAULT_DICT 12288
+#endif
+
+#if !defined FICL_DEFAULT_ENV
+#define FICL_DEFAULT_ENV 260
+#endif
+
+/*
+** FICL_DEFAULT_VOCS specifies the maximum number of wordlists in
+** the dictionary search order. See Forth DPANS sec 16.3.3
+** (file://dpans16.htm#16.3.3)
+*/
+#if !defined FICL_DEFAULT_VOCS
+#define FICL_DEFAULT_VOCS 16
+#endif
+
+/*
+** FICL_MAX_PARSE_STEPS controls the size of an array in the FICL_SYSTEM structure
+** that stores pointers to parser extension functions. I would never expect to have
+** more than 8 of these, so that's the default limit. Too many of these functions
+** will probably exact a nasty performance penalty.
+*/
+#if !defined FICL_MAX_PARSE_STEPS
+#define FICL_MAX_PARSE_STEPS 8
+#endif
+
+/*
+** FICL_ALIGN is the power of two to which the dictionary
+** pointer address must be aligned. This value is usually
+** either 1 or 2, depending on the memory architecture
+** of the target system; 2 is safe on any 16 or 32 bit
+** machine. 3 would be appropriate for a 64 bit machine.
+*/
+#if !defined FICL_ALIGN
+#define FICL_ALIGN 3
+#define FICL_ALIGN_ADD ((1 << FICL_ALIGN) - 1)
+#endif
+
+/*
+** System dependent routines --
+** edit the implementations in sysdep.c to be compatible
+** with your runtime environment...
+** ficlTextOut sends a NULL terminated string to the
+** default output device - used for system error messages
+** ficlMalloc and ficlFree have the same semantics as malloc and free
+** in standard C
+** ficlLongMul multiplies two UNS32s and returns a 64 bit unsigned
+** product
+** ficlLongDiv divides an UNS64 by an UNS32 and returns UNS32 quotient
+** and remainder
+*/
+struct vm;
+void ficlTextOut(struct vm *pVM, char *msg, int fNewline);
+void *ficlMalloc (size_t size);
+void ficlFree (void *p);
+void *ficlRealloc(void *p, size_t size);
+/*
+** Stub function for dictionary access control - does nothing
+** by default, user can redefine to guarantee exclusive dict
+** access to a single thread for updates. All dict update code
+** must be bracketed as follows:
+** ficlLockDictionary(TRUE);
+** <code that updates dictionary>
+** ficlLockDictionary(FALSE);
+**
+** Returns zero if successful, nonzero if unable to acquire lock
+** before timeout (optional - could also block forever)
+**
+** NOTE: this function must be implemented with lock counting
+** semantics: nested calls must behave properly.
+*/
+#if FICL_MULTITHREAD
+int ficlLockDictionary(short fLock);
+#else
+#define ficlLockDictionary(x) 0 /* ignore */
+#endif
+
+/*
+** 64 bit integer math support routines: multiply two UNS32s
+** to get a 64 bit product, & divide the product by an UNS32
+** to get an UNS32 quotient and remainder. Much easier in asm
+** on a 32 bit CPU than in C, which usually doesn't support
+** the double length result (but it should).
+*/
+DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y);
+UNSQR ficlLongDiv(DPUNS q, FICL_UNS y);
+
+
+/*
+** FICL_HAVE_FTRUNCATE indicates whether the current OS supports
+** the ftruncate() function (available on most UNIXes). This
+** function is necessary to provide the complete File-Access wordset.
+*/
+#if !defined (FICL_HAVE_FTRUNCATE)
+#define FICL_HAVE_FTRUNCATE 0
+#endif
+
+
+#endif /*__SYSDEP_H__*/
diff --git a/sys/boot/i386/libi386/bioscd.c b/sys/boot/i386/libi386/bioscd.c
index a6dba0c..a3abf34 100644
--- a/sys/boot/i386/libi386/bioscd.c
+++ b/sys/boot/i386/libi386/bioscd.c
@@ -117,6 +117,7 @@ bc_bios2unit(int biosdev)
int i;
DEBUG("looking for bios device 0x%x", biosdev);
+ printf("looking for bios device 0x%x, nbcinfo=%d\n", biosdev, nbcinfo);
for (i = 0; i < nbcinfo; i++) {
DEBUG("bc unit %d is BIOS device 0x%x", i, bcinfo[i].bc_unit);
if (bcinfo[i].bc_unit == biosdev)
@@ -148,6 +149,7 @@ bc_init(void)
int
bc_add(int biosdev)
{
+ printf("bc_add(%d)\n", biosdev);
if (nbcinfo >= MAXBCDEV)
return (-1);
@@ -159,8 +161,10 @@ bc_add(int biosdev)
v86.ds = VTOPSEG(&bcinfo[nbcinfo].bc_sp);
v86.esi = VTOPOFF(&bcinfo[nbcinfo].bc_sp);
v86int();
- if ((v86.eax & 0xff00) != 0)
+ if ((v86.eax & 0xff00) != 0) {
+ printf("CD probe failed, eax=0x%08x\n", v86.eax);
return (-1);
+ }
printf("BIOS CD is cd%d\n", nbcinfo);
nbcinfo++;
diff --git a/sys/boot/userboot/Makefile b/sys/boot/userboot/Makefile
new file mode 100644
index 0000000..f15c905
--- /dev/null
+++ b/sys/boot/userboot/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+SUBDIR= ficl libstand test userboot
+
+.include <bsd.subdir.mk>
+
diff --git a/sys/boot/userboot/ficl/Makefile b/sys/boot/userboot/ficl/Makefile
new file mode 100644
index 0000000..af5d1461
--- /dev/null
+++ b/sys/boot/userboot/ficl/Makefile
@@ -0,0 +1,73 @@
+# $FreeBSD$
+#
+.include <bsd.own.mk>
+MK_SSP= no
+
+.PATH: ${.CURDIR}/../../ficl
+.PATH: ${.CURDIR}/../../ficl/${MACHINE_CPUARCH}
+BASE_SRCS= dict.c ficl.c fileaccess.c float.c loader.c math64.c \
+ prefix.c search.c stack.c tools.c vm.c words.c
+
+SRCS= ${BASE_SRCS} sysdep.c softcore.c
+CLEANFILES= softcore.c testmain testmain.o
+CFLAGS+= -ffreestanding -fPIC
+.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
+CFLAGS+= -mno-mmx -mno-3dnow -mno-sse -mno-sse2
+.endif
+.if ${MACHINE_CPUARCH} == "i386"
+CFLAGS+= -mpreferred-stack-boundary=2
+CFLAGS+= -mno-sse3
+.endif
+.if ${MACHINE_CPUARCH} == "powerpc" || ${MACHINE_CPUARCH} == "arm"
+CFLAGS+= -msoft-float
+.endif
+.if ${MACHINE} == "pc98"
+CFLAGS+= -Os -DPC98
+.endif
+.if HAVE_PNP
+CFLAGS+= -DHAVE_PNP
+.endif
+.ifmake testmain
+CFLAGS+= -DTESTMAIN -D_TESTMAIN
+SRCS+= testmain.c
+PROG= testmain
+.include <bsd.prog.mk>
+.else
+LIB= ficl
+INTERNALLIB=
+.include <bsd.lib.mk>
+.endif
+
+# Standard softwords
+.PATH: ${.CURDIR}/../../ficl/softwords
+SOFTWORDS= softcore.fr jhlocal.fr marker.fr freebsd.fr ficllocal.fr \
+ ifbrack.fr
+# Optional OO extension softwords
+#SOFTWORDS+= oo.fr classes.fr
+
+#.if ${MACHINE_CPUARCH} == "amd64"
+#CFLAGS+= -m32 -march=i386 -I.
+#.endif
+
+.if ${MACHINE_ARCH} == "powerpc64"
+CFLAGS+= -m32 -mcpu=powerpc -I.
+.endif
+
+CFLAGS+= -I${.CURDIR}/../../ficl
+CFLAGS+= -I${.CURDIR}/../../ficl/${MACHINE_CPUARCH}
+CFLAGS+= -I${.CURDIR}/../../common
+
+softcore.c: ${SOFTWORDS} softcore.awk
+ (cd ${.CURDIR}/../../ficl/softwords; cat ${SOFTWORDS} \
+ | awk -f softcore.awk -v datestamp="`LC_ALL=C date`") > ${.TARGET}
+
+#.if ${MACHINE_CPUARCH} == "amd64"
+#${SRCS:M*.c:R:S/$/.o/g}: machine
+#
+#beforedepend ${OBJS}: machine
+#
+#machine:
+# ln -sf ${.CURDIR}/../../i386/include machine
+#
+#CLEANFILES+= machine
+#.endif
diff --git a/sys/boot/userboot/libstand/Makefile b/sys/boot/userboot/libstand/Makefile
new file mode 100644
index 0000000..9e71a24
--- /dev/null
+++ b/sys/boot/userboot/libstand/Makefile
@@ -0,0 +1,161 @@
+# $FreeBSD$
+# Originally from $NetBSD: Makefile,v 1.21 1997/10/26 22:08:38 lukem Exp $
+#
+# Notes:
+# - We don't use the libc strerror/sys_errlist because the string table is
+# quite large.
+#
+
+WITHOUT_SSP=
+NO_MAN=
+
+.include <bsd.own.mk>
+
+S= ${.CURDIR}/../../../../lib/libstand
+
+.PATH: ${S}
+LIB= stand
+INTERNALLIB=
+NO_PROFILE=
+NO_PIC=
+
+WARNS?= 0
+
+CFLAGS+= -ffreestanding -Wformat -fPIC
+CFLAGS+= -I${.CURDIR}/../../../../lib/libstand
+
+.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
+CFLAGS+= -mno-mmx -mno-3dnow -mno-sse -mno-sse2
+.endif
+.if ${MACHINE_CPUARCH} == "i386"
+CFLAGS+= -mpreferred-stack-boundary=2
+CFLAGS+= -mno-sse3
+.endif
+.if ${MACHINE} == "pc98"
+CFLAGS+= -Os
+.endif
+.if ${MACHINE_CPUARCH} == "powerpc"
+CFLAGS+= -msoft-float -D_STANDALONE -DNETIF_DEBUG
+.endif
+.if ${MACHINE_CPUARCH} == "arm"
+CFLAGS+= -msoft-float -D_STANDALONE
+.endif
+
+# standalone components and stuff we have modified locally
+SRCS+= zutil.h __main.c assert.c bcd.c bswap.c environment.c getopt.c gets.c \
+ globals.c pager.c printf.c strdup.c strerror.c strtol.c random.c \
+ sbrk.c twiddle.c zalloc.c zalloc_malloc.c
+
+# private (pruned) versions of libc string functions
+SRCS+= strcasecmp.c
+
+LIBC= ${.CURDIR}/../../../../lib/libc
+
+.PATH: ${LIBC}/net
+
+SRCS+= ntoh.c
+
+# string functions from libc
+.PATH: ${LIBC}/string
+.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "powerpc" || \
+ ${MACHINE_CPUARCH} == "sparc64" || ${MACHINE_CPUARCH} == "amd64" || \
+ ${MACHINE_CPUARCH} == "arm"
+SRCS+= bcmp.c bcopy.c bzero.c ffs.c index.c memccpy.c memchr.c memcmp.c \
+ memcpy.c memmove.c memset.c qdivrem.c rindex.c strcat.c strchr.c \
+ strcmp.c strcpy.c strcspn.c strlen.c strncat.c strncmp.c strncpy.c \
+ strpbrk.c strrchr.c strsep.c strspn.c strstr.c strtok.c swab.c
+.endif
+.if ${MACHINE_CPUARCH} == "arm"
+.PATH: ${LIBC}/arm/gen
+SRCS+= divsi3.S
+.endif
+.if ${MACHINE_CPUARCH} == "ia64"
+.PATH: ${LIBC}/ia64/string
+SRCS+= bcmp.c bcopy.S bzero.S ffs.S index.c memccpy.c memchr.c memcmp.c \
+ memcpy.S memmove.S memset.c rindex.c strcat.c strchr.c \
+ strcmp.c strcpy.c strcspn.c strlen.c \
+ strncat.c strncmp.c strncpy.c strpbrk.c strrchr.c strsep.c \
+ strspn.c strstr.c strtok.c swab.c
+
+.PATH: ${LIBC}/ia64/gen
+SRCS+= __divdi3.S __divsi3.S __moddi3.S __modsi3.S
+SRCS+= __udivdi3.S __udivsi3.S __umoddi3.S __umodsi3.S
+.endif
+.if ${MACHINE_CPUARCH} == "powerpc"
+.PATH: ${LIBC}/libc/quad
+SRCS+= ashldi3.c ashrdi3.c
+.PATH: ${LIBC}/powerpc/gen
+SRCS+= syncicache.c
+.endif
+
+# uuid functions from libc
+.PATH: ${LIBC}/uuid
+SRCS+= uuid_equal.c uuid_is_nil.c
+
+# _setjmp/_longjmp
+.if ${MACHINE_CPUARCH} == "amd64"
+.PATH: ${.CURDIR}/amd64
+.elif ${MACHINE_ARCH} == "powerpc64"
+.PATH: ${S}/powerpc
+.else
+.PATH: ${S}/${MACHINE_CPUARCH}
+.endif
+SRCS+= _setjmp.S
+
+# decompression functionality from libbz2
+# NOTE: to actually test this functionality after libbz2 upgrade compile
+# loader(8) with LOADER_BZIP2_SUPPORT defined
+.PATH: ${.CURDIR}/../../../../contrib/bzip2
+CFLAGS+= -DBZ_NO_STDIO -DBZ_NO_COMPRESS
+SRCS+= libstand_bzlib_private.h
+
+.for file in bzlib.c crctable.c decompress.c huffman.c randtable.c
+SRCS+= _${file}
+CLEANFILES+= _${file}
+
+_${file}: ${file}
+ sed "s|bzlib_private\.h|libstand_bzlib_private.h|" ${.ALLSRC} > ${.TARGET}
+.endfor
+
+CLEANFILES+= libstand_bzlib_private.h
+libstand_bzlib_private.h: bzlib_private.h
+ sed -e 's|<stdlib.h>|"stand.h"|' \
+ ${.ALLSRC} > ${.TARGET}
+
+# decompression functionality from libz
+.PATH: ${.CURDIR}/../../../../lib/libz
+CFLAGS+=-DHAVE_MEMCPY -I${.CURDIR}/../../../../lib/libz
+SRCS+= adler32.c crc32.c libstand_zutil.h
+
+.for file in infback.c inffast.c inflate.c inftrees.c zutil.c
+SRCS+= _${file}
+CLEANFILES+= _${file}
+
+_${file}: ${file}
+ sed "s|zutil\.h|libstand_zutil.h|" ${.ALLSRC} > ${.TARGET}
+.endfor
+
+# depend on stand.h being able to be included multiple times
+CLEANFILES+= libstand_zutil.h
+libstand_zutil.h: zutil.h
+ sed -e 's|<stddef.h>|"stand.h"|' \
+ -e 's|<string.h>|"stand.h"|' \
+ -e 's|<stdlib.h>|"stand.h"|' \
+ ${.ALLSRC} > ${.TARGET}
+
+# io routines
+SRCS+= closeall.c dev.c ioctl.c nullfs.c stat.c \
+ fstat.c close.c lseek.c open.c read.c write.c readdir.c
+
+# network routines
+SRCS+= arp.c ether.c inet_ntoa.c in_cksum.c net.c udp.c netif.c rpc.c
+
+# network info services:
+SRCS+= bootp.c rarp.c bootparam.c
+
+# boot filesystems
+SRCS+= ufs.c nfs.c cd9660.c tftp.c gzipfs.c bzipfs.c
+SRCS+= dosfs.c ext2fs.c
+SRCS+= splitfs.c
+
+.include <bsd.lib.mk>
diff --git a/sys/boot/userboot/libstand/amd64/_setjmp.S b/sys/boot/userboot/libstand/amd64/_setjmp.S
new file mode 100644
index 0000000..e841f49
--- /dev/null
+++ b/sys/boot/userboot/libstand/amd64/_setjmp.S
@@ -0,0 +1,93 @@
+/*-
+ * 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.
+ * 4. 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)
+ .asciz "@(#)_setjmp.s 5.1 (Berkeley) 4/23/90"
+#endif /* LIBC_SCCS and not lint */
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * _longjmp(a,v)
+ * will generate a "return(v)" from the last call to
+ * _setjmp(a)
+ * by restoring registers from the environment 'a'.
+ * The previous signal state is NOT restored.
+ */
+
+ENTRY(_setjmp)
+ movq %rdi,%rax
+ movq 0(%rsp),%rdx /* retval */
+ movq %rdx, 0(%rax) /* 0; retval */
+ movq %rbx, 8(%rax) /* 1; rbx */
+ movq %rsp,16(%rax) /* 2; rsp */
+ movq %rbp,24(%rax) /* 3; rbp */
+ movq %r12,32(%rax) /* 4; r12 */
+ movq %r13,40(%rax) /* 5; r13 */
+ movq %r14,48(%rax) /* 6; r14 */
+ movq %r15,56(%rax) /* 7; r15 */
+ fnstcw 64(%rax) /* 8; fpu cw */
+ stmxcsr 68(%rax) /* and mxcsr */
+ xorq %rax,%rax
+ ret
+END(_setjmp)
+
+ .weak CNAME(_longjmp)
+ENTRY(_longjmp)
+ movq %rdi,%rdx
+ /* Restore the mxcsr, but leave exception flags intact. */
+ stmxcsr -4(%rsp)
+ movl 68(%rdx),%eax
+ andl $0xffffffc0,%eax
+ movl -4(%rsp),%edi
+ andl $0x3f,%edi
+ xorl %eax,%edi
+ movl %edi,-4(%rsp)
+ ldmxcsr -4(%rsp)
+ movq %rsi,%rax /* retval */
+ movq 0(%rdx),%rcx
+ movq 8(%rdx),%rbx
+ movq 16(%rdx),%rsp
+ movq 24(%rdx),%rbp
+ movq 32(%rdx),%r12
+ movq 40(%rdx),%r13
+ movq 48(%rdx),%r14
+ movq 56(%rdx),%r15
+ fldcw 64(%rdx)
+ testq %rax,%rax
+ jnz 1f
+ incq %rax
+1: movq %rcx,0(%rsp)
+ ret
+END(_longjmp)
diff --git a/sys/boot/userboot/test/Makefile b/sys/boot/userboot/test/Makefile
new file mode 100644
index 0000000..24d89b7
--- /dev/null
+++ b/sys/boot/userboot/test/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+
+NO_MAN=
+WITHOUT_SSP=
+
+.include <bsd.own.mk>
+
+PROG= test
+INTERNALPROG=
+
+CFLAGS+= -I${.CURDIR}/..
+CFLAGS+= -I${.CURDIR}/../../..
+
+.include <bsd.prog.mk>
diff --git a/sys/boot/userboot/test/test.c b/sys/boot/userboot/test/test.c
new file mode 100644
index 0000000..a752a80
--- /dev/null
+++ b/sys/boot/userboot/test/test.c
@@ -0,0 +1,428 @@
+/*-
+ * Copyright (c) 2011 Google, Inc.
+ * 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 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <boot/userboot/userboot.h>
+
+char *host_base = NULL;
+struct termios term, oldterm;
+char *image;
+size_t image_size;
+int disk_fd = -1;
+
+uint64_t regs[16];
+uint64_t pc;
+
+void test_exit(void *arg, int v);
+
+/*
+ * Console i/o
+ */
+
+void
+test_putc(void *arg, int ch)
+{
+ char c = ch;
+
+ write(1, &c, 1);
+}
+
+int
+test_getc(void *arg)
+{
+ char c;
+
+ if (read(0, &c, 1) == 1)
+ return c;
+ return -1;
+}
+
+int
+test_poll(void *arg)
+{
+ int n;
+
+ if (ioctl(0, FIONREAD, &n) >= 0)
+ return (n > 0);
+ return (0);
+}
+
+/*
+ * Host filesystem i/o
+ */
+
+struct test_file {
+ int tf_isdir;
+ size_t tf_size;
+ struct stat tf_stat;
+ union {
+ int fd;
+ DIR *dir;
+ } tf_u;
+};
+
+int
+test_open(void *arg, const char *filename, void **h_return)
+{
+ struct stat st;
+ struct test_file *tf;
+ char path[PATH_MAX];
+
+ if (!host_base)
+ return (ENOENT);
+
+ strlcpy(path, host_base, PATH_MAX);
+ if (path[strlen(path) - 1] == '/')
+ path[strlen(path) - 1] = 0;
+ strlcat(path, filename, PATH_MAX);
+ tf = malloc(sizeof(struct test_file));
+ if (stat(path, &tf->tf_stat) < 0) {
+ free(tf);
+ return (errno);
+ }
+
+ tf->tf_size = st.st_size;
+ if (S_ISDIR(tf->tf_stat.st_mode)) {
+ tf->tf_isdir = 1;
+ tf->tf_u.dir = opendir(path);
+ if (!tf->tf_u.dir)
+ goto out;
+ *h_return = tf;
+ return (0);
+ }
+ if (S_ISREG(tf->tf_stat.st_mode)) {
+ tf->tf_isdir = 0;
+ tf->tf_u.fd = open(path, O_RDONLY);
+ if (tf->tf_u.fd < 0)
+ goto out;
+ *h_return = tf;
+ return (0);
+ }
+
+out:
+ free(tf);
+ return (EINVAL);
+}
+
+int
+test_close(void *arg, void *h)
+{
+ struct test_file *tf = h;
+
+ if (tf->tf_isdir)
+ closedir(tf->tf_u.dir);
+ else
+ close(tf->tf_u.fd);
+ free(tf);
+
+ return (0);
+}
+
+int
+test_isdir(void *arg, void *h)
+{
+ struct test_file *tf = h;
+
+ return (tf->tf_isdir);
+}
+
+int
+test_read(void *arg, void *h, void *dst, size_t size, size_t *resid_return)
+{
+ struct test_file *tf = h;
+ ssize_t sz;
+
+ if (tf->tf_isdir)
+ return (EINVAL);
+ sz = read(tf->tf_u.fd, dst, size);
+ if (sz < 0)
+ return (EINVAL);
+ *resid_return = size - sz;
+ return (0);
+}
+
+int
+test_readdir(void *arg, void *h, uint32_t *fileno_return, uint8_t *type_return,
+ size_t *namelen_return, char *name)
+{
+ struct test_file *tf = h;
+ struct dirent *dp;
+
+ if (!tf->tf_isdir)
+ return (EINVAL);
+
+ dp = readdir(tf->tf_u.dir);
+ if (!dp)
+ return (ENOENT);
+
+ /*
+ * Note: d_namlen is in the range 0..255 and therefore less
+ * than PATH_MAX so we don't need to test before copying.
+ */
+ *fileno_return = dp->d_fileno;
+ *type_return = dp->d_type;
+ *namelen_return = dp->d_namlen;
+ memcpy(name, dp->d_name, dp->d_namlen);
+ name[dp->d_namlen] = 0;
+
+ return (0);
+}
+
+int
+test_seek(void *arg, void *h, uint64_t offset, int whence)
+{
+ struct test_file *tf = h;
+
+ if (tf->tf_isdir)
+ return (EINVAL);
+ if (lseek(tf->tf_u.fd, offset, whence) < 0)
+ return (errno);
+ return (0);
+}
+
+int
+test_stat(void *arg, void *h, int *mode_return, int *uid_return, int *gid_return,
+ uint64_t *size_return)
+{
+ struct test_file *tf = h;
+
+ *mode_return = tf->tf_stat.st_mode;
+ *uid_return = tf->tf_stat.st_uid;
+ *gid_return = tf->tf_stat.st_gid;
+ *size_return = tf->tf_stat.st_size;
+ return (0);
+}
+
+/*
+ * Disk image i/o
+ */
+
+int
+test_diskread(void *arg, int unit, uint64_t offset, void *dst, size_t size,
+ size_t *resid_return)
+{
+ ssize_t n;
+
+ if (unit != 0 || disk_fd == -1)
+ return (EIO);
+ n = pread(disk_fd, dst, size, offset);
+ if (n < 0)
+ return (errno);
+ *resid_return = size - n;
+ return (0);
+}
+
+/*
+ * Guest virtual machine i/o
+ *
+ * Note: guest addresses are kernel virtual
+ */
+
+int
+test_copyin(void *arg, const void *from, uint64_t to, size_t size)
+{
+
+ to &= 0x7fffffff;
+ if (to > image_size)
+ return (EFAULT);
+ if (to + size > image_size)
+ size = image_size - to;
+ memcpy(&image[to], from, size);
+}
+
+int
+test_copyout(void *arg, uint64_t from, void *to, size_t size)
+{
+
+ from &= 0x7fffffff;
+ if (from > image_size)
+ return (EFAULT);
+ if (from + size > image_size)
+ size = image_size - from;
+ memcpy(to, &image[from], size);
+}
+
+void
+test_setreg(void *arg, int r, uint64_t v)
+{
+
+ if (r < 0 || r >= 16)
+ return;
+ regs[r] = v;
+}
+
+void
+test_setmsr(void *arg, int r, uint64_t v)
+{
+}
+
+void
+test_setcr(void *arg, int r, uint64_t v)
+{
+}
+
+void
+test_setgdt(void *arg, uint64_t v, size_t sz)
+{
+}
+
+void
+test_exec(void *arg, uint64_t pc)
+{
+ printf("Execute at 0x%llx\n", pc);
+ test_exit(arg, 0);
+}
+
+/*
+ * Misc
+ */
+
+void
+test_delay(void *arg, int usec)
+{
+
+ usleep(usec);
+}
+
+void
+test_exit(void *arg, int v)
+{
+
+ tcsetattr(0, TCSAFLUSH, &oldterm);
+ exit(v);
+}
+
+void
+test_getmem(void *arg, uint64_t *lowmem, uint64_t *highmem)
+{
+
+ *lowmem = 128*1024*1024;
+ *highmem = 0;
+}
+
+struct loader_callbacks_v1 cb = {
+ .putc = test_putc,
+ .getc = test_getc,
+ .poll = test_poll,
+
+ .open = test_open,
+ .close = test_close,
+ .isdir = test_isdir,
+ .read = test_read,
+ .readdir = test_readdir,
+ .seek = test_seek,
+ .stat = test_stat,
+
+ .diskread = test_diskread,
+
+ .copyin = test_copyin,
+ .copyout = test_copyout,
+ .setreg = test_setreg,
+ .setmsr = test_setmsr,
+ .setcr = test_setcr,
+ .setgdt = test_setgdt,
+ .exec = test_exec,
+
+ .delay = test_delay,
+ .exit = test_exit,
+ .getmem = test_getmem,
+};
+
+void
+usage()
+{
+
+ printf("usage: %s [-d <disk image path>] [-h <host filesystem path>\n");
+ exit(1);
+}
+
+int
+main(int argc, char** argv)
+{
+ void *h;
+ void (*func)(struct loader_callbacks_v1 *, void *, int, int);
+ int opt;
+ char *disk_image = NULL;
+
+ while ((opt = getopt(argc, argv, "d:h:")) != -1) {
+ switch (opt) {
+ case 'd':
+ disk_image = optarg;
+ break;
+
+ case 'h':
+ host_base = optarg;
+ break;
+
+ case '?':
+ usage();
+ }
+ }
+
+ h = dlopen("/boot/userboot.so",
+ RTLD_LOCAL);
+ if (!h) {
+ printf("%s\n", dlerror());
+ return (1);
+ }
+ func = dlsym(h, "loader_main");
+ if (!func) {
+ printf("%s\n", dlerror());
+ return (1);
+ }
+
+ image_size = 128*1024*1024;
+ image = malloc(image_size);
+ if (disk_image) {
+ disk_fd = open(disk_image, O_RDONLY);
+ if (disk_fd < 0)
+ err(1, "Can't open disk image '%s'", disk_image);
+ }
+
+ tcgetattr(0, &term);
+ oldterm = term;
+ term.c_iflag &= ~(ICRNL);
+ term.c_lflag &= ~(ICANON|ECHO);
+ tcsetattr(0, TCSAFLUSH, &term);
+
+ func(&cb, NULL, USERBOOT_VERSION_1, disk_fd >= 0);
+}
diff --git a/sys/boot/userboot/userboot.h b/sys/boot/userboot/userboot.h
new file mode 100644
index 0000000..7d8263e
--- /dev/null
+++ b/sys/boot/userboot/userboot.h
@@ -0,0 +1,178 @@
+/*-
+ * Copyright (c) 2011 Doug Rabson
+ * 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 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * USERBOOT interface versions
+ */
+#define USERBOOT_VERSION_1 1
+
+/*
+ * Exit codes from the loader
+ */
+#define USERBOOT_EXIT_QUIT 1
+#define USERBOOT_EXIT_REBOOT 2
+
+struct loader_callbacks_v1 {
+ /*
+ * Console i/o
+ */
+
+ /*
+ * Wait until a key is pressed on the console and then return it
+ */
+ int (*getc)(void *arg);
+
+ /*
+ * Write the character ch to the console
+ */
+ void (*putc)(void *arg, int ch);
+
+ /*
+ * Return non-zero if a key can be read from the console
+ */
+ int (*poll)(void *arg);
+
+ /*
+ * Host filesystem i/o
+ */
+
+ /*
+ * Open a file in the host filesystem
+ */
+ int (*open)(void *arg, const char *filename, void **h_return);
+
+ /*
+ * Close a file
+ */
+ int (*close)(void *arg, void *h);
+
+ /*
+ * Return non-zero if the file is a directory
+ */
+ int (*isdir)(void *arg, void *h);
+
+ /*
+ * Read size bytes from a file. The number of bytes remaining
+ * in dst after reading is returned in *resid_return
+ */
+ int (*read)(void *arg, void *h, void *dst, size_t size,
+ size_t *resid_return);
+
+ /*
+ * Read an entry from a directory. The entry's inode number is
+ * returned in *fileno_return, its type in *type_return and
+ * the name length in *namelen_return. The name itself is
+ * copied to the buffer name which must be at least PATH_MAX
+ * in size.
+ */
+ int (*readdir)(void *arg, void *h, uint32_t *fileno_return,
+ uint8_t *type_return, size_t *namelen_return, char *name);
+
+ /*
+ * Seek to a location within an open file
+ */
+ int (*seek)(void *arg, void *h, uint64_t offset,
+ int whence);
+
+ /*
+ * Return some stat(2) related information about the file
+ */
+ int (*stat)(void *arg, void *h, int *mode_return,
+ int *uid_return, int *gid_return, uint64_t *size_return);
+
+ /*
+ * Disk image i/o
+ */
+
+ /*
+ * Read from a disk image at the given offset
+ */
+ int (*diskread)(void *arg, int unit, uint64_t offset,
+ void *dst, size_t size, size_t *resid_return);
+
+ /*
+ * Guest virtual machine i/o
+ */
+
+ /*
+ * Copy to the guest address space
+ */
+ int (*copyin)(void *arg, const void *from,
+ uint64_t to, size_t size);
+
+ /*
+ * Copy from the guest address space
+ */
+ int (*copyout)(void *arg, uint64_t from,
+ void *to, size_t size);
+
+ /*
+ * Set a guest register value
+ */
+ void (*setreg)(void *arg, int, uint64_t);
+
+ /*
+ * Set a guest MSR value
+ */
+ void (*setmsr)(void *arg, int, uint64_t);
+
+ /*
+ * Set a guest CR value
+ */
+ void (*setcr)(void *arg, int, uint64_t);
+
+ /*
+ * Set the guest GDT address
+ */
+ void (*setgdt)(void *arg, uint64_t, size_t);
+
+ /*
+ * Transfer control to the guest at the given address
+ */
+ void (*exec)(void *arg, uint64_t pc);
+
+ /*
+ * Misc
+ */
+
+ /*
+ * Sleep for usec microseconds
+ */
+ void (*delay)(void *arg, int usec);
+
+ /*
+ * Exit with the given exit code
+ */
+ void (*exit)(void *arg, int v);
+
+ /*
+ * Return guest physical memory map details
+ */
+ void (*getmem)(void *arg, uint64_t *lowmem,
+ uint64_t *highmem);
+};
diff --git a/sys/boot/userboot/userboot/Makefile b/sys/boot/userboot/userboot/Makefile
new file mode 100644
index 0000000..7271fa7
--- /dev/null
+++ b/sys/boot/userboot/userboot/Makefile
@@ -0,0 +1,61 @@
+# $FreeBSD$
+
+NO_MAN=
+WITHOUT_SSP=
+
+.include <bsd.own.mk>
+
+SHLIB_NAME= userboot.so
+NO_CTF= yes
+STRIP=
+LIBDIR= /boot
+
+SRCS= autoload.c
+SRCS+= bootinfo.c
+SRCS+= bootinfo32.c
+SRCS+= bootinfo64.c
+SRCS+= conf.c
+SRCS+= console.c
+SRCS+= copy.c
+SRCS+= devicename.c
+SRCS+= elf32_freebsd.c
+SRCS+= elf64_freebsd.c
+SRCS+= host.c
+SRCS+= main.c
+SRCS+= userboot_cons.c
+SRCS+= userboot_disk.c
+SRCS+= vers.c
+
+CFLAGS+= -Wall
+CFLAGS+= -I${.CURDIR}/..
+CFLAGS+= -I${.CURDIR}/../../common
+CFLAGS+= -I${.CURDIR}/../../..
+CFLAGS+= -I${.CURDIR}/../../../../lib/libstand
+CFLAGS+= -ffreestanding -I.
+CFLAGS+= -DLOADER_GPT_SUPPORT
+
+LDFLAGS+= -nostdlib -Wl,-Bsymbolic
+
+NEWVERSWHAT= "User boot" ${MACHINE_CPUARCH}
+
+vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version
+ sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT}
+
+CLEANFILES= vers.c
+
+.if ${MK_FORTH} != "no"
+BOOT_FORTH= yes
+CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/i386
+LIBFICL= ${.OBJDIR}/../ficl/libficl.a
+LIBSTAND= ${.OBJDIR}/../libstand/libstand.a
+.endif
+
+# Always add MI sources
+.PATH: ${.CURDIR}/../../common
+.include "${.CURDIR}/../../common/Makefile.inc"
+CFLAGS+= -I${.CURDIR}/../../common
+CFLAGS+= -I.
+DPADD= ${LIBFICL} ${LIBSTAND}
+LDADD= ${LIBFICL} ${LIBSTAND}
+
+.include <bsd.lib.mk>
diff --git a/sys/boot/userboot/userboot/autoload.c b/sys/boot/userboot/userboot/autoload.c
new file mode 100644
index 0000000..a86afcf
--- /dev/null
+++ b/sys/boot/userboot/userboot/autoload.c
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2011 Google, Inc.
+ * 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+int
+userboot_autoload(void)
+{
+
+ return (0);
+}
diff --git a/sys/boot/userboot/userboot/bootinfo.c b/sys/boot/userboot/userboot/bootinfo.c
new file mode 100644
index 0000000..75ad5e7
--- /dev/null
+++ b/sys/boot/userboot/userboot/bootinfo.c
@@ -0,0 +1,192 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * 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 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 AUTHOR 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <sys/linker.h>
+
+#include "bootstrap.h"
+#include "libuserboot.h"
+
+/*
+ * Return a 'boothowto' value corresponding to the kernel arguments in
+ * (kargs) and any relevant environment variables.
+ */
+static struct
+{
+ const char *ev;
+ int mask;
+} howto_names[] = {
+ {"boot_askname", RB_ASKNAME},
+ {"boot_cdrom", RB_CDROM},
+ {"boot_ddb", RB_KDB},
+ {"boot_dfltroot", RB_DFLTROOT},
+ {"boot_gdb", RB_GDB},
+ {"boot_multicons", RB_MULTIPLE},
+ {"boot_mute", RB_MUTE},
+ {"boot_pause", RB_PAUSE},
+ {"boot_serial", RB_SERIAL},
+ {"boot_single", RB_SINGLE},
+ {"boot_verbose", RB_VERBOSE},
+ {NULL, 0}
+};
+
+int
+bi_getboothowto(char *kargs)
+{
+ char *cp;
+ char *curpos, *next, *string;
+ int howto;
+ int active;
+ int i;
+ int vidconsole;
+
+ /* Parse kargs */
+ howto = 0;
+ if (kargs != NULL) {
+ cp = kargs;
+ active = 0;
+ while (*cp != 0) {
+ if (!active && (*cp == '-')) {
+ active = 1;
+ } else if (active)
+ switch (*cp) {
+ case 'a':
+ howto |= RB_ASKNAME;
+ break;
+ case 'C':
+ howto |= RB_CDROM;
+ break;
+ case 'd':
+ howto |= RB_KDB;
+ break;
+ case 'D':
+ howto |= RB_MULTIPLE;
+ break;
+ case 'm':
+ howto |= RB_MUTE;
+ break;
+ case 'g':
+ howto |= RB_GDB;
+ break;
+ case 'h':
+ howto |= RB_SERIAL;
+ break;
+ case 'p':
+ howto |= RB_PAUSE;
+ break;
+ case 'r':
+ howto |= RB_DFLTROOT;
+ break;
+ case 's':
+ howto |= RB_SINGLE;
+ break;
+ case 'v':
+ howto |= RB_VERBOSE;
+ break;
+ default:
+ active = 0;
+ break;
+ }
+ cp++;
+ }
+ }
+ /* get equivalents from the environment */
+ for (i = 0; howto_names[i].ev != NULL; i++)
+ if (getenv(howto_names[i].ev) != NULL)
+ howto |= howto_names[i].mask;
+
+ /* Enable selected consoles */
+ string = next = strdup(getenv("console"));
+ vidconsole = 0;
+ while (next != NULL) {
+ curpos = strsep(&next, " ,");
+ if (*curpos == '\0')
+ continue;
+ if (!strcmp(curpos, "vidconsole"))
+ vidconsole = 1;
+ else if (!strcmp(curpos, "comconsole"))
+ howto |= RB_SERIAL;
+ else if (!strcmp(curpos, "nullconsole"))
+ howto |= RB_MUTE;
+ }
+
+ if (vidconsole && (howto & RB_SERIAL))
+ howto |= RB_MULTIPLE;
+
+ /*
+ * XXX: Note that until the kernel is ready to respect multiple consoles
+ * for the boot messages, the first named console is the primary console
+ */
+ if (!strcmp(string, "vidconsole"))
+ howto &= ~RB_SERIAL;
+
+ free(string);
+
+ return(howto);
+}
+
+void
+bi_setboothowto(int howto)
+{
+ int i;
+
+ for (i = 0; howto_names[i].ev != NULL; i++)
+ if (howto & howto_names[i].mask)
+ setenv(howto_names[i].ev, "YES", 1);
+}
+
+/*
+ * Copy the environment into the load area starting at (addr).
+ * Each variable is formatted as <name>=<value>, with a single nul
+ * separating each variable, and a double nul terminating the environment.
+ */
+vm_offset_t
+bi_copyenv(vm_offset_t addr)
+{
+ struct env_var *ep;
+
+ /* traverse the environment */
+ for (ep = environ; ep != NULL; ep = ep->ev_next) {
+ CALLBACK(copyin, ep->ev_name, addr, strlen(ep->ev_name));
+ addr += strlen(ep->ev_name);
+ CALLBACK(copyin, "=", addr, 1);
+ addr++;
+ if (ep->ev_value != NULL) {
+ CALLBACK(copyin, ep->ev_value, addr, strlen(ep->ev_value));
+ addr += strlen(ep->ev_value);
+ }
+ CALLBACK(copyin, "", addr, 1);
+ addr++;
+ }
+ CALLBACK(copyin, "", addr, 1);
+ addr++;
+ return(addr);
+}
diff --git a/sys/boot/userboot/userboot/bootinfo32.c b/sys/boot/userboot/userboot/bootinfo32.c
new file mode 100644
index 0000000..00784c9
--- /dev/null
+++ b/sys/boot/userboot/userboot/bootinfo32.c
@@ -0,0 +1,264 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * 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 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 AUTHOR 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <sys/linker.h>
+#include <i386/include/bootinfo.h>
+
+#include "bootstrap.h"
+#include "libuserboot.h"
+
+static struct bootinfo bi;
+
+/*
+ * Copy module-related data into the load area, where it can be
+ * used as a directory for loaded modules.
+ *
+ * Module data is presented in a self-describing format. Each datum
+ * is preceded by a 32-bit identifier and a 32-bit size field.
+ *
+ * Currently, the following data are saved:
+ *
+ * MOD_NAME (variable) module name (string)
+ * MOD_TYPE (variable) module type (string)
+ * MOD_ARGS (variable) module parameters (string)
+ * MOD_ADDR sizeof(vm_offset_t) module load address
+ * MOD_SIZE sizeof(size_t) module size
+ * MOD_METADATA (variable) type-specific metadata
+ */
+#define COPY32(v, a, c) { \
+ u_int32_t x = (v); \
+ if (c) \
+ CALLBACK(copyin, &x, a, sizeof(x)); \
+ a += sizeof(x); \
+}
+
+#define MOD_STR(t, a, s, c) { \
+ COPY32(t, a, c); \
+ COPY32(strlen(s) + 1, a, c); \
+ if (c) \
+ CALLBACK(copyin, s, a, strlen(s) + 1); \
+ a += roundup(strlen(s) + 1, sizeof(u_long));\
+}
+
+#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c)
+#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c)
+#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c)
+
+#define MOD_VAR(t, a, s, c) { \
+ COPY32(t, a, c); \
+ COPY32(sizeof(s), a, c); \
+ if (c) \
+ CALLBACK(copyin, &s, a, sizeof(s)); \
+ a += roundup(sizeof(s), sizeof(u_long)); \
+}
+
+#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c)
+#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c)
+
+#define MOD_METADATA(a, mm, c) { \
+ COPY32(MODINFO_METADATA | mm->md_type, a, c); \
+ COPY32(mm->md_size, a, c); \
+ if (c) \
+ CALLBACK(copyin, mm->md_data, a, mm->md_size); \
+ a += roundup(mm->md_size, sizeof(u_long));\
+}
+
+#define MOD_END(a, c) { \
+ COPY32(MODINFO_END, a, c); \
+ COPY32(0, a, c); \
+}
+
+static vm_offset_t
+bi_copymodules32(vm_offset_t addr)
+{
+ struct preloaded_file *fp;
+ struct file_metadata *md;
+ int c;
+
+ c = addr != 0;
+ /* start with the first module on the list, should be the kernel */
+ for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
+
+ MOD_NAME(addr, fp->f_name, c); /* this field must come first */
+ MOD_TYPE(addr, fp->f_type, c);
+ if (fp->f_args)
+ MOD_ARGS(addr, fp->f_args, c);
+ MOD_ADDR(addr, fp->f_addr, c);
+ MOD_SIZE(addr, fp->f_size, c);
+ for (md = fp->f_metadata; md != NULL; md = md->md_next)
+ if (!(md->md_type & MODINFOMD_NOCOPY))
+ MOD_METADATA(addr, md, c);
+ }
+ MOD_END(addr, c);
+ return(addr);
+}
+
+/*
+ * Load the information expected by an i386 kernel.
+ *
+ * - The 'boothowto' argument is constructed
+ * - The 'bootdev' argument is constructed
+ * - The 'bootinfo' struct is constructed, and copied into the kernel space.
+ * - The kernel environment is copied into kernel space.
+ * - Module metadata are formatted and placed in kernel space.
+ */
+int
+bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t *modulep, vm_offset_t *kernendp)
+{
+ struct preloaded_file *xp, *kfp;
+ struct i386_devdesc *rootdev;
+ struct file_metadata *md;
+ vm_offset_t addr;
+ vm_offset_t kernend;
+ vm_offset_t envp;
+ vm_offset_t size;
+ vm_offset_t ssym, esym;
+ char *rootdevname;
+ int bootdevnr, i, howto;
+ char *kernelname;
+ const char *kernelpath;
+
+ howto = bi_getboothowto(args);
+
+ /*
+ * Allow the environment variable 'rootdev' to override the supplied device
+ * This should perhaps go to MI code and/or have $rootdev tested/set by
+ * MI code before launching the kernel.
+ */
+ rootdevname = getenv("rootdev");
+ userboot_getdev((void **)(&rootdev), rootdevname, NULL);
+ if (rootdev == NULL) { /* bad $rootdev/$currdev */
+ printf("can't determine root device\n");
+ return(EINVAL);
+ }
+
+ /* Try reading the /etc/fstab file to select the root device */
+ getrootmount(userboot_fmtdev((void *)rootdev));
+
+ bootdevnr = 0;
+#if 0
+ if (bootdevnr == -1) {
+ printf("root device %s invalid\n", i386_fmtdev(rootdev));
+ return (EINVAL);
+ }
+#endif
+ free(rootdev);
+
+ /* find the last module in the chain */
+ addr = 0;
+ for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
+ if (addr < (xp->f_addr + xp->f_size))
+ addr = xp->f_addr + xp->f_size;
+ }
+ /* pad to a page boundary */
+ addr = roundup(addr, PAGE_SIZE);
+
+ /* copy our environment */
+ envp = addr;
+ addr = bi_copyenv(addr);
+
+ /* pad to a page boundary */
+ addr = roundup(addr, PAGE_SIZE);
+
+ kfp = file_findfile(NULL, "elf kernel");
+ if (kfp == NULL)
+ kfp = file_findfile(NULL, "elf32 kernel");
+ if (kfp == NULL)
+ panic("can't find kernel file");
+ kernend = 0; /* fill it in later */
+ file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
+ file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
+ file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
+#if 0
+ bios_addsmapdata(kfp);
+#endif
+
+ /* Figure out the size and location of the metadata */
+ *modulep = addr;
+ size = bi_copymodules32(0);
+ kernend = roundup(addr + size, PAGE_SIZE);
+ *kernendp = kernend;
+
+ /* patch MODINFOMD_KERNEND */
+ md = file_findmetadata(kfp, MODINFOMD_KERNEND);
+ bcopy(&kernend, md->md_data, sizeof kernend);
+
+ /* copy module list and metadata */
+ (void)bi_copymodules32(addr);
+
+ ssym = esym = 0;
+ md = file_findmetadata(kfp, MODINFOMD_SSYM);
+ if (md != NULL)
+ ssym = *((vm_offset_t *)&(md->md_data));
+ md = file_findmetadata(kfp, MODINFOMD_ESYM);
+ if (md != NULL)
+ esym = *((vm_offset_t *)&(md->md_data));
+ if (ssym == 0 || esym == 0)
+ ssym = esym = 0; /* sanity */
+
+ /* legacy bootinfo structure */
+ kernelname = getenv("kernelname");
+ userboot_getdev(NULL, kernelname, &kernelpath);
+ bi.bi_version = BOOTINFO_VERSION;
+ bi.bi_kernelname = 0; /* XXX char * -> kernel name */
+ bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */
+ bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */
+#if 0
+ for (i = 0; i < N_BIOS_GEOM; i++)
+ bi.bi_bios_geom[i] = bd_getbigeom(i);
+#endif
+ bi.bi_size = sizeof(bi);
+ bi.bi_memsizes_valid = 1;
+#if 0
+ bi.bi_basemem = bios_basemem / 1024;
+ bi.bi_extmem = bios_extmem / 1024;
+#endif
+ bi.bi_envp = envp;
+ bi.bi_modulep = *modulep;
+ bi.bi_kernend = kernend;
+ bi.bi_symtab = ssym; /* XXX this is only the primary kernel symtab */
+ bi.bi_esymtab = esym;
+
+ /*
+ * Copy the legacy bootinfo and kernel name to the guest at 0x2000
+ */
+ bi.bi_kernelname = (char *) (0x2000 + sizeof(bi));
+ CALLBACK(copyin, &bi, 0x2000, sizeof(bi));
+ CALLBACK(copyin, kernelname, 0x2000 + sizeof(bi), strlen(kernelname) + 1);
+
+ /* legacy boot arguments */
+ *howtop = howto | RB_BOOTINFO;
+ *bootdevp = bootdevnr;
+ *bip = 0x2000;
+
+ return(0);
+}
diff --git a/sys/boot/userboot/userboot/bootinfo64.c b/sys/boot/userboot/userboot/bootinfo64.c
new file mode 100644
index 0000000..fc7c14d
--- /dev/null
+++ b/sys/boot/userboot/userboot/bootinfo64.c
@@ -0,0 +1,304 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * 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 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 AUTHOR 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <sys/linker.h>
+#include <i386/include/bootinfo.h>
+#include <machine/cpufunc.h>
+#include <machine/psl.h>
+#include <machine/specialreg.h>
+
+#include "bootstrap.h"
+#include "libuserboot.h"
+
+/*
+ * Copy module-related data into the load area, where it can be
+ * used as a directory for loaded modules.
+ *
+ * Module data is presented in a self-describing format. Each datum
+ * is preceded by a 32-bit identifier and a 32-bit size field.
+ *
+ * Currently, the following data are saved:
+ *
+ * MOD_NAME (variable) module name (string)
+ * MOD_TYPE (variable) module type (string)
+ * MOD_ARGS (variable) module parameters (string)
+ * MOD_ADDR sizeof(vm_offset_t) module load address
+ * MOD_SIZE sizeof(size_t) module size
+ * MOD_METADATA (variable) type-specific metadata
+ */
+#define COPY32(v, a, c) { \
+ u_int32_t x = (v); \
+ if (c) \
+ CALLBACK(copyin, &x, a, sizeof(x)); \
+ a += sizeof(x); \
+}
+
+#define MOD_STR(t, a, s, c) { \
+ COPY32(t, a, c); \
+ COPY32(strlen(s) + 1, a, c); \
+ if (c) \
+ CALLBACK(copyin, s, a, strlen(s) + 1); \
+ a += roundup(strlen(s) + 1, sizeof(u_int64_t));\
+}
+
+#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c)
+#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c)
+#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c)
+
+#define MOD_VAR(t, a, s, c) { \
+ COPY32(t, a, c); \
+ COPY32(sizeof(s), a, c); \
+ if (c) \
+ CALLBACK(copyin, &s, a, sizeof(s)); \
+ a += roundup(sizeof(s), sizeof(u_int64_t)); \
+}
+
+#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c)
+#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c)
+
+#define MOD_METADATA(a, mm, c) { \
+ COPY32(MODINFO_METADATA | mm->md_type, a, c); \
+ COPY32(mm->md_size, a, c); \
+ if (c) \
+ CALLBACK(copyin, mm->md_data, a, mm->md_size); \
+ a += roundup(mm->md_size, sizeof(u_int64_t));\
+}
+
+#define MOD_END(a, c) { \
+ COPY32(MODINFO_END, a, c); \
+ COPY32(0, a, c); \
+}
+
+static vm_offset_t
+bi_copymodules64(vm_offset_t addr)
+{
+ struct preloaded_file *fp;
+ struct file_metadata *md;
+ int c;
+ u_int64_t v;
+
+ c = addr != 0;
+ /* start with the first module on the list, should be the kernel */
+ for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
+
+ MOD_NAME(addr, fp->f_name, c); /* this field must come first */
+ MOD_TYPE(addr, fp->f_type, c);
+ if (fp->f_args)
+ MOD_ARGS(addr, fp->f_args, c);
+ v = fp->f_addr;
+ MOD_ADDR(addr, v, c);
+ v = fp->f_size;
+ MOD_SIZE(addr, v, c);
+ for (md = fp->f_metadata; md != NULL; md = md->md_next)
+ if (!(md->md_type & MODINFOMD_NOCOPY))
+ MOD_METADATA(addr, md, c);
+ }
+ MOD_END(addr, c);
+ return(addr);
+}
+
+/*
+ * Check to see if this CPU supports long mode.
+ */
+static int
+bi_checkcpu(void)
+{
+#if 0
+ char *cpu_vendor;
+ int vendor[3];
+ int eflags, regs[4];
+
+ /* Check for presence of "cpuid". */
+ eflags = read_eflags();
+ write_eflags(eflags ^ PSL_ID);
+ if (!((eflags ^ read_eflags()) & PSL_ID))
+ return (0);
+
+ /* Fetch the vendor string. */
+ do_cpuid(0, regs);
+ vendor[0] = regs[1];
+ vendor[1] = regs[3];
+ vendor[2] = regs[2];
+ cpu_vendor = (char *)vendor;
+
+ /* Check for vendors that support AMD features. */
+ if (strncmp(cpu_vendor, INTEL_VENDOR_ID, 12) != 0 &&
+ strncmp(cpu_vendor, AMD_VENDOR_ID, 12) != 0 &&
+ strncmp(cpu_vendor, CENTAUR_VENDOR_ID, 12) != 0)
+ return (0);
+
+ /* Has to support AMD features. */
+ do_cpuid(0x80000000, regs);
+ if (!(regs[0] >= 0x80000001))
+ return (0);
+
+ /* Check for long mode. */
+ do_cpuid(0x80000001, regs);
+ return (regs[3] & AMDID_LM);
+#else
+ return (1);
+#endif
+}
+
+struct smap {
+ uint64_t base;
+ uint64_t length;
+ uint32_t type;
+} __packed;
+
+/* From FreeBSD <machine/pc/bios.h> */
+#define SMAP_TYPE_MEMORY 1
+
+#define GB (1024UL * 1024 * 1024)
+
+#define MODINFOMD_SMAP 0x1001
+
+static void
+bios_addsmapdata(struct preloaded_file *kfp)
+{
+ uint64_t lowmem, highmem;
+ int smapnum, len;
+ struct smap smap[3], *sm;
+
+ CALLBACK(getmem, &lowmem, &highmem);
+
+ sm = &smap[0];
+
+ sm->base = 0; /* base memory */
+ sm->length = 640 * 1024;
+ sm->type = SMAP_TYPE_MEMORY;
+ sm++;
+
+ sm->base = 0x100000; /* extended memory */
+ sm->length = lowmem - 0x100000;
+ sm->type = SMAP_TYPE_MEMORY;
+ sm++;
+
+ smapnum = 2;
+
+ if (highmem != 0) {
+ sm->base = 4 * GB;
+ sm->length = highmem;
+ sm->type = SMAP_TYPE_MEMORY;
+ smapnum++;
+ }
+
+ len = smapnum * sizeof (struct smap);
+ file_addmetadata(kfp, MODINFOMD_SMAP, len, &smap[0]);
+}
+
+/*
+ * Load the information expected by an amd64 kernel.
+ *
+ * - The 'boothowto' argument is constructed
+ * - The 'bootdev' argument is constructed
+ * - The 'bootinfo' struct is constructed, and copied into the kernel space.
+ * - The kernel environment is copied into kernel space.
+ * - Module metadata are formatted and placed in kernel space.
+ */
+int
+bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernendp)
+{
+ struct preloaded_file *xp, *kfp;
+ struct userboot_devdesc *rootdev;
+ struct file_metadata *md;
+ vm_offset_t addr;
+ u_int64_t kernend;
+ u_int64_t envp;
+ vm_offset_t size;
+ char *rootdevname;
+ int howto;
+
+ if (!bi_checkcpu()) {
+ printf("CPU doesn't support long mode\n");
+ return (EINVAL);
+ }
+
+ howto = bi_getboothowto(args);
+
+ /*
+ * Allow the environment variable 'rootdev' to override the supplied device
+ * This should perhaps go to MI code and/or have $rootdev tested/set by
+ * MI code before launching the kernel.
+ */
+ rootdevname = getenv("rootdev");
+ userboot_getdev((void **)(&rootdev), rootdevname, NULL);
+ if (rootdev == NULL) { /* bad $rootdev/$currdev */
+ printf("can't determine root device\n");
+ return(EINVAL);
+ }
+
+ /* Try reading the /etc/fstab file to select the root device */
+ getrootmount(userboot_fmtdev((void *)rootdev));
+
+ /* find the last module in the chain */
+ addr = 0;
+ for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
+ if (addr < (xp->f_addr + xp->f_size))
+ addr = xp->f_addr + xp->f_size;
+ }
+ /* pad to a page boundary */
+ addr = roundup(addr, PAGE_SIZE);
+
+ /* copy our environment */
+ envp = addr;
+ addr = bi_copyenv(addr);
+
+ /* pad to a page boundary */
+ addr = roundup(addr, PAGE_SIZE);
+
+ kfp = file_findfile(NULL, "elf kernel");
+ if (kfp == NULL)
+ kfp = file_findfile(NULL, "elf64 kernel");
+ if (kfp == NULL)
+ panic("can't find kernel file");
+ kernend = 0; /* fill it in later */
+ file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
+ file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
+ file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
+ bios_addsmapdata(kfp);
+
+ /* Figure out the size and location of the metadata */
+ *modulep = addr;
+ size = bi_copymodules64(0);
+ kernend = roundup(addr + size, PAGE_SIZE);
+ *kernendp = kernend;
+
+ /* patch MODINFOMD_KERNEND */
+ md = file_findmetadata(kfp, MODINFOMD_KERNEND);
+ bcopy(&kernend, md->md_data, sizeof kernend);
+
+ /* copy module list and metadata */
+ (void)bi_copymodules64(addr);
+
+ return(0);
+}
diff --git a/sys/boot/userboot/userboot/conf.c b/sys/boot/userboot/userboot/conf.c
new file mode 100644
index 0000000..0c57eba
--- /dev/null
+++ b/sys/boot/userboot/userboot/conf.c
@@ -0,0 +1,93 @@
+/*-
+ * 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.
+ *
+ * $NetBSD: conf.c,v 1.2 1997/03/22 09:03:29 thorpej Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+
+#include "libuserboot.h"
+
+/*
+ * We could use linker sets for some or all of these, but
+ * then we would have to control what ended up linked into
+ * the bootstrap. So it's easier to conditionalise things
+ * here.
+ *
+ * XXX rename these arrays to be consistent and less namespace-hostile
+ */
+
+/* Exported for libstand */
+struct devsw *devsw[] = {
+ &host_dev,
+ &userboot_disk,
+ NULL
+};
+
+struct fs_ops *file_system[] = {
+ &host_fsops,
+ &ufs_fsops,
+ &gzipfs_fsops,
+ NULL
+};
+
+/* Exported for i386 only */
+/*
+ * Sort formats so that those that can detect based on arguments
+ * rather than reading the file go first.
+ */
+extern struct file_format i386_elf;
+extern struct file_format i386_elf_obj;
+extern struct file_format amd64_elf;
+extern struct file_format amd64_elf_obj;
+
+struct file_format *file_formats[] = {
+ &i386_elf,
+ &i386_elf_obj,
+ &amd64_elf,
+ &amd64_elf_obj,
+ NULL
+};
+
+/*
+ * Consoles
+ *
+ * We don't prototype these in libuserboot.h because they require
+ * data structures from bootstrap.h as well.
+ */
+extern struct console userboot_console;
+
+struct console *consoles[] = {
+ &userboot_console,
+ NULL
+};
diff --git a/sys/boot/userboot/userboot/copy.c b/sys/boot/userboot/userboot/copy.c
new file mode 100644
index 0000000..94548f2
--- /dev/null
+++ b/sys/boot/userboot/userboot/copy.c
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2011 Google, Inc.
+ * 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+
+#include "libuserboot.h"
+
+ssize_t
+userboot_copyin(const void *src, vm_offset_t va, size_t len)
+{
+
+ CALLBACK(copyin, src, va, len);
+ return (len);
+}
+
+ssize_t
+userboot_copyout(vm_offset_t va, void *dst, size_t len)
+{
+
+ CALLBACK(copyout, va, dst, len);
+ return (len);
+}
+
+ssize_t
+userboot_readin(int fd, vm_offset_t va, size_t len)
+{
+ void *pa;
+ ssize_t res, s;
+ size_t sz;
+ char buf[4096];
+
+ res = 0;
+ while (len > 0) {
+ sz = len;
+ if (sz > sizeof(buf))
+ sz = sizeof(buf);
+ s = read(fd, buf, sz);
+ if (s == 0)
+ break;
+ if (s < 0)
+ return (s);
+ CALLBACK(copyin, buf, va, s);
+ len -= s;
+ res += s;
+ va += s;
+ }
+ return (res);
+}
diff --git a/sys/boot/userboot/userboot/devicename.c b/sys/boot/userboot/userboot/devicename.c
new file mode 100644
index 0000000..24c5179
--- /dev/null
+++ b/sys/boot/userboot/userboot/devicename.c
@@ -0,0 +1,274 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * 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 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 AUTHOR 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <string.h>
+#include <sys/disklabel.h>
+
+#include "bootstrap.h"
+#include "disk.h"
+#include "libuserboot.h"
+
+static int userboot_parsedev(struct disk_devdesc **dev, const char *devspec, const char **path);
+
+/*
+ * Point (dev) at an allocated device specifier for the device matching the
+ * path in (devspec). If it contains an explicit device specification,
+ * use that. If not, use the default device.
+ */
+int
+userboot_getdev(void **vdev, const char *devspec, const char **path)
+{
+ struct disk_devdesc **dev = (struct disk_devdesc **)vdev;
+ int rv;
+
+ /*
+ * If it looks like this is just a path and no
+ * device, go with the current device.
+ */
+ if ((devspec == NULL) ||
+ (devspec[0] == '/') ||
+ (strchr(devspec, ':') == NULL)) {
+
+ if (((rv = userboot_parsedev(dev, getenv("currdev"), NULL)) == 0) &&
+ (path != NULL))
+ *path = devspec;
+ return(rv);
+ }
+
+ /*
+ * Try to parse the device name off the beginning of the devspec
+ */
+ return(userboot_parsedev(dev, devspec, path));
+}
+
+/*
+ * Point (dev) at an allocated device specifier matching the string version
+ * at the beginning of (devspec). Return a pointer to the remaining
+ * text in (path).
+ *
+ * In all cases, the beginning of (devspec) is compared to the names
+ * of known devices in the device switch, and then any following text
+ * is parsed according to the rules applied to the device type.
+ *
+ * For disk-type devices, the syntax is:
+ *
+ * disk<unit>[s<slice>][<partition>]:
+ *
+ */
+static int
+userboot_parsedev(struct disk_devdesc **dev, const char *devspec, const char **path)
+{
+ struct disk_devdesc *idev;
+ struct devsw *dv;
+ int i, unit, slice, partition, err;
+ char *cp;
+ const char *np;
+
+ /* minimum length check */
+ if (strlen(devspec) < 2)
+ return(EINVAL);
+
+ /* look for a device that matches */
+ for (i = 0, dv = NULL; devsw[i] != NULL; i++) {
+ if (!strncmp(devspec, devsw[i]->dv_name, strlen(devsw[i]->dv_name))) {
+ dv = devsw[i];
+ break;
+ }
+ }
+ if (dv == NULL)
+ return(ENOENT);
+ idev = malloc(sizeof(struct disk_devdesc));
+ err = 0;
+ np = (devspec + strlen(dv->dv_name));
+
+ switch(dv->dv_type) {
+ case DEVT_NONE: /* XXX what to do here? Do we care? */
+ break;
+
+ case DEVT_DISK:
+ unit = -1;
+ slice = -1;
+ partition = -1;
+ if (*np && (*np != ':')) {
+ unit = strtol(np, &cp, 10); /* next comes the unit number */
+ if (cp == np) {
+ err = EUNIT;
+ goto fail;
+ }
+#ifdef LOADER_GPT_SUPPORT
+ if (*cp == 'p') { /* got a GPT partition */
+ np = cp + 1;
+ slice = strtol(np, &cp, 10);
+ if (cp == np) {
+ err = ESLICE;
+ goto fail;
+ }
+ if (*cp && (*cp != ':')) {
+ err = EINVAL;
+ goto fail;
+ }
+ partition = 0xff;
+ } else {
+#endif
+ if (*cp == 's') { /* got a slice number */
+ np = cp + 1;
+ slice = strtol(np, &cp, 10);
+ if (cp == np) {
+ err = ESLICE;
+ goto fail;
+ }
+ }
+ if (*cp && (*cp != ':')) {
+ partition = *cp - 'a'; /* got a partition number */
+ if ((partition < 0) || (partition >= MAXPARTITIONS)) {
+ err = EPART;
+ goto fail;
+ }
+ cp++;
+ }
+#ifdef LOADER_GPT_SUPPORT
+ }
+#endif
+ } else {
+ cp = np;
+ }
+ if (*cp && (*cp != ':')) {
+ err = EINVAL;
+ goto fail;
+ }
+
+ idev->d_unit = unit;
+ idev->d_slice = slice;
+ idev->d_partition = partition;
+ if (path != NULL)
+ *path = (*cp == 0) ? cp : cp + 1;
+ break;
+
+ case DEVT_CD:
+ case DEVT_NET:
+ case DEVT_ZFS:
+ unit = 0;
+
+ if (*np && (*np != ':')) {
+ unit = strtol(np, &cp, 0); /* get unit number if present */
+ if (cp == np) {
+ err = EUNIT;
+ goto fail;
+ }
+ } else {
+ cp = np;
+ }
+ if (*cp && (*cp != ':')) {
+ err = EINVAL;
+ goto fail;
+ }
+
+ idev->d_unit = unit;
+ if (path != NULL)
+ *path = (*cp == 0) ? cp : cp + 1;
+ break;
+
+ default:
+ err = EINVAL;
+ goto fail;
+ }
+ idev->d_dev = dv;
+ idev->d_type = dv->dv_type;
+ if (dev == NULL) {
+ free(idev);
+ } else {
+ *dev = idev;
+ }
+ return(0);
+
+ fail:
+ free(idev);
+ return(err);
+}
+
+
+char *
+userboot_fmtdev(void *vdev)
+{
+ struct disk_devdesc *dev = (struct disk_devdesc *)vdev;
+ static char buf[128]; /* XXX device length constant? */
+ char *cp;
+
+ switch(dev->d_type) {
+ case DEVT_NONE:
+ strcpy(buf, "(no device)");
+ break;
+
+ case DEVT_CD:
+ sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
+ break;
+
+ case DEVT_DISK:
+ cp = buf;
+ cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_unit);
+#ifdef LOADER_GPT_SUPPORT
+ if (dev->d_partition == 0xff) {
+ cp += sprintf(cp, "p%d", dev->d_slice);
+ } else {
+#endif
+ if (dev->d_slice > 0)
+ cp += sprintf(cp, "s%d", dev->d_slice);
+ if (dev->d_partition >= 0)
+ cp += sprintf(cp, "%c", dev->d_partition + 'a');
+#ifdef LOADER_GPT_SUPPORT
+ }
+#endif
+ strcat(cp, ":");
+ break;
+
+ case DEVT_NET:
+ case DEVT_ZFS:
+ sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
+ break;
+ }
+ return(buf);
+}
+
+
+/*
+ * Set currdev to suit the value being supplied in (value)
+ */
+int
+userboot_setcurrdev(struct env_var *ev, int flags, const void *value)
+{
+ struct disk_devdesc *ncurr;
+ int rv;
+
+ if ((rv = userboot_parsedev(&ncurr, value, NULL)) != 0)
+ return(rv);
+ free(ncurr);
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+ return(0);
+}
diff --git a/sys/boot/userboot/userboot/elf32_freebsd.c b/sys/boot/userboot/userboot/elf32_freebsd.c
new file mode 100644
index 0000000..8489385
--- /dev/null
+++ b/sys/boot/userboot/userboot/elf32_freebsd.c
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * 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 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 AUTHOR 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/linker.h>
+#include <string.h>
+#include <i386/include/bootinfo.h>
+#include <i386/include/elf.h>
+#include <stand.h>
+
+#include "bootstrap.h"
+#include "libuserboot.h"
+
+static int elf32_exec(struct preloaded_file *amp);
+static int elf32_obj_exec(struct preloaded_file *amp);
+
+struct file_format i386_elf = { elf32_loadfile, elf32_exec };
+struct file_format i386_elf_obj = { elf32_obj_loadfile, elf32_obj_exec };
+
+/*
+ * There is an ELF kernel and one or more ELF modules loaded.
+ * We wish to start executing the kernel image, so make such
+ * preparations as are required, and do so.
+ */
+static int
+elf32_exec(struct preloaded_file *fp)
+{
+ struct file_metadata *md;
+ Elf_Ehdr *ehdr;
+ vm_offset_t entry, bootinfop, modulep, kernend;
+ int boothowto, err, bootdev;
+ uint32_t stack[1024];
+
+
+ if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
+ return(EFTYPE);
+ ehdr = (Elf_Ehdr *)&(md->md_data);
+
+ err = bi_load32(fp->f_args, &boothowto, &bootdev, &bootinfop, &modulep, &kernend);
+ if (err != 0)
+ return(err);
+ entry = ehdr->e_entry & 0xffffff;
+
+#ifdef DEBUG
+ printf("Start @ 0x%lx ...\n", entry);
+#endif
+
+ dev_cleanup();
+
+ /*
+ * Build a scratch stack at physical 0x1000
+ */
+ stack[0] = boothowto;
+ stack[1] = bootdev;
+ stack[2] = 0;
+ stack[3] = 0;
+ stack[4] = 0;
+ stack[5] = bootinfop;
+ stack[6] = modulep;
+ stack[7] = kernend;
+ CALLBACK(copyin, stack, 0x1000, sizeof(stack));
+ CALLBACK(setreg, 4, 0x1000);
+ CALLBACK(exec, entry);
+
+ panic("exec returned");
+}
+
+static int
+elf32_obj_exec(struct preloaded_file *fp)
+{
+ return (EFTYPE);
+}
diff --git a/sys/boot/userboot/userboot/elf64_freebsd.c b/sys/boot/userboot/userboot/elf64_freebsd.c
new file mode 100644
index 0000000..36129ef
--- /dev/null
+++ b/sys/boot/userboot/userboot/elf64_freebsd.c
@@ -0,0 +1,172 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * 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 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 AUTHOR 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define __ELF_WORD_SIZE 64
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/linker.h>
+#include <string.h>
+#include <i386/include/bootinfo.h>
+#include <machine/elf.h>
+#include <stand.h>
+
+#include "bootstrap.h"
+#include "libuserboot.h"
+
+static int elf64_exec(struct preloaded_file *amp);
+static int elf64_obj_exec(struct preloaded_file *amp);
+
+struct file_format amd64_elf = { elf64_loadfile, elf64_exec };
+struct file_format amd64_elf_obj = { elf64_obj_loadfile, elf64_obj_exec };
+
+#define MSR_EFER 0xc0000080
+#define EFER_LME 0x00000100
+#define EFER_LMA 0x00000400 /* Long mode active (R) */
+#define CR4_PAE 0x00000020
+#define CR4_VMXE (1UL << 13)
+#define CR4_PSE 0x00000010
+#define CR0_PG 0x80000000
+#define CR0_PE 0x00000001 /* Protected mode Enable */
+#define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */
+
+#define PG_V 0x001
+#define PG_RW 0x002
+#define PG_U 0x004
+#define PG_PS 0x080
+
+typedef u_int64_t p4_entry_t;
+typedef u_int64_t p3_entry_t;
+typedef u_int64_t p2_entry_t;
+
+#define GUEST_NULL_SEL 0
+#define GUEST_CODE_SEL 1
+#define GUEST_DATA_SEL 2
+#define GUEST_GDTR_LIMIT (3 * 8 - 1)
+
+static void
+setup_freebsd_gdt(uint64_t *gdtr)
+{
+ gdtr[GUEST_NULL_SEL] = 0;
+ gdtr[GUEST_CODE_SEL] = 0x0020980000000000;
+ gdtr[GUEST_DATA_SEL] = 0x0000900000000000;
+}
+
+/*
+ * There is an ELF kernel and one or more ELF modules loaded.
+ * We wish to start executing the kernel image, so make such
+ * preparations as are required, and do so.
+ */
+static int
+elf64_exec(struct preloaded_file *fp)
+{
+ struct file_metadata *md;
+ Elf_Ehdr *ehdr;
+ vm_offset_t modulep, kernend;
+ int err;
+ int i;
+ uint32_t stack[1024];
+ p4_entry_t PT4[512];
+ p3_entry_t PT3[512];
+ p2_entry_t PT2[512];
+ uint64_t gdtr[3];
+
+ if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
+ return(EFTYPE);
+ ehdr = (Elf_Ehdr *)&(md->md_data);
+
+ err = bi_load64(fp->f_args, &modulep, &kernend);
+ if (err != 0)
+ return(err);
+
+ bzero(PT4, PAGE_SIZE);
+ bzero(PT3, PAGE_SIZE);
+ bzero(PT2, PAGE_SIZE);
+
+ /*
+ * Build a scratch stack at physical 0x1000, page tables:
+ * PT4 at 0x2000,
+ * PT3 at 0x3000,
+ * PT2 at 0x4000,
+ * gdtr at 0x5000,
+ */
+
+ /*
+ * This is kinda brutal, but every single 1GB VM memory segment
+ * points to the same first 1GB of physical memory. But it is
+ * more than adequate.
+ */
+ for (i = 0; i < 512; i++) {
+ /* Each slot of the level 4 pages points to the same level 3 page */
+ PT4[i] = (p4_entry_t) 0x3000;
+ PT4[i] |= PG_V | PG_RW | PG_U;
+
+ /* Each slot of the level 3 pages points to the same level 2 page */
+ PT3[i] = (p3_entry_t) 0x4000;
+ PT3[i] |= PG_V | PG_RW | PG_U;
+
+ /* The level 2 page slots are mapped with 2MB pages for 1GB. */
+ PT2[i] = i * (2 * 1024 * 1024);
+ PT2[i] |= PG_V | PG_RW | PG_PS | PG_U;
+ }
+
+#ifdef DEBUG
+ printf("Start @ %#llx ...\n", ehdr->e_entry);
+#endif
+
+ dev_cleanup();
+
+ stack[0] = 0; /* return address */;
+ stack[1] = modulep;
+ stack[2] = kernend;
+ CALLBACK(copyin, stack, 0x1000, sizeof(stack));
+ CALLBACK(copyin, PT4, 0x2000, sizeof(PT4));
+ CALLBACK(copyin, PT3, 0x3000, sizeof(PT3));
+ CALLBACK(copyin, PT2, 0x4000, sizeof(PT2));
+ CALLBACK(setreg, 4, 0x1000);
+
+ CALLBACK(setmsr, MSR_EFER, EFER_LMA | EFER_LME);
+ CALLBACK(setcr, 4, CR4_PAE | CR4_VMXE);
+ CALLBACK(setcr, 3, 0x2000);
+ CALLBACK(setcr, 0, CR0_PG | CR0_PE | CR0_NE);
+
+ setup_freebsd_gdt(gdtr);
+ CALLBACK(copyin, gdtr, 0x5000, sizeof(gdtr));
+ CALLBACK(setgdt, 0x5000, sizeof(gdtr));
+
+ CALLBACK(exec, ehdr->e_entry);
+
+ panic("exec returned");
+}
+
+static int
+elf64_obj_exec(struct preloaded_file *fp)
+{
+
+ return (EFTYPE);
+}
diff --git a/sys/boot/userboot/userboot/host.c b/sys/boot/userboot/userboot/host.c
new file mode 100644
index 0000000..81858a9
--- /dev/null
+++ b/sys/boot/userboot/userboot/host.c
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 2011 Google, Inc.
+ * 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 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 AUTHOR 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Read from the host filesystem
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stand.h>
+#include <bootstrap.h>
+
+#include "libuserboot.h"
+
+/*
+ * Open a file.
+ */
+static int
+host_open(const char *upath, struct open_file *f)
+{
+
+ if (f->f_dev != &host_dev)
+ return (EINVAL);
+
+ return (CALLBACK(open, upath, &f->f_fsdata));
+}
+
+static int
+host_close(struct open_file *f)
+{
+
+ CALLBACK(close, f->f_fsdata);
+ f->f_fsdata = (void *)0;
+
+ return (0);
+}
+
+/*
+ * Copy a portion of a file into memory.
+ */
+static int
+host_read(struct open_file *f, void *start, size_t size, size_t *resid)
+{
+
+ return (CALLBACK(read, f->f_fsdata, start, size, resid));
+}
+
+/*
+ * Don't be silly - the bootstrap has no business writing anything.
+ */
+static int
+host_write(struct open_file *f, void *start, size_t size, size_t *resid)
+{
+
+ return (EROFS);
+}
+
+static off_t
+host_seek(struct open_file *f, off_t offset, int where)
+{
+
+ return (CALLBACK(seek, f->f_fsdata, offset, where));
+}
+
+static int
+host_stat(struct open_file *f, struct stat *sb)
+{
+ int mode;
+ int uid;
+ int gid;
+ uint64_t size;
+
+ CALLBACK(stat, f->f_fsdata, &mode, &uid, &gid, &size);
+ sb->st_mode = mode;
+ sb->st_uid = uid;
+ sb->st_gid = gid;
+ sb->st_size = size;
+ return (0);
+}
+
+static int
+host_readdir(struct open_file *f, struct dirent *d)
+{
+ uint32_t fileno;
+ uint8_t type;
+ size_t namelen;
+ int rc;
+
+ rc = CALLBACK(readdir, f->f_fsdata, &fileno, &type, &namelen,
+ d->d_name);
+ if (rc)
+ return (rc);
+
+ d->d_fileno = fileno;
+ d->d_type = type;
+ d->d_namlen = namelen;
+
+ return (0);
+}
+
+static int
+host_dev_init(void)
+{
+
+ return (0);
+}
+
+static void
+host_dev_print(int verbose)
+{
+ char line[80];
+
+ sprintf(line, " host%d: Host filesystem\n", 0);
+ pager_output(line);
+}
+
+/*
+ * 'Open' the host device.
+ */
+static int
+host_dev_open(struct open_file *f, ...)
+{
+ va_list args;
+ struct devdesc *dev;
+
+ va_start(args, f);
+ dev = va_arg(args, struct devdesc*);
+ va_end(args);
+
+ return (0);
+}
+
+static int
+host_dev_close(struct open_file *f)
+{
+
+ return (0);
+}
+
+static int
+host_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
+ char *buf, size_t *rsize)
+{
+
+ return (ENOSYS);
+}
+
+struct fs_ops host_fsops = {
+ "host",
+ host_open,
+ host_close,
+ host_read,
+ host_write,
+ host_seek,
+ host_stat,
+ host_readdir
+};
+
+struct devsw host_dev = {
+ .dv_name = "host",
+ .dv_type = DEVT_NET,
+ .dv_init = host_dev_init,
+ .dv_strategy = host_dev_strategy,
+ .dv_open = host_dev_open,
+ .dv_close = host_dev_close,
+ .dv_ioctl = noioctl,
+ .dv_print = host_dev_print,
+ .dv_cleanup = NULL
+};
diff --git a/sys/boot/userboot/userboot/libuserboot.h b/sys/boot/userboot/userboot/libuserboot.h
new file mode 100644
index 0000000..0aa1a3f
--- /dev/null
+++ b/sys/boot/userboot/userboot/libuserboot.h
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2011 Google, Inc.
+ * 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 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "userboot.h"
+
+extern struct loader_callbacks_v1 *callbacks;
+extern void *callbacks_arg;
+
+#define CALLBACK(fn, args...) (callbacks->fn(callbacks_arg , ##args))
+
+#define MAXDEV 31 /* maximum number of distinct devices */
+
+typedef unsigned long physaddr_t;
+
+/* exported devices */
+extern struct devsw userboot_disk;
+extern int userboot_disk_maxunit;
+extern struct devsw host_dev;
+
+/* access to host filesystem */
+struct fs_ops host_fsops;
+
+struct bootinfo;
+struct preloaded_file;
+extern int bi_load(struct bootinfo *, struct preloaded_file *);
+
+extern void delay(int);
+
+extern int userboot_autoload(void);
+extern ssize_t userboot_copyin(const void *, vm_offset_t, size_t);
+extern ssize_t userboot_copyout(vm_offset_t, void *, size_t);
+extern ssize_t userboot_readin(int, vm_offset_t, size_t);
+extern int userboot_getdev(void **, const char *, const char **);
+char *userboot_fmtdev(void *vdev);
+int userboot_setcurrdev(struct env_var *ev, int flags, const void *value);
+
+int bi_getboothowto(char *kargs);
+void bi_setboothowto(int howto);
+vm_offset_t bi_copyenv(vm_offset_t addr);
+int bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip,
+ vm_offset_t *modulep, vm_offset_t *kernend);
+int bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernend);
diff --git a/sys/boot/userboot/userboot/main.c b/sys/boot/userboot/userboot/main.c
new file mode 100644
index 0000000..d01d95e
--- /dev/null
+++ b/sys/boot/userboot/userboot/main.c
@@ -0,0 +1,177 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 1998,2000 Doug Rabson <dfr@freebsd.org>
+ * 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 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 AUTHOR 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <string.h>
+#include <setjmp.h>
+
+#include "bootstrap.h"
+#include "disk.h"
+#include "libuserboot.h"
+
+struct loader_callbacks_v1 *callbacks;
+void *callbacks_arg;
+
+extern char bootprog_name[];
+extern char bootprog_rev[];
+extern char bootprog_date[];
+extern char bootprog_maker[];
+static jmp_buf jb;
+
+struct arch_switch archsw; /* MI/MD interface boundary */
+
+static void extract_currdev(void);
+
+void
+delay(int usec)
+{
+
+ CALLBACK(delay, usec);
+}
+
+void
+exit(int v)
+{
+
+ CALLBACK(exit, v);
+ longjmp(jb, 1);
+}
+
+void
+loader_main(struct loader_callbacks_v1 *cb, void *arg, int version, int ndisks)
+{
+ static char malloc[512*1024];
+ int i;
+
+ if (version != USERBOOT_VERSION_1)
+ abort();
+
+ callbacks = cb;
+ callbacks_arg = arg;
+ userboot_disk_maxunit = ndisks;
+
+ /*
+ * initialise the heap as early as possible. Once this is done,
+ * alloc() is usable. The stack is buried inside us, so this is
+ * safe.
+ */
+ setheap((void *)malloc, (void *)(malloc + 512*1024));
+
+ /*
+ * Hook up the console
+ */
+ cons_probe();
+
+ /*
+ * March through the device switch probing for things.
+ */
+ for (i = 0; devsw[i] != NULL; i++)
+ if (devsw[i]->dv_init != NULL)
+ (devsw[i]->dv_init)();
+
+ printf("\n");
+ printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
+ printf("(%s, %s)\n", bootprog_maker, bootprog_date);
+#if 0
+ printf("Memory: %ld k\n", memsize() / 1024);
+#endif
+
+ setenv("LINES", "24", 1); /* optional */
+
+ archsw.arch_autoload = userboot_autoload;
+ archsw.arch_getdev = userboot_getdev;
+ archsw.arch_copyin = userboot_copyin;
+ archsw.arch_copyout = userboot_copyout;
+ archsw.arch_readin = userboot_readin;
+
+ extract_currdev();
+
+ if (setjmp(jb))
+ return;
+
+ interact(); /* doesn't return */
+
+ exit(0);
+}
+
+/*
+ * Set the 'current device' by (if possible) recovering the boot device as
+ * supplied by the initial bootstrap.
+ */
+static void
+extract_currdev(void)
+{
+ struct disk_devdesc dev;
+
+ //bzero(&dev, sizeof(dev));
+
+ if (userboot_disk_maxunit > 0) {
+ dev.d_dev = &userboot_disk;
+ dev.d_type = dev.d_dev->dv_type;
+ dev.d_unit = 0;
+ dev.d_slice = 0;
+ dev.d_partition = 0;
+ /*
+ * Figure out if we are using MBR or GPT - for GPT we
+ * set the partition to 0 since everything is a GPT slice.
+ */
+ if (dev.d_dev->dv_open(NULL, &dev))
+ dev.d_partition = 255;
+ } else {
+ dev.d_dev = &host_dev;
+ dev.d_type = dev.d_dev->dv_type;
+ dev.d_unit = 0;
+ }
+
+ env_setenv("currdev", EV_VOLATILE, userboot_fmtdev(&dev),
+ userboot_setcurrdev, env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, userboot_fmtdev(&dev),
+ env_noset, env_nounset);
+}
+
+COMMAND_SET(quit, "quit", "exit the loader", command_quit);
+
+static int
+command_quit(int argc, char *argv[])
+{
+
+ exit(USERBOOT_EXIT_QUIT);
+ return (CMD_OK);
+}
+
+COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
+
+static int
+command_reboot(int argc, char *argv[])
+{
+
+ exit(USERBOOT_EXIT_REBOOT);
+ return (CMD_OK);
+}
diff --git a/sys/boot/userboot/userboot/userboot_cons.c b/sys/boot/userboot/userboot/userboot_cons.c
new file mode 100644
index 0000000..5ecb7c8
--- /dev/null
+++ b/sys/boot/userboot/userboot/userboot_cons.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 2011 Google, Inc.
+ * 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 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 AUTHOR 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include "bootstrap.h"
+#include "libuserboot.h"
+
+int console;
+
+static void userboot_cons_probe(struct console *cp);
+static int userboot_cons_init(int);
+static void userboot_cons_putchar(int);
+static int userboot_cons_getchar(void);
+static int userboot_cons_poll(void);
+
+struct console userboot_console = {
+ "userboot",
+ "userboot",
+ 0,
+ userboot_cons_probe,
+ userboot_cons_init,
+ userboot_cons_putchar,
+ userboot_cons_getchar,
+ userboot_cons_poll,
+};
+
+static void
+userboot_cons_probe(struct console *cp)
+{
+
+ cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
+}
+
+static int
+userboot_cons_init(int arg)
+{
+
+ return (0);
+}
+
+static void
+userboot_cons_putchar(int c)
+{
+
+ CALLBACK(putc, c);
+}
+
+static int
+userboot_cons_getchar()
+{
+
+ return (CALLBACK(getc));
+}
+
+static int
+userboot_cons_poll()
+{
+
+ return (CALLBACK(poll));
+}
diff --git a/sys/boot/userboot/userboot/userboot_disk.c b/sys/boot/userboot/userboot/userboot_disk.c
new file mode 100644
index 0000000..074d3e1
--- /dev/null
+++ b/sys/boot/userboot/userboot/userboot_disk.c
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 2011 Google, Inc.
+ * 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 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 AUTHOR 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Userboot disk image handling.
+ */
+
+#include <stand.h>
+
+#include <stdarg.h>
+#include <uuid.h>
+
+#include <bootstrap.h>
+
+#include "disk.h"
+#include "libuserboot.h"
+
+int userboot_disk_maxunit = 0;
+
+static int userdisk_init(void);
+static int userdisk_strategy(void *devdata, int flag, daddr_t dblk,
+ size_t size, char *buf, size_t *rsize);
+static int userdisk_open(struct open_file *f, ...);
+static int userdisk_close(struct open_file *f);
+static void userdisk_print(int verbose);
+
+struct devsw userboot_disk = {
+ "disk",
+ DEVT_DISK,
+ userdisk_init,
+ userdisk_strategy,
+ userdisk_open,
+ userdisk_close,
+ noioctl,
+ userdisk_print,
+ NULL
+};
+
+/*
+ * Nothing to do here.
+ */
+static int
+userdisk_init(void)
+{
+
+ return(0);
+}
+
+/*
+ * Print information about disks
+ */
+static void
+userdisk_print(int verbose)
+{
+ int i;
+ char line[80];
+ struct disk_devdesc dev;
+
+ for (i = 0; i < userboot_disk_maxunit; i++) {
+ sprintf(line, " disk%d: Guest drive image\n", i);
+ pager_output(line);
+ dev.d_dev = &userboot_disk;
+ dev.d_unit = i;
+ dev.d_slice = -1;
+ dev.d_partition = -1;
+ dev.d_offset = 0;
+ sprintf(line, " disk%d", i);
+ disk_print(&dev, line, verbose);
+ }
+}
+
+/*
+ * Attempt to open the disk described by (dev) for use by (f).
+ */
+static int
+userdisk_open(struct open_file *f, ...)
+{
+ va_list ap;
+ struct disk_devdesc *dev;
+
+ va_start(ap, f);
+ dev = va_arg(ap, struct disk_devdesc *);
+ va_end(ap);
+
+ if (dev->d_unit < 0 || dev->d_unit >= userboot_disk_maxunit)
+ return (EIO);
+
+ return (disk_open(dev));
+}
+
+static int
+userdisk_close(struct open_file *f)
+{
+
+ return(0);
+}
+
+static int
+userdisk_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
+ char *buf, size_t *rsize)
+{
+ struct disk_devdesc *dev = devdata;
+ uint64_t off;
+ size_t resid;
+ int rc;
+
+ if (rw == F_WRITE)
+ return (EROFS);
+ if (rw != F_READ)
+ return (EINVAL);
+ if (rsize)
+ *rsize = 0;
+ off = (dblk + dev->d_offset) * DISK_SECSIZE;
+ rc = CALLBACK(diskread, dev->d_unit, off, buf, size, &resid);
+ if (rc)
+ return (rc);
+ if (rsize)
+ *rsize = size - resid;
+ return (0);
+}
diff --git a/sys/boot/userboot/userboot/version b/sys/boot/userboot/userboot/version
new file mode 100644
index 0000000..ce6e270
--- /dev/null
+++ b/sys/boot/userboot/userboot/version
@@ -0,0 +1,4 @@
+$FreeBSD$
+
+1.1: Initial userland boot
+
OpenPOWER on IntegriCloud