1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _HARDWARE_EXCEPTION_H
8 #define _HARDWARE_EXCEPTION_H
9 
10 #include "pico.h"
11 #include "hardware/address_mapped.h"
12 
13 /** \file exception.h
14  *  \defgroup hardware_exception hardware_exception
15  *
16  * \brief Methods for setting processor exception handlers
17  *
18  * Exceptions are identified by a \ref exception_number which is a number from -15 to -1; these are the numbers relative to
19  * the index of the first IRQ vector in the vector table. (i.e. vector table index is exception_num plus 16)
20  *
21  * There is one set of exception handlers per core, so the exception handlers for each core as set by these methods are independent.
22  *
23  * \note That all exception APIs affect the executing core only (i.e. the core calling the function).
24  */
25 
26 // PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_EXCEPTION, Enable/disable assertions in the hardware_exception module, type=bool, default=0, group=hardware_exception
27 #ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_EXCEPTION
28 #ifdef PARAM_ASSERTIONS_ENABLED_EXCEPTION // backwards compatibility with SDK < 2.0.0
29 #define PARAM_ASSERTIONS_ENABLED_HARDWARE_EXCEPTION PARAM_ASSERTIONS_ENABLED_EXCEPTION
30 #else
31 #define PARAM_ASSERTIONS_ENABLED_HARDWARE_EXCEPTION 0
32 #endif
33 #endif
34 #ifdef __cplusplus
35 extern "C" {
36 #endif
37 
38 /*! \brief  Exception number definitions
39  *
40  * On Arm these are vector table indices:
41  *
42  * Name                  | Value | Exception
43  * ----------------------|-------|-----------------------
44  * NMI_EXCEPTION         | 2     | Non Maskable Interrupt
45  * HARDFAULT_EXCEPTION   | 3     | HardFault
46  * \if rp2350_specific
47  * MEMMANAGE_EXCEPTION   | 4     | MemManage
48  * BUSFAULT_EXCEPTION    | 5     | BusFault
49  * USAGEFAULT_EXCEPTION  | 6     | UsageFault
50  * SECUREFAULT_EXCEPTION | 7     | SecureFault
51  * \endif
52  * SVCALL_EXCEPTION      | 11    | SV Call
53  * PENDSV_EXCEPTION      | 14    | Pend SV
54  * SYSTICK_EXCEPTION     | 15    | System Tick
55  *
56  * \if rp2350_specific
57  * On RISC-V these are exception cause numbers:
58  *
59  * Name                    | Value | Exception
60  * ------------------------|-------|-----------------------------
61  * INSTR_ALIGN_EXCEPTION   | 0     | Instruction fetch misaligned
62  * INSTR_FAULT_EXCEPTION   | 1     | Instruction fetch bus fault
63  * INSTR_ILLEGAL_EXCEPTION | 2     | Invalid or illegal instruction
64  * EBREAK_EXCEPTION        | 3     | ebreak was not caught by an ex
65  * LOAD_ALIGN_EXCEPTION    | 4     | Load address not naturally ali
66  * LOAD_FAULT_EXCEPTION    | 5     | Load bus fault
67  * STORE_ALIGN_EXCEPTION   | 6     | Store or AMO address not natur
68  * STORE_FAULT_EXCEPTION   | 7     | Store or AMO bus fault
69  * ECALL_UMODE_EXCEPTION   | 8     | ecall was executed in U-mode
70  * ECALL_SMODE_EXCEPTION   | 9     | ecall was executed in S-mode
71  * ECALL_MMODE_EXCEPTION   | 11    | ecall was executed in M-mode
72  * \endif
73  *
74  * \ingroup hardware_exception
75  */
76 #ifdef __riscv
77 enum exception_number {
78     // Assigned to non-IRQ xcause values
79     MIN_EXCEPTION_NUM       = 0,
80     INSTR_ALIGN_EXCEPTION   = 0,  ///< Instruction fetch misaligned (never fires if C/Zca is present)
81     INSTR_FAULT_EXCEPTION   = 1,  ///< Instruction fetch bus fault
82     INSTR_ILLEGAL_EXCEPTION = 2,  ///< Invalid or illegal instruction
83     EBREAK_EXCEPTION        = 3,  ///< ebreak was not caught by an external debugger
84     LOAD_ALIGN_EXCEPTION    = 4,  ///< Load address not naturally aligned
85     LOAD_FAULT_EXCEPTION    = 5,  ///< Load bus fault
86     STORE_ALIGN_EXCEPTION   = 6,  ///< Store or AMO address not naturally aligned
87     STORE_FAULT_EXCEPTION   = 7,  ///< Store or AMO bus fault
88     ECALL_UMODE_EXCEPTION   = 8,  ///< ecall was executed in U-mode
89     ECALL_SMODE_EXCEPTION   = 9,  ///< ecall was executed in S-mode
90     ECALL_MMODE_EXCEPTION   = 11, ///< ecall was executed in M-mode
91     MAX_EXCEPTION_NUM       = 11
92 };
93 #else
94 enum exception_number {
95     // Assigned to VTOR indices
96     MIN_EXCEPTION_NUM = 2,
97     NMI_EXCEPTION = 2,         ///< Non Maskable Interrupt
98     HARDFAULT_EXCEPTION = 3,   ///< HardFault Interrupt
99 #if PICO_RP2350
100     MEMMANAGE_EXCEPTION = 4,   ///< MemManage Interrupt
101     BUSFAULT_EXCEPTION = 5,    ///< BusFault Interrupt
102     USAGEFAULT_EXCEPTION = 6,  ///< UsageFault Interrupt
103     SECUREFAULT_EXCEPTION = 7, ///< SecureFault Interrupt
104 #endif
105     SVCALL_EXCEPTION = 11,     ///< SV Call Interrupt
106     PENDSV_EXCEPTION = 14,     ///< Pend SV Interrupt
107     SYSTICK_EXCEPTION = 15,    ///< System Tick Interrupt
108     MAX_EXCEPTION_NUM = 15
109 };
110 #endif
111 
112 #define PICO_LOWEST_EXCEPTION_PRIORITY 0xff
113 #define PICO_HIGHEST_EXCEPTION_PRIORITY 0x00
114 
115 
116 /*! \brief Exception handler function type
117  *  \ingroup hardware_exception
118  *
119  * All exception handlers should be of this type, and follow normal ARM EABI register saving conventions
120  */
121 typedef void (*exception_handler_t)(void);
122 
123 /*! \brief  Set the exception handler for an exception on the executing core.
124  *  \ingroup hardware_exception
125  *
126  * This method will assert if an exception handler has been set for this exception number on this core via
127  * this method, without an intervening restore via exception_restore_handler.
128  *
129  * \note this method may not be used to override an exception handler that was specified at link time by
130  * providing a strong replacement for the weakly defined stub exception handlers. It will assert in this case too.
131  *
132  * \param num Exception number
133  * \param handler The handler to set
134  * \see exception_number
135  */
136 exception_handler_t exception_set_exclusive_handler(enum exception_number num, exception_handler_t handler);
137 
138 /*! \brief Restore the original exception handler for an exception on this core
139  *  \ingroup hardware_exception
140  *
141  * This method may be used to restore the exception handler for an exception on this core to the state
142  * prior to the call to exception_set_exclusive_handler(), so that exception_set_exclusive_handler()
143  * may be called again in the future.
144  *
145  * \param num Exception number \ref exception_number
146  * \param original_handler The original handler returned from \ref exception_set_exclusive_handler
147  * \see exception_set_exclusive_handler()
148  */
149 void exception_restore_handler(enum exception_number num, exception_handler_t original_handler);
150 
151 /*! \brief Get the current exception handler for the specified exception from the currently installed vector table
152  * of the execution core
153  *  \ingroup hardware_exception
154  *
155  * \param num Exception number
156  * \return the address stored in the VTABLE for the given exception number
157  */
158 exception_handler_t exception_get_vtable_handler(enum exception_number num);
159 
160 #ifndef __riscv
161 /*! \brief Set specified exception's priority
162  *  \ingroup hardware_exception
163  *
164  * \param num Exception number \ref exception_number
165  * \param hardware_priority Priority to set.
166  *
167  * Numerically-lower values indicate a higher priority. Hardware priorities
168  * range from 0 (highest priority) to 255 (lowest priority).
169  *
170  * \if rp2040_specific
171  * Only the top 2 bits are significant on ARM Cortex-M0+ on RP2040.
172  * \endif
173  *
174  * \if rp2350_specific
175  * Only the top 4 bits are significant on ARM Cortex-M33 on RP2350, and exception priorities
176  * are not supported on RISC-V
177  * \endif
178  */
179 bool exception_set_priority(uint num, uint8_t hardware_priority);
180 
181 /*! \brief Get specified exception's priority
182  *  \ingroup hardware_exception
183  *
184  * Numerically-lower values indicate a higher priority. Hardware priorities
185  * range from 0 (highest priority) to 255 (lowest priority).
186  *
187  * \if rp2040_specific
188  * Only the top 2 bits are significant on ARM Cortex-M0+ on RP2040.
189  * \endif
190  *
191  * \if rp2350_specific
192  * Only the top 4 bits are significant on ARM Cortex-M33 on RP2350, and exception priorities
193  * are not supported on RISC-V
194  * \endif
195  *
196  * \param num Exception number \ref exception_number
197  * \return the exception priority
198  */
199 uint exception_get_priority(uint num);
200 #endif
201 
202 #ifdef __cplusplus
203 }
204 #endif
205 
206 #endif
207