+ ;; contain the return address. used by Oops to print kernel errors.
+ sbfs [$sp=$sp-16] ; push the internal CPU status
+ push $dccr
+ di
+ subq 2*4, $sp
+ movem $r1, [$sp]
+ move.d [R_MMU_CAUSE], $r1
+ ;; ETRAX 100LX TR89 bugfix: if the second half of an unaligned
+ ;; write causes a MMU-fault, it will not be restarted correctly.
+ ;; This could happen if a write crosses a page-boundary and the
+ ;; second page is not yet COW'ed or even loaded. The workaround
+ ;; is to clear the unaligned bit in the CPU status record, so
+ ;; that the CPU will rerun both the first and second halves of
+ ;; the instruction. This will not have any sideeffects unless
+ ;; the first half goes to any device or memory that can't be
+ ;; written twice, and which is mapped through the MMU.
+ ;;
+ ;; We only need to do this for writes.
+ btstq 8, $r1 ; Write access?
+ bpl 1f
+ nop
+ move.d [$sp+16], $r0 ; Clear unaligned bit in csrinstr
+ and.d ~(1<<5), $r0
+ move.d $r0, [$sp+16]
+1: btstq 12, $r1 ; Refill?
+ bpl 2f
+ lsrq 24, $r1 ; Get PGD index (bit 24-31)
+ move.d [per_cpu__current_pgd], $r0 ; PGD for the current process
+ move.d [$r0+$r1.d], $r0 ; Get PMD
+ beq 2f
+ nop
+ and.w PAGE_MASK, $r0 ; Remove PMD flags
+ move.d [R_MMU_CAUSE], $r1
+ lsrq PAGE_SHIFT, $r1
+ and.d 0x7ff, $r1 ; Get PTE index into PGD (bit 13-23)
+ move.d [$r0+$r1.d], $r1 ; Get PTE
+ beq 2f
+ nop
+ ;; Store in TLB
+ move.d $r1, [R_TLB_LO]
+ ;; Return
+ movem [$sp+], $r1
+ pop $dccr
+ rbf [$sp+] ; return by popping the CPU status
+
+2: ; PMD or PTE missing, let the mm subsystem fix it up.
+ movem [$sp+], $r1
+ pop $dccr
+
+ ; Ok, not that easy, pass it on to the mm subsystem
+ ; The MMU status record is now on the stack