From 575440622ab6397b88e378c12e7cdf2086166a10 Mon Sep 17 00:00:00 2001 From: mlarkin Date: Tue, 17 Jul 2018 13:47:06 +0000 Subject: [PATCH] vmd(8): fix vmctl -b option for i386 kernels. ok pd@ --- usr.sbin/vmd/loadfile_elf.c | 50 ++++++++++++++++++++++++++++++------- usr.sbin/vmd/vm.c | 12 ++++----- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/usr.sbin/vmd/loadfile_elf.c b/usr.sbin/vmd/loadfile_elf.c index 586e4915a32..295852ef82c 100644 --- a/usr.sbin/vmd/loadfile_elf.c +++ b/usr.sbin/vmd/loadfile_elf.c @@ -1,5 +1,5 @@ /* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */ -/* $OpenBSD: loadfile_elf.c,v 1.29 2017/11/29 02:46:10 mlarkin Exp $ */ +/* $OpenBSD: loadfile_elf.c,v 1.30 2018/07/17 13:47:06 mlarkin Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -100,6 +100,7 @@ #include #include #include +#include #include #include "loadfile.h" @@ -124,7 +125,8 @@ static size_t create_bios_memmap(struct vm_create_params *, bios_memmap_t *); static uint32_t push_bootargs(bios_memmap_t *, size_t); static size_t push_stack(uint32_t, uint32_t, uint32_t, uint32_t); static void push_gdt(void); -static void push_pt(void); +static void push_pt_32(void); +static void push_pt_64(void); static void marc4random_buf(paddr_t, int); static void mbzero(paddr_t, int); static void mbcopy(void *, paddr_t, int); @@ -217,16 +219,35 @@ push_gdt(void) } /* - * push_pt + * push_pt_32 * * Create an identity-mapped page directory hierarchy mapping the first - * 1GB of physical memory. This is used during bootstrapping VMs on + * 4GB of physical memory. This is used during bootstrapping i386 VMs on * CPUs without unrestricted guest capability. */ static void -push_pt(void) +push_pt_32(void) { - uint64_t ptes[NPTE_PG], i; + uint32_t ptes[1024], i; + + memset(ptes, 0, sizeof(ptes)); + for (i = 0 ; i < 1024; i++) { + ptes[i] = PG_V | PG_RW | PG_u | PG_PS | ((4096 * 1024) * i); + } + write_mem(PML3_PAGE, ptes, PAGE_SIZE); +} + +/* + * push_pt_64 + * + * Create an identity-mapped page directory hierarchy mapping the first + * 1GB of physical memory. This is used during bootstrapping 64 bit VMs on + * CPUs without unrestricted guest capability. + */ +static void +push_pt_64(void) +{ + uint64_t ptes[512], i; /* PDPDE0 - first 1GB */ memset(ptes, 0, sizeof(ptes)); @@ -240,7 +261,7 @@ push_pt(void) /* First 1GB (in 2MB pages) */ memset(ptes, 0, sizeof(ptes)); - for (i = 0 ; i < NPTE_PG; i++) { + for (i = 0 ; i < 512; i++) { ptes[i] = PG_V | PG_RW | PG_u | PG_PS | ((2048 * 1024) * i); } write_mem(PML2_PAGE, ptes, PAGE_SIZE); @@ -267,7 +288,7 @@ int loadfile_elf(FILE *fp, struct vm_create_params *vcp, struct vcpu_reg_state *vrs, uint32_t bootdev, uint32_t howto) { - int r; + int r, is_i386 = 0; uint32_t bootargsz; size_t n, stacksize; u_long marks[MARK_MAX]; @@ -280,6 +301,7 @@ loadfile_elf(FILE *fp, struct vm_create_params *vcp, if (memcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 && hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { r = elf32_exec(fp, &hdr.elf32, marks, LOAD_ALL); + is_i386 = 1; } else if (memcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 && hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) { r = elf64_exec(fp, &hdr.elf64, marks, LOAD_ALL); @@ -290,7 +312,17 @@ loadfile_elf(FILE *fp, struct vm_create_params *vcp, return (r); push_gdt(); - push_pt(); + + if (is_i386) { + push_pt_32(); + /* Reconfigure the default flat-64 register set for 32 bit */ + vrs->vrs_crs[VCPU_REGS_CR3] = PML3_PAGE; + vrs->vrs_crs[VCPU_REGS_CR4] = CR4_PSE; + vrs->vrs_msrs[VCPU_REGS_EFER] = 0ULL; + } + else + push_pt_64(); + n = create_bios_memmap(vcp, memmap); bootargsz = push_bootargs(memmap, n); stacksize = push_stack(bootargsz, marks[MARK_END], bootdev, howto); diff --git a/usr.sbin/vmd/vm.c b/usr.sbin/vmd/vm.c index 67252e5cf89..046b2be8503 100644 --- a/usr.sbin/vmd/vm.c +++ b/usr.sbin/vmd/vm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm.c,v 1.37 2018/07/12 10:15:44 mlarkin Exp $ */ +/* $OpenBSD: vm.c,v 1.38 2018/07/17 13:47:06 mlarkin Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -110,7 +110,7 @@ uint8_t vcpu_done[VMM_MAX_VCPUS_PER_VM]; /* * Represents a standard register set for an OS to be booted - * as a flat 32 bit address space, before paging is enabled. + * as a flat 64 bit address space. * * NOT set here are: * RIP @@ -123,7 +123,7 @@ uint8_t vcpu_done[VMM_MAX_VCPUS_PER_VM]; * Note - CR3 and various bits in CR0 may be overridden by vmm(4) based on * features of the CPU in use. */ -static const struct vcpu_reg_state vcpu_init_flat32 = { +static const struct vcpu_reg_state vcpu_init_flat64 = { #ifdef __i386__ .vrs_gprs[VCPU_REGS_EFLAGS] = 0x2, .vrs_gprs[VCPU_REGS_EIP] = 0x0, @@ -136,7 +136,7 @@ static const struct vcpu_reg_state vcpu_init_flat32 = { .vrs_crs[VCPU_REGS_CR0] = CR0_CD | CR0_NW | CR0_ET | CR0_PE | CR0_PG, .vrs_crs[VCPU_REGS_CR3] = PML4_PAGE, .vrs_crs[VCPU_REGS_CR4] = CR4_PAE | CR4_PSE, - .vrs_crs[VCPU_REGS_PDPTE0] = PML3_PAGE | PG_V, + .vrs_crs[VCPU_REGS_PDPTE0] = 0ULL, .vrs_crs[VCPU_REGS_PDPTE1] = 0ULL, .vrs_crs[VCPU_REGS_PDPTE2] = 0ULL, .vrs_crs[VCPU_REGS_PDPTE3] = 0ULL, @@ -319,10 +319,10 @@ start_vm(struct vmd_vm *vm, int fd) vrs = vrp.vrwp_regs; } else { /* - * Set up default "flat 32 bit" register state - RIP, + * Set up default "flat 64 bit" register state - RIP, * RSP, and GDT info will be set in bootloader */ - memcpy(&vrs, &vcpu_init_flat32, sizeof(vrs)); + memcpy(&vrs, &vcpu_init_flat64, sizeof(vrs)); /* Find and open kernel image */ if ((fp = vmboot_open(vm->vm_kernel, -- 2.20.1