diff options
author | David Woodhouse <dwmw@amazon.co.uk> | 2025-03-26 14:16:01 +0000 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2025-04-10 12:17:13 +0200 |
commit | d358b45120cc8da9f10d8c1e8ec3559f72525147 (patch) | |
tree | c9c8a27bce4e93f11a3c45c3100c490732e97b77 | |
parent | a23be6ccd8b966ae2483bfc873720b2868ad63c3 (diff) |
x86/kexec: Add 8250 serial port output
If a serial port was configured for early_printk, use it for debug output
from the relocate_kernel exception handler too.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20250326142404.256980-2-dwmw2@infradead.org
-rw-r--r-- | arch/x86/include/asm/kexec.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/early_printk.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/relocate_kernel_64.S | 39 |
3 files changed, 40 insertions, 6 deletions
diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h index fb4537c58b54..9601094ac0ba 100644 --- a/arch/x86/include/asm/kexec.h +++ b/arch/x86/include/asm/kexec.h @@ -64,6 +64,7 @@ extern unsigned long kexec_pa_table_page; extern unsigned long kexec_pa_swap_page; extern gate_desc kexec_debug_idt[]; extern unsigned char kexec_debug_exc_vectors[]; +extern uint16_t kexec_debug_8250_port; #endif /* diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c index 611f27e3890c..acb7d05ab6af 100644 --- a/arch/x86/kernel/early_printk.c +++ b/arch/x86/kernel/early_printk.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/console.h> #include <linux/kernel.h> +#include <linux/kexec.h> #include <linux/init.h> #include <linux/string.h> #include <linux/screen_info.h> @@ -144,6 +145,11 @@ static __init void early_serial_hw_init(unsigned divisor) static_call(serial_out)(early_serial_base, DLL, divisor & 0xff); static_call(serial_out)(early_serial_base, DLH, (divisor >> 8) & 0xff); static_call(serial_out)(early_serial_base, LCR, c & ~DLAB); + +#if defined(CONFIG_KEXEC_CORE) && defined(CONFIG_X86_64) + if (static_call_query(serial_in) == io_serial_in) + kexec_debug_8250_port = early_serial_base; +#endif } #define DEFAULT_BAUD 9600 diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S index 29cb399a34d4..21011cd19c48 100644 --- a/arch/x86/kernel/relocate_kernel_64.S +++ b/arch/x86/kernel/relocate_kernel_64.S @@ -39,6 +39,7 @@ SYM_DATA(kexec_va_control_page, .quad 0) SYM_DATA(kexec_pa_table_page, .quad 0) SYM_DATA(kexec_pa_swap_page, .quad 0) SYM_DATA_LOCAL(pa_backup_pages_map, .quad 0) +SYM_DATA(kexec_debug_8250_port, .word 0) .balign 16 SYM_DATA_START_LOCAL(kexec_debug_gdt) @@ -380,24 +381,50 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages) SYM_CODE_END(swap_pages) /* - * Generic 'print character' routine (as yet unimplemented) + * Generic 'print character' routine * - %al: Character to be printed (may clobber %rax) * - %rdx: MMIO address or port. */ -SYM_CODE_START_LOCAL_NOALIGN(pr_char) +#define XMTRDY 0x20 + +#define TXR 0 /* Transmit register (WRITE) */ +#define LSR 5 /* Line Status */ + +SYM_CODE_START_LOCAL_NOALIGN(pr_char_8250) UNWIND_HINT_FUNC ANNOTATE_NOENDBR + addw $LSR, %dx + xchg %al, %ah +.Lxmtrdy_loop: + inb %dx, %al + testb $XMTRDY, %al + jnz .Lready + rep nop + jmp .Lxmtrdy_loop + +.Lready: + subw $LSR, %dx + xchg %al, %ah + outb %al, %dx +pr_char_null: + ANNOTATE_NOENDBR + ANNOTATE_UNRET_SAFE ret -SYM_CODE_END(pr_char) +SYM_CODE_END(pr_char_8250) /* * 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 +.macro pr_setup + leaq pr_char_8250(%rip), %rsi + movw kexec_debug_8250_port(%rip), %dx + testw %dx, %dx + jnz 1f + + leaq pr_char_null(%rip), %rsi +1: .endm /* Print the nybble in %bl, clobber %rax */ |