summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorDave Voutila <dv@cvs.openbsd.org>2022-06-26 06:49:10 +0000
committerDave Voutila <dv@cvs.openbsd.org>2022-06-26 06:49:10 +0000
commit7f62fea29967443132bf58e48cb91e0db775fd05 (patch)
tree15ad767c769c41ac7f1331766b800a022aff5557 /usr.sbin
parent9f15d1ddd02fbb8cad652b04d222444afa6ba66f (diff)
vmd: create a copy of bios at 4g boundary
Newer Linux kernels call into the bios to perform a reboot and our version of SeaBIOS assumes there's a "copy" of the bios ending at 4g. When SeaBIOS reads from this area, since vmd doesn't perform mmio yet, guests terminate with an unhandled fault. Carve out some space ending at 4g and copy the bios there. Technically we could load garbage there, but give SeaBIOS what it wants for now. ok mlarkin@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/vmd/vm.c82
1 files changed, 58 insertions, 24 deletions
diff --git a/usr.sbin/vmd/vm.c b/usr.sbin/vmd/vm.c
index d952ba4d8d0..5b40218aff6 100644
--- a/usr.sbin/vmd/vm.c
+++ b/usr.sbin/vmd/vm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm.c,v 1.69 2022/05/03 21:39:18 dv Exp $ */
+/* $OpenBSD: vm.c,v 1.70 2022/06/26 06:49:09 dv Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -65,6 +65,9 @@
#include "vmd.h"
#include "vmm.h"
+#define MB(x) (x * 1024UL * 1024UL)
+#define GB(x) (x * 1024UL * 1024UL * 1024UL)
+
io_fn_t ioports_map[MAX_PORTS];
int run_vm(int, int[][VM_MAX_BASE_PER_DISK], int *,
@@ -234,7 +237,7 @@ loadfile_bios(gzFile fp, off_t size, struct vcpu_reg_state *vrs)
return (-1);
/* The BIOS image must end at 1MB */
- if ((off = 1048576 - size) < 0)
+ if ((off = MB(1) - size) < 0)
return (-1);
/* Read BIOS image into memory */
@@ -243,6 +246,16 @@ loadfile_bios(gzFile fp, off_t size, struct vcpu_reg_state *vrs)
return (-1);
}
+ if (gzseek(fp, 0, SEEK_SET) == -1)
+ return (-1);
+
+ /* Read a second BIOS copy into memory ending at 4GB */
+ off = GB(4) - size;
+ if (mread(fp, off, size) != (size_t)size) {
+ errno = EIO;
+ return (-1);
+ }
+
log_debug("%s: loaded BIOS image", __func__);
return (0);
@@ -872,6 +885,7 @@ void
create_memory_map(struct vm_create_params *vcp)
{
size_t len, mem_bytes;
+ size_t above_1m = 0, above_4g = 0;
mem_bytes = vcp->vcp_memranges[0].vmr_size;
vcp->vcp_nmemranges = 0;
@@ -893,29 +907,47 @@ create_memory_map(struct vm_create_params *vcp)
* we need to make sure that vmm(4) permits accesses
* to it. So allocate guest memory for it.
*/
- len = 0x100000 - LOWMEM_KB * 1024;
+ len = MB(1) - (LOWMEM_KB * 1024);
vcp->vcp_memranges[1].vmr_gpa = LOWMEM_KB * 1024;
vcp->vcp_memranges[1].vmr_size = len;
mem_bytes -= len;
- /* Make sure that we do not place physical memory into MMIO ranges. */
- if (mem_bytes > VMM_PCI_MMIO_BAR_BASE - 0x100000)
- len = VMM_PCI_MMIO_BAR_BASE - 0x100000;
- else
- len = mem_bytes;
+ /* If we have less than 2MB remaining, still create a 2nd BIOS area. */
+ if (mem_bytes <= MB(2)) {
+ vcp->vcp_memranges[2].vmr_gpa = VMM_PCI_MMIO_BAR_END;
+ vcp->vcp_memranges[2].vmr_size = MB(2);
+ vcp->vcp_nmemranges = 3;
+ return;
+ }
- /* Third memory region: 1MB - (1MB + len) */
- vcp->vcp_memranges[2].vmr_gpa = 0x100000;
- vcp->vcp_memranges[2].vmr_size = len;
- mem_bytes -= len;
+ /*
+ * Calculate the how to split any remaining memory across the 4GB
+ * boundary while making sure we do not place physical memory into
+ * MMIO ranges.
+ */
+ if (mem_bytes > VMM_PCI_MMIO_BAR_BASE - MB(1)) {
+ above_1m = VMM_PCI_MMIO_BAR_BASE - MB(1);
+ above_4g = mem_bytes - above_1m;
+ } else {
+ above_1m = mem_bytes;
+ above_4g = 0;
+ }
- if (mem_bytes > 0) {
- /* Fourth memory region for the remaining memory (if any) */
- vcp->vcp_memranges[3].vmr_gpa = VMM_PCI_MMIO_BAR_END + 1;
- vcp->vcp_memranges[3].vmr_size = mem_bytes;
- vcp->vcp_nmemranges = 4;
+ /* Third memory region: area above 1MB to MMIO region */
+ vcp->vcp_memranges[2].vmr_gpa = MB(1);
+ vcp->vcp_memranges[2].vmr_size = above_1m;
+
+ /* Fourth region: 2nd copy of BIOS above MMIO ending at 4GB */
+ vcp->vcp_memranges[3].vmr_gpa = VMM_PCI_MMIO_BAR_END + 1;
+ vcp->vcp_memranges[3].vmr_size = MB(2);
+
+ /* Fifth region: any remainder above 4GB */
+ if (above_4g > 0) {
+ vcp->vcp_memranges[4].vmr_gpa = GB(4);
+ vcp->vcp_memranges[4].vmr_size = above_4g;
+ vcp->vcp_nmemranges = 5;
} else
- vcp->vcp_nmemranges = 3;
+ vcp->vcp_nmemranges = 4;
}
/*
@@ -1015,16 +1047,18 @@ init_emulated_hw(struct vmop_create_params *vmc, int child_cdrom,
int child_disks[][VM_MAX_BASE_PER_DISK], int *child_taps)
{
struct vm_create_params *vcp = &vmc->vmc_params;
- int i;
+ size_t i;
uint64_t memlo, memhi;
/* Calculate memory size for NVRAM registers */
memlo = memhi = 0;
- if (vcp->vcp_nmemranges > 2)
- memlo = vcp->vcp_memranges[2].vmr_size - 15 * 0x100000;
-
- if (vcp->vcp_nmemranges > 3)
- memhi = vcp->vcp_memranges[3].vmr_size;
+ for (i = 0; i < vcp->vcp_nmemranges; i++) {
+ if (vcp->vcp_memranges[i].vmr_gpa == MB(1) &&
+ vcp->vcp_memranges[i].vmr_size > (15 * MB(1)))
+ memlo = vcp->vcp_memranges[i].vmr_size - (15 * MB(1));
+ else if (vcp->vcp_memranges[i].vmr_gpa == GB(4))
+ memhi = vcp->vcp_memranges[i].vmr_size;
+ }
/* Reset the IO port map */
memset(&ioports_map, 0, sizeof(io_fn_t) * MAX_PORTS);