|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH] x86/AMD: expose SYSCFG, TOM, and TOM2 to Dom0
On Wed, May 26, 2021 at 02:59:00PM +0200, Jan Beulich wrote:
> Sufficiently old Linux (3.12-ish) accesses these MSRs in an unguarded
> manner. Furthermore these MSRs, at least on Fam11 and older CPUs, are
> also consulted by modern Linux, and their (bogus) built-in zapping of
> #GP faults from MSR accesses leads to it effectively reading zero
> instead of the intended values, which are relevant for PCI BAR placement
> (which ought to all live in MMIO-type space, not in DRAM-type one).
>
> For SYSCFG, only certain bits get exposed. In fact, whether to expose
> MtrrVarDramEn is debatable: It controls use of not just TOM, but also
> the IORRs. Introduce (consistently named) constants for the bits we're
> interested in and use them in pre-existing code as well.
I think we should also allow access to the IORRs MSRs for coherency
(c001001{6,9}) for the hardware domain.
> As a welcome side effect, verbosity on/of debug builds gets (perhaps
> significantly) reduced.
>
> Note that at least as far as those MSR accesses by Linux are concerned,
> there's no similar issue for DomU-s, as the accesses sit behind PCI
> device matching logic. The checked for devices would never be exposed to
> DomU-s in the first place. Nevertheless I think that at least for HVM we
> should return sensible values, not 0 (as svm_msr_read_intercept() does
> right now). The intended values may, however, need to be determined by
> hvmloader, and then get made known to Xen.
Could we maybe come up with a fixed memory layout that hvmloader had
to respect?
Ie: DRAM from 0 to 3G, MMIO from 3G to 4G, and then the remaining
DRAM from 4G in a contiguous single block?
hvmloader would have to place BARs that don't fit in the 3G-4G hole at
the end of DRAM (ie: after TOM2).
>
> Fixes: 322ec7c89f66 ("x86/pv: disallow access to unknown MSRs")
> Reported-by: Olaf Hering <olaf@xxxxxxxxx>
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
>
> --- a/xen/arch/x86/cpu/amd.c
> +++ b/xen/arch/x86/cpu/amd.c
> @@ -468,14 +468,14 @@ static void check_syscfg_dram_mod_en(voi
> return;
>
> rdmsrl(MSR_K8_SYSCFG, syscfg);
> - if (!(syscfg & K8_MTRRFIXRANGE_DRAM_MODIFY))
> + if (!(syscfg & SYSCFG_MTRR_FIX_DRAM_MOD_EN))
> return;
>
> if (!test_and_set_bool(printed))
> printk(KERN_ERR "MTRR: SYSCFG[MtrrFixDramModEn] not "
> "cleared by BIOS, clearing this bit\n");
>
> - syscfg &= ~K8_MTRRFIXRANGE_DRAM_MODIFY;
> + syscfg &= ~SYSCFG_MTRR_FIX_DRAM_MOD_EN;
> wrmsrl(MSR_K8_SYSCFG, syscfg);
> }
>
> --- a/xen/arch/x86/cpu/mtrr/generic.c
> +++ b/xen/arch/x86/cpu/mtrr/generic.c
> @@ -224,7 +224,7 @@ static void __init print_mtrr_state(cons
> uint64_t syscfg, tom2;
>
> rdmsrl(MSR_K8_SYSCFG, syscfg);
> - if (syscfg & (1 << 21)) {
> + if (syscfg & SYSCFG_MTRR_TOM2_EN) {
> rdmsrl(MSR_K8_TOP_MEM2, tom2);
> printk("%sTOM2: %012"PRIx64"%s\n", level, tom2,
> syscfg & (1 << 22) ? " (WB)" : "");
> --- a/xen/arch/x86/msr.c
> +++ b/xen/arch/x86/msr.c
> @@ -339,6 +339,19 @@ int guest_rdmsr(struct vcpu *v, uint32_t
> *val = msrs->tsc_aux;
> break;
>
> + case MSR_K8_SYSCFG:
> + case MSR_K8_TOP_MEM1:
> + case MSR_K8_TOP_MEM2:
> + if ( !(cp->x86_vendor & (X86_VENDOR_AMD | X86_VENDOR_HYGON)) )
> + goto gp_fault;
> + if ( !is_hardware_domain(d) )
> + return X86EMUL_UNHANDLEABLE;
It might be clearer to also handle the !is_hardware_domain case here,
instead of deferring to svm_msr_read_intercept:
if ( is_hardware_domain(d) )
rdmsrl(msr, *val);
else
*val = 0;
...
> + rdmsrl(msr, *val);
> + if ( msr == MSR_K8_SYSCFG )
> + *val &= (SYSCFG_TOM2_FORCE_WB | SYSCFG_MTRR_TOM2_EN |
> + SYSCFG_MTRR_VAR_DRAM_EN | SYSCFG_MTRR_FIX_DRAM_EN);
> + break;
> +
> case MSR_K8_HWCR:
> if ( !(cp->x86_vendor & (X86_VENDOR_AMD | X86_VENDOR_HYGON)) )
> goto gp_fault;
> --- a/xen/arch/x86/x86_64/mmconf-fam10h.c
> +++ b/xen/arch/x86/x86_64/mmconf-fam10h.c
> @@ -69,7 +69,7 @@ static void __init get_fam10h_pci_mmconf
> rdmsrl(address, val);
>
> /* TOP_MEM2 is not enabled? */
> - if (!(val & (1<<21))) {
> + if (!(val & SYSCFG_MTRR_TOM2_EN)) {
> tom2 = 1ULL << 32;
> } else {
> /* TOP_MEM2 */
> --- a/xen/include/asm-x86/msr-index.h
> +++ b/xen/include/asm-x86/msr-index.h
> @@ -116,6 +116,13 @@
> #define PASID_PASID_MASK 0x000fffff
> #define PASID_VALID (_AC(1, ULL) << 31)
>
> +#define MSR_K8_SYSCFG 0xc0010010
> +#define SYSCFG_MTRR_FIX_DRAM_EN (_AC(1, ULL) << 18)
> +#define SYSCFG_MTRR_FIX_DRAM_MOD_EN (_AC(1, ULL) << 19)
> +#define SYSCFG_MTRR_VAR_DRAM_EN (_AC(1, ULL) << 20)
> +#define SYSCFG_MTRR_TOM2_EN (_AC(1, ULL) << 21)
> +#define SYSCFG_TOM2_FORCE_WB (_AC(1, ULL) << 22)
> +
> #define MSR_K8_VM_CR 0xc0010114
> #define VM_CR_INIT_REDIRECTION (_AC(1, ULL) << 1)
> #define VM_CR_SVM_DISABLE (_AC(1, ULL) << 4)
> @@ -279,10 +286,7 @@
> #define MSR_K8_TOP_MEM1 0xc001001a
> #define MSR_K7_CLK_CTL 0xc001001b
> #define MSR_K8_TOP_MEM2 0xc001001d
> -#define MSR_K8_SYSCFG 0xc0010010
>
> -#define K8_MTRRFIXRANGE_DRAM_ENABLE 0x00040000 /* MtrrFixDramEn bit */
> -#define K8_MTRRFIXRANGE_DRAM_MODIFY 0x00080000 /* MtrrFixDramModEn bit */
> #define K8_MTRR_RDMEM_WRMEM_MASK 0x18181818 /* Mask: RdMem|WrMem */
That last one seem to be unused, I wonder if you could also drop it as
part of this cleanup?
Thanks, Roger.
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |