kexec_va_control_page = (unsigned long)control_page;
kexec_pa_table_page = (unsigned long)__pa(image->arch.pgd);
+ /*
+ * The relocate_kernel assembly code sets CR4 to a subset of the bits
+ * which were set during kernel runtime, including only:
+ * - physical address extension (which is always set in kernel)
+ * - 5-level paging (if it's enabled)
+ * - Machine check exception on TDX guests
+ *
+ * Clearing MCE may not be allowed in TDX guests, but it *should* be
+ * cleared in the general case. Because of the conditional nature of
+ * that, pass the set of bits in from the kernel for relocate_kernel
+ * to do a simple 'andl' with them.
+ */
+ kexec_preserve_cr4_bits = X86_CR4_PAE | X86_CR4_LA57;
+ if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
+ kexec_preserve_cr4_bits |= X86_CR4_MCE;
+
if (image->type == KEXEC_TYPE_DEFAULT)
kexec_pa_swap_page = page_to_pfn(image->swap_page) << PAGE_SHIFT;
SYM_DATA_LOCAL(pa_backup_pages_map, .quad 0)
SYM_DATA(kexec_debug_8250_mmio32, .quad 0)
SYM_DATA(kexec_debug_8250_port, .word 0)
+SYM_DATA(kexec_preserve_cr4_bits, .long 0)
.balign 16
SYM_DATA_START_LOCAL(kexec_debug_gdt)
movq %rax, %cr0
/*
- * Set cr4 to a known state:
- * - physical address extension enabled
- * - 5-level paging, if it was enabled before
- * - Machine check exception on TDX guest, if it was enabled before.
- * Clearing MCE might not be allowed in TDX guests, depending on setup.
+ * Set CR4 to a known state, using the bitmask which was set in
+ * machine_kexec_prepare().
*
* Use R13 that contains the original CR4 value, read in relocate_kernel().
- * PAE is always set in the original CR4.
*/
- andl $(X86_CR4_PAE | X86_CR4_LA57), %r13d
- ALTERNATIVE "", __stringify(orl $X86_CR4_MCE, %r13d), X86_FEATURE_TDX_GUEST
+ andl kexec_preserve_cr4_bits(%rip), %r13d
movq %r13, %cr4
/* Flush the TLB (needed?) */