bhyve: add support for MTRR
Some guests or driver might depend on MTRR to work properly. E.g. the nvidia gpu driver won't work without MTRR. Reviewed by: markj MFC after: 2 weeks Sponsored by: Beckhoff Automation GmbH & Co. KG Differential Revision: https://reviews.freebsd.org/D33333
This commit is contained in:
parent
62b4e25f05
commit
6171e026be
@ -120,9 +120,14 @@ svm_rdmsr(struct svm_softc *sc, int vcpu, u_int num, uint64_t *result,
|
||||
break;
|
||||
case MSR_MTRRcap:
|
||||
case MSR_MTRRdefType:
|
||||
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 8:
|
||||
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 7:
|
||||
case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1:
|
||||
case MSR_MTRR64kBase:
|
||||
case MSR_MTRRVarBase ... MSR_MTRRVarBase + (VMM_MTRR_VAR_MAX * 2) - 1:
|
||||
if (vm_rdmtrr(&sc->mtrr[vcpu], num, result) != 0) {
|
||||
vm_inject_gp(sc->vm, vcpu);
|
||||
}
|
||||
break;
|
||||
case MSR_SYSCFG:
|
||||
case MSR_AMDK8_IPM:
|
||||
case MSR_EXTFEATURES:
|
||||
@ -146,12 +151,15 @@ svm_wrmsr(struct svm_softc *sc, int vcpu, u_int num, uint64_t val, bool *retu)
|
||||
case MSR_MCG_STATUS:
|
||||
break; /* ignore writes */
|
||||
case MSR_MTRRcap:
|
||||
vm_inject_gp(sc->vm, vcpu);
|
||||
break;
|
||||
case MSR_MTRRdefType:
|
||||
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 8:
|
||||
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 7:
|
||||
case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1:
|
||||
case MSR_MTRR64kBase:
|
||||
case MSR_MTRRVarBase ... MSR_MTRRVarBase + (VMM_MTRR_VAR_MAX * 2) - 1:
|
||||
if (vm_wrmtrr(&sc->mtrr[vcpu], num, val) != 0) {
|
||||
vm_inject_gp(sc->vm, vcpu);
|
||||
}
|
||||
break;
|
||||
case MSR_SYSCFG:
|
||||
break; /* Ignore writes */
|
||||
case MSR_AMDK8_IPM:
|
||||
|
@ -31,6 +31,8 @@
|
||||
#ifndef _SVM_SOFTC_H_
|
||||
#define _SVM_SOFTC_H_
|
||||
|
||||
#include "x86.h"
|
||||
|
||||
#define SVM_IO_BITMAP_SIZE (3 * PAGE_SIZE)
|
||||
#define SVM_MSR_BITMAP_SIZE (2 * PAGE_SIZE)
|
||||
|
||||
@ -64,6 +66,7 @@ struct svm_softc {
|
||||
uint8_t *iopm_bitmap; /* shared by all vcpus */
|
||||
uint8_t *msr_bitmap; /* shared by all vcpus */
|
||||
struct vm *vm;
|
||||
struct vm_mtrr mtrr[VM_MAXCPU];
|
||||
};
|
||||
|
||||
CTASSERT((offsetof(struct svm_softc, nptp) & PAGE_MASK) == 0);
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define _VMX_H_
|
||||
|
||||
#include "vmcs.h"
|
||||
#include "x86.h"
|
||||
|
||||
struct pmap;
|
||||
|
||||
@ -134,6 +135,7 @@ struct vmx {
|
||||
uint64_t eptp;
|
||||
struct vm *vm;
|
||||
long eptgen[MAXCPU]; /* cached pmap->pm_eptgen */
|
||||
struct vm_mtrr mtrr[VM_MAXCPU];
|
||||
};
|
||||
CTASSERT((offsetof(struct vmx, vmcs) & PAGE_MASK) == 0);
|
||||
CTASSERT((offsetof(struct vmx, msr_bitmap) & PAGE_MASK) == 0);
|
||||
|
@ -425,10 +425,13 @@ vmx_rdmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t *val, bool *retu)
|
||||
break;
|
||||
case MSR_MTRRcap:
|
||||
case MSR_MTRRdefType:
|
||||
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 8:
|
||||
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 7:
|
||||
case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1:
|
||||
case MSR_MTRR64kBase:
|
||||
*val = 0;
|
||||
case MSR_MTRRVarBase ... MSR_MTRRVarBase + (VMM_MTRR_VAR_MAX * 2) - 1:
|
||||
if (vm_rdmtrr(&vmx->mtrr[vcpuid], num, val) != 0) {
|
||||
vm_inject_gp(vmx->vm, vcpuid);
|
||||
}
|
||||
break;
|
||||
case MSR_IA32_MISC_ENABLE:
|
||||
*val = misc_enable;
|
||||
@ -465,13 +468,15 @@ vmx_wrmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t val, bool *retu)
|
||||
case MSR_MCG_STATUS:
|
||||
break; /* ignore writes */
|
||||
case MSR_MTRRcap:
|
||||
vm_inject_gp(vmx->vm, vcpuid);
|
||||
break;
|
||||
case MSR_MTRRdefType:
|
||||
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 8:
|
||||
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 7:
|
||||
case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1:
|
||||
case MSR_MTRR64kBase:
|
||||
break; /* Ignore writes */
|
||||
case MSR_MTRRVarBase ... MSR_MTRRVarBase + (VMM_MTRR_VAR_MAX * 2) - 1:
|
||||
if (vm_wrmtrr(&vmx->mtrr[vcpuid], num, val) != 0) {
|
||||
vm_inject_gp(vmx->vm, vcpuid);
|
||||
}
|
||||
break;
|
||||
case MSR_IA32_MISC_ENABLE:
|
||||
changed = val ^ misc_enable;
|
||||
/*
|
||||
|
@ -648,3 +648,85 @@ vm_cpuid_capability(struct vm *vm, int vcpuid, enum vm_cpuid_capability cap)
|
||||
}
|
||||
return (rv);
|
||||
}
|
||||
|
||||
int
|
||||
vm_rdmtrr(struct vm_mtrr *mtrr, u_int num, uint64_t *val)
|
||||
{
|
||||
switch (num) {
|
||||
case MSR_MTRRcap:
|
||||
*val = MTRR_CAP_WC | MTRR_CAP_FIXED | VMM_MTRR_VAR_MAX;
|
||||
break;
|
||||
case MSR_MTRRdefType:
|
||||
*val = mtrr->def_type;
|
||||
break;
|
||||
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 7:
|
||||
*val = mtrr->fixed4k[num - MSR_MTRR4kBase];
|
||||
break;
|
||||
case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1:
|
||||
*val = mtrr->fixed16k[num - MSR_MTRR16kBase];
|
||||
break;
|
||||
case MSR_MTRR64kBase:
|
||||
*val = mtrr->fixed64k;
|
||||
break;
|
||||
case MSR_MTRRVarBase ... MSR_MTRRVarBase + (VMM_MTRR_VAR_MAX * 2) - 1: {
|
||||
u_int offset = num - MSR_MTRRVarBase;
|
||||
if (offset % 2 == 0) {
|
||||
*val = mtrr->var[offset / 2].base;
|
||||
} else {
|
||||
*val = mtrr->var[offset / 2].mask;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
vm_wrmtrr(struct vm_mtrr *mtrr, u_int num, uint64_t val)
|
||||
{
|
||||
switch (num) {
|
||||
case MSR_MTRRcap:
|
||||
/* MTRRCAP is read only */
|
||||
return (-1);
|
||||
case MSR_MTRRdefType:
|
||||
if (val & ~VMM_MTRR_DEF_MASK) {
|
||||
/* generate #GP on writes to reserved fields */
|
||||
return (-1);
|
||||
}
|
||||
mtrr->def_type = val;
|
||||
break;
|
||||
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 7:
|
||||
mtrr->fixed4k[num - MSR_MTRR4kBase] = val;
|
||||
break;
|
||||
case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1:
|
||||
mtrr->fixed16k[num - MSR_MTRR16kBase] = val;
|
||||
break;
|
||||
case MSR_MTRR64kBase:
|
||||
mtrr->fixed64k = val;
|
||||
break;
|
||||
case MSR_MTRRVarBase ... MSR_MTRRVarBase + (VMM_MTRR_VAR_MAX * 2) - 1: {
|
||||
u_int offset = num - MSR_MTRRVarBase;
|
||||
if (offset % 2 == 0) {
|
||||
if (val & ~VMM_MTRR_PHYSBASE_MASK) {
|
||||
/* generate #GP on writes to reserved fields */
|
||||
return (-1);
|
||||
}
|
||||
mtrr->var[offset / 2].base = val;
|
||||
} else {
|
||||
if (val & ~VMM_MTRR_PHYSMASK_MASK) {
|
||||
/* generate #GP on writes to reserved fields */
|
||||
return (-1);
|
||||
}
|
||||
mtrr->var[offset / 2].mask = val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -80,4 +80,24 @@ enum vm_cpuid_capability {
|
||||
* and 'false' otherwise.
|
||||
*/
|
||||
bool vm_cpuid_capability(struct vm *vm, int vcpuid, enum vm_cpuid_capability);
|
||||
|
||||
#define VMM_MTRR_VAR_MAX 10
|
||||
#define VMM_MTRR_DEF_MASK \
|
||||
(MTRR_DEF_ENABLE | MTRR_DEF_FIXED_ENABLE | MTRR_DEF_TYPE)
|
||||
#define VMM_MTRR_PHYSBASE_MASK (MTRR_PHYSBASE_PHYSBASE | MTRR_PHYSBASE_TYPE)
|
||||
#define VMM_MTRR_PHYSMASK_MASK (MTRR_PHYSMASK_PHYSMASK | MTRR_PHYSMASK_VALID)
|
||||
struct vm_mtrr {
|
||||
uint64_t def_type;
|
||||
uint64_t fixed4k[8];
|
||||
uint64_t fixed16k[2];
|
||||
uint64_t fixed64k;
|
||||
struct {
|
||||
uint64_t base;
|
||||
uint64_t mask;
|
||||
} var[VMM_MTRR_VAR_MAX];
|
||||
};
|
||||
|
||||
int vm_rdmtrr(struct vm_mtrr *mtrr, u_int num, uint64_t *val);
|
||||
int vm_wrmtrr(struct vm_mtrr *mtrr, u_int num, uint64_t val);
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user