From: David van Moolenbroek Date: Wed, 9 Mar 2016 12:02:03 +0000 (+0000) Subject: Kernel: disable assert in prefetch abort handler X-Git-Url: http://zhaoyanbai.com/repos/migration-4to9?a=commitdiff_plain;h=a3975fbc356715eac5dff4701d2e1b257fa36c1a;p=minix.git Kernel: disable assert in prefetch abort handler 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 --- diff --git a/minix/kernel/arch/earm/exception.c b/minix/kernel/arch/earm/exception.c index ee074a81e..19c400822 100644 --- a/minix/kernel/arch/earm/exception.c +++ b/minix/kernel/arch/earm/exception.c @@ -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; }