diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/powerpc64/powerpc64/trap.c | 57 |
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); |