|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2 2/2] xen/ppc: Implement a basic exception handler
On 13.10.2023 20:13, Shawn Anastasio wrote:
> --- /dev/null
> +++ b/xen/arch/ppc/ppc64/exceptions-asm.S
> @@ -0,0 +1,129 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +
> +#include <asm/asm-defns.h>
> +#include <asm/processor.h>
> +
> + .section .text.exceptions, "ax", %progbits
> +
> + /* 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)
This won't save the entry value of %r1, but the one that was already updated.
If this is not a problem, perhaps worth a comment?
> + /* 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)
Except for these four lines the two functions look identical. Is it
really good to duplicate all of the rest of the code?
> + 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
> +
> +/*
> + * Declare an ISR for the provided exception that jumps to the specified
> handler
> + */
> +.macro ISR name, exc, handler
> + . = (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 \handler
> +
> + .size \name, . - \name
> + .type \name, %function
> +.endm
> +
> +
Nit: No double blank lines please.
> +ISR exc_sysreset, EXC_SYSTEM_RESET, exception_common
> +ISR exc_mcheck, EXC_MACHINE_CHECK, exception_common
> +ISR exc_dstore, EXC_DATA_STORAGE, exception_common
> +ISR exc_dsegment, EXC_DATA_SEGMENT, exception_common
> +ISR exc_istore, EXC_INSN_STORAGE, exception_common
> +ISR exc_isegment, EXC_INSN_SEGMENT, exception_common
> +ISR exc_extern, EXC_EXTERNAL, exception_common
> +ISR exc_align, EXC_ALIGNMENT, exception_common
> +ISR exc_program, EXC_PROGRAM, exception_common
> +ISR exc_fpu, EXC_FPU_UNAVAIL, exception_common
> +ISR exc_dec, EXC_DECREMENTER, exception_common
> +ISR exc_h_dec, EXC_H_DECREMENTER, h_exception_common
> +/* EXC_PRIV_DOORBELL ... EXC_TRACE */
> +ISR exc_h_dstore, EXC_H_DATA_STORAGE, h_exception_common
> +ISR exc_h_istore, EXC_H_INSN_STORAGE, h_exception_common
Aiui these are required to be in order, or else the assembler will choke.
Maybe worth another comment?
> --- /dev/null
> +++ b/xen/arch/ppc/ppc64/exceptions.c
> @@ -0,0 +1,102 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +#include <xen/lib.h>
> +
> +#include <asm/processor.h>
> +
> +static const char *exception_name_from_vec(uint32_t vec)
> +{
> + switch ( vec )
> + {
> + case EXC_SYSTEM_RESET:
> + return "System Reset Interrupt";
> + case EXC_MACHINE_CHECK:
> + return "Machine Check Interrupt";
> + case EXC_DATA_STORAGE:
> + return "Data Storage Interrupt";
> + case EXC_DATA_SEGMENT:
> + return "Data Segment Interrupt";
> + case EXC_INSN_STORAGE:
> + return "Instruction Storage Interrupt";
> + case EXC_INSN_SEGMENT:
> + return "Instruction Segment Interrupt";
> + case EXC_EXTERNAL:
> + return "External Interrupt";
> + case EXC_ALIGNMENT:
> + return "Alignment Interrupt";
> + case EXC_PROGRAM:
> + return "Program Interrupt";
> + case EXC_FPU_UNAVAIL:
> + return "Floating-Point Unavailable Interrupt";
> + case EXC_DECREMENTER:
> + return "Decrementer Interrupt";
> + case EXC_H_DECREMENTER:
> + return "Hypervisor Decrementer Interrupt";
> + case EXC_PRIV_DOORBELL:
> + return "Directed Privileged Doorbell Interrupt";
> + case EXC_SYSTEM_CALL:
> + return "System Call Interrupt";
> + case EXC_TRACE:
> + return "Trace Interrupt";
> + case EXC_H_DATA_STORAGE:
> + return "Hypervisor Data Storage Interrupt";
> + case EXC_H_INSN_STORAGE:
> + return "Hypervisor Instruction Storage Interrupt";
> + case EXC_H_EMUL_ASST:
> + return "Hypervisor Emulation Assistance Interrupt";
> + case EXC_H_MAINTENANCE:
> + return "Hypervisor Maintenance Interrupt";
> + case EXC_H_DOORBELL:
> + return "Directed Hypervisor Doorbell Interrupt";
> + case EXC_H_VIRT:
> + return "Hypervisor Virtualization Interrupt";
> + case EXC_PERF_MON:
> + return "Performance Monitor Interrupt";
> + case EXC_VECTOR_UNAVAIL:
> + return "Vector Unavailable Interrupt";
> + case EXC_VSX_UNAVAIL:
> + return "VSX Unavailable Interrupt";
> + case EXC_FACIL_UNAVAIL:
> + return "Facility Unavailable Interrupt";
> + case EXC_H_FACIL_UNAVAIL:
> + return "Hypervisor Facility Unavailable Interrupt";
Every string here has Interrupt at the end - any chance of collapsing
all of them?
> + default:
> + return "(unknown)";
> + }
> +}
> +
> +void exception_handler(struct cpu_user_regs *regs)
> +{
> + /* TODO: this is currently only useful for debugging */
> +
> + printk("UNRECOVERABLE EXCEPTION: %s (0x%04x)\n\n"
> + "GPR 0-3 : 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n"
> + "GPR 4-7 : 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n"
> + "GPR 8-11 : 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n"
> + "GPR 12-15 : 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n"
> + "GPR 16-19 : 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n"
> + "GPR 20-23 : 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n"
> + "GPR 24-27 : 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n"
> + "GPR 28-31 : 0x%016lx 0x%016lx 0x%016lx 0x%016lx\n\n",
> + exception_name_from_vec(regs->entry_vector), regs->entry_vector,
> + regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3],
> + regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7],
> + regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11],
> + regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15],
> + regs->gprs[16], regs->gprs[17], regs->gprs[18], regs->gprs[19],
> + regs->gprs[20], regs->gprs[21], regs->gprs[22], regs->gprs[23],
> + regs->gprs[24], regs->gprs[25], regs->gprs[26], regs->gprs[27],
> + regs->gprs[28], regs->gprs[29], regs->gprs[30], regs->gprs[31]);
> + printk("LR : 0x%016lx\n"
> + "CTR : 0x%016lx\n"
> + "CR : 0x%08x\n"
> + "PC : 0x%016lx\n"
> + "MSR : 0x%016lx\n"
> + "SRR0 : 0x%016lx\n"
> + "SRR1 : 0x%016lx\n"
> + "DAR : 0x%016lx\n"
> + "DSISR : 0x%08x\n",
> + regs->lr, regs->ctr, regs->cr, regs->pc, regs->msr, regs->srr0,
> + regs->srr1, regs->dar, regs->dsisr);
While surely a matter of taste, I'd still like to ask: In dumping like
this, are 0x prefixes (taking space) actually useful?
> --- a/xen/arch/ppc/setup.c
> +++ b/xen/arch/ppc/setup.c
> @@ -11,6 +11,15 @@
> /* Xen stack for bringing up the first CPU. */
> unsigned char __initdata cpu0_boot_stack[STACK_SIZE] __aligned(STACK_SIZE);
>
> +void setup_exceptions(void)
> +{
> + unsigned long lpcr;
> +
> + /* Set appropriate interrupt location in LPCR */
> + lpcr = mfspr(SPRN_LPCR);
> + mtspr(SPRN_LPCR, lpcr | LPCR_AIL_3);
> +}
Please forgive my lack of PPC knowledge: There's no use of any address
here afaict. Where's the link to (presumably) AIL_VECTOR_BASE? If that
address is kind of magic, I'm then lacking a connection between
XEN_VIRT_START and that constant. (If Xen needed moving around in
address space, it would be nice if changing a single constant would
suffice.)
Also you only OR in LPCR_AIL_3 - is it guaranteed that the respective
field is zero when control is passed to Xen?
Jan
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |