diff options
author | Dave Voutila <dv@cvs.openbsd.org> | 2022-12-26 23:50:21 +0000 |
---|---|---|
committer | Dave Voutila <dv@cvs.openbsd.org> | 2022-12-26 23:50:21 +0000 |
commit | 139f99b5c2de2912195a8c50a10f725a85bff827 (patch) | |
tree | 9d54dcbc04dc03690dd78952362a0e48b901c761 /sys/arch/amd64 | |
parent | 590f29696a223c79b75b6b8a97d0903b8d76df49 (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.c | 62 | ||||
-rw-r--r-- | sys/arch/amd64/include/vmmvar.h | 6 |
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. */ }; /* |