Commit 7516e721 authored by David Woodhouse's avatar David Woodhouse Committed by Ingo Molnar
Browse files

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: default avatarDavid Woodhouse <dwmw@amazon.co.uk>
Signed-off-by: default avatarIngo 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
parent d358b451
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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

/*
+3 −0
Original line number Diff line number Diff line
@@ -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);
	}
+17 −0
Original line number Diff line number Diff line
@@ -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.
+22 −0
Original line number Diff line number Diff line
@@ -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