Skip to content

Commit dada858

Browse files
ardbiesheuvelbp3tk0v
authored andcommitted
x86/startup_64: Simplify CR4 handling in startup code
When paging is enabled, the CR4.PAE and CR4.LA57 control bits cannot be changed, and so they can simply be preserved rather than reason about whether or not they need to be set. CR4.MCE should be preserved unless the kernel was built without CONFIG_X86_MCE, in which case it must be cleared. CR4.PSE should be set explicitly, regardless of whether or not it was set before. CR4.PGE is set explicitly, and then cleared and set again after programming CR3 in order to flush TLB entries based on global translations. This makes the first assignment redundant, and can therefore be omitted. So clear PGE by omitting it from the preserve mask, and set it again explicitly after switching to the new page tables. [ bp: Document the exact operation of CR4.PGE ] Signed-off-by: Ard Biesheuvel <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Tested-by: Tom Lendacky <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 721f791 commit dada858

File tree

1 file changed

+17
-18
lines changed

1 file changed

+17
-18
lines changed

arch/x86/kernel/head_64.S

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,16 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
185185
addq $(init_top_pgt - __START_KERNEL_map), %rax
186186
1:
187187

188+
/*
189+
* Create a mask of CR4 bits to preserve. Omit PGE in order to flush
190+
* global 1:1 translations from the TLBs.
191+
*
192+
* From the SDM:
193+
* "If CR4.PGE is changing from 0 to 1, there were no global TLB
194+
* entries before the execution; if CR4.PGE is changing from 1 to 0,
195+
* there will be no global TLB entries after the execution."
196+
*/
197+
movl $(X86_CR4_PAE | X86_CR4_LA57), %edx
188198
#ifdef CONFIG_X86_MCE
189199
/*
190200
* Preserve CR4.MCE if the kernel will enable #MC support.
@@ -193,20 +203,13 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
193203
* configured will crash the system regardless of the CR4.MCE value set
194204
* here.
195205
*/
196-
movq %cr4, %rcx
197-
andl $X86_CR4_MCE, %ecx
198-
#else
199-
movl $0, %ecx
206+
orl $X86_CR4_MCE, %edx
200207
#endif
208+
movq %cr4, %rcx
209+
andl %edx, %ecx
201210

202-
/* Enable PAE mode, PSE, PGE and LA57 */
203-
orl $(X86_CR4_PAE | X86_CR4_PSE | X86_CR4_PGE), %ecx
204-
#ifdef CONFIG_X86_5LEVEL
205-
testb $1, __pgtable_l5_enabled(%rip)
206-
jz 1f
207-
orl $X86_CR4_LA57, %ecx
208-
1:
209-
#endif
211+
/* Even if ignored in long mode, set PSE uniformly on all logical CPUs. */
212+
btsl $X86_CR4_PSE_BIT, %ecx
210213
movq %rcx, %cr4
211214

212215
/* Setup early boot stage 4-/5-level pagetables. */
@@ -223,14 +226,10 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
223226
movq %rax, %cr3
224227

225228
/*
226-
* Do a global TLB flush after the CR3 switch to make sure the TLB
227-
* entries from the identity mapping are flushed.
229+
* Set CR4.PGE to re-enable global translations.
228230
*/
229-
movq %cr4, %rcx
230-
movq %rcx, %rax
231-
xorq $X86_CR4_PGE, %rcx
231+
btsl $X86_CR4_PGE_BIT, %ecx
232232
movq %rcx, %cr4
233-
movq %rax, %cr4
234233

235234
/* Ensure I am executing from virtual addresses */
236235
movq $1f, %rax

0 commit comments

Comments
 (0)