/* SPDX-License-Identifier: GPL-2.0+ */ /* * exceptions.c - report an abort through the console before parking, * so a firmware handoff bug says why it died instead of hanging quiet. * ESR/FAR decode follows armv8 DDI 0487, the EC and ISS fields. * * Copyright (C) 2026 Bradley Morgan */ #include #include struct exc_frame { uint64_t esr; uint64_t far; uint64_t lr; }; /* * exception class from ESR, bits 31:26. the classes a bootloader can * actually hit with any frequency. */ static const char *exc_class_str(uint64_t esr) { switch (esr >> 26) { case 0x04: return "data abort, lower EL"; case 0x05: return "data abort, same EL"; case 0x25: return "data abort, same EL"; case 0x08: return "stack pointer misaligned"; case 0x11: return "instruction abort, same EL"; case 0x16: return "SError"; case 0x1a: return "unhandled exception"; case 0x22: return "pc alignment fault"; case 0x24: return "unknown trap"; case 0x26: return "same EL exception return"; default: return "unknown EC"; } } /* * far is only meaningful for the abort and alignment classes, note it * for those and skip it otherwise so the report does not mislead. */ static int exc_far_valid(uint64_t esr) { switch (esr >> 26) { case 0x04: case 0x05: case 0x25: case 0x11: case 0x22: return 1; default: return 0; } } void exc_report(uint64_t esr, uint64_t far, uint64_t lr) { dprintf(CRITICAL, "tashaboot: exception %s\n", exc_class_str(esr)); dprintf(CRITICAL, "esr %016llx lr %016llx\n", (unsigned long long)esr, (unsigned long long)lr); if (exc_far_valid(esr)) dprintf(CRITICAL, "far %016llx\n", (unsigned long long)far); /* nothing recovers from an abort here, park after reporting */ }