]> Zhao Yanbai Git Server - minix.git/commitdiff
Kernel: disable assert in prefetch abort handler 07/3307/1
authorDavid van Moolenbroek <david@minix3.org>
Wed, 9 Mar 2016 12:02:03 +0000 (12:02 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Wed, 9 Mar 2016 12:11:23 +0000 (12:11 +0000)
For a reason currently unknown to us, the qemu-linaro emulator
sometimes produces a Prefetch Abort exception with a fault location
(IFAR) rather different from the location of the instruction being
executed (LR corrected by 4).  So far it has been observed in the
__udivmodsi4 routine of various processes, where the fault address is
for the first byte of the next page after the current instruction,
which itself is 44-64 bytes away from the start of that next page.
The affected instruction does not perform any sort of memory access.

Short of debugging qemu-linaro itself, we have no choice but to
disable the assert that previously went off in case the IFAR and
corrected LR are not equal.  Since we have not yet observed this case
on actual hardware, the kernel prints a warning when detecting such a
mismatch for the first time.  For the qemu-linaro case, the kernel's
actual page fault handling logic already handles this strange case
just fine.

Change-Id: Ibd19e624149ab4e68bfe75b918ec1554b825a431

minix/kernel/arch/earm/exception.c

index ee074a81e6fec9c08d3778a91b92c2cce72c80d8..19c400822bdc7975c3faa7cf7ddaf1ac72313848 100644 (file)
@@ -176,6 +176,7 @@ void exception_handler(int is_nested, reg_t *saved_lr, int vector)
   }
 
   if (!is_nested && vector == PREFETCH_ABORT_VECTOR) {
+       static int warned = FALSE;
        reg_t ifar = read_ifar(), ifsr = read_ifsr();
 
        /* The saved_lr is the instruction we're going to execute after
@@ -183,9 +184,21 @@ void exception_handler(int is_nested, reg_t *saved_lr, int vector)
         * while fetching the instruction. As far as we know the two
         * should be the same, if not this assumption will lead to very
         * hard to debug problems (instruction executing being off by one)
-        * and this assumption needs re-examining, hence the assert.
+        * and this assumption needs re-examining.
+        *
+        * UPDATE: at least qemu-linaro does in fact sometimes generate faults
+        * with LR and IFAR differing by as many as 64 bytes.  While the page
+        * fault resolution code below handles this case just fine, the cause
+        * of this behavior is unknown.  We have not yet seen the same on
+        * actual hardware, which is why we warn about this problem once.
         */
-       assert(*saved_lr == ifar);
+       if (*saved_lr != ifar && !warned) {
+               printf("KERNEL: prefetch abort with differing IFAR and LR\n");
+               printf("KERNEL: IFSR %"PRIx32" IFAR %"PRIx32" LR %"PRIx32" in "
+                   "%s/%d\n", ifsr, ifar, *saved_lr, saved_proc->p_name,
+                   saved_proc->p_endpoint);
+               warned = TRUE;
+       }
        pagefault(saved_proc, saved_lr, is_nested, ifar, ifsr);
        return;
   }