Changeset View
Changeset View
Standalone View
Standalone View
sys/amd64/vmm/amd/svm.c
Show First 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | |||||
* SVM host state saved area of size 4KB for each core. | * SVM host state saved area of size 4KB for each core. | ||||
*/ | */ | ||||
static uint8_t hsave[MAXCPU][PAGE_SIZE] __aligned(PAGE_SIZE); | static uint8_t hsave[MAXCPU][PAGE_SIZE] __aligned(PAGE_SIZE); | ||||
static VMM_STAT_AMD(VCPU_EXITINTINFO, "VM exits during event delivery"); | static VMM_STAT_AMD(VCPU_EXITINTINFO, "VM exits during event delivery"); | ||||
static VMM_STAT_AMD(VCPU_INTINFO_INJECTED, "Events pending at VM entry"); | static VMM_STAT_AMD(VCPU_INTINFO_INJECTED, "Events pending at VM entry"); | ||||
static VMM_STAT_AMD(VMEXIT_VINTR, "VM exits due to interrupt window"); | static VMM_STAT_AMD(VMEXIT_VINTR, "VM exits due to interrupt window"); | ||||
static int svm_getdesc(void *arg, int vcpu, int reg, struct seg_desc *desc); | |||||
static int svm_setreg(void *arg, int vcpu, int ident, uint64_t val); | static int svm_setreg(void *arg, int vcpu, int ident, uint64_t val); | ||||
static __inline int | static __inline int | ||||
flush_by_asid(void) | flush_by_asid(void) | ||||
{ | { | ||||
return (svm_feature & AMD_CPUID_SVM_FLUSH_BY_ASID); | return (svm_feature & AMD_CPUID_SVM_FLUSH_BY_ASID); | ||||
} | } | ||||
Show All 14 Lines | svm_disable(void *arg __unused) | ||||
efer &= ~EFER_SVM; | efer &= ~EFER_SVM; | ||||
wrmsr(MSR_EFER, efer); | wrmsr(MSR_EFER, efer); | ||||
} | } | ||||
/* | /* | ||||
* Disable SVM on all CPUs. | * Disable SVM on all CPUs. | ||||
*/ | */ | ||||
static int | static int | ||||
svm_cleanup(void) | svm_modcleanup(void) | ||||
{ | { | ||||
smp_rendezvous(NULL, svm_disable, NULL, NULL); | smp_rendezvous(NULL, svm_disable, NULL, NULL); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Verify that all the features required by bhyve are available. | * Verify that all the features required by bhyve are available. | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | if ((msr & VM_CR_SVMDIS) != 0) { | ||||
printf("SVM: disabled by BIOS.\n"); | printf("SVM: disabled by BIOS.\n"); | ||||
return (0); | return (0); | ||||
} | } | ||||
return (1); | return (1); | ||||
} | } | ||||
static int | static int | ||||
svm_init(int ipinum) | svm_modinit(int ipinum) | ||||
{ | { | ||||
int error, cpu; | int error, cpu; | ||||
if (!svm_available()) | if (!svm_available()) | ||||
return (ENXIO); | return (ENXIO); | ||||
error = check_svm_features(); | error = check_svm_features(); | ||||
if (error) | if (error) | ||||
Show All 17 Lines | svm_modinit(int ipinum) | ||||
/* Enable SVM on all CPUs */ | /* Enable SVM on all CPUs */ | ||||
smp_rendezvous(NULL, svm_enable, NULL, NULL); | smp_rendezvous(NULL, svm_enable, NULL, NULL); | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
svm_restore(void) | svm_modresume(void) | ||||
{ | { | ||||
svm_enable(NULL); | svm_enable(NULL); | ||||
} | } | ||||
#ifdef BHYVE_SNAPSHOT | #ifdef BHYVE_SNAPSHOT | ||||
int | int | ||||
svm_set_tsc_offset(struct svm_softc *sc, int vcpu, uint64_t offset) | svm_set_tsc_offset(struct svm_softc *sc, int vcpu, uint64_t offset) | ||||
▲ Show 20 Lines • Show All 260 Lines • ▼ Show 20 Lines | vmcb_init(struct svm_softc *sc, int vcpu, uint64_t iopm_base_pa, | ||||
state->dr6 = DBREG_DR6_RESERVED1; | state->dr6 = DBREG_DR6_RESERVED1; | ||||
state->dr7 = DBREG_DR7_RESERVED1; | state->dr7 = DBREG_DR7_RESERVED1; | ||||
} | } | ||||
/* | /* | ||||
* Initialize a virtual machine. | * Initialize a virtual machine. | ||||
*/ | */ | ||||
static void * | static void * | ||||
svm_vminit(struct vm *vm, pmap_t pmap) | svm_init(struct vm *vm, pmap_t pmap) | ||||
{ | { | ||||
struct svm_softc *svm_sc; | struct svm_softc *svm_sc; | ||||
struct svm_vcpu *vcpu; | struct svm_vcpu *vcpu; | ||||
vm_paddr_t msrpm_pa, iopm_pa, pml4_pa; | vm_paddr_t msrpm_pa, iopm_pa, pml4_pa; | ||||
int i; | int i; | ||||
uint16_t maxcpus; | uint16_t maxcpus; | ||||
svm_sc = malloc(sizeof (*svm_sc), M_SVM, M_WAITOK | M_ZERO); | svm_sc = malloc(sizeof (*svm_sc), M_SVM, M_WAITOK | M_ZERO); | ||||
▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | svm_inout_str_seginfo(struct svm_softc *svm_sc, int vcpu, int64_t info1, | ||||
if (in) { | if (in) { | ||||
vis->seg_name = VM_REG_GUEST_ES; | vis->seg_name = VM_REG_GUEST_ES; | ||||
} else { | } else { | ||||
/* The segment field has standard encoding */ | /* The segment field has standard encoding */ | ||||
s = (info1 >> 10) & 0x7; | s = (info1 >> 10) & 0x7; | ||||
vis->seg_name = vm_segment_name(s); | vis->seg_name = vm_segment_name(s); | ||||
} | } | ||||
error = vmcb_getdesc(svm_sc, vcpu, vis->seg_name, &vis->seg_desc); | error = svm_getdesc(svm_sc, vcpu, vis->seg_name, &vis->seg_desc); | ||||
KASSERT(error == 0, ("%s: svm_getdesc error %d", __func__, error)); | KASSERT(error == 0, ("%s: svm_getdesc error %d", __func__, error)); | ||||
} | } | ||||
static int | static int | ||||
svm_inout_str_addrsize(uint64_t info1) | svm_inout_str_addrsize(uint64_t info1) | ||||
{ | { | ||||
uint32_t size; | uint32_t size; | ||||
▲ Show 20 Lines • Show All 1,239 Lines • ▼ Show 20 Lines | svm_dr_leave_guest(struct svm_regctx *gctx) | ||||
wrmsr(MSR_DEBUGCTLMSR, gctx->host_debugctl); | wrmsr(MSR_DEBUGCTLMSR, gctx->host_debugctl); | ||||
load_dr7(gctx->host_dr7); | load_dr7(gctx->host_dr7); | ||||
} | } | ||||
/* | /* | ||||
* Start vcpu with specified RIP. | * Start vcpu with specified RIP. | ||||
*/ | */ | ||||
static int | static int | ||||
svm_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap, | svm_run(void *arg, int vcpu, register_t rip, pmap_t pmap, | ||||
struct vm_eventinfo *evinfo) | struct vm_eventinfo *evinfo) | ||||
{ | { | ||||
struct svm_regctx *gctx; | struct svm_regctx *gctx; | ||||
struct svm_softc *svm_sc; | struct svm_softc *svm_sc; | ||||
struct svm_vcpu *vcpustate; | struct svm_vcpu *vcpustate; | ||||
struct vmcb_state *state; | struct vmcb_state *state; | ||||
struct vmcb_ctrl *ctrl; | struct vmcb_ctrl *ctrl; | ||||
struct vm_exit *vmexit; | struct vm_exit *vmexit; | ||||
▲ Show 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | svm_run(void *arg, int vcpu, register_t rip, pmap_t pmap, | ||||
} while (handled); | } while (handled); | ||||
svm_msr_guest_exit(svm_sc, vcpu); | svm_msr_guest_exit(svm_sc, vcpu); | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
svm_vmcleanup(void *arg) | svm_cleanup(void *arg) | ||||
{ | { | ||||
struct svm_softc *sc = arg; | struct svm_softc *sc = arg; | ||||
contigfree(sc->iopm_bitmap, SVM_IO_BITMAP_SIZE, M_SVM); | contigfree(sc->iopm_bitmap, SVM_IO_BITMAP_SIZE, M_SVM); | ||||
contigfree(sc->msr_bitmap, SVM_MSR_BITMAP_SIZE, M_SVM); | contigfree(sc->msr_bitmap, SVM_MSR_BITMAP_SIZE, M_SVM); | ||||
free(sc, M_SVM); | free(sc, M_SVM); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | svm_setreg(void *arg, int vcpu, int ident, uint64_t val) | ||||
* vcpu's ASID. This needs to be treated differently depending on | * vcpu's ASID. This needs to be treated differently depending on | ||||
* whether 'running' is true/false. | * whether 'running' is true/false. | ||||
*/ | */ | ||||
VCPU_CTR1(svm_sc->vm, vcpu, "svm_setreg: unknown register %#x", ident); | VCPU_CTR1(svm_sc->vm, vcpu, "svm_setreg: unknown register %#x", ident); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
static int | |||||
svm_getdesc(void *arg, int vcpu, int reg, struct seg_desc *desc) | |||||
{ | |||||
return (vmcb_getdesc(arg, vcpu, reg, desc)); | |||||
} | |||||
static int | |||||
svm_setdesc(void *arg, int vcpu, int reg, struct seg_desc *desc) | |||||
{ | |||||
return (vmcb_setdesc(arg, vcpu, reg, desc)); | |||||
} | |||||
#ifdef BHYVE_SNAPSHOT | #ifdef BHYVE_SNAPSHOT | ||||
static int | static int | ||||
svm_snapshot_reg(void *arg, int vcpu, int ident, | svm_snapshot_reg(void *arg, int vcpu, int ident, | ||||
struct vm_snapshot_meta *meta) | struct vm_snapshot_meta *meta) | ||||
{ | { | ||||
int ret; | int ret; | ||||
uint64_t val; | uint64_t val; | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | case VM_CAP_UNRESTRICTED_GUEST: | ||||
break; | break; | ||||
default: | default: | ||||
error = ENOENT; | error = ENOENT; | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static struct vmspace * | |||||
svm_vmspace_alloc(vm_offset_t min, vm_offset_t max) | |||||
{ | |||||
return (svm_npt_alloc(min, max)); | |||||
} | |||||
static void | |||||
svm_vmspace_free(struct vmspace *vmspace) | |||||
{ | |||||
svm_npt_free(vmspace); | |||||
} | |||||
static struct vlapic * | static struct vlapic * | ||||
svm_vlapic_init(void *arg, int vcpuid) | svm_vlapic_init(void *arg, int vcpuid) | ||||
{ | { | ||||
struct svm_softc *svm_sc; | struct svm_softc *svm_sc; | ||||
struct vlapic *vlapic; | struct vlapic *vlapic; | ||||
svm_sc = arg; | svm_sc = arg; | ||||
vlapic = malloc(sizeof(struct vlapic), M_SVM_VLAPIC, M_WAITOK | M_ZERO); | vlapic = malloc(sizeof(struct vlapic), M_SVM_VLAPIC, M_WAITOK | M_ZERO); | ||||
Show All 11 Lines | |||||
{ | { | ||||
vlapic_cleanup(vlapic); | vlapic_cleanup(vlapic); | ||||
free(vlapic, M_SVM_VLAPIC); | free(vlapic, M_SVM_VLAPIC); | ||||
} | } | ||||
#ifdef BHYVE_SNAPSHOT | #ifdef BHYVE_SNAPSHOT | ||||
static int | static int | ||||
svm_snapshot_vmi(void *arg, struct vm_snapshot_meta *meta) | svm_snapshot(void *arg, struct vm_snapshot_meta *meta) | ||||
{ | { | ||||
/* struct svm_softc is AMD's representation for SVM softc */ | /* struct svm_softc is AMD's representation for SVM softc */ | ||||
struct svm_softc *sc; | struct svm_softc *sc; | ||||
struct svm_vcpu *vcpu; | struct svm_vcpu *vcpu; | ||||
struct vmcb *vmcb; | struct vmcb *vmcb; | ||||
uint64_t val; | uint64_t val; | ||||
int i; | int i; | ||||
int ret; | int ret; | ||||
▲ Show 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | svm_snapshot(void *arg, struct vm_snapshot_meta *meta) | ||||
if (meta->op == VM_SNAPSHOT_RESTORE) | if (meta->op == VM_SNAPSHOT_RESTORE) | ||||
flush_by_asid(); | flush_by_asid(); | ||||
done: | done: | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | static int | ||||
svm_snapshot_vmcx(void *arg, struct vm_snapshot_meta *meta, int vcpu) | svm_vmcx_snapshot(void *arg, struct vm_snapshot_meta *meta, int vcpu) | ||||
{ | { | ||||
struct vmcb *vmcb; | struct vmcb *vmcb; | ||||
struct svm_softc *sc; | struct svm_softc *sc; | ||||
int err, running, hostcpu; | int err, running, hostcpu; | ||||
sc = (struct svm_softc *)arg; | sc = (struct svm_softc *)arg; | ||||
err = 0; | err = 0; | ||||
▲ Show 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | svm_restore_tsc(void *arg, int vcpu, uint64_t offset) | ||||
int err; | int err; | ||||
err = svm_set_tsc_offset(arg, vcpu, offset); | err = svm_set_tsc_offset(arg, vcpu, offset); | ||||
return (err); | return (err); | ||||
} | } | ||||
#endif | #endif | ||||
struct vmm_ops vmm_ops_amd = { | const struct vmm_ops vmm_ops_amd = { | ||||
.modinit = svm_modinit, | |||||
.modcleanup = svm_modcleanup, | |||||
.modresume = svm_modresume, | |||||
.init = svm_init, | .init = svm_init, | ||||
.run = svm_run, | |||||
.cleanup = svm_cleanup, | .cleanup = svm_cleanup, | ||||
.resume = svm_restore, | .getreg = svm_getreg, | ||||
markj: Is there any reason this and vmm_ops_intel can't be marked `const`? | |||||
.vminit = svm_vminit, | .setreg = svm_setreg, | ||||
.vmrun = svm_vmrun, | .getdesc = svm_getdesc, | ||||
.vmcleanup = svm_vmcleanup, | .setdesc = svm_setdesc, | ||||
.vmgetreg = svm_getreg, | .getcap = svm_getcap, | ||||
.vmsetreg = svm_setreg, | .setcap = svm_setcap, | ||||
.vmgetdesc = vmcb_getdesc, | .vmspace_alloc = svm_vmspace_alloc, | ||||
.vmsetdesc = vmcb_setdesc, | .vmspace_free = svm_vmspace_free, | ||||
.vmgetcap = svm_getcap, | |||||
.vmsetcap = svm_setcap, | |||||
.vmspace_alloc = svm_npt_alloc, | |||||
.vmspace_free = svm_npt_free, | |||||
.vlapic_init = svm_vlapic_init, | .vlapic_init = svm_vlapic_init, | ||||
.vlapic_cleanup = svm_vlapic_cleanup, | .vlapic_cleanup = svm_vlapic_cleanup, | ||||
#ifdef BHYVE_SNAPSHOT | #ifdef BHYVE_SNAPSHOT | ||||
.vmsnapshot = svm_snapshot_vmi, | .snapshot = svm_snapshot, | ||||
.vmcx_snapshot = svm_snapshot_vmcx, | .vmcx_snapshot = svm_vmcx_snapshot, | ||||
.vm_restore_tsc = svm_restore_tsc, | .restore_tsc = svm_restore_tsc, | ||||
#endif | #endif | ||||
}; | }; |
Is there any reason this and vmm_ops_intel can't be marked const?