]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
x86/kexec: Add 8250 serial port output
authorDavid Woodhouse <dwmw@amazon.co.uk>
Sat, 23 Nov 2024 09:23:24 +0000 (09:23 +0000)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Wed, 15 Jan 2025 12:36:08 +0000 (12:36 +0000)
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>
arch/x86/include/asm/kexec.h
arch/x86/kernel/early_printk.c
arch/x86/kernel/relocate_kernel_64.S

index ec7636f4f86a7d795203d0a98630815572984fdb..8cbdb6fd10c21089c472d8576249d26e4f927269 100644 (file)
@@ -63,6 +63,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
 
 /*
index 44f937015e1e25bf41532eb7e1031a6be32a6523..bf06866ee90ac5c700d10e69d68f2356e337b1ef 100644 (file)
@@ -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>
@@ -141,6 +142,11 @@ static __init void early_serial_hw_init(unsigned divisor)
        serial_out(early_serial_base, DLL, divisor & 0xff);
        serial_out(early_serial_base, DLH, (divisor >> 8) & 0xff);
        serial_out(early_serial_base, LCR, c & ~DLAB);
+
+#ifdef CONFIG_KEXEC_DEBUG
+       if (serial_in == io_serial_in)
+               kexec_debug_8250_port = early_serial_base;
+#endif
 }
 
 #define DEFAULT_BAUD 9600
index 020f0f6e3e2ea97b7e7487b04a97dfb8af5b1d53..9781a28c246aac9e25e2c0e28d230b4153870900 100644 (file)
@@ -38,6 +38,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)
 
 #ifdef CONFIG_KEXEC_DEBUG
        .balign 16
@@ -385,24 +386,50 @@ SYM_CODE_END(swap_pages)
 
 #ifdef CONFIG_KEXEC_DEBUG
 /*
- * 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 */