Difference between revisions of "Cortex-A/R Fault"
(Created page with "This article describes the analysis of fault exceptions on Cortex-A and Cortex-R CPUs. == Cortex-A and Cortex-R Exceptions == On Cortex-A and Cortex-R CPUs, an exception caus...") |
m (→Unaligned Access) |
||
Line 554: | Line 554: | ||
* - DFAR <struct> |
* - DFAR <struct> |
||
* - DFAR 0x0013ffff <--- Fault was caused by accessing this address |
* - DFAR 0x0013ffff <--- Fault was caused by accessing this address |
||
− | * - Valid VALID |
+ | * - Valid VALID <--- Value contained in DFAR is valid on alignment faults |
* - ADFSR 0x00000000 |
* - ADFSR 0x00000000 |
||
* - ExceptionReturn 0xfc029982 <--- Address that holds the faulting instruction |
* - ExceptionReturn 0xfc029982 <--- Address that holds the faulting instruction |
||
Line 570: | Line 570: | ||
} |
} |
||
</source> |
</source> |
||
− | |||
− | |||
== File listing == |
== File listing == |
Revision as of 16:55, 16 March 2023
This article describes the analysis of fault exceptions on Cortex-A and Cortex-R CPUs.
Contents
- 1 Cortex-A and Cortex-R Exceptions
- 2 Fault Exception Handling
- 3 Fault Status Registers
- 4 Example Fault analysis
- 5 File listing
Cortex-A and Cortex-R Exceptions
On Cortex-A and Cortex-R CPUs, an exception causes the processor to suspend program execution to handle an event, e.g. an externally generated interrupt or an attempt to execute an undefined instruction.
When an exception is taken, processor execution jumps to an exception vector that matches the type of exception that has occurred.
By default, the exception vectors are eight consecutive word-aligned memory addresses, starting at an exception base address:
Vector offset | Vectored exception |
---|---|
0x00 | Reset |
0x04 | Undefined Instruction |
0x08 | Secure Monitor Call (SMC) |
Supervisor Call (SVC) | |
0x0C | Prefetch Abort |
0x10 | Data Abort |
0x14 | Reserved |
0x18 | Interrupt (IRQ) |
0x1C | Fast Interrupt (FIQ) |
Of these exceptions, the Undefined Instruction exception, the Prefetch Abort exception, and the Data Abort exception are considered fault exceptions.
Other types of exceptions, such as SVC, IRQ, and FIQ are not covered by this article.
Undefined Instruction Exception
An Undefined Instruction exception might be caused by
- a co-processor instruction that is not accessible
- a co-processor instruction that is not implemented
- an instruction that is undefined
- an attempt to execute an instruction in an unsupported instruction set state
- division by zero
Prefetch Abort Exception
A Prefetch Abort exception can be generated by
- a synchronous memory abort on an instruction fetch
- a Breakpoint, Vector Catch or BKPT Instruction debug event
Data Abort Exception
A Data Abort exception can be generated by
- a synchronous abort on a data read or write memory access
- an asynchronous abort on a data read or write access
- an asynchronous abort on an instruction fetch or prefetch
- an asynchronous abort on a translation table access
- a Watchpoint debug event
Fault Exception Handling
Fault exception handling is usually done differently during development and in production firmware.
Fault Exception Handling During Development
During development of a firmware, errors can happen. Developers usually want to analyze what went wrong to resolve the error.
The Cortex-A and Cortex-R CPUs provide various registers to analyze the reason of Prefetch Abort and Data Abort exceptions.
Exception handlers may contain development code to gather the contents of these registers in order to easily make them available in a debugger.
The SEGGER Prefetch Abort and Data Abort Handlers listed below read the corresponding fault registers and make them accessible in a single, comprehensive struct.
The only mechanism to determine the cause of an Undefined Instruction exception is analysis of the instruction indicated by the return link in the LR on exception entry.
Fault Exception Handling in Productive Firmware
Exceptions might also occur in release firmwares and should be caught.
Some exceptions might not be caused by an error.
For example executing a BKPT instruction when no debugger is connected causes a Prefetch Abort.
Firmware may simply return from such exception and continue program execution.
The system might also want to recover from certain cases which are caused by errors, but are recoverable.
In the exception handler, the error reason can be analyzed and, for example, terminate the task that has caused the error.
In the case of a unrecoverable error, the system could recover e.g. by simply resetting it. In more advanced scenarios, a crash dump could be generated before the reset, to be send or saved on reboot.
Fault Status Registers
Instruction Fault Status Register
The Instruction Fault Status Register (IFSR) is a 32-bit register and can be accessed by reads to the CP15 registers with <opc1> set to 0, <CRn> set to c5, <CRm set to c0, and <opc2> set to 1:
MRC p15, 0, <Rt>, c5, c0, 1 ; Read IFSR into Rt
The fault status bits contained in this register may be used to determine the source of the Prefetch Abort exception.
Three different formats of the IFSR exist, one for PMSAv7 implementations (Cortex-R) and two for VMSAv7 implementations (Cortex-A).
The latter depend on whether the short-descriptor translation table format or the long-descriptor translation table format is used by the implementation.
IFSR format in a PMSAv7 implementation
Bit(s) | Description |
---|---|
[3:0] | Fault status bits[3:0]. |
[9:4] | UNK/SBZP. |
[10] | Fault status bit[4]. |
[11] | UNK/SBZP. |
[12] | External abort type. This bit can provide an implementation defined classification of external aborts. For aborts other than external aborts this bit always returns 0. |
[31:13] | UNK/SBZP. |
In this format, the fault status bits ([10, 3:0]) encode the source of the Prefetch Abort exception as follows.
All encodings not shown in the table are reserved.
Value | Source |
---|---|
0x00 | Background fault (MPU fault). |
0x01 | Alignment fault. |
0x02 | Debug event that generates a Prefetch Abort exception. |
0x08 | Synchronous external abort. |
0x0D | Permission fault (MPU fault). |
0x14 | Implementation defined (Lock-down). |
0x19 | Synchronous parity error on memory access. |
0x1A | Implementation defined (Co-processor abort). |
IFSR format when using the Short-descriptor translation table format in a VMSAv7 implementation
Bit(s) | Description |
---|---|
[3:0] | Fault status bits[3:0] |
[8:4] | UNK/SBZP. |
[9] | If the implementation does not include the Large Physical Address Extension: UNK/SBZP. |
If the implementation includes the Large Physical Address Extension: On taking a Prefetch Abort exception, this bit is set to 0 to indicate use of the Short-descriptor translation table format. | |
[10] | Fault status bit[4]. |
[11] | UNK/SBZP. |
[12] | External abort type. This bit can provide an implementation defined classification of external aborts. For aborts other than external aborts this bit always returns 0. |
[31:13] | UNK/SBZP. |
In this format, the fault status bits ([10, 3:0]) encode the source of the Prefetch Abort exception as follows.
All encodings not shown in the table are reserved.
Value | Source |
---|---|
0x02 | Debug event. |
0x03 | Access flag fault (MMU fault). First level. |
0x05 | Translation fault (MMU fault). First level. |
0x06 | Access flag fault (MMU fault). Second level. |
0x07 | Translation fault (MMU fault). Second level. |
0x08 | Synchronous external abort. |
0x09 | Domain fault (MMU fault). First level. |
0x0B | Domain fault (MMU fault). Second level. |
0x0C | Synchronous external abort on translation table walk. First level. |
0x0D | Permission fault (MMU fault). First level. |
0x0E | Synchronous external abort on translation table walk. Second level. |
0x0F | Permission fault (MMU fault). Second level. |
0x10 | TLB conflict abort. |
0x14 | Implementation defined (Lock-down). |
0x19 | Synchronous parity error on memory access. |
0x1A | Implementation defined (Co-processor abort). |
0x1C | Synchronous parity error on translation table walk. First level. |
0x1E | Synchronous parity error on translation table walk. Second level. |
IFSR format when using the Long-descriptor translation table format in a VMSAv7 implementation
Bit(s) | Description |
---|---|
[5:0] | Fault status bits. |
[8:6] | UNK/SBZP. |
[9] | On taking a Prefetch Abort exception, this bit is set to 1 to indicate use of the Long-descriptor translation table format. |
[11:10] | UNK/SBZP. |
[12] | External abort type. This bit can provide an implementation defined classification of external aborts. For aborts other than external aborts this bit always returns 0. |
[31:13] | UNK/SBZP. |
In this format, the fault status bits ([5:0]) encode the source of the Prefetch Abort exception as follows.
All encodings not shown in the table are reserved.
Value | Source |
---|---|
0x05 | Translation fault (MMU fault). First level. |
0x06 | Translation fault (MMU fault). Second level. |
0x07 | Translation fault (MMU fault). Third level. |
0x09 | Access flag fault (MMU fault). First level. |
0x0A | Access flag fault (MMU fault). Second level. |
0x0B | Access flag fault (MMU fault). Third level. |
0x0D | Permission fault (MMU fault). First level. |
0x0E | Permission fault (MMU fault). Second level. |
0x0F | Permission fault (MMU fault). Third level. |
0x10 | Synchronous external abort. |
0x15 | Synchronous external abort on translation table walk. First level. |
0x16 | Synchronous external abort on translation table walk. Second level. |
0x17 | Synchronous external abort on translation table walk. Third level. |
0x18 | Synchronous parity error on memory access. |
0x1D | Synchronous parity error on memory access on translation table walk. First level. |
0x1E | Synchronous parity error on memory access on translation table walk. Second level. |
0x1F | Synchronous parity error on memory access on translation table walk. Third level. |
0x21 | Alignment fault. |
0x22 | Debug event. |
0x30 | TLB conflict abort. |
0x3D | Domain fault. First level. |
0x3E | Domain fault. Second level. |
Instruction Fault Address Register
The Instruction Fault Address Register (IFAR) is a 32-bit register and can be accessed by reads to the CP15 registers with <opc1> set to 0, <CRn> set to c6, <CRm> set to c0, and <opc2> set to 2:
MRC p15, 0, <Rt>, c6, c0, 2 ; Read IFAR into Rt
The IFAR holds the address (PMSAv7) / virtual address (VMSAv7) of the faulting access that caused a synchronous Prefetch Abort exception.
Its content is invalid e.g. for asynchronous Prefetch Abort exceptions.
Auxiliary Instruction Fault Status Register
The Auxiliary Instruction Fault Status Register (AIFSR) is a 32-bit register and can be accessed by reads to the CP15 registers with <opc1> set to 0, <CRn> set to c5, <CRm set to c1, and <opc2> set to 1:
MRC p15, 0, %[Reg], c5, c1, 1 ; Read AIFSR into Rt
The content and use of this register is implementation defined.
An implementation can use this register to return additional fault status information.
Data Fault Status Register
The Data Fault Status Register (DFSR) is a 32-bit register and can be accessed by reads to the CP15 registers with <opc1> set to 0, <CRn> set to c5, <CRm set to c0, and <opc2> set to 0:
MRC p15, 0, <Rt>, c5, c0, 0 ; Read DFSR into Rt
The fault status bits contained in this register may be used to determine the source of the Data Abort exception.
Three different formats of the DFSR exist, one for PMSAv7 implementations (Cortex-R) and two for VMSAv7 implementations (Cortex-A).
The latter depend on whether the short-descriptor translation table format or the long-descriptor translation table format is used by the implementation.
DFSR format in a PMSAv7 implementation
Bit(s) | Description |
---|---|
[3:0] | Fault status bits[3:0]. |
[9:4] | UNK/SBZP. |
[10] | Fault status bit[4]. |
[11] | Write not Read bit. On a synchronous exception, indicates whether the abort was caused by a write or a read access. For faults on CP15 cache maintenance operations, including the address translation operations, this bit always returns a value of 1. This bit is unknown on an asynchronous Data Abort exception, or on a Data Abort exception caused by a debug exception. |
[12] | External abort type. This bit can provide an implementation defined classification of external aborts. For aborts other than external aborts this bit always returns 0. |
[31:13] | UNK/SBZP. |
In this format, the fault status bits ([10, 3:0]) encode the source of the Data Abort exception as follows.
All encodings not shown in the table are reserved.
Value | Source |
---|---|
0x00 | Background fault (MPU fault). |
0x01 | Alignment fault. |
0x02 | (A)synchronous Watchpoint debug event. |
0x08 | Synchronous external abort. |
0x0D | Permission fault (MPU fault). |
0x14 | Implementation defined (Lock-down). |
0x16 | Asynchronous external abort. |
0x18 | Asynchronous parity error on memory access. |
0x19 | Synchronous parity error on memory access. |
0x1A | Implementation defined (Co-processor abort). |
DFSR format when using the Short-descriptor translation table format in a VMSAv7 implementation
Bit(s) | Description |
---|---|
[3:0] | Fault status bits[3:0]. |
[7:4] | The domain of the fault address. From ARMv7, ARM deprecates any use of this field. This field is unknown on a Data Abort exception caused by a debug exception, or caused by a Permission fault in an implementation includes the Large Physical Address Extension. |
[8] | UNK/SBZP. |
[9] | If the implementation does not include the Large Physical Address Extension: UNK/SBZP. |
If the implementation includes the Large Physical Address Extension: On taking a Data Abort exception, this bit is set to 0 to indicate use of the Short-descriptor translation table formats. | |
[10] | Fault status bit[4]. |
[11] | Write not Read bit. On a synchronous exception, indicates whether the abort was caused by a write or a read access. For faults on CP15 cache maintenance operations, including the address translation operations, this bit always returns a value of 1. This bit is unknown on an asynchronous Data Abort exception, or on a Data Abort exception caused by a debug exception. |
[12] | External abort type. This bit can provide an implementation defined classification of external aborts. For aborts other than external aborts this bit always returns 0. |
[13] | If the implementation does not include the Large Physical Address Extension: UNK/SBZP. |
If the implementation includes the Large Physical Address Extension: Cache maintenance fault. For synchronous faults, this bit indicates whether a cache maintenance operation generated the fault. On an asynchronous fault, this bit is unknown. | |
[31:14] | UNK/SBZP. |
In this format, the fault status bits ([10, 3:0]) encode the source of the Data Abort exception as follows.
All encodings not shown in the table are reserved.
Value | Source |
---|---|
0x01 | Alignment fault. |
0x02 | Debug event. |
0x03 | Access flag fault (MMU fault). First level. |
0x04 | Fault on instruction cache maintenance. |
0x05 | Translation fault (MMU fault). First level. |
0x06 | Access flag fault (MMU fault). Second level. |
0x07 | Translation fault (MMU fault). Second level. |
0x08 | Synchronous external abort. |
0x09 | Domain fault (MMU fault). First level. |
0x0B | Domain fault (MMU fault). Second level. |
0x0C | Synchronous external abort on translation table walk. First level. |
0x0D | Permission fault (MMU fault). First level. |
0x0E | Synchronous external abort on translation table walk. Second level. |
0x0F | Permission fault (MMU fault). Second level. |
0x10 | TLB conflict abort. |
0x14 | Implementation defined (Lock-down). |
0x16 | Asynchronous external abort. |
0x18 | Asynchronous parity error on memory access. |
0x19 | Synchronous parity error on memory access. |
0x1A | Implementation defined (Co-processor abort). |
0x1C | Synchronous parity error on translation table walk. First level. |
0x1E | Synchronous parity error on translation table walk. Second level. |
DFSR format when using the Long-descriptor translation table format in a VMSAv7 implementation
Bit(s) | Description |
---|---|
[5:0] | Fault status bits. |
[8:6] | UNK/SBZP. |
[9] | On taking a Data Abort exception, this bit is set to 1 to indicate use of the Long-descriptor translation table formats. |
[10] | UNK/SBZP. |
[11] | Write not Read bit. On a synchronous exception, indicates whether the abort was caused by a write or a read access. For faults on CP15 cache maintenance operations, including the address translation operations, this bit always returns a value of 1. This bit is unknown on an asynchronous Data Abort exception, or on a Data Abort exception caused by a debug exception. |
[12] | External abort type. This bit can provide an implementation defined classification of external aborts. For aborts other than external aborts this bit always returns 0. |
[13] | Cache maintenance fault. For synchronous faults, this bit indicates whether a cache maintenance operation generated the fault. On an asynchronous fault, this bit is unknown. |
[31:14] | UNK/SBZP. |
In this format, the fault status bits ([5:0]) encode the source of the Data Abort exception as follows.
All encodings not shown in the table are reserved.
Value | Source |
---|---|
0x05 | Translation fault (MMU fault). First level. |
0x06 | Translation fault (MMU fault). Second level. |
0x07 | Translation fault (MMU fault). Third level. |
0x09 | Access flag fault (MMU fault). First level. |
0x0A | Access flag fault (MMU fault). Second level. |
0x0B | Access flag fault (MMU fault). Third level. |
0x0D | Permission fault (MMU fault). First level. |
0x0E | Permission fault (MMU fault). Second level. |
0x0F | Permission fault (MMU fault). Third level.. |
0x10 | Synchronous external abort. |
0x11 | Asynchronous external abort. |
0x15 | Synchronous external abort on translation table walk. First level. |
0x16 | Synchronous external abort on translation table walk. Second level. |
0x17 | Synchronous external abort on translation table walk. Third level. |
0x18 | Synchronous parity error on memory access. |
0x19 | Asynchronous parity error on memory access. |
0x1D | Synchronous parity error on memory access on translation table walk. First level. |
0x1E | Synchronous parity error on memory access on translation table walk. Second level. |
0x1F | Synchronous parity error on memory access on translation table walk. Third level. |
0x21 | Alignment fault. |
0x22 | Debug event. |
0x30 | TLB conflict abort. |
0x34 | Implementation defined (Lock-down). |
0x3A | Implementation defined (Co-processor abort). |
0x3D | Domain fault. First level. |
0x3E | Domain fault. Second level. |
Data Fault Address Register
The Data Fault Address Register (DFAR) is a 32-bit register and can be accessed by reads to the CP15 registers with <opc1> set to 0, <CRn> set to c6, <CRm> set to c0, and <opc2> set to 0:
MRC p15, 0, <Rt>, c6, c0, 0 ; Read DFAR into Rt
The DFAR holds the address (PMSAv7) / virtual address (VMSAv7) of the faulting access that caused a synchronous Data Abort exception.
Its content is invalid e.g. for asynchronous Data Abort exceptions.
Auxiliary Data Fault Status Register
The Auxiliary Data Fault Status Register (ADFSR) is a 32-bit register and can be accessed by reads to the CP15 registers with <opc1> set to 0, <CRn> set to c5, <CRm set to c1, and <opc2> set to 0:
MRC p15, 0, %[Reg], c5, c1, 0 ; Read ADFSR into Rt
The content and use of this register is implementation defined.
An implementation can use this register to return additional fault status information.
Example Fault analysis
Unaligned Access
/*********************************************************************
*
* _UnalignedAccess()
*
* Function description
* Trigger a Data Abort exception by an unaligned word access.
*
* Additional Information
* Data Abort is triggered immediately on the read instruction.
*
* DAbortRegs <struct>
* - DFSR <struct>
* - DFSR.word 0x000000f1
* - DFSR.bits_short <struct>
* - FS_3_0 0x1
* - Domain 0xf
* - LPAE 0x0 <--- Short format is used
* - FS_4 0x0
* - WnR 0x0 <--- Fault caused by read access
* - ExT 0x0
* - CM 0x0
* - DFSR.bits_long <struct>
* - FaultSource_Short S_ALIGNMENT_FAULT <--- Alignment fault detected
* - FaultSource_Long L_FORMAT_NOT_USED
* - DFAR <struct>
* - DFAR 0x0013ffff <--- Fault was caused by accessing this address
* - Valid VALID <--- Value contained in DFAR is valid on alignment faults
* - ADFSR 0x00000000
* - ExceptionReturn 0xfc029982 <--- Address that holds the faulting instruction
*/
static int _UnalignedAccess(void) {
int r;
volatile unsigned int* p;
p = (unsigned int*)0x0013FFFF;
// F64F70FF movw r0, #0xFFFF
// F2C00013 movt r0, #19 <--- Not a word aligned address
r = *p;
// 6800 ldr r0, [r0] <--- Load word from unaligned address raises exception
return r;
}
File listing
The system state that led to a Prefetch Abort or a Data Abort exception can be analyzed with the SEGGER Prefetch Abort and Data Abort Handlers, which collect the contents of the exception fault registers described above.
On the other hand, in order to determine the cause of an Undefined Instruction exception, applications should analyze the instruction indicated by the return link in the LR on exception entry.
SEGGER Prefetch Abort Handler
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2023 SEGGER Microcontroller GmbH *
* *
* Internet: segger.com Support: support_embos@segger.com *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* conditions are met: *
* *
* - Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* *
* - Neither the name of SEGGER Microcontroller GmbH *
* nor the names of its contributors may be used to endorse or *
* promote products derived from this software without specific *
* prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. *
* IN NO EVENT SHALL SEGGER Microcontroller GmbH BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
* DAMAGE. *
* *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : SEGGER_PAbortHandler.c
Purpose : Generic SEGGER Prefetch Abort handler for Cortex-A/R
Additional information:
This Prefetch Abort handler enables user-friendly analysis of
Prefetch Aborts in debug configurations.
If a release configuration requires handling of Prefetch Aborts,
a specific Prefetch Abort handler should be included instead,
which for example issues a reset or turns on an error LED.
Literature:
[1] ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition
\\fileserver.segger.local\Techinfo\Company\ARM\ArchitectureV7\DDI0406C_d_ARMv7-AR_ArchitectureReference.pdf
*/
/*********************************************************************
*
* Defines
*
**********************************************************************
*/
#ifndef DEBUG // Should be overwritten by project settings
#define DEBUG (0) // in debug builds
#endif
#if ((defined(__SEGGER_CC__) && ( defined(__ARM_ARCH_7A__) )) \
|| (defined(__clang__) && ( defined(__ARM_ARCH_7A__) )) \
|| (defined(__GNUC__) && ( defined(__ARM_ARCH_7A__) )) \
|| (defined(__ICCARM__) && ((defined(__ARM7A__) && (__CORE__ == __ARM7A__)))) \
|| (defined(__CC_ARM) && ( defined(__TARGET_ARCH_7_A) )))
#define ARMv7A (1)
#elif ((defined(__SEGGER_CC__) && ( defined(__ARM_ARCH_7R__) )) \
|| (defined(__clang__) && ( defined(__ARM_ARCH_7R__) )) \
|| (defined(__GNUC__) && ( defined(__ARM_ARCH_7R__) )) \
|| (defined(__ICCARM__) && ((defined(__ARM7R__) && (__CORE__ == __ARM7R__)))) \
|| (defined(__CC_ARM) && ( defined(__TARGET_ARCH_7_R) )))
#define ARMv7R (1)
#else
#error "This handler currently supports ARMv7-A and ARMv7-R only."
#endif
/*********************************************************************
*
* Typedefs
*
**********************************************************************
*/
#if (ARMv7A == 1)
/*********************************************************************
*
* VMSAv7 instruction fault sources when address translation
* is using the Short-descriptor translation table format.
* See [1]: Table B3-23, Short-descriptor format FSR encodings
*/
typedef enum {
S_DEBUG_EVENT = 0x02u, // Debug event.
S_ACCESS_FLAG_FAULT_L1 = 0x03u, // Access flag fault (MMU fault). First level.
S_TRANSLATION_FAULT_L1 = 0x05u, // Translation fault (MMU fault). First level.
S_ACCESS_FLAG_FAULT_L2 = 0x06u, // Access flag fault (MMU fault). Second level.
S_TRANSLATION_FAULT_L2 = 0x07u, // Translation fault (MMU fault). Second level.
S_SYNC_EXTERNAL_ABORT = 0x08u, // Synchronous external abort.
S_DOMAIN_FAULT_L1 = 0x09u, // Domain fault (MMU fault). First level.
S_DOMAIN_FAULT_L2 = 0x0Bu, // Domain fault (MMU fault). Second level.
S_SYNC_EXTERNAL_ABORT_TT_L1 = 0x0Cu, // Synchronous external abort on translation table walk. First level.
S_PERMISSION_FAULT_L1 = 0x0Du, // Permission fault (MMU fault). First level.
S_SYNC_EXTERNAL_ABORT_TT_L2 = 0x0Eu, // Synchronous external abort on translation table walk. Second level.
S_PERMISSION_FAULT_L2 = 0x0Fu, // Permission fault (MMU fault). Second level.
S_TLB_CONFLICT_ABORT = 0x10u, // TLB conflict abort.
S_LOCKDOWN = 0x14u, // Implementation defined (Lock-down).
S_SYNC_PARITY_ERROR = 0x19u, // Synchronous parity error on memory access.
S_COPROCESSOR_ABORT = 0x1Au, // Implementation defined (Co-processor abort).
S_SYNC_PARITY_ERROR_TT_L1 = 0x1Cu, // Synchronous parity error on translation table walk. First level.
S_SYNC_PARITY_ERROR_TT_L2 = 0x1Eu, // Synchronous parity error on translation table walk. Second level.
S_FORMAT_NOT_USED = 0xDEADBEEFu
} INSTRUCTION_FAULT_SOURCE_SHORT_FORMAT;
/*********************************************************************
*
* VMSAv7 instruction fault sources when address translation
* is using the long-descriptor translation table format.
* See [1]: Table B3-24, Long-descriptor format FSR encodings
* and Table B3-25, Use of LL bits to encode the lookup level
*/
typedef enum {
L_TRANSLATION_FAULT_L1 = 0x05u, // Translation fault (MMU fault). First level.
L_TRANSLATION_FAULT_L2 = 0x06u, // Translation fault (MMU fault). Second level.
L_TRANSLATION_FAULT_L3 = 0x07u, // Translation fault (MMU fault). Third level.
L_ACCESS_FLAG_FAULT_L1 = 0x09u, // Access flag fault (MMU fault). First level.
L_ACCESS_FLAG_FAULT_L2 = 0x0Au, // Access flag fault (MMU fault). Second level.
L_ACCESS_FLAG_FAULT_L3 = 0x0Bu, // Access flag fault (MMU fault). Third level.
L_PERMISSION_FAULT_L1 = 0x0Du, // Permission fault (MMU fault). First level.
L_PERMISSION_FAULT_L2 = 0x0Eu, // Permission fault (MMU fault). Second level.
L_PERMISSION_FAULT_L3 = 0x0Fu, // Permission fault (MMU fault). Third level.
L_SYNC_EXTERNAL_ABORT = 0x10u, // Synchronous external abort.
L_SYNC_EXTERNAL_ABORT_TT_L1 = 0x15u, // Synchronous external abort on translation table walk. First level.
L_SYNC_EXTERNAL_ABORT_TT_L2 = 0x16u, // Synchronous external abort on translation table walk. Second level.
L_SYNC_EXTERNAL_ABORT_TT_L3 = 0x17u, // Synchronous external abort on translation table walk. Third level.
L_SYNC_PARITY_ERROR = 0x18u, // Synchronous parity error on memory access.
L_SYNC_PARITY_ERROR_TT_L1 = 0x1Du, // Synchronous parity error on memory access on translation table walk. First level.
L_SYNC_PARITY_ERROR_TT_L2 = 0x1Eu, // Synchronous parity error on memory access on translation table walk. Second level.
L_SYNC_PARITY_ERROR_TT_L3 = 0x1Fu, // Synchronous parity error on memory access on translation table walk. Third level.
L_ALIGNMENT_FAULT = 0x21u, // Alignment fault.
L_DEBUG_EVENT = 0x22u, // Debug event.
L_TLB_CONFLICT_ABORT = 0x30u, // TLB conflict abort.
L_DOMAIN_FAULT_L1 = 0x3Du, // Domain fault. First level.
L_DOMAIN_FAULT_L2 = 0x3Eu, // Domain fault. Second level.
L_FORMAT_NOT_USED = 0xDEADBEEFu
} INSTRUCTION_FAULT_SOURCE_LONG_FORMAT;
#elif (ARMv7R == 1)
/*********************************************************************
*
* PMSAv7 instruction fault sources
* See [1]: Table B5-7, PMSAv7 IFSR encodings
*/
typedef enum {
BACKGROUND_FAULT = 0x00u, // Background fault (MPU fault).
ALIGNMENT_FAULT = 0x01u, // Alignment fault.
DEBUG_EVENT = 0x02u, // Debug event that generates a Prefetch Abort exception.
SYNC_EXTERNAL_ABORT = 0x08u, // Synchronous external abort.
PERMISSION_FAULT = 0x0Du, // Permission fault (MPU fault).
LOCKDOWN = 0x14u, // Implementation defined (Lock-down).
SYNC_PARITY_ERROR = 0x19u, // Synchronous parity error on memory access.
COPROCESSOR_ABORT = 0x1Au // Implementation defined (Co-processor abort).
} INSTRUCTION_FAULT_SOURCE;
#endif // ARMv7A or ARMv7R
typedef enum {
INVALID = 0x0u,
VALID = 0x1u
} IFAR_VALID;
/*********************************************************************
*
* Prototypes
*
**********************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
void pabort_handler(void);
#ifdef __cplusplus
}
#endif
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
#if (DEBUG != 0)
static volatile unsigned int _Continue; // Set this variable to 1 to run further
volatile static struct {
#if (ARMv7A == 1)
//
// The following struct is for a VMSAv7 implementation.
// It covers the short-descriptor translation table format (bits_short) and the long-descriptor translation table format (bits_long) for a VMSAv7 implementation that does include the Large Physical Address Extension.
// For a VMSAv7 implementation that does not include the Large Physical Address Extension, this pabort_handler() implementation will use bits_short, too, since that format only differs in the additional LPAE bit.
//
struct {
union {
unsigned int word;
//
// See [1]: B4.1.96 IFSR, Instruction Fault Status Register, VMSA; IFSR format when using the Short-descriptor translation table format
//
struct {
unsigned int FS_3_0 : 4; // [3:0] Fault status bits[3:0].
unsigned int : 5; // [8:4] UNK/SBZP.
unsigned int LPAE : 1; // [9] If the implementation does not include the Large Physical Address Extension: UNK/SBZP. If the implementation includes the Large Physical Address Extension: On taking an exception, this bit is set to 0 to indicate use of the Short-descriptor translation table format. Hardware does not interpret this bit to determine the behavior of the memory system, and therefore software can set this bit to 0 or 1 without affecting operation. Unless the register has been updated to report a fault, a subsequent read of the register returns the value written to it.
unsigned int FS_4 : 1; // [10] Fault status bit[4].
unsigned int : 1; // [11] UNK/SBZP.
unsigned int ExT : 1; // [12] External abort type. This bit can provide an implementation defined classification of external aborts. For aborts other than external aborts this bit always returns 0.
unsigned int : 19; // [31:13] UNK/SBZP.
} bits_short;
//
// See [1]: B4.1.96 IFSR, Instruction Fault Status Register, VMSA; IFSR format when using the Long-descriptor translation table format
//
struct {
unsigned int Status : 6; // [5:0] Fault status bits.
unsigned int : 3; // [8:6] UNK/SBZP.
unsigned int LPAE : 1; // [9] On taking an exception, this bit is set to 1 to indicate use of the Long-descriptor translation table format. Hardware does not interpret this bit to determine the behavior of the memory system, and therefore software can set this bit to 0 or 1 without affecting operation. Unless the register has been updated to report a fault, a subsequent read of the register returns the value written to it.
unsigned int : 2; // [11:10] UNK/SBZP.
unsigned int ExT : 1; // [12] External abort type. This bit can provide an implementation defined classification of external aborts. For aborts other than external aborts this bit always returns 0.
unsigned int : 19; // [31:13] UNK/SBZP.
} bits_long;
} IFSR;
INSTRUCTION_FAULT_SOURCE_SHORT_FORMAT FaultSource_Short; // Decoded Fault Source IFSR.FS[4:0], if applicable.
INSTRUCTION_FAULT_SOURCE_LONG_FORMAT FaultSource_Long ; // Decoded Fault Source IFSR.Status, if applicable.
} IFSR;
#elif (ARMv7R == 1)
//
// The following struct is for a PMSAv7 implementation.
//
struct {
union {
unsigned int word;
//
// See [1]: B6.1.59 IFSR, Instruction Fault Status Register, PMSA
//
struct {
unsigned int FS_3_0 : 4; // [3:0] Fault status bits[3:0].
unsigned int : 6; // [9:4] UNK/SBZP.
unsigned int FS_4 : 1; // [10] Fault status bit[4].
unsigned int : 1; // [11] UNK/SBZP.
unsigned int ExT : 1; // [12] External abort type. This bit can provide an implementation defined classification of external aborts. For aborts other than external aborts this bit always returns 0.
unsigned int : 19; // [31:13] UNK/SBZP.
} bits;
} IFSR;
INSTRUCTION_FAULT_SOURCE FaultSource; // Decoded Fault Source IFSR.FS[4:0].
} IFSR;
#endif // ARMv7A or ARMv7R
struct {
unsigned int IFAR; // See [1]: B4.1.95 IFAR, Instruction Fault Address Register, VMSA; and B6.1.59 IFSR, Instruction Fault Status Register, PMSA
IFAR_VALID Valid; // See [1]: Table B3-26, Effect of a fault taken to a PL1 mode on the reporting registers; and Table B5-7, PMSAv7 IFSR encodings
} IFAR;
unsigned int AIFSR; // Auxiliary Instruction Fault Status Register, can return additional implementation defined fault status information.
unsigned int ExceptionReturn; // Applications may e.g. use this value to return from this pabort_handler by executing __asm volatile("SUBS pc, lr, #4;"); Whether this is possible depends on the type of prefetch abort and whether the application relies on the proper execution of the instruction that caused the abort.
} PAbortRegs;
#endif // (DEBUG != 0)
/*********************************************************************
*
* Global functions
*
**********************************************************************
*/
/*********************************************************************
*
* pabort_handler()
*
* Function description
* Prefetch abort handler which is called when
* a prefetch abort exception occurs.
*/
void pabort_handler(void) {
#if (DEBUG != 0)
#if (ARMv7A == 1)
//
// Read Instruction Fault Status register.
//
__asm volatile("MRC p15, 0, %[Reg], c5, c0, 1;" : [Reg] "=r" (PAbortRegs.IFSR.IFSR.word) : : "memory");
//
// Decode the fault source. Initially check bit[9], LPAE, on whether short or long descriptor format is being used.
// This bit reads 0 when the short and 1 when the long format is being used.
//
if ((PAbortRegs.IFSR.IFSR.word & (1u << 9)) == 0u) {
//
// Short descriptor format is being used -> decode IFSR.FS.
//
PAbortRegs.IFSR.FaultSource_Short = ((PAbortRegs.IFSR.IFSR.word >> 5) & 0x10u) + (PAbortRegs.IFSR.IFSR.word & 0x0Fu);
PAbortRegs.IFSR.FaultSource_Long = L_FORMAT_NOT_USED;
//
// Mark if IFAR is valid.
// See [1]: Table B3-26, Effect of a fault taken to a PL1 mode on the reporting registers
//
switch (PAbortRegs.IFSR.FaultSource_Short) {
case S_ACCESS_FLAG_FAULT_L1:
case S_TRANSLATION_FAULT_L1:
case S_ACCESS_FLAG_FAULT_L2:
case S_TRANSLATION_FAULT_L2:
case S_SYNC_EXTERNAL_ABORT:
case S_DOMAIN_FAULT_L1:
case S_DOMAIN_FAULT_L2:
case S_SYNC_EXTERNAL_ABORT_TT_L1:
case S_PERMISSION_FAULT_L1:
case S_SYNC_EXTERNAL_ABORT_TT_L2:
case S_PERMISSION_FAULT_L2:
case S_TLB_CONFLICT_ABORT:
case S_LOCKDOWN:
case S_SYNC_PARITY_ERROR:
case S_COPROCESSOR_ABORT:
case S_SYNC_PARITY_ERROR_TT_L1:
case S_SYNC_PARITY_ERROR_TT_L2:
PAbortRegs.IFAR.Valid = VALID;
break;
case S_DEBUG_EVENT:
default: // Reserved encoding, should never happen.
PAbortRegs.IFAR.Valid = INVALID;
break;
}
} else {
//
// Long descriptor format is being used -> decode IFSR.Status.
//
PAbortRegs.IFSR.FaultSource_Long = (PAbortRegs.IFSR.IFSR.word & 0x3Fu);
PAbortRegs.IFSR.FaultSource_Short = S_FORMAT_NOT_USED;
//
// Mark if IFAR is valid.
// See [1]: Table B3-26, Effect of a fault taken to a PL1 mode on the reporting registers
//
switch (PAbortRegs.IFSR.FaultSource_Long) {
case L_TRANSLATION_FAULT_L1:
case L_TRANSLATION_FAULT_L2:
case L_TRANSLATION_FAULT_L3:
case L_ACCESS_FLAG_FAULT_L1:
case L_ACCESS_FLAG_FAULT_L2:
case L_ACCESS_FLAG_FAULT_L3:
case L_PERMISSION_FAULT_L1:
case L_PERMISSION_FAULT_L2:
case L_PERMISSION_FAULT_L3:
case L_SYNC_EXTERNAL_ABORT:
case L_SYNC_EXTERNAL_ABORT_TT_L1:
case L_SYNC_EXTERNAL_ABORT_TT_L2:
case L_SYNC_EXTERNAL_ABORT_TT_L3:
case L_SYNC_PARITY_ERROR:
case L_SYNC_PARITY_ERROR_TT_L1:
case L_SYNC_PARITY_ERROR_TT_L2:
case L_SYNC_PARITY_ERROR_TT_L3:
case L_ALIGNMENT_FAULT:
case L_TLB_CONFLICT_ABORT:
case L_DOMAIN_FAULT_L1:
case L_DOMAIN_FAULT_L2:
PAbortRegs.IFAR.Valid = VALID;
break;
case L_DEBUG_EVENT:
default: // Reserved encoding, should never happen.
PAbortRegs.IFAR.Valid = INVALID;
break;
}
}
#elif (ARMv7R == 1)
//
// Read Instruction Fault Status register.
//
__asm volatile("MRC p15, 0, %[Reg], c5, c0, 1;" : [Reg] "=r" (PAbortRegs.IFSR.IFSR.word) : : "memory");
//
// Decode the fault source.
//
PAbortRegs.IFSR.FaultSource = ((PAbortRegs.IFSR.IFSR.word >> 5) & 0x10u) + (PAbortRegs.IFSR.IFSR.word & 0x0Fu);
//
// Mark if IFAR is valid.
// See [1]: Table B5-7, PMSAv7 IFSR encodings
//
switch (PAbortRegs.IFSR.FaultSource) {
case BACKGROUND_FAULT:
case ALIGNMENT_FAULT:
case SYNC_EXTERNAL_ABORT:
case PERMISSION_FAULT:
case SYNC_PARITY_ERROR:
PAbortRegs.IFAR.Valid = VALID;
break;
case DEBUG_EVENT:
case LOCKDOWN:
case COPROCESSOR_ABORT:
default: // Reserved encoding, should never happen.
PAbortRegs.IFAR.Valid = INVALID;
break;
}
#endif // ARMv7A or ARMv7R
//
// Read Auxiliary Instruction Fault Status Register.
//
__asm volatile("MRC p15, 0, %[Reg], c5, c1, 1;" : [Reg] "=r" (PAbortRegs.AIFSR) : : "memory");
//
// Read Instruction Fault Address Register.
//
__asm volatile("MRC p15, 0, %[Reg], c6, c0, 2;" : [Reg] "=r" (PAbortRegs.IFAR.IFAR) : : "memory");
//
// Recover PC value on exception entry.
//
__asm volatile("SUB %[Reg], lr, #4;" : [Reg] "=r" (PAbortRegs.ExceptionReturn) : : "memory");
//
// Halt execution.
//
_Continue = 0u;
do {
} while (_Continue == 0u);
#else // (DEBUG != 0)
//
// If this module is included in a release configuration, simply stay in the pabort_handler().
//
do {
} while (1);
#endif
}
/*************************** End of file ****************************/
SEGGER Data Abort Handler
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2023 SEGGER Microcontroller GmbH *
* *
* Internet: segger.com Support: support_embos@segger.com *
* *
**********************************************************************
* *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or *
* without modification, are permitted provided that the following *
* conditions are met: *
* *
* - Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* *
* - Neither the name of SEGGER Microcontroller GmbH *
* nor the names of its contributors may be used to endorse or *
* promote products derived from this software without specific *
* prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. *
* IN NO EVENT SHALL SEGGER Microcontroller GmbH BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
* DAMAGE. *
* *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : SEGGER_DAbortHandler.c
Purpose : Generic SEGGER Data Abort handler for Cortex-A/R
Additional information:
This Data Abort handler enables user-friendly analysis of
Data Aborts in debug configurations.
If a release configuration requires handling of Data Aborts,
a specific Data Abort handler should be included instead,
which for example issues a reset or turns on an error LED.
Literature:
[1] ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition
\\fileserver.segger.local\Techinfo\Company\ARM\ArchitectureV7\DDI0406C_d_ARMv7-AR_ArchitectureReference.pdf
*/
/*********************************************************************
*
* Defines
*
**********************************************************************
*/
#ifndef DEBUG // Should be overwritten by project settings
#define DEBUG (0) // in debug builds
#endif
#if ((defined(__SEGGER_CC__) && ( defined(__ARM_ARCH_7A__) )) \
|| (defined(__clang__) && ( defined(__ARM_ARCH_7A__) )) \
|| (defined(__GNUC__) && ( defined(__ARM_ARCH_7A__) )) \
|| (defined(__ICCARM__) && ((defined(__ARM7A__) && (__CORE__ == __ARM7A__)))) \
|| (defined(__CC_ARM) && ( defined(__TARGET_ARCH_7_A) )))
#define ARMv7A (1)
#elif ((defined(__SEGGER_CC__) && ( defined(__ARM_ARCH_7R__) )) \
|| (defined(__clang__) && ( defined(__ARM_ARCH_7R__) )) \
|| (defined(__GNUC__) && ( defined(__ARM_ARCH_7R__) )) \
|| (defined(__ICCARM__) && ((defined(__ARM7R__) && (__CORE__ == __ARM7R__)))) \
|| (defined(__CC_ARM) && ( defined(__TARGET_ARCH_7_R) )))
#define ARMv7R (1)
#else
#error "This handler currently supports ARMv7-A and ARMv7-R only."
#endif
/*********************************************************************
*
* Typedefs
*
**********************************************************************
*/
#if (ARMv7A == 1)
/*********************************************************************
*
* VMSAv7 data fault sources when address translation
* is using the Short-descriptor translation table format.
* See [1]: Table B3-23, Short-descriptor format FSR encodings
*/
typedef enum {
S_ALIGNMENT_FAULT = 0x01u, // Alignment fault.
S_DEBUG_EVENT = 0x02u, // Debug event.
S_ACCESS_FLAG_FAULT_L1 = 0x03u, // Access flag fault (MMU fault). First level.
S_INST_MAINTENANCE_FAULT = 0x04u, // Fault on instruction cache maintenance.
S_TRANSLATION_FAULT_L1 = 0x05u, // Translation fault (MMU fault). First level.
S_ACCESS_FLAG_FAULT_L2 = 0x06u, // Access flag fault (MMU fault). Second level.
S_TRANSLATION_FAULT_L2 = 0x07u, // Translation fault (MMU fault). Second level.
S_SYNC_EXTERNAL_ABORT = 0x08u, // Synchronous external abort.
S_DOMAIN_FAULT_L1 = 0x09u, // Domain fault (MMU fault). First level.
S_DOMAIN_FAULT_L2 = 0x0Bu, // Domain fault (MMU fault). Second level.
S_SYNC_EXTERNAL_ABORT_TT_L1 = 0x0Cu, // Synchronous external abort on translation table walk. First level.
S_PERMISSION_FAULT_L1 = 0x0Du, // Permission fault (MMU fault). First level.
S_SYNC_EXTERNAL_ABORT_TT_L2 = 0x0Eu, // Synchronous external abort on translation table walk. Second level.
S_PERMISSION_FAULT_L2 = 0x0Fu, // Permission fault (MMU fault). Second level.
S_TLB_CONFLICT_ABORT = 0x10u, // TLB conflict abort.
S_LOCKDOWN = 0x14u, // Implementation defined (Lock-down).
S_ASYNC_EXTERNAL_ABORT = 0x16u, // Asynchronous external abort.
S_ASYNC_PARITY_ERROR = 0x18u, // Asynchronous parity error on memory access.
S_SYNC_PARITY_ERROR = 0x19u, // Synchronous parity error on memory access.
S_COPROCESSOR_ABORT = 0x1Au, // Implementation defined (Co-processor abort).
S_SYNC_PARITY_ERROR_TT_L1 = 0x1Cu, // Synchronous parity error on translation table walk. First level.
S_SYNC_PARITY_ERROR_TT_L2 = 0x1Eu, // Synchronous parity error on translation table walk. Second level.
S_FORMAT_NOT_USED = 0xDEADBEEFu
} DATA_FAULT_SOURCE_SHORT_FORMAT;
/*********************************************************************
*
* VMSAv7 data fault sources when address translation
* is using the long-descriptor translation table format
* See [1]: Table B3-24, Long-descriptor format FSR encodings
* and Table B3-25, Use of LL bits to encode the lookup level
*/
typedef enum {
L_TRANSLATION_FAULT_L1 = 0x05u, // Translation fault (MMU fault). First level.
L_TRANSLATION_FAULT_L2 = 0x06u, // Translation fault (MMU fault). Second level.
L_TRANSLATION_FAULT_L3 = 0x07u, // Translation fault (MMU fault). Third level.
L_ACCESS_FLAG_FAULT_L1 = 0x09u, // Access flag fault (MMU fault). First level.
L_ACCESS_FLAG_FAULT_L2 = 0x0Au, // Access flag fault (MMU fault). Second level.
L_ACCESS_FLAG_FAULT_L3 = 0x0Bu, // Access flag fault (MMU fault). Third level.
L_PERMISSION_FAULT_L1 = 0x0Du, // Permission fault (MMU fault). First level.
L_PERMISSION_FAULT_L2 = 0x0Eu, // Permission fault (MMU fault). Second level.
L_PERMISSION_FAULT_L3 = 0x0Fu, // Permission fault (MMU fault). Third level..
L_SYNC_EXTERNAL_ABORT = 0x10u, // Synchronous external abort.
L_ASYNC_EXTERNAL_ABORT = 0x11u, // Asynchronous external abort.
L_SYNC_EXTERNAL_ABORT_TT_L1 = 0x15u, // Synchronous external abort on translation table walk. First level.
L_SYNC_EXTERNAL_ABORT_TT_L2 = 0x16u, // Synchronous external abort on translation table walk. Second level.
L_SYNC_EXTERNAL_ABORT_TT_L3 = 0x17u, // Synchronous external abort on translation table walk. Third level.
L_SYNC_PARITY_ERROR = 0x18u, // Synchronous parity error on memory access.
L_ASYNC_PARITY_ERROR = 0x19u, // Asynchronous parity error on memory access.
L_SYNC_PARITY_ERROR_TT_L1 = 0x1Du, // Synchronous parity error on memory access on translation table walk. First level.
L_SYNC_PARITY_ERROR_TT_L2 = 0x1Eu, // Synchronous parity error on memory access on translation table walk. Second level.
L_SYNC_PARITY_ERROR_TT_L3 = 0x1Fu, // Synchronous parity error on memory access on translation table walk. Third level.
L_ALIGNMENT_FAULT = 0x21u, // Alignment fault.
L_DEBUG_EVENT = 0x22u, // Debug event.
L_TLB_CONFLICT_ABORT = 0x30u, // TLB conflict abort.
L_LOCKDOWN = 0x34u, // Implementation defined (Lock-down).
L_COPROCESSOR_ABORT = 0x3Au, // Implementation defined (Co-processor abort).
L_DOMAIN_FAULT_L1 = 0x3Du, // Domain fault. First level.
L_DOMAIN_FAULT_L2 = 0x3Eu, // Domain fault. Second level.
L_FORMAT_NOT_USED = 0xDEADBEEFu
} DATA_FAULT_SOURCE_LONG_FORMAT;
#elif (ARMv7R == 1)
/*********************************************************************
*
* PMSAv7 data fault sources
* See [1]: Table B5-8, PMSAv7 DFSR encodings
*/
typedef enum {
BACKGROUND_FAULT = 0x00u, // Background fault (MPU fault).
ALIGNMENT_FAULT = 0x01u, // Alignment fault.
DEBUG_EVENT = 0x02u, // (A)synchronous Watchpoint debug event.
SYNC_EXTERNAL_ABORT = 0x08u, // Synchronous external abort.
PERMISSION_FAULT = 0x0Du, // Permission fault (MPU fault).
LOCKDOWN = 0x14u, // Implementation defined (Lock-down).
ASYNC_EXTERNAL_ABORT = 0x16u, // Asynchronous external abort.
ASYNC_PARITY_ERROR = 0x18u, // Asynchronous parity error on memory access.
SYNC_PARITY_ERROR = 0x19u, // Synchronous parity error on memory access.
COPROCESSOR_ABORT = 0x1Au // Implementation defined (Co-processor abort).
} DATA_FAULT_SOURCE;
#endif // ARMv7A or ARMv7R
typedef enum {
INVALID = 0x0u,
VALID = 0x1u,
IMPLEMENTATION_DEFINED = 0x2u
} DFAR_VALID;
/*********************************************************************
*
* Prototypes
*
**********************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
void dabort_handler(void);
#ifdef __cplusplus
}
#endif
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
#if (DEBUG != 0)
static volatile unsigned int _Continue; // Set this variable to 1 to run further
volatile static struct {
#if (ARMv7A == 1)
//
// The following struct is for a VMSAv7 implementation.
// It covers the short-descriptor translation table format (bits_short) and the long-descriptor translation table format (bits_long) for a VMSAv7 implementation that does include the Large Physical Address Extension.
// For a VMSAv7 implementation that does not include the Large Physical Address Extension, this dabort_handler() implementation will use bits_short, too, since that format only differs in the additional LPAE and CM bits.
//
struct {
union {
unsigned int word;
//
// See [1]: B4.1.52: DFSR, Data Fault Status Register, VMSA; DFSR format when using the Short-descriptor translation table format
//
struct {
unsigned int FS_3_0 : 4; // [3:0] Fault status bits[3:0].
unsigned int Domain : 4; // [7:4] The domain of the fault address. From ARMv7, ARM deprecates any use of this field. This field is unknown on a Data Abort exception caused by a debug exception, or caused by a Permission fault in an implementation includes the Large Physical Address Extension.
unsigned int : 1; // [8] UNK/SBZP.
unsigned int LPAE : 1; // [9] If the implementation does not include the Large Physical Address Extension: UNK/SBZP. If the implementation includes the Large Physical Address Extension: On taking a Data Abort exception, this bit is set to 0 to indicate use of the Short-descriptor translation table formats. Hardware does not interpret this bit to determine the behavior of the memory system, and therefore software can set this bit to 0 or 1 without affecting operation. Unless the register has been updated to report a fault, a subsequent read of the register returns the value written to it.
unsigned int FS_4 : 1; // [10] Fault status bit[4].
unsigned int WnR : 1; // [11] Write not Read bit. On a synchronous exception, indicates whether the abort was caused by a write or a read access. For faults on CP15 cache maintenance operations, including the address translation operations, this bit always returns a value of 1. This bit is unknown on an asynchronous Data Abort exception, or on a Data Abort exception caused by a debug exception.
unsigned int ExT : 1; // [12] External abort type. This bit can provide an implementation defined classification of external aborts. For aborts other than external aborts this bit always returns 0.
unsigned int CM : 1; // [13] If the implementation does not include the Large Physical Address Extension: UNK/SBZP. If the implementation includes the Large Physical Address Extension: Cache maintenance fault. For synchronous faults, this bit indicates whether a cache maintenance operation generated the fault. On an asynchronous fault, this bit is unknown.
unsigned int : 18; // [31:14] UNK/SBZP.
} bits_short;
//
// See [1]: B4.1.52: DFSR, Data Fault Status Register, VMSA; DFSR format when using the Long-descriptor translation table format
//
struct {
unsigned int Status : 6; // [5:0] Fault status bits.
unsigned int : 3; // [8:6] UNK/SBZP.
unsigned int LPAE : 1; // [9] On taking a Data Abort exception, this bit is set to 1 to indicate use of the Long-descriptor translation table formats. Hardware does not interpret this bit to determine the behavior of the memory system, and therefore software can set this bit to 0 or 1 without affecting operation. Unless the register has been updated to report a fault, a subsequent read of the register returns the value written to it.
unsigned int : 1; // [10] UNK/SBZP.
unsigned int WnR : 1; // [11] Write not Read bit. On a synchronous exception, indicates whether the abort was caused by a write or a read access. For faults on CP15 cache maintenance operations, including the address translation operations, this bit always returns a value of 1. This bit is unknown on an asynchronous Data Abort exception, or on a Data Abort exception caused by a debug exception.
unsigned int ExT : 1; // [12] External abort type. This bit can provide an implementation defined classification of external aborts. For aborts other than external aborts this bit always returns 0.
unsigned int CM : 1; // [13] Cache maintenance fault. For synchronous faults, this bit indicates whether a cache maintenance operation generated the fault. On an asynchronous fault, this bit is unknown.
unsigned int : 18; // [31:14] UNK/SBZP.
} bits_long;
} DFSR;
DATA_FAULT_SOURCE_SHORT_FORMAT FaultSource_Short; // Decoded Fault Source DFSR.FS[4:0], if applicable.
DATA_FAULT_SOURCE_LONG_FORMAT FaultSource_Long; // Decoded Fault Source DFSR.Status, if applicable.
} DFSR;
#elif (ARMv7R == 1)
//
// The following struct is for a PMSAv7 implementation.
//
struct {
union {
unsigned int word;
//
// See [1]: B6.1.34 DFSR, Data Fault Status Register, PMSA
//
struct {
unsigned int FS_3_0 : 4; // [3:0] Fault status bits[3:0].
unsigned int : 6; // [9:4] UNK/SBZP.
unsigned int FS_4 : 1; // [10] Fault status bit[4].
unsigned int WnR : 1; // [11] Write not Read bit. On a synchronous exception, indicates whether the abort was caused by a write or a read access. For faults on CP15 cache maintenance operations, including the address translation operations, this bit always returns a value of 1. This bit is unknown on an asynchronous Data Abort exception, or on a Data Abort exception caused by a debug exception.
unsigned int ExT : 1; // [12] External abort type. This bit can provide an implementation defined classification of external aborts. For aborts other than external aborts this bit always returns 0.
unsigned int : 19; // [31:13] UNK/SBZP.
} bits;
} DFSR;
DATA_FAULT_SOURCE FaultSource; // Decoded Fault Source DFSR.FS[4:0].
} DFSR;
#endif // ARMv7A or ARMv7R
struct {
unsigned int DFAR; // See [1]: B4.1.51 DFAR, Data Fault Address Register, VMSA; and B6.1.33 DFAR, Data Fault Address Register, PMSA
DFAR_VALID Valid; // See [1]: Table B3-26, Effect of a fault taken to a PL1 mode on the reporting registers; and Table B5-8, PMSAv7 DFSR encodings
} DFAR;
unsigned int ADFSR; // Auxiliary Data Fault Status Register, can return additional implementation defined fault status information.
unsigned int ExceptionReturn; // Applications may e.g. use this value to return from this dabort_handler by executing __asm volatile("SUBS pc, lr, #8;"); Whether this is possible depends on the type of data abort and whether the application relies on the proper execution of the instruction that caused the abort.
} DAbortRegs;
#endif // (DEBUG != 0)
/*********************************************************************
*
* Global functions
*
**********************************************************************
*/
/*********************************************************************
*
* dabort_handler()
*
* Function description
* Data abort handler which is called when
* a data abort exception occurs.
*/
void dabort_handler(void) {
#if (DEBUG != 0)
#if (ARMv7A == 1)
//
// Read Data Fault Status register.
//
__asm volatile("MRC p15, 0, %[Reg], c5, c0, 0;" : [Reg] "=r" (DAbortRegs.DFSR.DFSR.word) : : "memory");
//
// Decode the fault source. Initially check bit[9], LPAE, on whether short or long descriptor format is being used.
// This bit reads 0 when the short and 1 when the long format is being used.
//
if ((DAbortRegs.DFSR.DFSR.word & (1u << 9)) == 0u) {
//
// Short descriptor format is being used -> decode DFSR.FS.
//
DAbortRegs.DFSR.FaultSource_Short = ((DAbortRegs.DFSR.DFSR.word >> 5) & 0x10u) + (DAbortRegs.DFSR.DFSR.word & 0x0Fu);
DAbortRegs.DFSR.FaultSource_Long = L_FORMAT_NOT_USED;
//
// Mark if DFAR is valid.
// See [1]: Table B3-26, Effect of a fault taken to a PL1 mode on the reporting registers
//
switch (DAbortRegs.DFSR.FaultSource_Short) {
case S_ALIGNMENT_FAULT:
case S_ACCESS_FLAG_FAULT_L1:
case S_INST_MAINTENANCE_FAULT:
case S_TRANSLATION_FAULT_L1:
case S_ACCESS_FLAG_FAULT_L2:
case S_TRANSLATION_FAULT_L2:
case S_SYNC_EXTERNAL_ABORT:
case S_DOMAIN_FAULT_L1:
case S_DOMAIN_FAULT_L2:
case S_SYNC_EXTERNAL_ABORT_TT_L1:
case S_PERMISSION_FAULT_L1:
case S_SYNC_EXTERNAL_ABORT_TT_L2:
case S_PERMISSION_FAULT_L2:
case S_TLB_CONFLICT_ABORT:
case S_LOCKDOWN:
case S_SYNC_PARITY_ERROR:
case S_COPROCESSOR_ABORT:
case S_SYNC_PARITY_ERROR_TT_L1:
case S_SYNC_PARITY_ERROR_TT_L2:
DAbortRegs.DFAR.Valid = VALID;
break;
case S_DEBUG_EVENT: // Depends on specific debug event and implemented debug interface.
DAbortRegs.DFAR.Valid = IMPLEMENTATION_DEFINED;
break;
case S_ASYNC_EXTERNAL_ABORT:
case S_ASYNC_PARITY_ERROR:
default: // Reserved encoding, should never happen.
DAbortRegs.DFAR.Valid = INVALID;
break;
}
} else {
//
// Long descriptor format is being used -> decode DFSR.Status.
//
DAbortRegs.DFSR.FaultSource_Long = (DAbortRegs.DFSR.DFSR.word & 0x3Fu);
DAbortRegs.DFSR.FaultSource_Short = S_FORMAT_NOT_USED;
//
// Mark if DFAR is valid.
// See [1]: Table B3-26, Effect of a fault taken to a PL1 mode on the reporting registers
//
switch (DAbortRegs.DFSR.FaultSource_Long) {
case L_TRANSLATION_FAULT_L1:
case L_TRANSLATION_FAULT_L2:
case L_TRANSLATION_FAULT_L3:
case L_ACCESS_FLAG_FAULT_L1:
case L_ACCESS_FLAG_FAULT_L2:
case L_ACCESS_FLAG_FAULT_L3:
case L_PERMISSION_FAULT_L1:
case L_PERMISSION_FAULT_L2:
case L_PERMISSION_FAULT_L3:
case L_SYNC_EXTERNAL_ABORT:
case L_SYNC_EXTERNAL_ABORT_TT_L1:
case L_SYNC_EXTERNAL_ABORT_TT_L2:
case L_SYNC_EXTERNAL_ABORT_TT_L3:
case L_SYNC_PARITY_ERROR:
case L_SYNC_PARITY_ERROR_TT_L1:
case L_SYNC_PARITY_ERROR_TT_L2:
case L_SYNC_PARITY_ERROR_TT_L3:
case L_ALIGNMENT_FAULT:
case L_TLB_CONFLICT_ABORT:
case L_LOCKDOWN:
case L_COPROCESSOR_ABORT:
case L_DOMAIN_FAULT_L1:
case L_DOMAIN_FAULT_L2:
DAbortRegs.DFAR.Valid = VALID;
break;
case L_DEBUG_EVENT: // Depends on specific debug event and implemented debug interface.
DAbortRegs.DFAR.Valid = IMPLEMENTATION_DEFINED;
break;
case L_ASYNC_EXTERNAL_ABORT:
case L_ASYNC_PARITY_ERROR:
default: // Reserved encoding, should never happen.
DAbortRegs.DFAR.Valid = INVALID;
break;
}
}
#elif (ARMv7R == 1)
//
// Read Data Fault Status register.
//
__asm volatile("MRC p15, 0, %[Reg], c5, c0, 0;" : [Reg] "=r" (DAbortRegs.DFSR.DFSR.word) : : "memory");
//
// Decode the fault source.
//
DAbortRegs.DFSR.FaultSource = ((DAbortRegs.DFSR.DFSR.word >> 5) & 0x10u) + (DAbortRegs.DFSR.DFSR.word & 0x0Fu);
//
// Mark if DFAR is valid.
// See [1]: Table B5-8, PMSAv7 DFSR encodings
//
switch (DAbortRegs.DFSR.FaultSource) {
case BACKGROUND_FAULT:
case ALIGNMENT_FAULT:
case SYNC_EXTERNAL_ABORT:
case PERMISSION_FAULT:
DAbortRegs.DFAR.Valid = VALID;
break;
case DEBUG_EVENT: // Depends on specific debug event and implemented debug interface.
case SYNC_PARITY_ERROR: // Implementation defined.
DAbortRegs.DFAR.Valid = IMPLEMENTATION_DEFINED;
break;
case LOCKDOWN:
case ASYNC_EXTERNAL_ABORT:
case ASYNC_PARITY_ERROR:
case COPROCESSOR_ABORT:
default: // Reserved encoding, should never happen.
DAbortRegs.DFAR.Valid = INVALID;
break;
}
#endif // ARMv7A or ARMv7R
//
// Read Auxiliary Data Fault Status Register.
//
__asm volatile("MRC p15, 0, %[Reg], c5, c1, 0;" : [Reg] "=r" (DAbortRegs.ADFSR) : : "memory");
//
// Read Data Fault Address Register.
//
__asm volatile("MRC p15, 0, %[Reg], c6, c0, 0;" : [Reg] "=r" (DAbortRegs.DFAR.DFAR) : : "memory");
//
// Recover PC value on exception entry.
//
__asm volatile("SUB %[Reg], lr, #8;" : [Reg] "=r" (DAbortRegs.ExceptionReturn) : : "memory");
//
// Halt execution.
//
_Continue = 0u;
do {
} while (_Continue == 0u);
#else // (DEBUG != 0)
//
// If this module is included in a release configuration, simply stay in the dabort_handler().
//
do {
} while (1);
#endif
}
/*************************** End of file ****************************/