Skip to content

Commit bb99836

Browse files
Lai JiangshanKAGA-KOKO
authored andcommitted
x86/entry: Avoid redundant CR3 write on paranoid returns
The CR3 restore happens in: 1. #NMI return. 2. paranoid_exit() (i.e. #MCE, #VC, #DB and #DF return) Contrary to the implication in commit 21e9445 ("x86/mm: Optimize RESTORE_CR3"), the kernel never modifies CR3 in any of these exceptions, except for switching from user to kernel pagetables under PTI. That means that most of the time when returning from an exception that interrupted the kernel no CR3 restore is necessary. Writing CR3 is expensive on some machines. Most of the time because the interrupt might have come during kernel entry before the user to kernel CR3 switch or the during exit after the kernel to user switch. In the former case skipping the restore would be correct, but definitely not for the latter. So check the saved CR3 value and restore it only, if it is a user CR3. Give the macro a new name to clarify its usage, and remove a comment that was describing the original behaviour along with the not longer needed jump label. Signed-off-by: Lai Jiangshan <laijs@linux.alibaba.com> Signed-off-by: Brendan Jackman <jackmanb@google.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lore.kernel.org/r/20240108113950.360438-1-jackmanb@google.com [Rewrote commit message; responded to review comments] Change-Id: I6e56978c4753fb943a7897ff101f519514fa0827
1 parent 6613476 commit bb99836

File tree

2 files changed

+13
-20
lines changed

2 files changed

+13
-20
lines changed

arch/x86/entry/calling.h

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -239,38 +239,32 @@ For 32-bit we have the following conventions - kernel is built with
239239
.Ldone_\@:
240240
.endm
241241

242-
.macro RESTORE_CR3 scratch_reg:req save_reg:req
242+
/* Restore CR3 from a kernel context. May restore a user CR3 value. */
243+
.macro PARANOID_RESTORE_CR3 scratch_reg:req save_reg:req
243244
ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI
244245

245-
ALTERNATIVE "jmp .Lwrcr3_\@", "", X86_FEATURE_PCID
246-
247246
/*
248-
* KERNEL pages can always resume with NOFLUSH as we do
249-
* explicit flushes.
247+
* If CR3 contained the kernel page tables at the paranoid exception
248+
* entry, then there is nothing to restore as CR3 is not modified while
249+
* handling the exception.
250250
*/
251251
bt $PTI_USER_PGTABLE_BIT, \save_reg
252-
jnc .Lnoflush_\@
252+
jnc .Lend_\@
253+
254+
ALTERNATIVE "jmp .Lwrcr3_\@", "", X86_FEATURE_PCID
253255

254256
/*
255257
* Check if there's a pending flush for the user ASID we're
256258
* about to set.
257259
*/
258260
movq \save_reg, \scratch_reg
259261
andq $(0x7FF), \scratch_reg
260-
bt \scratch_reg, THIS_CPU_user_pcid_flush_mask
261-
jnc .Lnoflush_\@
262-
263262
btr \scratch_reg, THIS_CPU_user_pcid_flush_mask
264-
jmp .Lwrcr3_\@
263+
jc .Lwrcr3_\@
265264

266-
.Lnoflush_\@:
267265
SET_NOFLUSH_BIT \save_reg
268266

269267
.Lwrcr3_\@:
270-
/*
271-
* The CR3 write could be avoided when not changing its value,
272-
* but would require a CR3 read *and* a scratch register.
273-
*/
274268
movq \save_reg, %cr3
275269
.Lend_\@:
276270
.endm
@@ -285,7 +279,7 @@ For 32-bit we have the following conventions - kernel is built with
285279
.endm
286280
.macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req
287281
.endm
288-
.macro RESTORE_CR3 scratch_reg:req save_reg:req
282+
.macro PARANOID_RESTORE_CR3 scratch_reg:req save_reg:req
289283
.endm
290284

291285
#endif

arch/x86/entry/entry_64.S

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -968,14 +968,14 @@ SYM_CODE_START_LOCAL(paranoid_exit)
968968
IBRS_EXIT save_reg=%r15
969969

970970
/*
971-
* The order of operations is important. RESTORE_CR3 requires
971+
* The order of operations is important. PARANOID_RESTORE_CR3 requires
972972
* kernel GSBASE.
973973
*
974974
* NB to anyone to try to optimize this code: this code does
975975
* not execute at all for exceptions from user mode. Those
976976
* exceptions go through error_return instead.
977977
*/
978-
RESTORE_CR3 scratch_reg=%rax save_reg=%r14
978+
PARANOID_RESTORE_CR3 scratch_reg=%rax save_reg=%r14
979979

980980
/* Handle the three GSBASE cases */
981981
ALTERNATIVE "jmp .Lparanoid_exit_checkgs", "", X86_FEATURE_FSGSBASE
@@ -1404,8 +1404,7 @@ end_repeat_nmi:
14041404
/* Always restore stashed SPEC_CTRL value (see paranoid_entry) */
14051405
IBRS_EXIT save_reg=%r15
14061406

1407-
/* Always restore stashed CR3 value (see paranoid_entry) */
1408-
RESTORE_CR3 scratch_reg=%r15 save_reg=%r14
1407+
PARANOID_RESTORE_CR3 scratch_reg=%r15 save_reg=%r14
14091408

14101409
/*
14111410
* The above invocation of paranoid_entry stored the GSBASE

0 commit comments

Comments
 (0)