Skip to content

Commit 0521e8b

Browse files
Peter ZijlstraKAGA-KOKO
authored andcommitted
x86/mm/cpa: Fix set_mce_nospec()
The recent commit fe0937b ("x86/mm/cpa: Fold cpa_flush_range() and cpa_flush_array() into a single cpa_flush() function") accidentally made the call to make_addr_canonical_again() go away, which breaks set_mce_nospec(). Re-instate the call to convert the address back into canonical form right before invoking either CLFLUSH or INVLPG. Rename the function while at it to be shorter (and less MAGA). Fixes: fe0937b ("x86/mm/cpa: Fold cpa_flush_range() and cpa_flush_array() into a single cpa_flush() function") Reported-by: Tony Luck <tony.luck@intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Tony Luck <tony.luck@intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Rik van Riel <riel@surriel.com> Link: https://lkml.kernel.org/r/20190208120859.GH32511@hirez.programming.kicks-ass.net
1 parent 45b13b4 commit 0521e8b

File tree

1 file changed

+25
-25
lines changed

1 file changed

+25
-25
lines changed

arch/x86/mm/pageattr.c

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,29 @@ static bool __cpa_pfn_in_highmap(unsigned long pfn)
230230

231231
#endif
232232

233+
/*
234+
* See set_mce_nospec().
235+
*
236+
* Machine check recovery code needs to change cache mode of poisoned pages to
237+
* UC to avoid speculative access logging another error. But passing the
238+
* address of the 1:1 mapping to set_memory_uc() is a fine way to encourage a
239+
* speculative access. So we cheat and flip the top bit of the address. This
240+
* works fine for the code that updates the page tables. But at the end of the
241+
* process we need to flush the TLB and cache and the non-canonical address
242+
* causes a #GP fault when used by the INVLPG and CLFLUSH instructions.
243+
*
244+
* But in the common case we already have a canonical address. This code
245+
* will fix the top bit if needed and is a no-op otherwise.
246+
*/
247+
static inline unsigned long fix_addr(unsigned long addr)
248+
{
249+
#ifdef CONFIG_X86_64
250+
return (long)(addr << 1) >> 1;
251+
#else
252+
return addr;
253+
#endif
254+
}
255+
233256
static unsigned long __cpa_addr(struct cpa_data *cpa, unsigned long idx)
234257
{
235258
if (cpa->flags & CPA_PAGES_ARRAY) {
@@ -313,7 +336,7 @@ void __cpa_flush_tlb(void *data)
313336
unsigned int i;
314337

315338
for (i = 0; i < cpa->numpages; i++)
316-
__flush_tlb_one_kernel(__cpa_addr(cpa, i));
339+
__flush_tlb_one_kernel(fix_addr(__cpa_addr(cpa, i)));
317340
}
318341

319342
static void cpa_flush(struct cpa_data *data, int cache)
@@ -347,7 +370,7 @@ static void cpa_flush(struct cpa_data *data, int cache)
347370
* Only flush present addresses:
348371
*/
349372
if (pte && (pte_val(*pte) & _PAGE_PRESENT))
350-
clflush_cache_range_opt((void *)addr, PAGE_SIZE);
373+
clflush_cache_range_opt((void *)fix_addr(addr), PAGE_SIZE);
351374
}
352375
mb();
353376
}
@@ -1627,29 +1650,6 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias)
16271650
return ret;
16281651
}
16291652

1630-
/*
1631-
* Machine check recovery code needs to change cache mode of poisoned
1632-
* pages to UC to avoid speculative access logging another error. But
1633-
* passing the address of the 1:1 mapping to set_memory_uc() is a fine
1634-
* way to encourage a speculative access. So we cheat and flip the top
1635-
* bit of the address. This works fine for the code that updates the
1636-
* page tables. But at the end of the process we need to flush the cache
1637-
* and the non-canonical address causes a #GP fault when used by the
1638-
* CLFLUSH instruction.
1639-
*
1640-
* But in the common case we already have a canonical address. This code
1641-
* will fix the top bit if needed and is a no-op otherwise.
1642-
*/
1643-
static inline unsigned long make_addr_canonical_again(unsigned long addr)
1644-
{
1645-
#ifdef CONFIG_X86_64
1646-
return (long)(addr << 1) >> 1;
1647-
#else
1648-
return addr;
1649-
#endif
1650-
}
1651-
1652-
16531653
static int change_page_attr_set_clr(unsigned long *addr, int numpages,
16541654
pgprot_t mask_set, pgprot_t mask_clr,
16551655
int force_split, int in_flag,

0 commit comments

Comments
 (0)