Skip to content

Commit 6cff64b

Browse files
hansendcIngo Molnar
authored andcommitted
x86/mm: Use INVPCID for __native_flush_tlb_single()
This uses INVPCID to shoot down individual lines of the user mapping instead of marking the entire user map as invalid. This could/might/possibly be faster. This for sure needs tlb_single_page_flush_ceiling to be redetermined; esp. since INVPCID is _slow_. A detailed performance analysis is available here: https://lkml.kernel.org/r/[email protected] [ Peterz: Split out from big combo patch ] Signed-off-by: Dave Hansen <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Boris Ostrovsky <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Brian Gerst <[email protected]> Cc: Denys Vlasenko <[email protected]> Cc: Eduardo Valentin <[email protected]> Cc: Greg KH <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Josh Poimboeuf <[email protected]> Cc: Juergen Gross <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Will Deacon <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 21e9445 commit 6cff64b

File tree

3 files changed

+60
-28
lines changed

3 files changed

+60
-28
lines changed

arch/x86/include/asm/cpufeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@
197197
#define X86_FEATURE_CAT_L3 ( 7*32+ 4) /* Cache Allocation Technology L3 */
198198
#define X86_FEATURE_CAT_L2 ( 7*32+ 5) /* Cache Allocation Technology L2 */
199199
#define X86_FEATURE_CDP_L3 ( 7*32+ 6) /* Code and Data Prioritization L3 */
200+
#define X86_FEATURE_INVPCID_SINGLE ( 7*32+ 7) /* Effectively INVPCID && CR4.PCIDE=1 */
200201

201202
#define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */
202203
#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */

arch/x86/include/asm/tlbflush.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,18 @@ static inline u16 kern_pcid(u16 asid)
8585
return asid + 1;
8686
}
8787

88+
/*
89+
* The user PCID is just the kernel one, plus the "switch bit".
90+
*/
91+
static inline u16 user_pcid(u16 asid)
92+
{
93+
u16 ret = kern_pcid(asid);
94+
#ifdef CONFIG_PAGE_TABLE_ISOLATION
95+
ret |= 1 << X86_CR3_PTI_SWITCH_BIT;
96+
#endif
97+
return ret;
98+
}
99+
88100
struct pgd_t;
89101
static inline unsigned long build_cr3(pgd_t *pgd, u16 asid)
90102
{
@@ -335,6 +347,8 @@ static inline void __native_flush_tlb_global(void)
335347
/*
336348
* Using INVPCID is considerably faster than a pair of writes
337349
* to CR4 sandwiched inside an IRQ flag save/restore.
350+
*
351+
* Note, this works with CR4.PCIDE=0 or 1.
338352
*/
339353
invpcid_flush_all();
340354
return;
@@ -368,7 +382,14 @@ static inline void __native_flush_tlb_single(unsigned long addr)
368382
if (!static_cpu_has(X86_FEATURE_PTI))
369383
return;
370384

371-
invalidate_user_asid(loaded_mm_asid);
385+
/*
386+
* Some platforms #GP if we call invpcid(type=1/2) before CR4.PCIDE=1.
387+
* Just use invalidate_user_asid() in case we are called early.
388+
*/
389+
if (!this_cpu_has(X86_FEATURE_INVPCID_SINGLE))
390+
invalidate_user_asid(loaded_mm_asid);
391+
else
392+
invpcid_flush_one(user_pcid(loaded_mm_asid), addr);
372393
}
373394

374395
/*

arch/x86/mm/init.c

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -203,34 +203,44 @@ static void __init probe_page_size_mask(void)
203203

204204
static void setup_pcid(void)
205205
{
206-
#ifdef CONFIG_X86_64
207-
if (boot_cpu_has(X86_FEATURE_PCID)) {
208-
if (boot_cpu_has(X86_FEATURE_PGE)) {
209-
/*
210-
* This can't be cr4_set_bits_and_update_boot() --
211-
* the trampoline code can't handle CR4.PCIDE and
212-
* it wouldn't do any good anyway. Despite the name,
213-
* cr4_set_bits_and_update_boot() doesn't actually
214-
* cause the bits in question to remain set all the
215-
* way through the secondary boot asm.
216-
*
217-
* Instead, we brute-force it and set CR4.PCIDE
218-
* manually in start_secondary().
219-
*/
220-
cr4_set_bits(X86_CR4_PCIDE);
221-
} else {
222-
/*
223-
* flush_tlb_all(), as currently implemented, won't
224-
* work if PCID is on but PGE is not. Since that
225-
* combination doesn't exist on real hardware, there's
226-
* no reason to try to fully support it, but it's
227-
* polite to avoid corrupting data if we're on
228-
* an improperly configured VM.
229-
*/
230-
setup_clear_cpu_cap(X86_FEATURE_PCID);
231-
}
206+
if (!IS_ENABLED(CONFIG_X86_64))
207+
return;
208+
209+
if (!boot_cpu_has(X86_FEATURE_PCID))
210+
return;
211+
212+
if (boot_cpu_has(X86_FEATURE_PGE)) {
213+
/*
214+
* This can't be cr4_set_bits_and_update_boot() -- the
215+
* trampoline code can't handle CR4.PCIDE and it wouldn't
216+
* do any good anyway. Despite the name,
217+
* cr4_set_bits_and_update_boot() doesn't actually cause
218+
* the bits in question to remain set all the way through
219+
* the secondary boot asm.
220+
*
221+
* Instead, we brute-force it and set CR4.PCIDE manually in
222+
* start_secondary().
223+
*/
224+
cr4_set_bits(X86_CR4_PCIDE);
225+
226+
/*
227+
* INVPCID's single-context modes (2/3) only work if we set
228+
* X86_CR4_PCIDE, *and* we INVPCID support. It's unusable
229+
* on systems that have X86_CR4_PCIDE clear, or that have
230+
* no INVPCID support at all.
231+
*/
232+
if (boot_cpu_has(X86_FEATURE_INVPCID))
233+
setup_force_cpu_cap(X86_FEATURE_INVPCID_SINGLE);
234+
} else {
235+
/*
236+
* flush_tlb_all(), as currently implemented, won't work if
237+
* PCID is on but PGE is not. Since that combination
238+
* doesn't exist on real hardware, there's no reason to try
239+
* to fully support it, but it's polite to avoid corrupting
240+
* data if we're on an improperly configured VM.
241+
*/
242+
setup_clear_cpu_cap(X86_FEATURE_PCID);
232243
}
233-
#endif
234244
}
235245

236246
#ifdef CONFIG_X86_32

0 commit comments

Comments
 (0)