Signed-off-by: Nicholas Piggin <npiggin@xxxxxxxxx>
---
lib/powerpc/asm/processor.h | 4 +
lib/powerpc/asm/reg.h | 17 ++
lib/powerpc/setup.c | 11 +
lib/ppc64/asm/ptrace.h | 16 ++
powerpc/Makefile.common | 3 +-
powerpc/interrupts.c | 415 ++++++++++++++++++++++++++++++++++++
powerpc/unittests.cfg | 3 +
7 files changed, 468 insertions(+), 1 deletion(-)
create mode 100644 powerpc/interrupts.c
diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index cf1b9d8ff..eed37d1f4 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -11,7 +11,11 @@ void do_handle_exception(struct pt_regs *regs);
#endif /* __ASSEMBLY__ */
extern bool cpu_has_hv;
+extern bool cpu_has_power_mce;
+extern bool cpu_has_siar;
extern bool cpu_has_heai;
+extern bool cpu_has_prefix;
+extern bool cpu_has_sc_lev;
static inline uint64_t mfspr(int nr)
{
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 782e75527..d6097f48f 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -5,8 +5,15 @@
#define UL(x) _AC(x, UL)
+#define SPR_DSISR 0x012
+#define SPR_DAR 0x013
+#define SPR_DEC 0x016
#define SPR_SRR0 0x01a
#define SPR_SRR1 0x01b
+#define SRR1_PREFIX UL(0x20000000)
+#define SPR_FSCR 0x099
+#define FSCR_PREFIX UL(0x2000)
+#define SPR_HFSCR 0x0be
#define SPR_TB 0x10c
#define SPR_SPRG0 0x110
#define SPR_SPRG1 0x111
@@ -22,12 +29,17 @@
#define PVR_VER_POWER8 UL(0x004d0000)
#define PVR_VER_POWER9 UL(0x004e0000)
#define PVR_VER_POWER10 UL(0x00800000)
+#define SPR_HDEC 0x136
#define SPR_HSRR0 0x13a
#define SPR_HSRR1 0x13b
+#define SPR_LPCR 0x13e
+#define LPCR_HDICE UL(0x1)
+#define SPR_HEIR 0x153
#define SPR_MMCR0 0x31b
#define MMCR0_FC UL(0x80000000)
#define MMCR0_PMAE UL(0x04000000)
#define MMCR0_PMAO UL(0x00000080)
+#define SPR_SIAR 0x31c
/* Machine State Register definitions: */
#define MSR_LE_BIT 0
@@ -35,6 +47,11 @@
#define MSR_HV_BIT 60 /* Hypervisor mode */
#define MSR_SF_BIT 63 /* 64-bit mode */
+#define MSR_DR UL(0x0010)
+#define MSR_IR UL(0x0020)
+#define MSR_BE UL(0x0200) /* Branch Trace Enable */
+#define MSR_SE UL(0x0400) /* Single Step Enable */
+#define MSR_EE UL(0x8000)
#define MSR_ME UL(0x1000)
#endif
diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index 3c81aee9e..9b665f59c 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -87,7 +87,11 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
}
bool cpu_has_hv;
+bool cpu_has_power_mce; /* POWER CPU machine checks */
+bool cpu_has_siar;
bool cpu_has_heai;
+bool cpu_has_prefix;
+bool cpu_has_sc_lev; /* sc interrupt has LEV field in SRR1 */
static void cpu_init(void)
{
@@ -112,15 +116,22 @@ static void cpu_init(void)
switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
case PVR_VER_POWER10:
+ cpu_has_prefix = true;
+ cpu_has_sc_lev = true;
case PVR_VER_POWER9:
case PVR_VER_POWER8E:
case PVR_VER_POWER8NVL:
case PVR_VER_POWER8:
+ cpu_has_power_mce = true;
cpu_has_heai = true;
+ cpu_has_siar = true;
break;
default:
break;
}
+
+ if (!cpu_has_hv) /* HEIR is HV register */
+ cpu_has_heai = false;
}
static void mem_init(phys_addr_t freemem_start)
diff --git a/lib/ppc64/asm/ptrace.h b/lib/ppc64/asm/ptrace.h
index 12de7499b..db263a59e 100644
--- a/lib/ppc64/asm/ptrace.h
+++ b/lib/ppc64/asm/ptrace.h
@@ -5,6 +5,9 @@
#define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */
#ifndef __ASSEMBLY__
+
+#include <asm/reg.h>
+
struct pt_regs {
unsigned long gpr[32];
unsigned long nip;
@@ -17,6 +20,19 @@ struct pt_regs {
unsigned long _pad; /* stack must be 16-byte aligned */
};
+static inline bool regs_is_prefix(volatile struct pt_regs *regs)
+{
+ return regs->msr & SRR1_PREFIX;
+}
+
+static inline void regs_advance_insn(struct pt_regs *regs)
+{
+ if (regs_is_prefix(regs))
+ regs->nip += 8;
+ else
+ regs->nip += 4;
+}
+
#define STACK_INT_FRAME_SIZE (sizeof(struct pt_regs) + \
STACK_FRAME_OVERHEAD + KERNEL_REDZONE_SIZE)
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index 1e181da69..68165fc25 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -12,7 +12,8 @@ tests-common = \
$(TEST_DIR)/rtas.elf \
$(TEST_DIR)/emulator.elf \
$(TEST_DIR)/tm.elf \
- $(TEST_DIR)/sprs.elf
+ $(TEST_DIR)/sprs.elf \
+ $(TEST_DIR)/interrupts.elf
tests-all = $(tests-common) $(tests)
all: directories $(TEST_DIR)/boot_rom.bin $(tests-all)
diff --git a/powerpc/interrupts.c b/powerpc/interrupts.c
new file mode 100644
index 000000000..442f8c569
--- /dev/null
+++ b/powerpc/interrupts.c
@@ -0,0 +1,415 @@
+/*
+ * Test interrupts
+ *
+ * Copyright 2024 Nicholas Piggin, IBM Corp.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.