* [PATCH v6 1/7] x86/kexec: Add CONFIG_KEXEC_DEBUG option
2025-01-15 19:09 [PATCH v6 0/7] x86/kexec: Add exception handling for relocate_kernel David Woodhouse
@ 2025-01-15 19:09 ` David Woodhouse
2025-01-15 19:09 ` [PATCH v6 2/7] x86/kexec: Debugging support: load a GDT David Woodhouse
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: David Woodhouse @ 2025-01-15 19:09 UTC (permalink / raw)
To: kexec
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H . Peter Anvin, David Woodhouse, Kirill A . Shutemov, Kai Huang,
Nikolay Borisov, linux-kernel, Simon Horman, Dave Young,
Peter Zijlstra, jpoimboe, bsz
From: David Woodhouse <dwmw@amazon.co.uk>
This does nothing yet. Support for x86_64 will follow in subsequent
commits, and an Arm64 version is also being worked on.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
arch/x86/Kconfig.debug | 1 +
kernel/Kconfig.kexec | 11 +++++++++++
2 files changed, 12 insertions(+)
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 74777a97e394..c54cbd36c710 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -13,6 +13,7 @@ config X86_VERBOSE_BOOTUP
config EARLY_PRINTK
bool "Early printk" if EXPERT
+ select HAVE_KEXEC_DEBUG if X86_64
default y
help
Write kernel log output directly into the VGA buffer or to a serial
diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec
index 4d111f871951..a65b49c083c9 100644
--- a/kernel/Kconfig.kexec
+++ b/kernel/Kconfig.kexec
@@ -17,6 +17,9 @@ config KEXEC_ELF
config HAVE_IMA_KEXEC
bool
+config HAVE_KEXEC_DEBUG
+ bool
+
config KEXEC
bool "Enable kexec system call"
depends on ARCH_SUPPORTS_KEXEC
@@ -95,6 +98,14 @@ config KEXEC_JUMP
Jump between original kernel and kexeced kernel and invoke
code in physical address mode via KEXEC
+config KEXEC_DEBUG
+ bool "Debug kexec transition"
+ depends on HAVE_KEXEC_DEBUG
+ help
+ Faults during kexec can be difficult to debug. This installs exception
+ handlers and attempts to report faults. On x86_64 this would use the
+ serial port configured for earlyprintk.
+
config CRASH_DUMP
bool "kernel crash dumps"
default ARCH_DEFAULT_CRASH_DUMP
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v6 2/7] x86/kexec: Debugging support: load a GDT
2025-01-15 19:09 [PATCH v6 0/7] x86/kexec: Add exception handling for relocate_kernel David Woodhouse
2025-01-15 19:09 ` [PATCH v6 1/7] x86/kexec: Add CONFIG_KEXEC_DEBUG option David Woodhouse
@ 2025-01-15 19:09 ` David Woodhouse
2025-02-23 9:53 ` Ingo Molnar
2025-01-15 19:09 ` [PATCH v6 3/7] x86/kexec: Debugging support: Load an IDT and basic exception entry points David Woodhouse
` (4 subsequent siblings)
6 siblings, 1 reply; 10+ messages in thread
From: David Woodhouse @ 2025-01-15 19:09 UTC (permalink / raw)
To: kexec
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H . Peter Anvin, David Woodhouse, Kirill A . Shutemov, Kai Huang,
Nikolay Borisov, linux-kernel, Simon Horman, Dave Young,
Peter Zijlstra, jpoimboe, bsz
From: David Woodhouse <dwmw@amazon.co.uk>
There are some failure modes which lead to triple-faults in the
relocate_kernel function, which is fairly much undebuggable for normal
mortals.
Adding a GDT in the relocate_kernel environment is step 1 towards being
able to catch faults and do something more useful.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
arch/x86/kernel/relocate_kernel_64.S | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S
index af2cd06ff318..c62f03808f18 100644
--- a/arch/x86/kernel/relocate_kernel_64.S
+++ b/arch/x86/kernel/relocate_kernel_64.S
@@ -39,6 +39,18 @@ 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)
+#ifdef CONFIG_KEXEC_DEBUG
+ .balign 16
+SYM_DATA_START_LOCAL(kexec_debug_gdt)
+ .word kexec_debug_gdt_end - kexec_debug_gdt - 1
+ .long 0
+ .word 0
+ .quad 0x00cf9a000000ffff /* __KERNEL32_CS */
+ .quad 0x00af9a000000ffff /* __KERNEL_CS */
+ .quad 0x00cf92000000ffff /* __KERNEL_DS */
+SYM_DATA_END_LABEL(kexec_debug_gdt, SYM_L_LOCAL, kexec_debug_gdt_end)
+#endif /* CONFIG_KEXEC_DEBUG */
+
.section .text..relocate_kernel,"ax";
.code64
SYM_CODE_START_NOALIGN(relocate_kernel)
@@ -115,6 +127,21 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
/* store the start address on the stack */
pushq %rdx
+#ifdef CONFIG_KEXEC_DEBUG
+ /* Create a GDTR (16 bits limit, 64 bits addr) on stack */
+ leaq kexec_debug_gdt(%rip), %rax
+ pushq %rax
+ pushw (%rax)
+
+ /* Load the GDT, put the stack back */
+ lgdt (%rsp)
+ addq $10, %rsp
+
+ /* Test that we can load segments */
+ movq %ds, %rax
+ movq %rax, %ds
+#endif /* CONFIG_KEXEC_DEBUG */
+
/*
* Clear X86_CR4_CET (if it was set) such that we can clear CR0_WP
* below.
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v6 2/7] x86/kexec: Debugging support: load a GDT
2025-01-15 19:09 ` [PATCH v6 2/7] x86/kexec: Debugging support: load a GDT David Woodhouse
@ 2025-02-23 9:53 ` Ingo Molnar
2025-02-23 10:53 ` David Woodhouse
0 siblings, 1 reply; 10+ messages in thread
From: Ingo Molnar @ 2025-02-23 9:53 UTC (permalink / raw)
To: David Woodhouse
Cc: kexec, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
x86, H . Peter Anvin, David Woodhouse, Kirill A . Shutemov,
Kai Huang, Nikolay Borisov, linux-kernel, Simon Horman,
Dave Young, Peter Zijlstra, jpoimboe, bsz
* David Woodhouse <dwmw2@infradead.org> wrote:
> From: David Woodhouse <dwmw@amazon.co.uk>
>
> There are some failure modes which lead to triple-faults in the
> relocate_kernel function, which is fairly much undebuggable for normal
> mortals.
>
> Adding a GDT in the relocate_kernel environment is step 1 towards being
> able to catch faults and do something more useful.
>
> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
> ---
> arch/x86/kernel/relocate_kernel_64.S | 27 +++++++++++++++++++++++++++
> 1 file changed, 27 insertions(+)
>
> diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S
> index af2cd06ff318..c62f03808f18 100644
> --- a/arch/x86/kernel/relocate_kernel_64.S
> +++ b/arch/x86/kernel/relocate_kernel_64.S
> @@ -39,6 +39,18 @@ 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)
>
> +#ifdef CONFIG_KEXEC_DEBUG
> + .balign 16
> +SYM_DATA_START_LOCAL(kexec_debug_gdt)
> + .word kexec_debug_gdt_end - kexec_debug_gdt - 1
> + .long 0
> + .word 0
> + .quad 0x00cf9a000000ffff /* __KERNEL32_CS */
> + .quad 0x00af9a000000ffff /* __KERNEL_CS */
> + .quad 0x00cf92000000ffff /* __KERNEL_DS */
> +SYM_DATA_END_LABEL(kexec_debug_gdt, SYM_L_LOCAL, kexec_debug_gdt_end)
> +#endif /* CONFIG_KEXEC_DEBUG */
Yeah, so is there any reason (other than paranoia) why the early-early
GDT and IDT shouldn't be unconditional? There's many ways for such an
approach to bitrot, it's much better to not hide it behind a
default-disabled debug option...
Some of the other bits, like the hard-coded serial debugging
assumptions, probably need to be behind the debug option - but much of
the new debug mechanism looks safe and generic and can be always-on,
IMHO.
This would also throw regressions back into the face of whoever manages
to introduce them, ideally. ;-)
Thanks,
Ingo
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v6 2/7] x86/kexec: Debugging support: load a GDT
2025-02-23 9:53 ` Ingo Molnar
@ 2025-02-23 10:53 ` David Woodhouse
0 siblings, 0 replies; 10+ messages in thread
From: David Woodhouse @ 2025-02-23 10:53 UTC (permalink / raw)
To: Ingo Molnar
Cc: kexec, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
x86, H . Peter Anvin, David Woodhouse, Kirill A . Shutemov,
Kai Huang, Nikolay Borisov, linux-kernel, Simon Horman,
Dave Young, Peter Zijlstra, jpoimboe, bsz
On 23 February 2025 09:53:07 GMT, Ingo Molnar <mingo@kernel.org> wrote:
>
>* David Woodhouse <dwmw2@infradead.org> wrote:
>
>> From: David Woodhouse <dwmw@amazon.co.uk>
>>
>> There are some failure modes which lead to triple-faults in the
>> relocate_kernel function, which is fairly much undebuggable for normal
>> mortals.
>>
>> Adding a GDT in the relocate_kernel environment is step 1 towards being
>> able to catch faults and do something more useful.
>>
>> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
>> ---
>> arch/x86/kernel/relocate_kernel_64.S | 27 +++++++++++++++++++++++++++
>> 1 file changed, 27 insertions(+)
>>
>> diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S
>> index af2cd06ff318..c62f03808f18 100644
>> --- a/arch/x86/kernel/relocate_kernel_64.S
>> +++ b/arch/x86/kernel/relocate_kernel_64.S
>> @@ -39,6 +39,18 @@ 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)
>>
>> +#ifdef CONFIG_KEXEC_DEBUG
>> + .balign 16
>> +SYM_DATA_START_LOCAL(kexec_debug_gdt)
>> + .word kexec_debug_gdt_end - kexec_debug_gdt - 1
>> + .long 0
>> + .word 0
>> + .quad 0x00cf9a000000ffff /* __KERNEL32_CS */
>> + .quad 0x00af9a000000ffff /* __KERNEL_CS */
>> + .quad 0x00cf92000000ffff /* __KERNEL_DS */
>> +SYM_DATA_END_LABEL(kexec_debug_gdt, SYM_L_LOCAL, kexec_debug_gdt_end)
>> +#endif /* CONFIG_KEXEC_DEBUG */
>
>Yeah, so is there any reason (other than paranoia) why the early-early
>GDT and IDT shouldn't be unconditional? There's many ways for such an
>approach to bitrot, it's much better to not hide it behind a
>default-disabled debug option...
>
>Some of the other bits, like the hard-coded serial debugging
>assumptions, probably need to be behind the debug option - but much of
>the new debug mechanism looks safe and generic and can be always-on,
>IMHO.
>
>This would also throw regressions back into the face of whoever manages
>to introduce them, ideally. ;-)
>
>Thanks,
>
> Ingo
Makes sense to me. I was just trying to be as unobtrusive as possible. In a test branch where I was trying to fix up the objtool vs. CFI pain, I did move the IDT/GDT setup entirely into the ASM code and remove the C code which clears them (before the call into relocate_kernel() which might now trap if we remove the __nocfi hack). I never did get objtool to tolerate both clang and GCC builds though.
I think even the serial output (tied as it is to earlyprintk setup) could reasonably be enabled by default too.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v6 3/7] x86/kexec: Debugging support: Load an IDT and basic exception entry points
2025-01-15 19:09 [PATCH v6 0/7] x86/kexec: Add exception handling for relocate_kernel David Woodhouse
2025-01-15 19:09 ` [PATCH v6 1/7] x86/kexec: Add CONFIG_KEXEC_DEBUG option David Woodhouse
2025-01-15 19:09 ` [PATCH v6 2/7] x86/kexec: Debugging support: load a GDT David Woodhouse
@ 2025-01-15 19:09 ` David Woodhouse
2025-01-15 19:09 ` [PATCH v6 4/7] x86/kexec: Debugging support: Dump registers on exception David Woodhouse
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: David Woodhouse @ 2025-01-15 19:09 UTC (permalink / raw)
To: kexec
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H . Peter Anvin, David Woodhouse, Kirill A . Shutemov, Kai Huang,
Nikolay Borisov, linux-kernel, Simon Horman, Dave Young,
Peter Zijlstra, jpoimboe, bsz
From: David Woodhouse <dwmw@amazon.co.uk>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
arch/x86/include/asm/kexec.h | 5 ++
arch/x86/kernel/machine_kexec_64.c | 23 ++++++++
arch/x86/kernel/relocate_kernel_64.S | 82 ++++++++++++++++++++++++++++
3 files changed, 110 insertions(+)
diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h
index 8ad187462b68..ec7636f4f86a 100644
--- a/arch/x86/include/asm/kexec.h
+++ b/arch/x86/include/asm/kexec.h
@@ -8,6 +8,9 @@
# define PA_PGD 2
# define PA_SWAP_PAGE 3
# define PAGES_NR 4
+#else
+/* Size of each exception handler referenced by the IDT */
+# define KEXEC_DEBUG_EXC_HANDLER_SIZE 6 /* pushi, pushi, 2-byte jmp */
#endif
# define KEXEC_CONTROL_PAGE_SIZE 4096
@@ -58,6 +61,8 @@ struct kimage;
extern unsigned long kexec_va_control_page;
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[];
#endif
/*
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
index a68f5a0a9f37..535438375568 100644
--- a/arch/x86/kernel/machine_kexec_64.c
+++ b/arch/x86/kernel/machine_kexec_64.c
@@ -304,6 +304,26 @@ static void load_segments(void)
);
}
+static void prepare_debug_idt(unsigned long control_page, unsigned long vec_ofs)
+{
+#ifdef CONFIG_KEXEC_DEBUG
+ gate_desc idtentry = { 0 };
+ int i;
+
+ idtentry.bits.p = 1;
+ idtentry.bits.type = GATE_TRAP;
+ idtentry.segment = __KERNEL_CS;
+ idtentry.offset_low = (control_page & 0xFFFF) + vec_ofs;
+ idtentry.offset_middle = (control_page >> 16) & 0xFFFF;
+ idtentry.offset_high = control_page >> 32;
+
+ for (i = 0; i < 16; i++) {
+ kexec_debug_idt[i] = idtentry;
+ idtentry.offset_low += KEXEC_DEBUG_EXC_HANDLER_SIZE;
+ }
+#endif
+}
+
int machine_kexec_prepare(struct kimage *image)
{
void *control_page = page_address(image->control_code_page);
@@ -321,6 +341,9 @@ int machine_kexec_prepare(struct kimage *image)
if (image->type == KEXEC_TYPE_DEFAULT)
kexec_pa_swap_page = page_to_pfn(image->swap_page) << PAGE_SHIFT;
+ prepare_debug_idt((unsigned long)__pa(control_page),
+ (unsigned long)kexec_debug_exc_vectors - reloc_start);
+
__memcpy(control_page, __relocate_kernel_start, reloc_end - reloc_start);
set_memory_rox((unsigned long)control_page, 1);
diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S
index c62f03808f18..f5b134a81827 100644
--- a/arch/x86/kernel/relocate_kernel_64.S
+++ b/arch/x86/kernel/relocate_kernel_64.S
@@ -49,6 +49,12 @@ SYM_DATA_START_LOCAL(kexec_debug_gdt)
.quad 0x00af9a000000ffff /* __KERNEL_CS */
.quad 0x00cf92000000ffff /* __KERNEL_DS */
SYM_DATA_END_LABEL(kexec_debug_gdt, SYM_L_LOCAL, kexec_debug_gdt_end)
+
+ .balign 8
+SYM_DATA_START(kexec_debug_idt)
+ .skip 0x100, 0x00
+SYM_DATA_END(kexec_debug_idt)
+
#endif /* CONFIG_KEXEC_DEBUG */
.section .text..relocate_kernel,"ax";
@@ -113,6 +119,11 @@ SYM_CODE_START_NOALIGN(relocate_kernel)
jmp *%rsi
SYM_CODE_END(relocate_kernel)
+#ifdef DEBUG
+ UNWIND_HINT_UNDEFINED
+ .balign 0x100 /* relocate_kernel will be overwritten with an IDT */
+#endif
+
SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
UNWIND_HINT_END_OF_STACK
/*
@@ -140,6 +151,15 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
/* Test that we can load segments */
movq %ds, %rax
movq %rax, %ds
+
+ /* Now an IDTR on the stack to load the IDT the kernel created */
+ leaq kexec_debug_idt(%rip), %rsi
+ pushq %rsi
+ pushw $0xff
+ lidt (%rsp)
+ addq $10, %rsp
+
+ //int3
#endif /* CONFIG_KEXEC_DEBUG */
/*
@@ -367,3 +387,65 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
ret
int3
SYM_CODE_END(swap_pages)
+
+#ifdef CONFIG_KEXEC_DEBUG
+SYM_CODE_START_NOALIGN(kexec_debug_exc_vectors)
+ /* Each of these is 6 bytes. */
+.macro vec_err exc
+ UNWIND_HINT_ENTRY
+ . = kexec_debug_exc_vectors + (\exc * KEXEC_DEBUG_EXC_HANDLER_SIZE)
+ nop
+ nop
+ pushq $\exc
+ jmp exc_handler
+.endm
+
+.macro vec_noerr exc
+ UNWIND_HINT_ENTRY
+ . = kexec_debug_exc_vectors + (\exc * KEXEC_DEBUG_EXC_HANDLER_SIZE)
+ pushq $0
+ pushq $\exc
+ jmp exc_handler
+.endm
+
+ ANNOTATE_NOENDBR
+ vec_noerr 0 // #DE
+ vec_noerr 1 // #DB
+ vec_noerr 2 // #NMI
+ vec_noerr 3 // #BP
+ vec_noerr 4 // #OF
+ vec_noerr 5 // #BR
+ vec_noerr 6 // #UD
+ vec_noerr 7 // #NM
+ vec_err 8 // #DF
+ vec_noerr 9
+ vec_err 10 // #TS
+ vec_err 11 // #NP
+ vec_err 12 // #SS
+ vec_err 13 // #GP
+ vec_err 14 // #PF
+ vec_noerr 15
+SYM_CODE_END(kexec_debug_exc_vectors)
+
+SYM_CODE_START_LOCAL_NOALIGN(exc_handler)
+ pushq %rax
+ pushq %rdx
+ movw $0x3f8, %dx
+ movb $'A', %al
+ outb %al, %dx
+ popq %rdx
+ popq %rax
+
+ /* Only return from int3 */
+ cmpq $3, (%rsp)
+ jne .Ldie
+
+ addq $16, %rsp
+ iretq
+
+.Ldie:
+ hlt
+ jmp .Ldie
+
+SYM_CODE_END(exc_handler)
+#endif /* CONFIG_KEXEC_DEBUG */
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v6 4/7] x86/kexec: Debugging support: Dump registers on exception
2025-01-15 19:09 [PATCH v6 0/7] x86/kexec: Add exception handling for relocate_kernel David Woodhouse
` (2 preceding siblings ...)
2025-01-15 19:09 ` [PATCH v6 3/7] x86/kexec: Debugging support: Load an IDT and basic exception entry points David Woodhouse
@ 2025-01-15 19:09 ` David Woodhouse
2025-01-15 19:09 ` [PATCH v6 5/7] x86/kexec: Add 8250 serial port output David Woodhouse
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: David Woodhouse @ 2025-01-15 19:09 UTC (permalink / raw)
To: kexec
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H . Peter Anvin, David Woodhouse, Kirill A . Shutemov, Kai Huang,
Nikolay Borisov, linux-kernel, Simon Horman, Dave Young,
Peter Zijlstra, jpoimboe, bsz
From: David Woodhouse <dwmw@amazon.co.uk>
The actual serial output function is a no-op for now.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
arch/x86/kernel/relocate_kernel_64.S | 106 +++++++++++++++++++++++++--
1 file changed, 98 insertions(+), 8 deletions(-)
diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S
index f5b134a81827..020f0f6e3e2e 100644
--- a/arch/x86/kernel/relocate_kernel_64.S
+++ b/arch/x86/kernel/relocate_kernel_64.S
@@ -119,11 +119,6 @@ SYM_CODE_START_NOALIGN(relocate_kernel)
jmp *%rsi
SYM_CODE_END(relocate_kernel)
-#ifdef DEBUG
- UNWIND_HINT_UNDEFINED
- .balign 0x100 /* relocate_kernel will be overwritten with an IDT */
-#endif
-
SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
UNWIND_HINT_END_OF_STACK
/*
@@ -389,6 +384,69 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
SYM_CODE_END(swap_pages)
#ifdef CONFIG_KEXEC_DEBUG
+/*
+ * 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
@@ -429,11 +487,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 */
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v6 5/7] x86/kexec: Add 8250 serial port output
2025-01-15 19:09 [PATCH v6 0/7] x86/kexec: Add exception handling for relocate_kernel David Woodhouse
` (3 preceding siblings ...)
2025-01-15 19:09 ` [PATCH v6 4/7] x86/kexec: Debugging support: Dump registers on exception David Woodhouse
@ 2025-01-15 19:09 ` David Woodhouse
2025-01-15 19:09 ` [PATCH v6 6/7] x86/kexec: Add 8250 MMIO " David Woodhouse
2025-01-15 19:09 ` [PATCH v6 7/7] [DO NOT MERGE] x86/kexec: Add int3 in kexec path for testing David Woodhouse
6 siblings, 0 replies; 10+ messages in thread
From: David Woodhouse @ 2025-01-15 19:09 UTC (permalink / raw)
To: kexec
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H . Peter Anvin, David Woodhouse, Kirill A . Shutemov, Kai Huang,
Nikolay Borisov, linux-kernel, Simon Horman, Dave Young,
Peter Zijlstra, jpoimboe, bsz
From: David Woodhouse <dwmw@amazon.co.uk>
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 | 1 +
arch/x86/kernel/early_printk.c | 6 +++++
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 ec7636f4f86a..8cbdb6fd10c2 100644
--- a/arch/x86/include/asm/kexec.h
+++ b/arch/x86/include/asm/kexec.h
@@ -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
/*
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index 44f937015e1e..bf06866ee90a 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>
@@ -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
diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S
index 020f0f6e3e2e..9781a28c246a 100644
--- a/arch/x86/kernel/relocate_kernel_64.S
+++ b/arch/x86/kernel/relocate_kernel_64.S
@@ -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 */
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v6 6/7] x86/kexec: Add 8250 MMIO serial port output
2025-01-15 19:09 [PATCH v6 0/7] x86/kexec: Add exception handling for relocate_kernel David Woodhouse
` (4 preceding siblings ...)
2025-01-15 19:09 ` [PATCH v6 5/7] x86/kexec: Add 8250 serial port output David Woodhouse
@ 2025-01-15 19:09 ` David Woodhouse
2025-01-15 19:09 ` [PATCH v6 7/7] [DO NOT MERGE] x86/kexec: Add int3 in kexec path for testing David Woodhouse
6 siblings, 0 replies; 10+ messages in thread
From: David Woodhouse @ 2025-01-15 19:09 UTC (permalink / raw)
To: kexec
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H . Peter Anvin, David Woodhouse, Kirill A . Shutemov, Kai Huang,
Nikolay Borisov, linux-kernel, Simon Horman, Dave Young,
Peter Zijlstra, jpoimboe, bsz
From: David Woodhouse <dwmw@amazon.co.uk>
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>
---
arch/x86/include/asm/kexec.h | 1 +
arch/x86/kernel/early_printk.c | 3 +++
arch/x86/kernel/machine_kexec_64.c | 22 ++++++++++++++++++++++
arch/x86/kernel/relocate_kernel_64.S | 22 ++++++++++++++++++++++
4 files changed, 48 insertions(+)
diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h
index 8cbdb6fd10c2..5081d0b9e290 100644
--- a/arch/x86/include/asm/kexec.h
+++ b/arch/x86/include/asm/kexec.h
@@ -64,6 +64,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
/*
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index bf06866ee90a..14f548e095c9 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -296,6 +296,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);
+#ifdef CONFIG_KEXEC_DEBUG
+ kexec_debug_8250_mmio32 = bar0 & PCI_BASE_ADDRESS_MEM_MASK;
+#endif
write_pci_config(bus, slot, func, PCI_COMMAND,
cmdreg|PCI_COMMAND_MEMORY);
}
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
index 535438375568..d47ca1a06a4d 100644
--- a/arch/x86/kernel/machine_kexec_64.c
+++ b/arch/x86/kernel/machine_kexec_64.c
@@ -76,6 +76,24 @@ 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
+#ifdef CONFIG_KEXEC_DEBUG
+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);
+}
+#else
+static int map_mmio_serial(struct x86_mapping_info *info, pgd_t *level4p) { return 0; }
+#endif
+
+
#ifdef CONFIG_KEXEC_FILE
const struct kexec_file_ops * const kexec_file_loaders[] = {
&kexec_bzImage64_ops,
@@ -285,6 +303,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.
diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S
index 9781a28c246a..493b378713e5 100644
--- a/arch/x86/kernel/relocate_kernel_64.S
+++ b/arch/x86/kernel/relocate_kernel_64.S
@@ -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_mmio32, .quad 0)
SYM_DATA(kexec_debug_8250_port, .word 0)
#ifdef CONFIG_KEXEC_DEBUG
@@ -418,6 +419,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).
@@ -428,6 +445,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
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v6 7/7] [DO NOT MERGE] x86/kexec: Add int3 in kexec path for testing
2025-01-15 19:09 [PATCH v6 0/7] x86/kexec: Add exception handling for relocate_kernel David Woodhouse
` (5 preceding siblings ...)
2025-01-15 19:09 ` [PATCH v6 6/7] x86/kexec: Add 8250 MMIO " David Woodhouse
@ 2025-01-15 19:09 ` David Woodhouse
6 siblings, 0 replies; 10+ messages in thread
From: David Woodhouse @ 2025-01-15 19:09 UTC (permalink / raw)
To: kexec
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H . Peter Anvin, David Woodhouse, Kirill A . Shutemov, Kai Huang,
Nikolay Borisov, linux-kernel, Simon Horman, Dave Young,
Peter Zijlstra, jpoimboe, bsz
From: David Woodhouse <dwmw@amazon.co.uk>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
arch/x86/kernel/relocate_kernel_64.S | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S
index 493b378713e5..e4253102b234 100644
--- a/arch/x86/kernel/relocate_kernel_64.S
+++ b/arch/x86/kernel/relocate_kernel_64.S
@@ -156,7 +156,7 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
lidt (%rsp)
addq $10, %rsp
- //int3
+ int3
#endif /* CONFIG_KEXEC_DEBUG */
/*
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread