From 2b9b009195e403f0f2fc9bf0d9eeefc2297d94b8 Mon Sep 17 00:00:00 2001 From: dfr Date: Thu, 30 Jun 2011 16:08:56 +0000 Subject: 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. --- sys/boot/Makefile.amd64 | 1 + sys/boot/common/Makefile.inc | 2 +- sys/boot/common/disk.c | 788 +++++++++++++++++++++++++++++ sys/boot/common/disk.h | 99 ++++ sys/boot/common/load_elf.c | 2 +- sys/boot/common/reloc_elf.c | 2 +- sys/boot/ficl/amd64/sysdep.c | 101 ++++ sys/boot/ficl/amd64/sysdep.h | 434 ++++++++++++++++ sys/boot/i386/libi386/bioscd.c | 6 +- sys/boot/userboot/Makefile | 8 + sys/boot/userboot/ficl/Makefile | 73 +++ sys/boot/userboot/libstand/Makefile | 161 ++++++ sys/boot/userboot/libstand/amd64/_setjmp.S | 93 ++++ sys/boot/userboot/test/Makefile | 15 + sys/boot/userboot/test/test.c | 428 ++++++++++++++++ sys/boot/userboot/userboot.h | 178 +++++++ sys/boot/userboot/userboot/Makefile | 61 +++ sys/boot/userboot/userboot/autoload.c | 35 ++ sys/boot/userboot/userboot/bootinfo.c | 192 +++++++ sys/boot/userboot/userboot/bootinfo32.c | 264 ++++++++++ sys/boot/userboot/userboot/bootinfo64.c | 304 +++++++++++ sys/boot/userboot/userboot/conf.c | 93 ++++ sys/boot/userboot/userboot/copy.c | 74 +++ sys/boot/userboot/userboot/devicename.c | 274 ++++++++++ sys/boot/userboot/userboot/elf32_freebsd.c | 99 ++++ sys/boot/userboot/userboot/elf64_freebsd.c | 172 +++++++ sys/boot/userboot/userboot/host.c | 198 ++++++++ sys/boot/userboot/userboot/libuserboot.h | 67 +++ sys/boot/userboot/userboot/main.c | 177 +++++++ sys/boot/userboot/userboot/userboot_cons.c | 86 ++++ sys/boot/userboot/userboot/userboot_disk.c | 146 ++++++ sys/boot/userboot/userboot/version | 4 + 32 files changed, 4633 insertions(+), 4 deletions(-) create mode 100644 sys/boot/common/disk.c create mode 100644 sys/boot/common/disk.h create mode 100644 sys/boot/ficl/amd64/sysdep.c create mode 100644 sys/boot/ficl/amd64/sysdep.h create mode 100644 sys/boot/userboot/Makefile create mode 100644 sys/boot/userboot/ficl/Makefile create mode 100644 sys/boot/userboot/libstand/Makefile create mode 100644 sys/boot/userboot/libstand/amd64/_setjmp.S create mode 100644 sys/boot/userboot/test/Makefile create mode 100644 sys/boot/userboot/test/test.c create mode 100644 sys/boot/userboot/userboot.h create mode 100644 sys/boot/userboot/userboot/Makefile create mode 100644 sys/boot/userboot/userboot/autoload.c create mode 100644 sys/boot/userboot/userboot/bootinfo.c create mode 100644 sys/boot/userboot/userboot/bootinfo32.c create mode 100644 sys/boot/userboot/userboot/bootinfo64.c create mode 100644 sys/boot/userboot/userboot/conf.c create mode 100644 sys/boot/userboot/userboot/copy.c create mode 100644 sys/boot/userboot/userboot/devicename.c create mode 100644 sys/boot/userboot/userboot/elf32_freebsd.c create mode 100644 sys/boot/userboot/userboot/elf64_freebsd.c create mode 100644 sys/boot/userboot/userboot/host.c create mode 100644 sys/boot/userboot/userboot/libuserboot.h create mode 100644 sys/boot/userboot/userboot/main.c create mode 100644 sys/boot/userboot/userboot/userboot_cons.c create mode 100644 sys/boot/userboot/userboot/userboot_disk.c create mode 100644 sys/boot/userboot/userboot/version 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 + * 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 +__FBSDID("$FreeBSD$"); + +/* + * MBR/GPT partitioned disk device handling. + * + * Ideas and algorithms from: + * + * - NetBSD libi386/biosdisk.c + * - FreeBSD biosboot/disk.c + * + */ + +#include + +#include +#include +#include + +#include +#include + +#include + +#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 +#include +#else +#include +#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); +** +** 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 + +#include /* size_t, NULL */ +#include +#include + +#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); +** +** 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 + +SUBDIR= ficl libstand test userboot + +.include + 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 +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 +.else +LIB= ficl +INTERNALLIB= +.include +.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 + +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||"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||"stand.h"|' \ + -e 's||"stand.h"|' \ + -e 's||"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 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 +__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 + +PROG= test +INTERNALPROG= + +CFLAGS+= -I${.CURDIR}/.. +CFLAGS+= -I${.CURDIR}/../../.. + +.include 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 ] [-h \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 + +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 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 +__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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#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 =, 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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 */ +#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 +__FBSDID("$FreeBSD$"); + +#include + +#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 +__FBSDID("$FreeBSD$"); + +#include + +#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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#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[s][]: + * + */ +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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#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 + * 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 +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 64 +#include +#include +#include +#include +#include +#include +#include + +#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 +__FBSDID("$FreeBSD$"); + +/* + * Read from the host filesystem + */ + +#include +#include +#include +#include +#include +#include +#include + +#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 + * Copyright (c) 1998,2000 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#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 +__FBSDID("$FreeBSD$"); + +#include +#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 +__FBSDID("$FreeBSD$"); + +/* + * Userboot disk image handling. + */ + +#include + +#include +#include + +#include + +#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 + -- cgit v1.1