--- //depot/vendor/freebsd/src/lib/libvmmapi/vmmapi.h +++ //depot/user/jhb/bhyve/lib/libvmmapi/vmmapi.h @@ -111,5 +111,8 @@ int vm_setup_freebsd_registers(struct vmctx *ctx, int vcpu, uint64_t rip, uint64_t cr3, uint64_t gdtbase, uint64_t rsp); +int vm_setup_freebsd_registers_i386(struct vmctx *vmctx, int vcpu, + uint32_t eip, uint32_t gdtbase, + uint32_t esp); void vm_setup_freebsd_gdt(uint64_t *gdtr); #endif /* _VMMAPI_H_ */ --- //depot/vendor/freebsd/src/lib/libvmmapi/vmmapi_freebsd.c +++ //depot/user/jhb/bhyve/lib/libvmmapi/vmmapi_freebsd.c @@ -35,14 +35,176 @@ #include #include +#include +#include + #include "vmmapi.h" +#define I386_TSS_SIZE 104 + +#define DESC_PRESENT 0x00000080 +#define DESC_LONGMODE 0x00002000 +#define DESC_DEF32 0x00004000 +#define DESC_GRAN 0x00008000 #define DESC_UNUSABLE 0x00010000 #define GUEST_NULL_SEL 0 #define GUEST_CODE_SEL 1 #define GUEST_DATA_SEL 2 -#define GUEST_GDTR_LIMIT (3 * 8 - 1) +#define GUEST_TSS_SEL 3 +#define GUEST_GDTR_LIMIT64 (3 * 8 - 1) + +static struct segment_descriptor i386_gdt[] = { + {}, /* NULL */ + { .sd_lolimit = 0xffff, .sd_type = SDT_MEMER, /* CODE */ + .sd_p = 1, .sd_hilimit = 0xf, .sd_def32 = 1, .sd_gran = 1 }, + { .sd_lolimit = 0xffff, .sd_type = SDT_MEMRW, /* DATA */ + .sd_p = 1, .sd_hilimit = 0xf, .sd_def32 = 1, .sd_gran = 1 }, + { .sd_lolimit = I386_TSS_SIZE - 1, /* TSS */ + .sd_type = SDT_SYS386TSS, .sd_p = 1 } +}; + +/* + * Setup the 'vcpu' register set such that it will begin execution at + * 'eip' in flat mode. + */ +int +vm_setup_freebsd_registers_i386(struct vmctx *vmctx, int vcpu, uint32_t eip, + uint32_t gdtbase, uint32_t esp) +{ + uint64_t cr0, rflags, desc_base; + uint32_t desc_access, desc_limit, tssbase; + uint16_t gsel; + struct segment_descriptor *gdt; + int error, tmp; + + /* A 32-bit guest requires unrestricted mode. */ + error = vm_get_capability(vmctx, vcpu, VM_CAP_UNRESTRICTED_GUEST, &tmp); + if (error) + goto done; + error = vm_set_capability(vmctx, vcpu, VM_CAP_UNRESTRICTED_GUEST, 1); + if (error) + goto done; + + cr0 = CR0_PE | CR0_NE; + if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR0, cr0)) != 0) + goto done; + + if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CR4, 0)) != 0) + goto done; + + /* + * Forcing EFER to 0 causes bhyve to clear the "IA-32e guest + * mode" entry control. + */ + if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_EFER, 0))) + goto done; + + gdt = vm_map_gpa(vmctx, gdtbase, 0x1000); + if (gdt == NULL) + return (EFAULT); + memcpy(gdt, i386_gdt, sizeof(i386_gdt)); + desc_base = gdtbase; + desc_limit = sizeof(i386_gdt) - 1; + error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GDTR, + desc_base, desc_limit, 0); + if (error != 0) + goto done; + + /* Place the TSS one page above the GDT. */ + tssbase = gdtbase + 0x1000; + gdt[3].sd_lobase = tssbase; + + rflags = 0x2; + error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RFLAGS, rflags); + if (error) + goto done; + + desc_base = 0; + desc_limit = 0xffffffff; + desc_access = DESC_GRAN | DESC_DEF32 | DESC_PRESENT | SDT_MEMERA; + error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_CS, + desc_base, desc_limit, desc_access); + + desc_access = DESC_GRAN | DESC_DEF32 | DESC_PRESENT | SDT_MEMRWA; + error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_DS, + desc_base, desc_limit, desc_access); + if (error) + goto done; + + error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_ES, + desc_base, desc_limit, desc_access); + if (error) + goto done; + + error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_FS, + desc_base, desc_limit, desc_access); + if (error) + goto done; + + error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GS, + desc_base, desc_limit, desc_access); + if (error) + goto done; + + error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_SS, + desc_base, desc_limit, desc_access); + if (error) + goto done; + + desc_base = tssbase; + desc_limit = I386_TSS_SIZE - 1; + desc_access = DESC_PRESENT | SDT_SYS386BSY; + error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_TR, + desc_base, desc_limit, desc_access); + if (error) + goto done; + + + error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_LDTR, 0, 0, + DESC_UNUSABLE); + if (error) + goto done; + + gsel = GSEL(GUEST_CODE_SEL, SEL_KPL); + if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_CS, gsel)) != 0) + goto done; + + gsel = GSEL(GUEST_DATA_SEL, SEL_KPL); + if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_DS, gsel)) != 0) + goto done; + + if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_ES, gsel)) != 0) + goto done; + + if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_FS, gsel)) != 0) + goto done; + + if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_GS, gsel)) != 0) + goto done; + + if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_SS, gsel)) != 0) + goto done; + + gsel = GSEL(GUEST_TSS_SEL, SEL_KPL); + if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_TR, gsel)) != 0) + goto done; + + /* LDTR is pointing to the null selector */ + if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_LDTR, 0)) != 0) + goto done; + + /* entry point */ + if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RIP, eip)) != 0) + goto done; + + if ((error = vm_set_register(vmctx, vcpu, VM_REG_GUEST_RSP, esp)) != 0) + goto done; + + error = 0; +done: + return (error); +} void vm_setup_freebsd_gdt(uint64_t *gdtr) @@ -168,7 +330,7 @@ goto done; desc_base = gdtbase; - desc_limit = GUEST_GDTR_LIMIT; + desc_limit = GUEST_GDTR_LIMIT64; error = vm_set_desc(vmctx, vcpu, VM_REG_GUEST_GDTR, desc_base, desc_limit, 0); if (error != 0) --- //depot/vendor/freebsd/src/sys/amd64/include/vmm.h +++ //depot/user/jhb/bhyve/sys/amd64/include/vmm.h @@ -323,6 +323,8 @@ uint64_t gpa; uint64_t gla; uint64_t cr3; + enum vie_cpu_mode cpu_mode; + enum vie_paging_mode paging_mode; struct vie vie; } inst_emul; /* --- //depot/vendor/freebsd/src/sys/amd64/include/vmm_instruction_emul.h +++ //depot/user/jhb/bhyve/sys/amd64/include/vmm_instruction_emul.h @@ -29,6 +29,18 @@ #ifndef _VMM_INSTRUCTION_EMUL_H_ #define _VMM_INSTRUCTION_EMUL_H_ +enum vie_cpu_mode { + CPU_MODE_COMPATIBILITY, /* IA-32E mode (CS.L = 0) */ + CPU_MODE_64BIT, /* IA-32E mode (CS.L = 1) */ +}; + +enum vie_paging_mode { + PAGING_MODE_FLAT, + PAGING_MODE_32, + PAGING_MODE_PAE, + PAGING_MODE_64, +}; + /* * The data structures 'vie' and 'vie_op' are meant to be opaque to the * consumers of instruction decoding. The only reason why their contents @@ -107,7 +119,7 @@ */ int vmm_fetch_instruction(struct vm *vm, int cpuid, uint64_t rip, int inst_length, uint64_t cr3, - struct vie *vie); + enum vie_paging_mode paging_mode, struct vie *vie); void vie_init(struct vie *vie); @@ -123,8 +135,8 @@ * in VIE_INVALID_GLA instead. */ #define VIE_INVALID_GLA (1UL << 63) /* a non-canonical address */ -int vmm_decode_instruction(struct vm *vm, int cpuid, - uint64_t gla, struct vie *vie); +int vmm_decode_instruction(struct vm *vm, int cpuid, uint64_t gla, + enum vie_cpu_mode cpu_mode, struct vie *vie); #endif /* _KERNEL */ #endif /* _VMM_INSTRUCTION_EMUL_H_ */ --- //depot/vendor/freebsd/src/sys/amd64/vmm/intel/vmx.c +++ //depot/user/jhb/bhyve/sys/amd64/vmm/intel/vmx.c @@ -1327,6 +1361,30 @@ return (HANDLED); } +static enum vie_cpu_mode +vmx_cpu_mode(void) +{ + + if (vmcs_read(VMCS_GUEST_IA32_EFER) & EFER_LMA) + return (CPU_MODE_64BIT); + else + return (CPU_MODE_COMPATIBILITY); +} + +static enum vie_paging_mode +vmx_paging_mode(void) +{ + + if (!(vmcs_read(VMCS_GUEST_CR0) & CR0_PG)) + return (PAGING_MODE_FLAT); + if (!(vmcs_read(VMCS_GUEST_CR4) & CR4_PAE)) + return (PAGING_MODE_32); + if (vmcs_read(VMCS_GUEST_IA32_EFER) & EFER_LME) + return (PAGING_MODE_64); + else + return (PAGING_MODE_PAE); +} + static int ept_fault_type(uint64_t ept_qual) { @@ -1486,6 +1544,8 @@ vmexit->u.inst_emul.gpa = DEFAULT_APIC_BASE + offset; vmexit->u.inst_emul.gla = VIE_INVALID_GLA; vmexit->u.inst_emul.cr3 = vmcs_guest_cr3(); + vmexit->u.inst_emul.cpu_mode = vmx_cpu_mode(); + vmexit->u.inst_emul.paging_mode = vmx_paging_mode(); } /* @@ -1713,6 +1773,8 @@ vmexit->u.inst_emul.gpa = gpa; vmexit->u.inst_emul.gla = vmcs_gla(); vmexit->u.inst_emul.cr3 = vmcs_guest_cr3(); + vmexit->u.inst_emul.cpu_mode = vmx_cpu_mode(); + vmexit->u.inst_emul.paging_mode = vmx_paging_mode(); } /* * If Virtual NMIs control is 1 and the VM-exit is due to an --- //depot/vendor/freebsd/src/sys/amd64/vmm/vmm.c +++ //depot/user/jhb/bhyve/sys/amd64/vmm/vmm.c @@ -1056,6 +1068,8 @@ struct vm_exit *vme; int error, inst_length; uint64_t rip, gla, gpa, cr3; + enum vie_cpu_mode cpu_mode; + enum vie_paging_mode paging_mode; mem_region_read_t mread; mem_region_write_t mwrite; @@ -1068,15 +1082,18 @@ gla = vme->u.inst_emul.gla; gpa = vme->u.inst_emul.gpa; cr3 = vme->u.inst_emul.cr3; + cpu_mode = vme->u.inst_emul.cpu_mode; + paging_mode = vme->u.inst_emul.paging_mode; vie = &vme->u.inst_emul.vie; vie_init(vie); /* Fetch, decode and emulate the faulting instruction */ - if (vmm_fetch_instruction(vm, vcpuid, rip, inst_length, cr3, vie) != 0) + if (vmm_fetch_instruction(vm, vcpuid, rip, inst_length, cr3, + paging_mode, vie) != 0) return (EFAULT); - if (vmm_decode_instruction(vm, vcpuid, gla, vie) != 0) + if (vmm_decode_instruction(vm, vcpuid, gla, cpu_mode, vie) != 0) return (EFAULT); /* return to userland unless this is an in-kernel emulated device */ --- //depot/vendor/freebsd/src/sys/amd64/vmm/vmm_instruction_emul.c +++ //depot/user/jhb/bhyve/sys/amd64/vmm/vmm_instruction_emul.c @@ -49,11 +49,6 @@ #include #endif /* _KERNEL */ -enum cpu_mode { - CPU_MODE_COMPATIBILITY, /* IA-32E mode (CS.L = 0) */ - CPU_MODE_64BIT, /* IA-32E mode (CS.L = 1) */ -}; - /* struct vie_op.op_type */ enum { VIE_OP_TYPE_NONE = 0, @@ -476,16 +471,76 @@ static int gla2gpa(struct vm *vm, uint64_t gla, uint64_t ptpphys, - uint64_t *gpa, uint64_t *gpaend) + uint64_t *gpa, enum vie_paging_mode paging_mode) { int nlevels, ptpshift, ptpindex; uint64_t *ptpbase, pte, pgsize; + uint32_t *ptpbase32, pte32; void *cookie; - /* - * XXX assumes 64-bit guest with 4 page walk levels - */ - nlevels = 4; + if (paging_mode == PAGING_MODE_FLAT) { + *gpa = gla; + return (0); + } + + if (paging_mode == PAGING_MODE_32) { + nlevels = 2; + while (--nlevels >= 0) { + /* Zero out the lower 12 bits. */ + ptpphys &= ~0xfff; + + ptpbase32 = vm_gpa_hold(vm, ptpphys, PAGE_SIZE, + VM_PROT_READ, &cookie); + + if (ptpbase32 == NULL) + goto error; + + ptpshift = PAGE_SHIFT + nlevels * 10; + ptpindex = (gla >> ptpshift) & 0x3FF; + pgsize = 1UL << ptpshift; + + pte32 = ptpbase32[ptpindex]; + + vm_gpa_release(cookie); + + if ((pte32 & PG_V) == 0) + goto error; + + if (pte32 & PG_PS) + break; + + ptpphys = pte32; + } + + /* Zero out the lower 'ptpshift' bits */ + pte32 >>= ptpshift; pte32 <<= ptpshift; + *gpa = pte32 | (gla & (pgsize - 1)); + return (0); + } + + if (paging_mode == PAGING_MODE_PAE) { + /* Zero out the lower 5 bits and the upper 12 bits */ + ptpphys >>= 5; ptpphys <<= 17; ptpphys >>= 12; + + ptpbase = vm_gpa_hold(vm, ptpphys, sizeof(*ptpbase) * 4, + VM_PROT_READ, &cookie); + if (ptpbase == NULL) + goto error; + + ptpindex = (gla >> 30) & 0x3; + + pte = ptpbase[ptpindex]; + + vm_gpa_release(cookie); + + if ((pte & PG_V) == 0) + goto error; + + ptpphys = pte; + + nlevels = 2; + } else + nlevels = 4; while (--nlevels >= 0) { /* Zero out the lower 12 bits and the upper 12 bits */ ptpphys >>= 12; ptpphys <<= 24; ptpphys >>= 12; @@ -519,7 +574,6 @@ /* Zero out the lower 'ptpshift' bits and the upper 12 bits */ pte >>= ptpshift; pte <<= (ptpshift + 12); pte >>= 12; *gpa = pte | (gla & (pgsize - 1)); - *gpaend = pte + pgsize; return (0); error: @@ -528,10 +582,11 @@ int vmm_fetch_instruction(struct vm *vm, int cpuid, uint64_t rip, int inst_length, - uint64_t cr3, struct vie *vie) + uint64_t cr3, enum vie_paging_mode paging_mode, + struct vie *vie) { int n, err, prot; - uint64_t gpa, gpaend, off; + uint64_t gpa, off; void *hpa, *cookie; /* @@ -544,7 +599,7 @@ /* Copy the instruction into 'vie' */ while (vie->num_valid < inst_length) { - err = gla2gpa(vm, rip, cr3, &gpa, &gpaend); + err = gla2gpa(vm, rip, cr3, &gpa, paging_mode); if (err) break; @@ -626,16 +681,10 @@ } static int -decode_modrm(struct vie *vie) +decode_modrm(struct vie *vie, enum vie_cpu_mode cpu_mode) { uint8_t x; - enum cpu_mode cpu_mode; - /* - * XXX assuming that guest is in IA-32E 64-bit mode - */ - cpu_mode = CPU_MODE_64BIT; - if (vie_peek(vie, &x)) return (-1); @@ -911,16 +960,19 @@ } int -vmm_decode_instruction(struct vm *vm, int cpuid, uint64_t gla, struct vie *vie) +vmm_decode_instruction(struct vm *vm, int cpuid, uint64_t gla, + enum vie_cpu_mode cpu_mode, struct vie *vie) { - if (decode_rex(vie)) - return (-1); + if (cpu_mode == CPU_MODE_64BIT) { + if (decode_rex(vie)) + return (-1); + } if (decode_opcode(vie)) return (-1); - if (decode_modrm(vie)) + if (decode_modrm(vie, cpu_mode)) return (-1); if (decode_sib(vie)) --- //depot/vendor/freebsd/src/sys/boot/common/load_elf32.c +++ //depot/user/jhb/bhyve/sys/boot/common/load_elf32.c @@ -2,5 +2,6 @@ __FBSDID("$FreeBSD: head/sys/boot/common/load_elf32.c 119483 2003-08-25 23:30:41Z obrien $"); #define __ELF_WORD_SIZE 32 +#define _MACHINE_ELF_WANT_32BIT #include "load_elf.c" --- //depot/vendor/freebsd/src/sys/boot/common/load_elf32_obj.c +++ //depot/user/jhb/bhyve/sys/boot/common/load_elf32_obj.c @@ -2,5 +2,6 @@ __FBSDID("$FreeBSD: head/sys/boot/common/load_elf32_obj.c 134459 2004-08-29 00:48:42Z iedowse $"); #define __ELF_WORD_SIZE 32 +#define _MACHINE_ELF_WANT_32BIT #include "load_elf_obj.c" --- //depot/vendor/freebsd/src/sys/boot/userboot/userboot/Makefile +++ //depot/user/jhb/bhyve/sys/boot/userboot/userboot/Makefile @@ -11,6 +11,7 @@ LIBDIR= /boot SRCS= autoload.c +SRCS+= biossmap.c SRCS+= bootinfo.c SRCS+= bootinfo32.c SRCS+= bootinfo64.c --- /dev/null +++ //depot/user/jhb/bhyve/sys/boot/userboot/userboot/biossmap.c @@ -0,0 +1,74 @@ +/*- + * 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: head/sys/boot/userboot/userboot/bootinfo.c 223695 2011-06-30 16:08:56Z dfr $"); + +#include +#include +#include +#include +#include +#include + +#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]); +} --- //depot/vendor/freebsd/src/sys/boot/userboot/userboot/bootinfo32.c +++ //depot/user/jhb/bhyve/sys/boot/userboot/userboot/bootinfo32.c @@ -66,7 +66,7 @@ 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 @@ 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 @@ 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 @@ int bootdevnr, howto; char *kernelname; const char *kernelpath; + uint64_t lowmem, highmem; howto = bi_getboothowto(args); @@ -198,9 +199,7 @@ 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.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 @@ /* * 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); --- //depot/vendor/freebsd/src/sys/boot/userboot/userboot/bootinfo64.c +++ //depot/user/jhb/bhyve/sys/boot/userboot/userboot/bootinfo64.c @@ -169,53 +169,6 @@ #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. * --- //depot/vendor/freebsd/src/sys/boot/userboot/userboot/elf32_freebsd.c +++ //depot/user/jhb/bhyve/sys/boot/userboot/userboot/elf32_freebsd.c @@ -45,6 +45,9 @@ 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 @@ 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 @@ /* * 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"); --- //depot/vendor/freebsd/src/sys/boot/userboot/userboot/libuserboot.h +++ //depot/user/jhb/bhyve/sys/boot/userboot/userboot/libuserboot.h @@ -65,3 +65,4 @@ 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); --- //depot/vendor/freebsd/src/usr.sbin/bhyveload/bhyveload.c +++ //depot/user/jhb/bhyve/usr.sbin/bhyveload/bhyveload.c @@ -465,7 +465,12 @@ { int error; - error = vm_setup_freebsd_registers(ctx, BSP, rip, cr3, gdtbase, rsp); + if (cr3 == 0) + error = vm_setup_freebsd_registers_i386(ctx, BSP, rip, gdtbase, + rsp); + else + error = vm_setup_freebsd_registers(ctx, BSP, rip, cr3, gdtbase, + rsp); if (error) { perror("vm_setup_freebsd_registers"); cb_exit(NULL, USERBOOT_EXIT_QUIT);