x86/kexec: Add 8250 MMIO serial port output

This supports the same 32-bit MMIO-mapped 8250 as the early_printk code.

It's not clear why the early_printk code supports this form and only this
form; the actual runtime 8250_pci doesn't seem to support it. But having
hacked up QEMU to expose such a device, early_printk does work with it,
and now so does the kexec debug code.

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-3-dwmw2@infradead.org
This commit is contained in:
David Woodhouse 2025-03-26 14:16:02 +00:00 committed by Ingo Molnar
parent d358b45120
commit 7516e7216b
4 changed files with 43 additions and 0 deletions

View File

@ -65,6 +65,7 @@ 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;
extern unsigned long kexec_debug_8250_mmio32;
#endif
/*

View File

@ -333,6 +333,9 @@ static __init void early_pci_serial_init(char *s)
/* WARNING! assuming the address is always in the first 4G */
early_serial_base =
(unsigned long)early_ioremap(bar0 & PCI_BASE_ADDRESS_MEM_MASK, 0x10);
#if defined(CONFIG_KEXEC_CORE) && defined(CONFIG_X86_64)
kexec_debug_8250_mmio32 = bar0 & PCI_BASE_ADDRESS_MEM_MASK;
#endif
write_pci_config(bus, slot, func, PCI_COMMAND,
cmdreg|PCI_COMMAND_MEMORY);
}

View File

@ -76,6 +76,19 @@ map_acpi_tables(struct x86_mapping_info *info, pgd_t *level4p)
static int map_acpi_tables(struct x86_mapping_info *info, pgd_t *level4p) { return 0; }
#endif
static int map_mmio_serial(struct x86_mapping_info *info, pgd_t *level4p)
{
unsigned long mstart, mend;
if (!kexec_debug_8250_mmio32)
return 0;
mstart = kexec_debug_8250_mmio32 & PAGE_MASK;
mend = (kexec_debug_8250_mmio32 + PAGE_SIZE + 23) & PAGE_MASK;
pr_info("Map PCI serial at %lx - %lx\n", mstart, mend);
return kernel_ident_mapping_init(info, level4p, mstart, mend);
}
#ifdef CONFIG_KEXEC_FILE
const struct kexec_file_ops * const kexec_file_loaders[] = {
&kexec_bzImage64_ops,
@ -285,6 +298,10 @@ static int init_pgtable(struct kimage *image, unsigned long control_page)
if (result)
return result;
result = map_mmio_serial(&info, image->arch.pgd);
if (result)
return result;
/*
* This must be last because the intermediate page table pages it
* allocates will not be control pages and may overlap the image.

View File

@ -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_mmio32, .quad 0)
SYM_DATA(kexec_debug_8250_port, .word 0)
.balign 16
@ -413,6 +414,22 @@ pr_char_null:
ret
SYM_CODE_END(pr_char_8250)
SYM_CODE_START_LOCAL_NOALIGN(pr_char_8250_mmio32)
UNWIND_HINT_FUNC
ANNOTATE_NOENDBR
.Lxmtrdy_loop_mmio:
movb (LSR*4)(%rdx), %ah
testb $XMTRDY, %ah
jnz .Lready_mmio
rep nop
jmp .Lxmtrdy_loop_mmio
.Lready_mmio:
movb %al, (%rdx)
ANNOTATE_UNRET_SAFE
ret
SYM_CODE_END(pr_char_8250_mmio32)
/*
* Load pr_char function pointer into %rsi and load %rdx with whatever
* that function wants to see there (typically port/MMIO address).
@ -423,6 +440,11 @@ SYM_CODE_END(pr_char_8250)
testw %dx, %dx
jnz 1f
leaq pr_char_8250_mmio32(%rip), %rsi
movq kexec_debug_8250_mmio32(%rip), %rdx
testq %rdx, %rdx
jnz 1f
leaq pr_char_null(%rip), %rsi
1:
.endm