[tip: x86/boot] x86/kexec: Add relocate_kernel() debugging support: Dump registers on exception

From: tip-bot2 for David Woodhouse
Date: Thu Mar 13 2025 - 06:42:27 EST


The following commit has been merged into the x86/boot branch of tip:

Commit-ID: d181cfc0609bcbbc1fb70dbd73f7aa9025c11b6b
Gitweb: https://git.kernel.org/tip/d181cfc0609bcbbc1fb70dbd73f7aa9025c11b6b
Author: David Woodhouse <dwmw@xxxxxxxxxxxx>
AuthorDate: Wed, 12 Mar 2025 14:34:15
Committer: Ingo Molnar <mingo@xxxxxxxxxx>
CommitterDate: Thu, 13 Mar 2025 11:23:39 +01:00

x86/kexec: Add relocate_kernel() debugging support: Dump registers on exception

The actual serial output function is a no-op for now.

Signed-off-by: David Woodhouse <dwmw@xxxxxxxxxxxx>
Signed-off-by: Ingo Molnar <mingo@xxxxxxxxxx>
Cc: Andy Lutomirski <luto@xxxxxxxxxx>
Cc: Brian Gerst <brgerst@xxxxxxxxx>
Cc: H. Peter Anvin <hpa@xxxxxxxxx>
Cc: Kees Cook <keescook@xxxxxxxxxxxx>
Cc: Ard Biesheuvel <ardb@xxxxxxxxxx>
Cc: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
Link: https://lore.kernel.org/r/20250312144257.2348250-4-dwmw2@xxxxxxxxxxxxx
---
arch/x86/kernel/relocate_kernel_64.S | 101 +++++++++++++++++++++++++-
1 file changed, 98 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S
index bce0cb7..e0af37e 100644
--- a/arch/x86/kernel/relocate_kernel_64.S
+++ b/arch/x86/kernel/relocate_kernel_64.S
@@ -379,6 +379,69 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
int3
SYM_CODE_END(swap_pages)

+/*
+ * Generic 'print character' routine (as yet unimplemented)
+ * - %al: Character to be printed (may clobber %rax)
+ * - %rdx: MMIO address or port.
+ */
+SYM_CODE_START_LOCAL_NOALIGN(pr_char)
+ UNWIND_HINT_FUNC
+ ANNOTATE_NOENDBR
+ ANNOTATE_UNRET_SAFE
+ ret
+SYM_CODE_END(pr_char)
+
+/*
+ * Load pr_char function pointer into %rsi and load %rdx with whatever
+ * that function wants to see there (typically port/MMIO address).
+ */
+.macro pr_setup
+ /* No output; pr_char just returns */
+ leaq pr_char(%rip), %rsi
+.endm
+
+/* Print the nybble in %bl, clobber %rax */
+SYM_CODE_START_LOCAL_NOALIGN(pr_nybble)
+ UNWIND_HINT_FUNC
+ movb %bl, %al
+ nop
+ andb $0x0f, %al
+ addb $0x30, %al
+ cmpb $0x3a, %al
+ jb 1f
+ addb $('a' - '0' - 10), %al
+ ANNOTATE_RETPOLINE_SAFE
+1: jmp *%rsi
+SYM_CODE_END(pr_nybble)
+
+SYM_CODE_START_LOCAL_NOALIGN(pr_qword)
+ UNWIND_HINT_FUNC
+ movq $16, %rcx
+1: rolq $4, %rbx
+ call pr_nybble
+ loop 1b
+ movb $'\n', %al
+ ANNOTATE_RETPOLINE_SAFE
+ jmp *%rsi
+SYM_CODE_END(pr_qword)
+
+.macro print_reg a, b, c, d, r
+ movb $\a, %al
+ ANNOTATE_RETPOLINE_SAFE
+ call *%rsi
+ movb $\b, %al
+ ANNOTATE_RETPOLINE_SAFE
+ call *%rsi
+ movb $\c, %al
+ ANNOTATE_RETPOLINE_SAFE
+ call *%rsi
+ movb $\d, %al
+ ANNOTATE_RETPOLINE_SAFE
+ call *%rsi
+ movq \r, %rbx
+ call pr_qword
+.endm
+
SYM_CODE_START_NOALIGN(kexec_debug_exc_vectors)
/* Each of these is 6 bytes. */
.macro vec_err exc
@@ -419,11 +482,43 @@ SYM_CODE_END(kexec_debug_exc_vectors)

SYM_CODE_START_LOCAL_NOALIGN(exc_handler)
pushq %rax
+ pushq %rbx
+ pushq %rcx
pushq %rdx
- movw $0x3f8, %dx
- movb $'A', %al
- outb %al, %dx
+ pushq %rsi
+
+ /* Set up %rdx/%rsi for debug output */
+ pr_setup
+
+ /* rip and exception info */
+ print_reg 'E', 'x', 'c', ':', 0x28(%rsp)
+ print_reg 'E', 'r', 'r', ':', 0x30(%rsp)
+ print_reg 'r', 'i', 'p', ':', 0x38(%rsp)
+ print_reg 'r', 's', 'p', ':', 0x50(%rsp)
+
+ /* We spilled these to the stack */
+ print_reg 'r', 'a', 'x', ':', 0x20(%rsp)
+ print_reg 'r', 'b', 'x', ':', 0x18(%rsp)
+ print_reg 'r', 'c', 'x', ':', 0x10(%rsp)
+ print_reg 'r', 'd', 'x', ':', 0x08(%rsp)
+
+ /* Other registers */
+ print_reg 'r', 's', 'i', ':', (%rsp)
+ print_reg 'r', 'd', 'i', ':', %rdi
+ print_reg 'r', '8', ' ', ':', %r8
+ print_reg 'r', '9', ' ', ':', %r9
+ print_reg 'r', '1', '0', ':', %r10
+ print_reg 'r', '1', '1', ':', %r11
+ print_reg 'r', '1', '2', ':', %r12
+ print_reg 'r', '1', '3', ':', %r13
+ print_reg 'r', '1', '4', ':', %r14
+ print_reg 'r', '1', '5', ':', %r15
+ print_reg 'c', 'r', '2', ':', %cr2
+
+ popq %rsi
popq %rdx
+ popq %rcx
+ popq %rbx
popq %rax

/* Only return from int3 */