[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH 3/3] xen/ppc: Implement a basic exception handler
On 9/29/23 4:48 AM, Andrew Cooper wrote: > On 29/09/2023 12:19 am, Shawn Anastasio wrote: >> Implement a basic exception handler that dumps the CPU state to the >> console, as well as the code required to set the correct exception >> vector table's base address in setup.c. >> >> Signed-off-by: Shawn Anastasio <sanastasio@xxxxxxxxxxxxxxxxxxxxx> >> --- >> xen/arch/ppc/include/asm/processor.h | 31 +++++++ >> xen/arch/ppc/ppc64/Makefile | 2 + >> xen/arch/ppc/ppc64/asm-offsets.c | 1 + >> xen/arch/ppc/ppc64/exceptions-asm.S | 122 +++++++++++++++++++++++++++ >> xen/arch/ppc/ppc64/exceptions.c | 102 ++++++++++++++++++++++ >> xen/arch/ppc/setup.c | 11 +++ >> 6 files changed, 269 insertions(+) >> create mode 100644 xen/arch/ppc/ppc64/exceptions-asm.S >> create mode 100644 xen/arch/ppc/ppc64/exceptions.c >> >> diff --git a/xen/arch/ppc/include/asm/processor.h >> b/xen/arch/ppc/include/asm/processor.h >> index d3dd943c20..a01b62b8a4 100644 >> --- a/xen/arch/ppc/include/asm/processor.h >> +++ b/xen/arch/ppc/include/asm/processor.h >> @@ -103,6 +103,37 @@ >> #define PVR_BE 0x0070 >> #define PVR_PA6T 0x0090 >> >> +/* Exception Definitions */ >> +#define EXC_SYSTEM_RESET 0x0100 /* System Reset Interrupt */ >> +#define EXC_MACHINE_CHECK 0x0200 /* Machine Check Interrupt */ >> +#define EXC_DATA_STORAGE 0x0300 /* Data Storage Interrupt */ >> +#define EXC_DATA_SEGMENT 0x0380 /* Data Segment Interrupt */ >> +#define EXC_INSN_STORAGE 0x0400 /* Instruction Storage Interrupt */ >> +#define EXC_INSN_SEGMENT 0x0480 /* Instruction Segment Interrupt */ >> +#define EXC_EXTERNAL 0x0500 /* External Interrupt */ >> +#define EXC_ALIGNMENT 0x0600 /* Alignment Interrupt */ >> +#define EXC_PROGRAM 0x0700 /* Program Interrupt */ >> +#define EXC_FPU_UNAVAIL 0x0800 /* Floating-Point Unavailable Interrupt >> */ >> +#define EXC_DECREMENTER 0x0900 /* Decrementer Interrupt */ >> +#define EXC_H_DECREMENTER 0x0980 /* Hypervisor Decrementer Interrupt */ >> +#define EXC_PRIV_DOORBELL 0x0A00 /* Directed Privileged Doorbell >> Interrupt */ >> +#define EXC_SYSTEM_CALL 0x0C00 /* System Call Interrupt */ >> +#define EXC_TRACE 0x0D00 /* Trace Interrupt */ >> +#define EXC_H_DATA_STORAGE 0x0E00 /* Hypervisor Data Storage Interrupt */ >> +#define EXC_H_INSN_STORAGE 0x0E20 /* Hypervisor Instruction Storage >> Interrupt */ >> +#define EXC_H_EMUL_ASST 0x0E40 /* Hypervisor Emulation Assistance >> Interrupt */ >> +#define EXC_H_MAINTENANCE 0x0E60 /* Hypervisor Maintenance Interrupt */ >> +#define EXC_H_DOORBELL 0x0E80 /* Directed Hypervisor Doorbell >> Interrupt */ >> +#define EXC_H_VIRT 0x0EA0 /* Hypervisor Virtualization Interrupt */ >> +#define EXC_PERF_MON 0x0F00 /* Performance Monitor Interrupt */ >> +#define EXC_VECTOR_UNAVAIL 0x0F20 /* Vector Unavailable Interrupt */ >> +#define EXC_VSX_UNAVAIL 0x0F40 /* VSX Unavailable Interrupt */ >> +#define EXC_FACIL_UNAVAIL 0x0F60 /* Facility Unavailable Interrupt */ >> +#define EXC_H_FACIL_UNAVAIL 0x0F80 /* Hypervisor Facility Unavailable >> Interrupt */ >> + >> +/* Base address of interrupt vector table when LPCR[AIL]=3 */ >> +#define AIL_VECTOR_BASE _AC(0xc000000000004000, UL) >> + >> #ifndef __ASSEMBLY__ >> >> #include <xen/types.h> >> diff --git a/xen/arch/ppc/ppc64/Makefile b/xen/arch/ppc/ppc64/Makefile >> index 5b88355bb2..914bb21c40 100644 >> --- a/xen/arch/ppc/ppc64/Makefile >> +++ b/xen/arch/ppc/ppc64/Makefile >> @@ -1,2 +1,4 @@ >> +obj-y += exceptions.o >> +obj-y += exceptions-asm.o >> obj-y += head.o >> obj-y += opal-calls.o >> diff --git a/xen/arch/ppc/ppc64/asm-offsets.c >> b/xen/arch/ppc/ppc64/asm-offsets.c >> index c15c1bf136..634d7260e3 100644 >> --- a/xen/arch/ppc/ppc64/asm-offsets.c >> +++ b/xen/arch/ppc/ppc64/asm-offsets.c >> @@ -46,6 +46,7 @@ void __dummy__(void) >> OFFSET(UREGS_dsisr, struct cpu_user_regs, dsisr); >> OFFSET(UREGS_cr, struct cpu_user_regs, cr); >> OFFSET(UREGS_fpscr, struct cpu_user_regs, fpscr); >> + OFFSET(UREGS_entry_vector, struct cpu_user_regs, entry_vector); >> DEFINE(UREGS_sizeof, sizeof(struct cpu_user_regs)); >> >> OFFSET(OPAL_base, struct opal, base); >> diff --git a/xen/arch/ppc/ppc64/exceptions-asm.S >> b/xen/arch/ppc/ppc64/exceptions-asm.S >> new file mode 100644 >> index 0000000000..877df97c9b >> --- /dev/null >> +++ b/xen/arch/ppc/ppc64/exceptions-asm.S >> @@ -0,0 +1,122 @@ >> +/* SPDX-License-Identifier: GPL-2.0-or-later */ >> + >> +#include <asm/asm-defns.h> >> +#include <asm/processor.h> >> + >> + /* Helper to dump CPU state to struct cpu_user_regs pointed to by r1. */ >> +ENTRY(exception_common) >> + /* Save GPRs 1-31 */ >> + SAVE_GPRS(1, 31, %r1) >> + >> + /* Save LR, CTR, CR */ >> + mflr %r0 >> + std %r0, UREGS_lr(%r1) >> + mfctr %r0 >> + std %r0, UREGS_ctr(%r1) >> + mfcr %r0 >> + stw %r0, UREGS_cr(%r1) /* 32-bit */ >> + >> + /* Save Exception Registers */ >> + mfsrr0 %r0 >> + std %r0, UREGS_pc(%r1) >> + mfsrr1 %r0 >> + std %r0, UREGS_msr(%r1) >> + mfdsisr %r0 >> + stw %r0, UREGS_dsisr(%r1) /* 32-bit */ >> + mfdar %r0 >> + std %r0, UREGS_dar(%r1) >> + li %r0, -1 /* OS's SRR0/SRR1 have been clobbered */ >> + std %r0, UREGS_srr0(%r1) >> + std %r0, UREGS_srr1(%r1) >> + >> + /* Setup TOC and a stack frame then call C exception handler */ >> + mr %r3, %r1 >> + bcl 20, 31, 1f >> +1: mflr %r12 >> + addis %r2, %r12, .TOC.-1b@ha >> + addi %r2, %r2, .TOC.-1b@l >> + >> + li %r0, 0 >> + stdu %r0, -STACK_FRAME_OVERHEAD(%r1) >> + bl exception_handler >> + >> + .size exception_common, . - exception_common >> + .type exception_common, %function >> + >> + /* Same as exception_common, but for exceptions that set HSRR{0,1} */ >> +ENTRY(h_exception_common) >> + /* Save GPRs 1-31 */ >> + SAVE_GPRS(1, 31, %r1) >> + >> + /* Save LR, CTR, CR */ >> + mflr %r0 >> + std %r0, UREGS_lr(%r1) >> + mfctr %r0 >> + std %r0, UREGS_ctr(%r1) >> + mfcr %r0 >> + stw %r0, UREGS_cr(%r1) /* 32-bit */ >> + >> + /* Save Exception Registers */ >> + mfhsrr0 %r0 >> + std %r0, UREGS_pc(%r1) >> + mfhsrr1 %r0 >> + std %r0, UREGS_msr(%r1) >> + mfsrr0 %r0 >> + std %r0, UREGS_srr0(%r1) >> + mfsrr1 %r0 >> + std %r0, UREGS_srr1(%r1) >> + mfdsisr %r0 >> + stw %r0, UREGS_dsisr(%r1) /* 32-bit */ >> + mfdar %r0 >> + std %r0, UREGS_dar(%r1) >> + >> + /* Setup TOC and a stack frame then call C exception handler */ >> + mr %r3, %r1 >> + bcl 20, 31, 1f >> +1: mflr %r12 >> + addis %r2, %r12, .TOC.-1b@ha >> + addi %r2, %r2, .TOC.-1b@l >> + >> + li %r0, 0 >> + stdu %r0, -STACK_FRAME_OVERHEAD(%r1) >> + bl exception_handler >> + >> + .size h_exception_common, . - h_exception_common >> + .type h_exception_common, %function > > These two are almost identical, and differ only by the handling of > srr{0,1} as far as I can tell. > > Is that just because the handler is fatal, or are they likely to stay > this similar longterm? > > One thing you could do, which would remove the duplicated logic > constructing cpu_regs would be > > exception_common_ssr > mfsrr0 %r0 > std %r0, UREGS_srr0(%r1) > mfsrr1 %r0 > std %r0, UREGS_srr1(%r1) > b exception_common > > exception_common_clobber_ssr > li %r0, -1 /* OS's SRR0/SRR1 have been clobbered */ > std %r0, UREGS_srr0(%r1) > std %r0, UREGS_srr1(%r1) > b exception_common > > but this only works if the internal differences aren't going to get larger. > I anticipate that these two will end up diverging further in the medium-to-long term, so if you'd accept it I'd rather keep them separate initially. >> + >> +/* >> + * Declare an ISR for the provided exception that jumps to `continue` >> + */ >> +#define DEFINE_ISR(name, exc, continue) >> \ >> + . = (AIL_VECTOR_BASE - EXCEPTION_VECTORS_START) + (exc); >> \ >> + ENTRY(name) >> \ >> + /* TODO: switch stack */ >> \ >> + /* Reserve space for struct cpu_user_regs */ >> \ >> + subi %r1, %r1, UREGS_sizeof; >> \ >> + /* Save r0 immediately so we can use it as scratch space */ >> \ >> + SAVE_GPR(0, %r1); >> \ >> + /* Save exception vector number */ >> \ >> + li %r0, (exc); >> \ >> + std %r0, UREGS_entry_vector(%r1); >> \ >> + /* Branch to common code */ >> \ >> + b (continue); >> \ >> + .size name, . - name; >> \ >> + .type name, %function; > > This will be much nicer as an ASM macro rather than a preprocessor macro. > > .macro ISR name, exc, handler > ... > .endm > > Everything inside can stay the same, but no need for ; or \, and a few > newlines go a long way for readability. > Fair enough, will do. > >> + >> + .section .text.exceptions, "ax", %progbits >> + >> +DEFINE_ISR(exc_sysreset, EXC_SYSTEM_RESET, exception_common) >> +DEFINE_ISR(exc_mcheck, EXC_MACHINE_CHECK, exception_common) >> +DEFINE_ISR(exc_dstore, EXC_DATA_STORAGE, exception_common) >> +DEFINE_ISR(exc_dsegment, EXC_DATA_SEGMENT, exception_common) >> +DEFINE_ISR(exc_istore, EXC_INSN_STORAGE, exception_common) >> +DEFINE_ISR(exc_isegment, EXC_INSN_SEGMENT, exception_common) >> +DEFINE_ISR(exc_extern, EXC_EXTERNAL, exception_common) >> +DEFINE_ISR(exc_align, EXC_ALIGNMENT, exception_common) >> +DEFINE_ISR(exc_program, EXC_PROGRAM, exception_common) >> +DEFINE_ISR(exc_fpu, EXC_FPU_UNAVAIL, exception_common) >> +DEFINE_ISR(exc_dec, EXC_DECREMENTER, exception_common) >> +DEFINE_ISR(exc_h_dec, EXC_H_DECREMENTER, h_exception_common) >> +/* EXC_PRIV_DOORBELL ... EXC_TRACE */ >> +DEFINE_ISR(exc_h_dstore, EXC_H_DATA_STORAGE, h_exception_common) >> +DEFINE_ISR(exc_h_istore, EXC_H_INSN_STORAGE, h_exception_common) > > It also makes this less cluttered, and I'd recommend tabulating it too. > Ditto. > ~Andrew Thanks, Shawn
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |