diff options
author | jhb <jhb@FreeBSD.org> | 2014-02-05 04:39:03 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2014-02-05 04:39:03 +0000 |
commit | f4e46bef9870d0ed15e9f02b57af7ccf63794d09 (patch) | |
tree | 9028dde86802e6e728a5c5a95359f88aeedcf6dc /sys/boot/userboot | |
parent | c9758b2e1cc84a86a515276115bc1bc41de75c54 (diff) | |
download | FreeBSD-src-f4e46bef9870d0ed15e9f02b57af7ccf63794d09.zip FreeBSD-src-f4e46bef9870d0ed15e9f02b57af7ccf63794d09.tar.gz |
Add support for FreeBSD/i386 guests under bhyve.
- Similar to the hack for bootinfo32.c in userboot, define
_MACHINE_ELF_WANT_32BIT in the load_elf32 file handlers in userboot.
This allows userboot to load 32-bit kernels and modules.
- Copy the SMAP generation code out of bootinfo64.c and into its own
file so it can be shared with bootinfo32.c to pass an SMAP to the i386
kernel.
- Use uint32_t instead of u_long when aligning module metadata in
bootinfo32.c in userboot, as otherwise the metadata used 64-bit
alignment which corrupted the layout.
- Populate the basemem and extmem members of the bootinfo struct passed
to 32-bit kernels.
- Fix the 32-bit stack in userboot to start at the top of the stack
instead of the bottom so that there is room to grow before the
kernel switches to its own stack.
- Push a fake return address onto the 32-bit stack in addition to the
arguments normally passed to exec() in the loader. This return
address is needed to convince recover_bootinfo() in the 32-bit
locore code that it is being invoked from a "new" boot block.
- Add a routine to libvmmapi to setup a 32-bit flat mode register state
including a GDT and TSS that is able to start the i386 kernel and
update bhyveload to use it when booting an i386 kernel.
- Use the guest register state to determine the CPU's current instruction
mode (32-bit vs 64-bit) and paging mode (flat, 32-bit, PAE, or long
mode) in the instruction emulation code. Update the gla2gpa() routine
used when fetching instructions to handle flat mode, 32-bit paging, and
PAE paging in addition to long mode paging. Don't look for a REX
prefix when the CPU is in 32-bit mode, and use the detected mode to
enable the existing 32-bit mode code when decoding the mod r/m byte.
Reviewed by: grehan, neel
MFC after: 1 month
Diffstat (limited to 'sys/boot/userboot')
-rw-r--r-- | sys/boot/userboot/userboot/Makefile | 1 | ||||
-rw-r--r-- | sys/boot/userboot/userboot/biossmap.c | 74 | ||||
-rw-r--r-- | sys/boot/userboot/userboot/bootinfo32.c | 18 | ||||
-rw-r--r-- | sys/boot/userboot/userboot/bootinfo64.c | 47 | ||||
-rw-r--r-- | sys/boot/userboot/userboot/elf32_freebsd.c | 36 | ||||
-rw-r--r-- | sys/boot/userboot/userboot/libuserboot.h | 1 |
6 files changed, 109 insertions, 68 deletions
diff --git a/sys/boot/userboot/userboot/Makefile b/sys/boot/userboot/userboot/Makefile index 1df1f30..076b4b2 100644 --- a/sys/boot/userboot/userboot/Makefile +++ b/sys/boot/userboot/userboot/Makefile @@ -11,6 +11,7 @@ STRIP= LIBDIR= /boot SRCS= autoload.c +SRCS+= biossmap.c SRCS+= bootinfo.c SRCS+= bootinfo32.c SRCS+= bootinfo64.c diff --git a/sys/boot/userboot/userboot/biossmap.c b/sys/boot/userboot/userboot/biossmap.c new file mode 100644 index 0000000..9e556be --- /dev/null +++ b/sys/boot/userboot/userboot/biossmap.c @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include <sys/param.h> +#include <sys/reboot.h> +#include <sys/linker.h> +#include <machine/pc/bios.h> +#include <machine/metadata.h> + +#include "bootstrap.h" +#include "libuserboot.h" + +#define GB (1024UL * 1024 * 1024) + +void +bios_addsmapdata(struct preloaded_file *kfp) +{ + uint64_t lowmem, highmem; + int smapnum, len; + struct bios_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 bios_smap); + file_addmetadata(kfp, MODINFOMD_SMAP, len, &smap[0]); +} diff --git a/sys/boot/userboot/userboot/bootinfo32.c b/sys/boot/userboot/userboot/bootinfo32.c index 4e6447a..6498461 100644 --- a/sys/boot/userboot/userboot/bootinfo32.c +++ b/sys/boot/userboot/userboot/bootinfo32.c @@ -66,7 +66,7 @@ static struct bootinfo bi; COPY32(strlen(s) + 1, a, c); \ if (c) \ CALLBACK(copyin, s, a, strlen(s) + 1); \ - a += roundup(strlen(s) + 1, sizeof(u_long));\ + a += roundup(strlen(s) + 1, sizeof(uint32_t));\ } #define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) @@ -78,7 +78,7 @@ static struct bootinfo bi; COPY32(sizeof(s), a, c); \ if (c) \ CALLBACK(copyin, &s, a, sizeof(s)); \ - a += roundup(sizeof(s), sizeof(u_long)); \ + a += roundup(sizeof(s), sizeof(uint32_t)); \ } #define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) @@ -89,7 +89,7 @@ static struct bootinfo bi; 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));\ + a += roundup(mm->md_size, sizeof(uint32_t));\ } #define MOD_END(a, c) { \ @@ -146,6 +146,7 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t int bootdevnr, howto; char *kernelname; const char *kernelpath; + uint64_t lowmem, highmem; howto = bi_getboothowto(args); @@ -198,9 +199,7 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t 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; @@ -237,11 +236,10 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t bi.bi_bios_geom[i] = bd_getbigeom(i); #endif bi.bi_size = sizeof(bi); + CALLBACK(getmem, &lowmem, &highmem); bi.bi_memsizes_valid = 1; -#if 0 - bi.bi_basemem = bios_basemem / 1024; - bi.bi_extmem = bios_extmem / 1024; -#endif + bi.bi_basemem = 640; + bi.bi_extmem = (lowmem - 0x100000) / 1024; bi.bi_envp = envp; bi.bi_modulep = *modulep; bi.bi_kernend = kernend; @@ -251,7 +249,7 @@ bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t /* * Copy the legacy bootinfo and kernel name to the guest at 0x2000 */ - bi.bi_kernelname = (char *) (0x2000 + sizeof(bi)); + bi.bi_kernelname = 0x2000 + sizeof(bi); CALLBACK(copyin, &bi, 0x2000, sizeof(bi)); CALLBACK(copyin, kernelname, 0x2000 + sizeof(bi), strlen(kernelname) + 1); diff --git a/sys/boot/userboot/userboot/bootinfo64.c b/sys/boot/userboot/userboot/bootinfo64.c index fc7c14d..10ff133 100644 --- a/sys/boot/userboot/userboot/bootinfo64.c +++ b/sys/boot/userboot/userboot/bootinfo64.c @@ -169,53 +169,6 @@ bi_checkcpu(void) #endif } -struct smap { - uint64_t base; - uint64_t length; - uint32_t type; -} __packed; - -/* From FreeBSD <machine/pc/bios.h> */ -#define SMAP_TYPE_MEMORY 1 - -#define GB (1024UL * 1024 * 1024) - -#define MODINFOMD_SMAP 0x1001 - -static void -bios_addsmapdata(struct preloaded_file *kfp) -{ - uint64_t lowmem, highmem; - int smapnum, len; - struct smap smap[3], *sm; - - CALLBACK(getmem, &lowmem, &highmem); - - sm = &smap[0]; - - sm->base = 0; /* base memory */ - sm->length = 640 * 1024; - sm->type = SMAP_TYPE_MEMORY; - sm++; - - sm->base = 0x100000; /* extended memory */ - sm->length = lowmem - 0x100000; - sm->type = SMAP_TYPE_MEMORY; - sm++; - - smapnum = 2; - - if (highmem != 0) { - sm->base = 4 * GB; - sm->length = highmem; - sm->type = SMAP_TYPE_MEMORY; - smapnum++; - } - - len = smapnum * sizeof (struct smap); - file_addmetadata(kfp, MODINFOMD_SMAP, len, &smap[0]); -} - /* * Load the information expected by an amd64 kernel. * diff --git a/sys/boot/userboot/userboot/elf32_freebsd.c b/sys/boot/userboot/userboot/elf32_freebsd.c index bb5b693..d8ccc33 100644 --- a/sys/boot/userboot/userboot/elf32_freebsd.c +++ b/sys/boot/userboot/userboot/elf32_freebsd.c @@ -45,6 +45,9 @@ 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 }; +#define GUEST_STACK 0x1000 /* Initial stack base */ +#define GUEST_GDT 0x3000 /* Address of initial GDT */ + /* * There is an ELF kernel and one or more ELF modules loaded. * We wish to start executing the kernel image, so make such @@ -57,7 +60,7 @@ elf32_exec(struct preloaded_file *fp) Elf_Ehdr *ehdr; vm_offset_t entry, bootinfop, modulep, kernend; int boothowto, err, bootdev; - uint32_t stack[1024]; + uint32_t stack[1024], *sp; if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) @@ -78,16 +81,27 @@ elf32_exec(struct preloaded_file *fp) /* * 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); + memset(stack, 0, sizeof(stack)); + sp = (uint32_t *)((char *)stack + sizeof(stack)); + *--sp = kernend; + *--sp = modulep; + *--sp = bootinfop; + *--sp = 0; + *--sp = 0; + *--sp = 0; + *--sp = bootdev; + *--sp = boothowto; + + /* + * Fake return address to mimic "new" boot blocks. For more + * details see recover_bootinfo in locore.S. + */ + *--sp = 0xbeefface; + CALLBACK(copyin, stack, GUEST_STACK, sizeof(stack)); + CALLBACK(setreg, 4, (char *)sp - (char *)stack + GUEST_STACK); + + CALLBACK(setgdt, GUEST_GDT, 8 * 4 - 1); + CALLBACK(exec, entry); panic("exec returned"); diff --git a/sys/boot/userboot/userboot/libuserboot.h b/sys/boot/userboot/userboot/libuserboot.h index d795188..e2048d5 100644 --- a/sys/boot/userboot/userboot/libuserboot.h +++ b/sys/boot/userboot/userboot/libuserboot.h @@ -65,3 +65,4 @@ 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); +void bios_addsmapdata(struct preloaded_file *kfp); |