Перейти к содержанию

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.

Главные биты

ПолеБитПричина
MMFSRIACCVIOLвыборка команды из запрещённой области, в том числе из XN
MMFSRDACCVIOLчтение или запись по запрещённому адресу, адрес в MMFAR
MMFSRMSTKERR, MUNSTKERRнарушение при сохранении или восстановлении кадра
BFSRPRECISERRточная ошибка шины данных, адрес в BFAR
BFSRIMPRECISERRнеточная ошибка шины данных, адреса нет
BFSRIBUSERRошибка шины при выборке команды
BFSRSTKERR, UNSTKERRошибка шины при сохранении или восстановлении кадра
UFSRUNDEFINSTRнеизвестная команда
UFSRINVSTATEпопытка выполнить не Thumb-код, например переход по адресу с нулевым младшим битом
UFSRINVPCневерный EXC_RETURN при возврате из исключения
UFSRUNALIGNED, DIVBYZEROневыровненный доступ или деление на ноль, если их ловушки включены в CCR
UFSRNOCPобращение к сопроцессору, например к выключенному 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 липкие: ядро только устанавливает их, а сбрасывает программа записью единицы в нужный бит или сброс. После разбора отказа регистр очищают записью прочитанного значения обратно, иначе следующий отказ будет трудно отличить от старого.

Источники

  1. 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
  2. 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
  3. Arm. CMSIS 6, CMSIS-Core core_cm3.h (v6.4.0) — SCB->CFSR и маски полей вида SCB_CFSR_IMPRECISERR_Msk, SCB_CFSR_DIVBYZERO_Msk

Нашли ошибку?