summaryrefslogtreecommitdiff
path: root/sys/arch/amd64
diff options
context:
space:
mode:
authorDave Voutila <dv@cvs.openbsd.org>2022-12-26 23:50:21 +0000
committerDave Voutila <dv@cvs.openbsd.org>2022-12-26 23:50:21 +0000
commit139f99b5c2de2912195a8c50a10f725a85bff827 (patch)
tree9d54dcbc04dc03690dd78952362a0e48b901c761 /sys/arch/amd64
parent590f29696a223c79b75b6b8a97d0903b8d76df49 (diff)
vmd(8): provide a detailed e820 memory map.
When booting guests with SeaBIOS, vmd(8) supplied details about the available guest memory via CMOS registers. Consequently, we've been carrying some patches in the ports tree to SeaBIOS to fetch this information like it's the 1990s. When a vm initializes memory ranges, we now track what each range represents. This information can be used to supply the e820 memory map to SeaBIOS via the fw_cfg interface allowing it to properly communicate memory ranges to a guest operating system. (This will also allow us to drop some patches from the port.) Given the ranges can now be marked with a purpose, this also allows vmm(4) to switch from hard-coded mmio ranges and instead let the information on the memory range dictate if vmm should be handling a page fault or sending to vmd for a memory assist. Tested by Mischa Peters and others. OK mlarkin@.
Diffstat (limited to 'sys/arch/amd64')
-rw-r--r--sys/arch/amd64/amd64/vmm.c62
-rw-r--r--sys/arch/amd64/include/vmmvar.h6
2 files changed, 33 insertions, 35 deletions
diff --git a/sys/arch/amd64/amd64/vmm.c b/sys/arch/amd64/amd64/vmm.c
index d7659a2ddfc..13cf7643cb4 100644
--- a/sys/arch/amd64/amd64/vmm.c
+++ b/sys/arch/amd64/amd64/vmm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmm.c,v 1.333 2022/12/19 04:48:07 dlg Exp $ */
+/* $OpenBSD: vmm.c,v 1.334 2022/12/26 23:50:20 dv Exp $ */
/*
* Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
*
@@ -1626,8 +1626,8 @@ vmx_remote_vmclear(struct cpu_info *ci, struct vcpu *vcpu)
* The last physical address may not exceed VMM_MAX_VM_MEM_SIZE.
*
* Return Values:
- * The total memory size in MB if the checks were successful
- * 0: One of the memory ranges was invalid, or VMM_MAX_VM_MEM_SIZE was
+ * The total memory size in bytes if the checks were successful
+ * 0: One of the memory ranges was invalid or VMM_MAX_VM_MEM_SIZE was
* exceeded
*/
size_t
@@ -1638,21 +1638,27 @@ vm_create_check_mem_ranges(struct vm_create_params *vcp)
const paddr_t maxgpa = VMM_MAX_VM_MEM_SIZE;
if (vcp->vcp_nmemranges == 0 ||
- vcp->vcp_nmemranges > VMM_MAX_MEM_RANGES)
+ vcp->vcp_nmemranges > VMM_MAX_MEM_RANGES) {
+ DPRINTF("invalid number of guest memory ranges\n");
return (0);
+ }
for (i = 0; i < vcp->vcp_nmemranges; i++) {
vmr = &vcp->vcp_memranges[i];
/* Only page-aligned addresses and sizes are permitted */
if ((vmr->vmr_gpa & PAGE_MASK) || (vmr->vmr_va & PAGE_MASK) ||
- (vmr->vmr_size & PAGE_MASK) || vmr->vmr_size == 0)
+ (vmr->vmr_size & PAGE_MASK) || vmr->vmr_size == 0) {
+ DPRINTF("memory range %zu is not page aligned\n", i);
return (0);
+ }
/* Make sure that VMM_MAX_VM_MEM_SIZE is not exceeded */
if (vmr->vmr_gpa >= maxgpa ||
- vmr->vmr_size > maxgpa - vmr->vmr_gpa)
+ vmr->vmr_size > maxgpa - vmr->vmr_gpa) {
+ DPRINTF("exceeded max memory size\n");
return (0);
+ }
/*
* Make sure that all virtual addresses are within the address
@@ -1662,39 +1668,29 @@ vm_create_check_mem_ranges(struct vm_create_params *vcp)
*/
if (vmr->vmr_va < VM_MIN_ADDRESS ||
vmr->vmr_va >= VM_MAXUSER_ADDRESS ||
- vmr->vmr_size >= VM_MAXUSER_ADDRESS - vmr->vmr_va)
- return (0);
-
- /*
- * Specifying ranges within the PCI MMIO space is forbidden.
- * Disallow ranges that start inside the MMIO space:
- * [VMM_PCI_MMIO_BAR_BASE .. VMM_PCI_MMIO_BAR_END]
- */
- if (vmr->vmr_gpa >= VMM_PCI_MMIO_BAR_BASE &&
- vmr->vmr_gpa <= VMM_PCI_MMIO_BAR_END)
- return (0);
-
- /*
- * ... and disallow ranges that end inside the MMIO space:
- * (VMM_PCI_MMIO_BAR_BASE .. VMM_PCI_MMIO_BAR_END]
- */
- if (vmr->vmr_gpa + vmr->vmr_size > VMM_PCI_MMIO_BAR_BASE &&
- vmr->vmr_gpa + vmr->vmr_size <= VMM_PCI_MMIO_BAR_END)
+ vmr->vmr_size >= VM_MAXUSER_ADDRESS - vmr->vmr_va) {
+ DPRINTF("guest va not within range or wraps\n");
return (0);
+ }
/*
* Make sure that guest physical memory ranges do not overlap
* and that they are ascending.
*/
- if (i > 0 && pvmr->vmr_gpa + pvmr->vmr_size > vmr->vmr_gpa)
+ if (i > 0 && pvmr->vmr_gpa + pvmr->vmr_size > vmr->vmr_gpa) {
+ DPRINTF("guest range %zu overlaps or !ascending\n", i);
return (0);
+ }
- memsize += vmr->vmr_size;
+ /*
+ * No memory is mappable in MMIO ranges, so don't count towards
+ * the total guest memory size.
+ */
+ if (vmr->vmr_type != VM_MEM_MMIO)
+ memsize += vmr->vmr_size;
pvmr = vmr;
}
- if (memsize % (1024 * 1024) != 0)
- return (0);
return (memsize);
}
@@ -5628,11 +5624,6 @@ vmm_get_guest_memtype(struct vm *vm, paddr_t gpa)
int i;
struct vm_mem_range *vmr;
- if (gpa >= VMM_PCI_MMIO_BAR_BASE && gpa <= VMM_PCI_MMIO_BAR_END) {
- DPRINTF("guest mmio access @ 0x%llx\n", (uint64_t)gpa);
- return (VMM_MEM_TYPE_MMIO);
- }
-
/* XXX Use binary search? */
for (i = 0; i < vm->vm_nmemranges; i++) {
vmr = &vm->vm_memranges[i];
@@ -5644,8 +5635,11 @@ vmm_get_guest_memtype(struct vm *vm, paddr_t gpa)
if (gpa < vmr->vmr_gpa)
break;
- if (gpa < vmr->vmr_gpa + vmr->vmr_size)
+ if (gpa < vmr->vmr_gpa + vmr->vmr_size) {
+ if (vmr->vmr_type == VM_MEM_MMIO)
+ return (VMM_MEM_TYPE_MMIO);
return (VMM_MEM_TYPE_REGULAR);
+ }
}
DPRINTF("guest memtype @ 0x%llx unknown\n", (uint64_t)gpa);
diff --git a/sys/arch/amd64/include/vmmvar.h b/sys/arch/amd64/include/vmmvar.h
index 94feca15471..6b4802abf4b 100644
--- a/sys/arch/amd64/include/vmmvar.h
+++ b/sys/arch/amd64/include/vmmvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmmvar.h,v 1.84 2022/11/10 11:46:39 dv Exp $ */
+/* $OpenBSD: vmmvar.h,v 1.85 2022/12/26 23:50:20 dv Exp $ */
/*
* Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
*
@@ -451,6 +451,10 @@ struct vm_mem_range {
paddr_t vmr_gpa;
vaddr_t vmr_va;
size_t vmr_size;
+ int vmr_type;
+#define VM_MEM_RAM 0 /* Presented as usable system memory. */
+#define VM_MEM_RESERVED 1 /* Reserved for BIOS, etc. */
+#define VM_MEM_MMIO 2 /* Special region for device mmio. */
};
/*