MFC 261504:

Add support for FreeBSD/i386 guests under bhyve.
This commit is contained in:
jhb 2014-06-12 15:20:59 +00:00
parent a9824f54c0
commit fa121e2a05
16 changed files with 413 additions and 101 deletions

View File

@ -111,5 +111,8 @@ int vcpu_reset(struct vmctx *ctx, int vcpu);
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_ */

View File

@ -35,14 +35,176 @@ __FBSDID("$FreeBSD$");
#include <machine/segments.h>
#include <machine/vmm.h>
#include <errno.h>
#include <string.h>
#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 @@ vm_setup_freebsd_registers(struct vmctx *vmctx, int vcpu,
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)

View File

@ -323,6 +323,8 @@ struct vm_exit {
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;
/*

View File

@ -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_emulate_instruction(void *vm, int cpuid, uint64_t gpa, struct vie *vie,
*/
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 @@ void vie_init(struct vie *vie);
* 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_ */

View File

@ -1337,6 +1337,30 @@ vmx_emulate_cr_access(struct vmx *vmx, int vcpu, uint64_t exitqual)
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)
{
@ -1496,6 +1520,8 @@ vmx_handle_apic_access(struct vmx *vmx, int vcpuid, struct vm_exit *vmexit)
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();
}
/*
@ -1714,6 +1740,8 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit)
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();
vmm_stat_incr(vmx->vm, vcpu, VMEXIT_INST_EMUL, 1);
}
/*

View File

@ -1082,6 +1082,8 @@ vm_handle_inst_emul(struct vm *vm, int vcpuid, bool *retu)
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;
@ -1094,15 +1096,18 @@ vm_handle_inst_emul(struct vm *vm, int vcpuid, bool *retu)
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 */

View File

@ -49,11 +49,6 @@ __FBSDID("$FreeBSD$");
#include <vmmapi.h>
#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,
@ -578,16 +573,76 @@ vie_init(struct vie *vie)
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;
@ -621,7 +676,6 @@ gla2gpa(struct vm *vm, uint64_t gla, uint64_t ptpphys,
/* 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:
@ -630,10 +684,11 @@ error:
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;
/*
@ -646,7 +701,7 @@ vmm_fetch_instruction(struct vm *vm, int cpuid, uint64_t rip, int inst_length,
/* 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;
@ -749,15 +804,9 @@ decode_opcode(struct vie *vie)
}
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);
@ -1034,16 +1083,19 @@ verify_gla(struct vm *vm, int cpuid, uint64_t gla, struct vie *vie)
}
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))

View File

@ -2,5 +2,6 @@
__FBSDID("$FreeBSD$");
#define __ELF_WORD_SIZE 32
#define _MACHINE_ELF_WANT_32BIT
#include "load_elf.c"

View File

@ -2,5 +2,6 @@
__FBSDID("$FreeBSD$");
#define __ELF_WORD_SIZE 32
#define _MACHINE_ELF_WANT_32BIT
#include "load_elf_obj.c"

View File

@ -11,6 +11,7 @@ STRIP=
LIBDIR= /boot
SRCS= autoload.c
SRCS+= biossmap.c
SRCS+= bootinfo.c
SRCS+= bootinfo32.c
SRCS+= bootinfo64.c

View File

@ -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]);
}

View File

@ -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);

View File

@ -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.
*

View File

@ -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");

View File

@ -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);

View File

@ -465,7 +465,12 @@ cb_exec(void *arg, uint64_t rip)
{
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);