Index: sys/amd64/include/vmm.h =================================================================== --- sys/amd64/include/vmm.h +++ sys/amd64/include/vmm.h @@ -162,9 +162,9 @@ int *iptr; /* reqidle cookie */ }; -typedef int (*vmm_init_func_t)(int ipinum); -typedef int (*vmm_cleanup_func_t)(void); -typedef void (*vmm_resume_func_t)(void); +typedef int (*vmm_modinit_func_t)(int ipinum); +typedef int (*vmm_modcleanup_func_t)(void); +typedef void (*vmm_modresume_func_t)(void); typedef void * (*vmi_init_func_t)(struct vm *vm, struct pmap *pmap); typedef int (*vmi_run_func_t)(void *vmi, int vcpu, register_t rip, struct pmap *pmap, struct vm_eventinfo *info); @@ -189,28 +189,28 @@ typedef int (*vmi_restore_tsc_t)(void *vmi, int vcpuid, uint64_t now); struct vmm_ops { - vmm_init_func_t init; /* module wide initialization */ - vmm_cleanup_func_t cleanup; - vmm_resume_func_t resume; - - vmi_init_func_t vminit; /* vm-specific initialization */ - vmi_run_func_t vmrun; - vmi_cleanup_func_t vmcleanup; - vmi_get_register_t vmgetreg; - vmi_set_register_t vmsetreg; - vmi_get_desc_t vmgetdesc; - vmi_set_desc_t vmsetdesc; - vmi_get_cap_t vmgetcap; - vmi_set_cap_t vmsetcap; + vmm_modinit_func_t modinit; /* module wide initialization */ + vmm_modcleanup_func_t modcleanup; + vmm_modresume_func_t modresume; + + vmi_init_func_t init; /* vm-specific initialization */ + vmi_run_func_t run; + vmi_cleanup_func_t cleanup; + vmi_get_register_t getreg; + vmi_set_register_t setreg; + vmi_get_desc_t getdesc; + vmi_set_desc_t setdesc; + vmi_get_cap_t getcap; + vmi_set_cap_t setcap; vmi_vmspace_alloc vmspace_alloc; vmi_vmspace_free vmspace_free; vmi_vlapic_init vlapic_init; vmi_vlapic_cleanup vlapic_cleanup; /* checkpoint operations */ - vmi_snapshot_t vmsnapshot; + vmi_snapshot_t snapshot; vmi_snapshot_vmcx_t vmcx_snapshot; - vmi_restore_tsc_t vm_restore_tsc; + vmi_restore_tsc_t restore_tsc; }; extern struct vmm_ops vmm_ops_intel; Index: sys/amd64/vmm/amd/svm.c =================================================================== --- sys/amd64/vmm/amd/svm.c +++ sys/amd64/vmm/amd/svm.c @@ -2673,25 +2673,25 @@ #endif struct vmm_ops vmm_ops_amd = { - .init = svm_init, - .cleanup = svm_cleanup, - .resume = svm_restore, - .vminit = svm_vminit, - .vmrun = svm_vmrun, - .vmcleanup = svm_vmcleanup, - .vmgetreg = svm_getreg, - .vmsetreg = svm_setreg, - .vmgetdesc = vmcb_getdesc, - .vmsetdesc = vmcb_setdesc, - .vmgetcap = svm_getcap, - .vmsetcap = svm_setcap, + .modinit = svm_init, + .modcleanup = svm_cleanup, + .modresume = svm_restore, + .init = svm_vminit, + .run = svm_vmrun, + .cleanup = svm_vmcleanup, + .getreg = svm_getreg, + .setreg = svm_setreg, + .getdesc = vmcb_getdesc, + .setdesc = vmcb_setdesc, + .getcap = svm_getcap, + .setcap = svm_setcap, .vmspace_alloc = svm_npt_alloc, .vmspace_free = svm_npt_free, .vlapic_init = svm_vlapic_init, .vlapic_cleanup = svm_vlapic_cleanup, #ifdef BHYVE_SNAPSHOT - .vmsnapshot = svm_snapshot_vmi, + .snapshot = svm_snapshot_vmi, .vmcx_snapshot = svm_snapshot_vmcx, - .vm_restore_tsc = svm_restore_tsc, + .restore_tsc = svm_restore_tsc, #endif }; Index: sys/amd64/vmm/intel/vmx.c =================================================================== --- sys/amd64/vmm/intel/vmx.c +++ sys/amd64/vmm/intel/vmx.c @@ -4178,25 +4178,25 @@ #endif struct vmm_ops vmm_ops_intel = { - .init = vmx_init, - .cleanup = vmx_cleanup, - .resume = vmx_restore, - .vminit = vmx_vminit, - .vmrun = vmx_run, - .vmcleanup = vmx_vmcleanup, - .vmgetreg = vmx_getreg, - .vmsetreg = vmx_setreg, - .vmgetdesc = vmx_getdesc, - .vmsetdesc = vmx_setdesc, - .vmgetcap = vmx_getcap, - .vmsetcap = vmx_setcap, + .modinit = vmx_init, + .modcleanup = vmx_cleanup, + .modresume = vmx_restore, + .init = vmx_vminit, + .run = vmx_run, + .cleanup = vmx_vmcleanup, + .getreg = vmx_getreg, + .setreg = vmx_setreg, + .getdesc = vmx_getdesc, + .setdesc = vmx_setdesc, + .getcap = vmx_getcap, + .setcap = vmx_setcap, .vmspace_alloc = ept_vmspace_alloc, .vmspace_free = ept_vmspace_free, .vlapic_init = vmx_vlapic_init, .vlapic_cleanup = vmx_vlapic_cleanup, #ifdef BHYVE_SNAPSHOT - .vmsnapshot = vmx_snapshot_vmi, + .snapshot = vmx_snapshot_vmi, .vmcx_snapshot = vmx_snapshot_vmcx, - .vm_restore_tsc = vmx_restore_tsc, + .restore_tsc = vmx_restore_tsc, #endif }; Index: sys/amd64/vmm/vmm.c =================================================================== --- sys/amd64/vmm/vmm.c +++ sys/amd64/vmm/vmm.c @@ -67,6 +67,7 @@ #include #include #include +#include #include #include @@ -184,42 +185,53 @@ static int vmm_initialized; -static struct vmm_ops *ops; -#define VMM_INIT(num) (ops != NULL ? (*ops->init)(num) : 0) -#define VMM_CLEANUP() (ops != NULL ? (*ops->cleanup)() : 0) -#define VMM_RESUME() (ops != NULL ? (*ops->resume)() : 0) - -#define VMINIT(vm, pmap) (ops != NULL ? (*ops->vminit)(vm, pmap): NULL) -#define VMRUN(vmi, vcpu, rip, pmap, evinfo) \ - (ops != NULL ? (*ops->vmrun)(vmi, vcpu, rip, pmap, evinfo) : ENXIO) -#define VMCLEANUP(vmi) (ops != NULL ? (*ops->vmcleanup)(vmi) : NULL) -#define VMSPACE_ALLOC(min, max) \ - (ops != NULL ? (*ops->vmspace_alloc)(min, max) : NULL) -#define VMSPACE_FREE(vmspace) \ - (ops != NULL ? (*ops->vmspace_free)(vmspace) : ENXIO) -#define VMGETREG(vmi, vcpu, num, retval) \ - (ops != NULL ? (*ops->vmgetreg)(vmi, vcpu, num, retval) : ENXIO) -#define VMSETREG(vmi, vcpu, num, val) \ - (ops != NULL ? (*ops->vmsetreg)(vmi, vcpu, num, val) : ENXIO) -#define VMGETDESC(vmi, vcpu, num, desc) \ - (ops != NULL ? (*ops->vmgetdesc)(vmi, vcpu, num, desc) : ENXIO) -#define VMSETDESC(vmi, vcpu, num, desc) \ - (ops != NULL ? (*ops->vmsetdesc)(vmi, vcpu, num, desc) : ENXIO) -#define VMGETCAP(vmi, vcpu, num, retval) \ - (ops != NULL ? (*ops->vmgetcap)(vmi, vcpu, num, retval) : ENXIO) -#define VMSETCAP(vmi, vcpu, num, val) \ - (ops != NULL ? (*ops->vmsetcap)(vmi, vcpu, num, val) : ENXIO) -#define VLAPIC_INIT(vmi, vcpu) \ - (ops != NULL ? (*ops->vlapic_init)(vmi, vcpu) : NULL) -#define VLAPIC_CLEANUP(vmi, vlapic) \ - (ops != NULL ? (*ops->vlapic_cleanup)(vmi, vlapic) : NULL) +static void vmmops_panic(void); + +static void +vmmops_panic(void) +{ + panic("vmm_ops func called when !vmm_is_intel() && !vmm_is_svm()"); +} + +#define DEFINE_VMMOPS_IFUNC(ret_type, opname, args) \ + DEFINE_IFUNC(static, ret_type, vmmops_##opname, args) \ + { \ + if (vmm_is_intel()) \ + return (vmm_ops_intel.opname); \ + else if (vmm_is_svm()) \ + return (vmm_ops_amd.opname); \ + else \ + return ((ret_type (*)args)vmmops_panic); \ + } + +DEFINE_VMMOPS_IFUNC(int, modinit, (int ipinum)) +DEFINE_VMMOPS_IFUNC(int, modcleanup, (void)) +DEFINE_VMMOPS_IFUNC(void, modresume, (void)) +DEFINE_VMMOPS_IFUNC(void *, init, (struct vm *vm, struct pmap *pmap)) +DEFINE_VMMOPS_IFUNC(int, run, (void *vmi, int vcpu, register_t rip, + struct pmap *pmap, struct vm_eventinfo *info)) +DEFINE_VMMOPS_IFUNC(void, cleanup, (void *vmi)) +DEFINE_VMMOPS_IFUNC(int, getreg, (void *vmi, int vcpu, int num, + uint64_t *retval)) +DEFINE_VMMOPS_IFUNC(int, setreg, (void *vmi, int vcpu, int num, + uint64_t val)) +DEFINE_VMMOPS_IFUNC(int, getdesc, (void *vmi, int vcpu, int num, + struct seg_desc *desc)) +DEFINE_VMMOPS_IFUNC(int, setdesc, (void *vmi, int vcpu, int num, + struct seg_desc *desc)) +DEFINE_VMMOPS_IFUNC(int, getcap, (void *vmi, int vcpu, int num, int *retval)) +DEFINE_VMMOPS_IFUNC(int, setcap, (void *vmi, int vcpu, int num, int val)) +DEFINE_VMMOPS_IFUNC(struct vmspace *, vmspace_alloc, (vm_offset_t min, + vm_offset_t max)) +DEFINE_VMMOPS_IFUNC(void, vmspace_free, (struct vmspace *vmspace)) +DEFINE_VMMOPS_IFUNC(struct vlapic *, vlapic_init, (void *vmi, int vcpu)) +DEFINE_VMMOPS_IFUNC(void, vlapic_cleanup, (void *vmi, struct vlapic *vlapic)) #ifdef BHYVE_SNAPSHOT -#define VM_SNAPSHOT_VMI(vmi, meta) \ - (ops != NULL ? (*ops->vmsnapshot)(vmi, meta) : ENXIO) -#define VM_SNAPSHOT_VMCX(vmi, meta, vcpuid) \ - (ops != NULL ? (*ops->vmcx_snapshot)(vmi, meta, vcpuid) : ENXIO) -#define VM_RESTORE_TSC(vmi, vcpuid, offset) \ - (ops != NULL ? (*ops->vm_restore_tsc)(vmi, vcpuid, offset) : ENXIO) +DEFINE_VMMOPS_IFUNC(int, snapshot, (void *vmi, struct vm_snapshot_meta + *meta)) +DEFINE_VMMOPS_IFUNC(int, vmcx_snapshot, (void *vmi, struct vm_snapshot_meta + *meta, int vcpu)) +DEFINE_VMMOPS_IFUNC(int, restore_tsc, (void *vmi, int vcpuid, uint64_t now)) #endif #define fpu_start_emulating() load_cr0(rcr0() | CR0_TS) @@ -282,7 +294,7 @@ { struct vcpu *vcpu = &vm->vcpu[i]; - VLAPIC_CLEANUP(vm->cookie, vcpu->vlapic); + vmmops_vlapic_cleanup(vm->cookie, vcpu->vlapic); if (destroy) { vmm_stat_free(vcpu->stats); fpu_save_area_free(vcpu->guestfpu); @@ -310,7 +322,7 @@ vcpu->tsc_offset = 0; } - vcpu->vlapic = VLAPIC_INIT(vm->cookie, vcpu_id); + vcpu->vlapic = vmmops_vlapic_init(vm->cookie, vcpu_id); vm_set_x2apic_state(vm, vcpu_id, X2APIC_DISABLED); vcpu->reqidle = 0; vcpu->exitintinfo = 0; @@ -342,17 +354,14 @@ return (&vcpu->exitinfo); } -static void -vmm_resume(void) -{ - VMM_RESUME(); -} - static int vmm_init(void) { int error; + if (!vmm_is_hw_supported()) + return (ENXIO); + vmm_host_state_init(); vmm_ipinum = lapic_ipi_alloc(pti ? &IDTVEC(justreturn1_pti) : @@ -364,16 +373,9 @@ if (error) return (error); - if (vmm_is_intel()) - ops = &vmm_ops_intel; - else if (vmm_is_svm()) - ops = &vmm_ops_amd; - else - return (ENXIO); - - vmm_resume_p = vmm_resume; + vmm_resume_p = vmmops_modresume; - return (VMM_INIT(vmm_ipinum)); + return (vmmops_modinit(vmm_ipinum)); } static int @@ -383,25 +385,33 @@ switch (what) { case MOD_LOAD: - vmmdev_init(); - error = vmm_init(); - if (error == 0) - vmm_initialized = 1; + if (vmm_is_hw_supported()) { + vmmdev_init(); + error = vmm_init(); + if (error == 0) + vmm_initialized = 1; + } else { + error = ENXIO; + } break; case MOD_UNLOAD: - error = vmmdev_cleanup(); - if (error == 0) { - vmm_resume_p = NULL; - iommu_cleanup(); - if (vmm_ipinum != IPI_AST) - lapic_ipi_free(vmm_ipinum); - error = VMM_CLEANUP(); - /* - * Something bad happened - prevent new - * VMs from being created - */ - if (error) - vmm_initialized = 0; + if (vmm_is_hw_supported()) { + error = vmmdev_cleanup(); + if (error == 0) { + vmm_resume_p = NULL; + iommu_cleanup(); + if (vmm_ipinum != IPI_AST) + lapic_ipi_free(vmm_ipinum); + error = vmmops_modcleanup(); + /* + * Something bad happened - prevent new + * VMs from being created + */ + if (error) + vmm_initialized = 0; + } + } else { + error = 0; } break; default: @@ -431,7 +441,7 @@ { int i; - vm->cookie = VMINIT(vm, vmspace_pmap(vm->vmspace)); + vm->cookie = vmmops_init(vm, vmspace_pmap(vm->vmspace)); vm->iommu = NULL; vm->vioapic = vioapic_init(vm); vm->vhpet = vhpet_init(vm); @@ -473,7 +483,7 @@ if (name == NULL || strlen(name) >= VM_MAX_NAMELEN) return (EINVAL); - vmspace = VMSPACE_ALLOC(0, VM_MAXUSER_ADDRESS); + vmspace = vmmops_vmspace_alloc(0, VM_MAXUSER_ADDRESS); if (vmspace == NULL) return (ENOMEM); @@ -549,7 +559,7 @@ for (i = 0; i < vm->maxcpus; i++) vcpu_cleanup(vm, i, destroy); - VMCLEANUP(vm->cookie); + vmmops_cleanup(vm->cookie); /* * System memory is removed from the guest address space only when @@ -569,7 +579,7 @@ for (i = 0; i < VM_MAX_MEMSEGS; i++) vm_free_memseg(vm, i); - VMSPACE_FREE(vm->vmspace); + vmmops_vmspace_free(vm->vmspace); vm->vmspace = NULL; } } @@ -1033,7 +1043,7 @@ if (reg >= VM_REG_LAST) return (EINVAL); - return (VMGETREG(vm->cookie, vcpu, reg, retval)); + return (vmmops_getreg(vm->cookie, vcpu, reg, retval)); } int @@ -1048,7 +1058,7 @@ if (reg >= VM_REG_LAST) return (EINVAL); - error = VMSETREG(vm->cookie, vcpuid, reg, val); + error = vmmops_setreg(vm->cookie, vcpuid, reg, val); if (error || reg != VM_REG_GUEST_RIP) return (error); @@ -1102,7 +1112,7 @@ if (!is_segment_register(reg) && !is_descriptor_table(reg)) return (EINVAL); - return (VMGETDESC(vm->cookie, vcpu, reg, desc)); + return (vmmops_getdesc(vm->cookie, vcpu, reg, desc)); } int @@ -1115,7 +1125,7 @@ if (!is_segment_register(reg) && !is_descriptor_table(reg)) return (EINVAL); - return (VMSETDESC(vm->cookie, vcpu, reg, desc)); + return (vmmops_setdesc(vm->cookie, vcpu, reg, desc)); } static void @@ -1333,7 +1343,7 @@ * software events that would cause this vcpu to wakeup. * * These interrupts/events could have happened after the - * vcpu returned from VMRUN() and before it acquired the + * vcpu returned from vmmops_run() and before it acquired the * vcpu lock above. */ if (vm->rendezvous_func != NULL || vm->suspend || vcpu->reqidle) @@ -1730,7 +1740,7 @@ restore_guest_fpustate(vcpu); vcpu_require_state(vm, vcpuid, VCPU_RUNNING); - error = VMRUN(vm->cookie, vcpuid, vcpu->nextrip, pmap, &evinfo); + error = vmmops_run(vm->cookie, vcpuid, vcpu->nextrip, pmap, &evinfo); vcpu_require_state(vm, vcpuid, VCPU_FROZEN); save_guest_fpustate(vcpu); @@ -1819,9 +1829,9 @@ } else if (state == VCPU_FROZEN) { /* * When a vcpu is "frozen" it is outside the critical section - * around VMRUN() and 'nextrip' points to the next instruction. - * Thus instruction restart is achieved by setting 'nextrip' - * to the vcpu's %rip. + * around vmmops_run() and 'nextrip' points to the next + * instruction. Thus instruction restart is achieved by setting + * 'nextrip' to the vcpu's %rip. */ error = vm_get_register(vm, vcpuid, VM_REG_GUEST_RIP, &rip); KASSERT(!error, ("%s: error %d getting rip", __func__, error)); @@ -2226,7 +2236,7 @@ if (type < 0 || type >= VM_CAP_MAX) return (EINVAL); - return (VMGETCAP(vm->cookie, vcpu, type, retval)); + return (vmmops_getcap(vm->cookie, vcpu, type, retval)); } int @@ -2238,7 +2248,7 @@ if (type < 0 || type >= VM_CAP_MAX) return (EINVAL); - return (VMSETCAP(vm->cookie, vcpu, type, val)); + return (vmmops_setcap(vm->cookie, vcpu, type, val)); } struct vlapic * @@ -2824,7 +2834,7 @@ error = 0; for (i = 0; i < VM_MAXCPU; i++) { - error = VM_SNAPSHOT_VMCX(vm->cookie, meta, i); + error = vmmops_vmcx_snapshot(vm->cookie, meta, i); if (error != 0) { printf("%s: failed to snapshot vmcs/vmcb data for " "vCPU: %d; error: %d\n", __func__, i, error); @@ -2846,7 +2856,7 @@ switch (meta->dev_req) { case STRUCT_VMX: - ret = VM_SNAPSHOT_VMI(vm->cookie, meta); + ret = vmmops_snapshot(vm->cookie, meta); break; case STRUCT_VMCX: ret = vm_snapshot_vmcx(vm, meta); @@ -2913,7 +2923,8 @@ for (i = 0; i < nitems(vm->vcpu); i++) { vcpu = &vm->vcpu[i]; - error = VM_RESTORE_TSC(vm->cookie, i, vcpu->tsc_offset - now); + error = vmmops_restore_tsc(vm->cookie, i, vcpu->tsc_offset - + now); if (error) return (error); } Index: sys/amd64/vmm/vmm_util.h =================================================================== --- sys/amd64/vmm/vmm_util.h +++ sys/amd64/vmm/vmm_util.h @@ -33,6 +33,7 @@ struct trapframe; +bool vmm_is_hw_supported(void); bool vmm_is_intel(void); bool vmm_is_svm(void); bool vmm_supports_1G_pages(void); Index: sys/amd64/vmm/vmm_util.c =================================================================== --- sys/amd64/vmm/vmm_util.c +++ sys/amd64/vmm/vmm_util.c @@ -38,6 +38,12 @@ #include "vmm_util.h" +bool +vmm_is_hw_supported(void) +{ + return (vmm_is_intel() || vmm_is_svm()); +} + bool vmm_is_intel(void) {