Commit 6171e026 authored by Corvin Köhne's avatar Corvin Köhne Committed by Emmanuel Vadot
Browse files

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
parent 62b4e25f
...@@ -120,9 +120,14 @@ svm_rdmsr(struct svm_softc *sc, int vcpu, u_int num, uint64_t *result, ...@@ -120,9 +120,14 @@ svm_rdmsr(struct svm_softc *sc, int vcpu, u_int num, uint64_t *result,
break; break;
case MSR_MTRRcap: case MSR_MTRRcap:
case MSR_MTRRdefType: case MSR_MTRRdefType:
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 8: case MSR_MTRR4kBase ... MSR_MTRR4kBase + 7:
case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1: case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1:
case MSR_MTRR64kBase: 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_SYSCFG:
case MSR_AMDK8_IPM: case MSR_AMDK8_IPM:
case MSR_EXTFEATURES: case MSR_EXTFEATURES:
...@@ -146,12 +151,15 @@ svm_wrmsr(struct svm_softc *sc, int vcpu, u_int num, uint64_t val, bool *retu) ...@@ -146,12 +151,15 @@ svm_wrmsr(struct svm_softc *sc, int vcpu, u_int num, uint64_t val, bool *retu)
case MSR_MCG_STATUS: case MSR_MCG_STATUS:
break; /* ignore writes */ break; /* ignore writes */
case MSR_MTRRcap: case MSR_MTRRcap:
vm_inject_gp(sc->vm, vcpu);
break;
case MSR_MTRRdefType: case MSR_MTRRdefType:
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 8: case MSR_MTRR4kBase ... MSR_MTRR4kBase + 7:
case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1: case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1:
case MSR_MTRR64kBase: 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: case MSR_SYSCFG:
break; /* Ignore writes */ break; /* Ignore writes */
case MSR_AMDK8_IPM: case MSR_AMDK8_IPM:
......
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#ifndef _SVM_SOFTC_H_ #ifndef _SVM_SOFTC_H_
#define _SVM_SOFTC_H_ #define _SVM_SOFTC_H_
#include "x86.h"
#define SVM_IO_BITMAP_SIZE (3 * PAGE_SIZE) #define SVM_IO_BITMAP_SIZE (3 * PAGE_SIZE)
#define SVM_MSR_BITMAP_SIZE (2 * PAGE_SIZE) #define SVM_MSR_BITMAP_SIZE (2 * PAGE_SIZE)
...@@ -64,6 +66,7 @@ struct svm_softc { ...@@ -64,6 +66,7 @@ struct svm_softc {
uint8_t *iopm_bitmap; /* shared by all vcpus */ uint8_t *iopm_bitmap; /* shared by all vcpus */
uint8_t *msr_bitmap; /* shared by all vcpus */ uint8_t *msr_bitmap; /* shared by all vcpus */
struct vm *vm; struct vm *vm;
struct vm_mtrr mtrr[VM_MAXCPU];
}; };
CTASSERT((offsetof(struct svm_softc, nptp) & PAGE_MASK) == 0); CTASSERT((offsetof(struct svm_softc, nptp) & PAGE_MASK) == 0);
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#define _VMX_H_ #define _VMX_H_
#include "vmcs.h" #include "vmcs.h"
#include "x86.h"
struct pmap; struct pmap;
...@@ -134,6 +135,7 @@ struct vmx { ...@@ -134,6 +135,7 @@ struct vmx {
uint64_t eptp; uint64_t eptp;
struct vm *vm; struct vm *vm;
long eptgen[MAXCPU]; /* cached pmap->pm_eptgen */ 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, vmcs) & PAGE_MASK) == 0);
CTASSERT((offsetof(struct vmx, msr_bitmap) & 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) ...@@ -425,10 +425,13 @@ vmx_rdmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t *val, bool *retu)
break; break;
case MSR_MTRRcap: case MSR_MTRRcap:
case MSR_MTRRdefType: case MSR_MTRRdefType:
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 8: case MSR_MTRR4kBase ... MSR_MTRR4kBase + 7:
case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1: case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1:
case MSR_MTRR64kBase: 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; break;
case MSR_IA32_MISC_ENABLE: case MSR_IA32_MISC_ENABLE:
*val = misc_enable; *val = misc_enable;
...@@ -465,13 +468,15 @@ vmx_wrmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t val, bool *retu) ...@@ -465,13 +468,15 @@ vmx_wrmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t val, bool *retu)
case MSR_MCG_STATUS: case MSR_MCG_STATUS:
break; /* ignore writes */ break; /* ignore writes */
case MSR_MTRRcap: case MSR_MTRRcap:
vm_inject_gp(vmx->vm, vcpuid);
break;
case MSR_MTRRdefType: case MSR_MTRRdefType:
case MSR_MTRR4kBase ... MSR_MTRR4kBase + 8: case MSR_MTRR4kBase ... MSR_MTRR4kBase + 7:
case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1: case MSR_MTRR16kBase ... MSR_MTRR16kBase + 1:
case MSR_MTRR64kBase: 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: case MSR_IA32_MISC_ENABLE:
changed = val ^ misc_enable; changed = val ^ misc_enable;
/* /*
......
...@@ -648,3 +648,85 @@ vm_cpuid_capability(struct vm *vm, int vcpuid, enum vm_cpuid_capability cap) ...@@ -648,3 +648,85 @@ vm_cpuid_capability(struct vm *vm, int vcpuid, enum vm_cpuid_capability cap)
} }
return (rv); 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 { ...@@ -80,4 +80,24 @@ enum vm_cpuid_capability {
* and 'false' otherwise. * and 'false' otherwise.
*/ */
bool vm_cpuid_capability(struct vm *vm, int vcpuid, enum vm_cpuid_capability); 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 #endif
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment