summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/powerpc64/powerpc64/trap.c57
1 files changed, 56 insertions, 1 deletions
diff --git a/sys/arch/powerpc64/powerpc64/trap.c b/sys/arch/powerpc64/powerpc64/trap.c
index e3bac5a5df5..3be8dde4f45 100644
--- a/sys/arch/powerpc64/powerpc64/trap.c
+++ b/sys/arch/powerpc64/powerpc64/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.45 2020/10/22 13:41:49 deraadt Exp $ */
+/* $OpenBSD: trap.c,v 1.46 2020/10/27 12:50:49 kettenis Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -162,6 +162,61 @@ trap(struct trapframe *frame)
printf("dar 0x%lx dsisr 0x%lx\n", frame->dar, frame->dsisr);
goto fatal;
+ case EXC_ALI:
+ {
+ /*
+ * In general POWER allows unaligned loads and stores
+ * and executes those instructions in an efficient
+ * way. As a result compilers may combine word-sized
+ * stores into a single doubleword store instruction
+ * even if the address is not guaranteed to be
+ * doubleword aligned. Such unaligned stores are not
+ * supported in storage that is Caching Inibited.
+ * Access to such storage should be done through
+ * volatile pointers which inhibit the aforementioned
+ * optimizations. Unfortunately code in the amdgpu(4)
+ * and radeondrm(4) drivers happens to run into such
+ * unaligned access because pointers aren't always
+ * marked as volatile. For that reason we emulate
+ * certain store instructions here.
+ */
+ uint32_t insn = *(uint32_t *)frame->srr0;
+
+ /* std and stdu */
+ if ((insn & 0xfc000002) == 0xf8000000) {
+ uint32_t rs = (insn >> 21) & 0x1f;
+ uint32_t ra = (insn >> 16) & 0x1f;
+ uint64_t ds = insn & 0xfffc;
+ uint64_t ea;
+
+ if ((insn & 0x00000001) == 0 && ra == 0)
+ panic("invalid stdu instruction form");
+
+ if (ds & 0x8000)
+ ds |= ~0x7fff; /* sign extend */
+ if (ra == 0)
+ ea = ds;
+ else
+ ea = frame->fixreg[ra] + ds;
+
+ /*
+ * If the effective address isn't 32-bit
+ * aligned, or if data access cannot be
+ * performed because of the access violates
+ * storage protection, this will trigger
+ * another trap, which we can handle.
+ */
+ *(volatile uint32_t *)ea = frame->fixreg[rs] >> 32;
+ *(volatile uint32_t *)(ea + 4) = frame->fixreg[rs];
+ if (insn & 0x00000001)
+ frame->fixreg[ra] = ea;
+ frame->srr0 += 4;
+ return;
+ }
+ printf("dar 0x%lx dsisr 0x%lx\n", frame->dar, frame->dsisr);
+ goto fatal;
+ }
+
case EXC_DSE|EXC_USER:
pm = p->p_vmspace->vm_map.pmap;
error = pmap_slbd_fault(pm, frame->dar);