| From cb7f4a8b1fb426a175d1708f05581939c61329d4 Mon Sep 17 00:00:00 2001 |
| From: Ying-Tsun Huang <ying-tsun.huang@amd.com> |
| Date: Tue, 15 Dec 2020 15:07:20 +0800 |
| Subject: x86/mtrr: Correct the range check before performing MTRR type lookups |
| |
| From: Ying-Tsun Huang <ying-tsun.huang@amd.com> |
| |
| commit cb7f4a8b1fb426a175d1708f05581939c61329d4 upstream. |
| |
| In mtrr_type_lookup(), if the input memory address region is not in the |
| MTRR, over 4GB, and not over the top of memory, a write-back attribute |
| is returned. These condition checks are for ensuring the input memory |
| address region is actually mapped to the physical memory. |
| |
| However, if the end address is just aligned with the top of memory, |
| the condition check treats the address is over the top of memory, and |
| write-back attribute is not returned. |
| |
| And this hits in a real use case with NVDIMM: the nd_pmem module tries |
| to map NVDIMMs as cacheable memories when NVDIMMs are connected. If a |
| NVDIMM is the last of the DIMMs, the performance of this NVDIMM becomes |
| very low since it is aligned with the top of memory and its memory type |
| is uncached-minus. |
| |
| Move the input end address change to inclusive up into |
| mtrr_type_lookup(), before checking for the top of memory in either |
| mtrr_type_lookup_{variable,fixed}() helpers. |
| |
| [ bp: Massage commit message. ] |
| |
| Fixes: 0cc705f56e40 ("x86/mm/mtrr: Clean up mtrr_type_lookup()") |
| Signed-off-by: Ying-Tsun Huang <ying-tsun.huang@amd.com> |
| Signed-off-by: Borislav Petkov <bp@suse.de> |
| Link: https://lkml.kernel.org/r/20201215070721.4349-1-ying-tsun.huang@amd.com |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/kernel/cpu/mtrr/generic.c | 6 +++--- |
| 1 file changed, 3 insertions(+), 3 deletions(-) |
| |
| --- a/arch/x86/kernel/cpu/mtrr/generic.c |
| +++ b/arch/x86/kernel/cpu/mtrr/generic.c |
| @@ -166,9 +166,6 @@ static u8 mtrr_type_lookup_variable(u64 |
| *repeat = 0; |
| *uniform = 1; |
| |
| - /* Make end inclusive instead of exclusive */ |
| - end--; |
| - |
| prev_match = MTRR_TYPE_INVALID; |
| for (i = 0; i < num_var_ranges; ++i) { |
| unsigned short start_state, end_state, inclusive; |
| @@ -260,6 +257,9 @@ u8 mtrr_type_lookup(u64 start, u64 end, |
| int repeat; |
| u64 partial_end; |
| |
| + /* Make end inclusive instead of exclusive */ |
| + end--; |
| + |
| if (!mtrr_state_set) |
| return MTRR_TYPE_INVALID; |
| |