| From edfe63ec97ed8d4496225f7ba54c9ce4207c5431 Mon Sep 17 00:00:00 2001 |
| From: Toshi Kani <toshi.kani@hpe.com> |
| Date: Wed, 23 Mar 2016 15:42:00 -0600 |
| Subject: x86/mtrr: Fix Xorg crashes in Qemu sessions |
| |
| From: Toshi Kani <toshi.kani@hpe.com> |
| |
| commit edfe63ec97ed8d4496225f7ba54c9ce4207c5431 upstream. |
| |
| A Xorg failure on qemu32 was reported as a regression [1] caused by |
| commit 9cd25aac1f44 ("x86/mm/pat: Emulate PAT when it is disabled"). |
| |
| This patch fixes the Xorg crash. |
| |
| Negative effects of this regression were the following two failures [2] |
| in Xorg on QEMU with QEMU CPU model "qemu32" (-cpu qemu32), which were |
| triggered by the fact that its virtual CPU does not support MTRRs. |
| |
| #1. copy_process() failed in the check in reserve_pfn_range() |
| |
| copy_process |
| copy_mm |
| dup_mm |
| dup_mmap |
| copy_page_range |
| track_pfn_copy |
| reserve_pfn_range |
| |
| A WC map request was tracked as WC in memtype, which set a PTE as |
| UC (pgprot) per __cachemode2pte_tbl[]. This led to this error in |
| reserve_pfn_range() called from track_pfn_copy(), which obtained |
| a pgprot from a PTE. It converts pgprot to page_cache_mode, which |
| does not necessarily result in the original page_cache_mode since |
| __cachemode2pte_tbl[] redirects multiple types to UC. |
| |
| #2. error path in copy_process() then hit WARN_ON_ONCE in |
| untrack_pfn(). |
| |
| x86/PAT: Xorg:509 map pfn expected mapping type uncached- |
| minus for [mem 0xfd000000-0xfdffffff], got write-combining |
| Call Trace: |
| dump_stack |
| warn_slowpath_common |
| ? untrack_pfn |
| ? untrack_pfn |
| warn_slowpath_null |
| untrack_pfn |
| ? __kunmap_atomic |
| unmap_single_vma |
| ? pagevec_move_tail_fn |
| unmap_vmas |
| exit_mmap |
| mmput |
| copy_process.part.47 |
| _do_fork |
| SyS_clone |
| do_syscall_32_irqs_on |
| entry_INT80_32 |
| |
| These negative effects are caused by two separate bugs, but they |
| can be addressed in separate patches. Fixing the pat_init() issue |
| described below addresses the root cause, and avoids Xorg to hit |
| these cases. |
| |
| When the CPU does not support MTRRs, MTRR does not call pat_init(), |
| which leaves PAT enabled without initializing PAT. This pat_init() |
| issue is a long-standing issue, but manifested as issue #1 (and then |
| hit issue #2) with the above-mentioned commit because the memtype |
| now tracks cache attribute with 'page_cache_mode'. |
| |
| This pat_init() issue existed before the commit, but we used pgprot |
| in memtype. Hence, we did not have issue #1 before. But WC request |
| resulted in WT in effect because WC pgrot is actually WT when PAT |
| is not initialized. This is not how it was designed to work. When |
| PAT is set to disable properly, WC is converted to UC. The use of |
| WT can result in a system crash if the target range does not support |
| WT. Fortunately, nobody ran into such issue before. |
| |
| To fix this pat_init() issue, PAT code has been enhanced to provide |
| pat_disable() interface. Call this interface when MTRRs are disabled. |
| By setting PAT to disable properly, PAT bypasses the memtype check, |
| and avoids issue #1. |
| |
| [1]: https://lkml.org/lkml/2016/3/3/828 |
| [2]: https://lkml.org/lkml/2016/3/4/775 |
| |
| Signed-off-by: Toshi Kani <toshi.kani@hpe.com> |
| Reviewed-by: Thomas Gleixner <tglx@linutronix.de> |
| Cc: Andrew Morton <akpm@linux-foundation.org> |
| Cc: Andy Lutomirski <luto@amacapital.net> |
| Cc: Borislav Petkov <bp@alien8.de> |
| Cc: Borislav Petkov <bp@suse.de> |
| Cc: Brian Gerst <brgerst@gmail.com> |
| Cc: Denys Vlasenko <dvlasenk@redhat.com> |
| Cc: H. Peter Anvin <hpa@zytor.com> |
| Cc: Juergen Gross <jgross@suse.com> |
| Cc: Linus Torvalds <torvalds@linux-foundation.org> |
| Cc: Luis R. Rodriguez <mcgrof@suse.com> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Cc: Toshi Kani <toshi.kani@hp.com> |
| Cc: elliott@hpe.com |
| Cc: konrad.wilk@oracle.com |
| Cc: paul.gortmaker@windriver.com |
| Cc: xen-devel@lists.xenproject.org |
| Link: http://lkml.kernel.org/r/1458769323-24491-5-git-send-email-toshi.kani@hpe.com |
| Signed-off-by: Ingo Molnar <mingo@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/include/asm/mtrr.h | 6 +++++- |
| arch/x86/kernel/cpu/mtrr/main.c | 10 +++++++++- |
| 2 files changed, 14 insertions(+), 2 deletions(-) |
| |
| --- a/arch/x86/include/asm/mtrr.h |
| +++ b/arch/x86/include/asm/mtrr.h |
| @@ -24,6 +24,7 @@ |
| #define _ASM_X86_MTRR_H |
| |
| #include <uapi/asm/mtrr.h> |
| +#include <asm/pat.h> |
| |
| |
| /* |
| @@ -83,9 +84,12 @@ static inline int mtrr_trim_uncached_mem |
| static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) |
| { |
| } |
| +static inline void mtrr_bp_init(void) |
| +{ |
| + pat_disable("MTRRs disabled, skipping PAT initialization too."); |
| +} |
| |
| #define mtrr_ap_init() do {} while (0) |
| -#define mtrr_bp_init() do {} while (0) |
| #define set_mtrr_aps_delayed_init() do {} while (0) |
| #define mtrr_aps_init() do {} while (0) |
| #define mtrr_bp_restore() do {} while (0) |
| --- a/arch/x86/kernel/cpu/mtrr/main.c |
| +++ b/arch/x86/kernel/cpu/mtrr/main.c |
| @@ -759,8 +759,16 @@ void __init mtrr_bp_init(void) |
| } |
| } |
| |
| - if (!mtrr_enabled()) |
| + if (!mtrr_enabled()) { |
| pr_info("MTRR: Disabled\n"); |
| + |
| + /* |
| + * PAT initialization relies on MTRR's rendezvous handler. |
| + * Skip PAT init until the handler can initialize both |
| + * features independently. |
| + */ |
| + pat_disable("MTRRs disabled, skipping PAT initialization too."); |
| + } |
| } |
| |
| void mtrr_ap_init(void) |