CFSR (регистр состояния отказов)
Программа упала в HardFault, и нужно понять почему. Ответ лежит в регистре CFSR: в нём по одному биту на каждую причину отказа — от обращения по запрещённому адресу до деления на ноль, — а рядом регистры с адресом, на котором всё сломалось.
Обновлено Редакция GAW
CFSR (Configurable Fault Status Register) — регистр блока управления системой Cortex-M3 и M4 по адресу 0xE000ED28, в котором ядро отмечает причину отказов MemManage, BusFault и UsageFault. Регистр состоит из трёх полей, к которым можно обращаться и по отдельности: байт MMFSR (0xE000ED28), байт BFSR (0xE000ED29) и полуслово UFSR (0xE000ED2A) (DUI 0552A, разд. 4.3.10). Если отказ эскалировал в HardFault, бит FORCED в HFSR лишь говорит об эскалации, а настоящую причину показывает CFSR.
Главные биты
| Поле | Бит | Причина |
|---|---|---|
| MMFSR | IACCVIOL | выборка команды из запрещённой области, в том числе из XN |
| MMFSR | DACCVIOL | чтение или запись по запрещённому адресу, адрес в MMFAR |
| MMFSR | MSTKERR, MUNSTKERR | нарушение при сохранении или восстановлении кадра |
| BFSR | PRECISERR | точная ошибка шины данных, адрес в BFAR |
| BFSR | IMPRECISERR | неточная ошибка шины данных, адреса нет |
| BFSR | IBUSERR | ошибка шины при выборке команды |
| BFSR | STKERR, UNSTKERR | ошибка шины при сохранении или восстановлении кадра |
| UFSR | UNDEFINSTR | неизвестная команда |
| UFSR | INVSTATE | попытка выполнить не Thumb-код, например переход по адресу с нулевым младшим битом |
| UFSR | INVPC | неверный EXC_RETURN при возврате из исключения |
| UFSR | UNALIGNED, DIVBYZERO | невыровненный доступ или деление на ноль, если их ловушки включены в CCR |
| UFSR | NOCP | обращение к сопроцессору, например к выключенному FPU |
По табл. 4-25 — 4-27 DUI 0552A. У Cortex-M4 с FPU добавлены MLSPERR и LSPERR — отказ при отложенном сохранении регистров FPU (DUI 0553B). Ловушки невыровненного доступа и деления на ноль выключены по умолчанию: без них такие ошибки не попадают в CFSR.
Адрес отказа: MMFAR и BFAR
Для точных отказов памяти ядро сохраняет адрес обращения: MMFAR (0xE000ED34) для MemManage и BFAR (0xE000ED38) для BusFault. Адрес верен, только если стоит флаг MMARVALID или BFARVALID. Arm советует сначала прочитать и сохранить сам адрес, а потом проверить флаг: отказ более высокого приоритета может перезаписать регистр между двумя чтениями (разд. 4.3.15).
Точный отказ — это когда сохранённый в кадре стека исключения PC указывает на виновную команду. При IMPRECISERR это не так: запись ушла через буфер, ядро успело выполнить ещё несколько команд, и адрес не сохраняется вовсе.
Биты CFSR липкие — сбрасываются записью единицы или сбросом. Как сохранить CFSR, HFSR и адреса в обработчике и разобрать их после перезапуска, показано в статье «Переполнение стека и ошибки памяти в прошивке».
Частые вопросы
Как понять по CFSR, где упала программа?
Сначала посмотреть, какой бит стоит. При PRECISERR, DACCVIOL, UNDEFINSTR, INVSTATE и DIVBYZERO PC в кадре стека исключения указывает прямо на виновную команду. При PRECISERR адрес обращения лежит в BFAR, при DACCVIOL — в MMFAR, если стоят флаги BFARVALID или MMARVALID. Сравнив PC с map-файлом или дизассемблером, находят строку кода.
Что значит IMPRECISERR?
Ошибка шины при записи, которая завершилась уже после того, как ядро ушло дальше по программе: запись прошла через буфер. Адрес возврата в кадре не связан с виновной командой, а BFAR не заполняется. Для отладки буферизацию записи можно временно отключить битом DISDEFWBUF в ACTLR — тогда ошибка станет точной.
Почему в CFSR стоят биты от прошлого отказа?
Биты CFSR липкие: ядро только устанавливает их, а сбрасывает программа записью единицы в нужный бит или сброс. После разбора отказа регистр очищают записью прочитанного значения обратно, иначе следующий отказ будет трудно отличить от старого.
Источники
- Arm. Cortex-M3 Devices Generic User Guide, DUI 0552A, 2010 — разд. 4.3.10: CFSR показывает причину MemManage, BusFault или UsageFault; слово по адресу 0xE000ED28, байт MMFSR 0xE000ED28, байт BFSR 0xE000ED29, полуслово UFSR 0xE000ED2A; табл. 4-25: MMFSR — MMARVALID, MSTKERR, MUNSTKERR, DACCVIOL (адрес в MMFAR), IACCVIOL (в том числе при любом выполнении из XN); табл. 4-26: BFSR — BFARVALID, STKERR, UNSTKERR, IMPRECISERR (асинхронная ошибка, адрес возврата не связан с командой, BFAR не пишется), PRECISERR (PC в кадре указывает на команду, адрес в BFAR), IBUSERR; табл. 4-27: UFSR — DIVBYZERO (при CCR.DIV_0_TRP = 1), UNALIGNED (при UNALIGN_TRP = 1; LDM, STM, LDRD, STRD без выравнивания — всегда), NOCP, INVPC, INVSTATE, UNDEFINSTR; биты липкие, сбрасываются записью 1 или сбросом; разд. 4.3.12–4.3.13: MMFAR 0xE000ED34, BFAR 0xE000ED38; табл. 4-13: бит DISDEFWBUF регистра ACTLR отключает буфер записи для карты памяти по умолчанию — все BusFault становятся точными ценой скорости; разд. 4.3.15: сначала прочитать и сохранить MMFAR или BFAR, затем проверить MMARVALID или BFARVALID — адрес мог перезаписать отказ более высокого приоритета; при эскалации в HardFault обработчик должен сбросить MMARVALID и BFARVALID
- Arm. Cortex-M4 Devices Generic User Guide, DUI 0553B, 2011 — табл. 2-18 и разд. 4.3.10: у Cortex-M4 с FPU добавлены биты MLSPERR в MMFSR и LSPERR в BFSR — отказ при отложенном сохранении состояния FPU; разд. 4.6.1: поля CP10 и CP11 регистра CPACR = 0b00 — доступ к FPU запрещён, любое обращение даёт UsageFault NOCP
- Arm. CMSIS 6, CMSIS-Core core_cm3.h (v6.4.0) — SCB->CFSR и маски полей вида SCB_CFSR_IMPRECISERR_Msk, SCB_CFSR_DIVBYZERO_Msk
Нашли ошибку?
Смотрите также
- HardFaultИсключение Cortex-M при необработанной ошибке
- Кадр стека исключенияВосемь регистров, которые Cortex-M сам сохраняет в стек при входе в исключение
- SCB (блок управления системой)Регистры ядра Cortex-M для настройки исключений, сна и отказов
- Невыровненный доступОбращение к слову или полуслову по адресу, не кратному его размеру
- Переполнение стека и памятьОценка стека, раскраска ОЗУ, защитная область MPU, HardFault, куча