Skip to content

Commit 53f1915

Browse files
authored
Add hardware_exception for setting exception handlers at runtime (#380)
1 parent 7fc75d8 commit 53f1915

File tree

9 files changed

+185
-1
lines changed

9 files changed

+185
-1
lines changed

docs/index.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* \defgroup hardware_clocks hardware_clocks
1818
* \defgroup hardware_divider hardware_divider
1919
* \defgroup hardware_dma hardware_dma
20+
* \defgroup hardware_exception hardware_exception
2021
* \defgroup hardware_flash hardware_flash
2122
* \defgroup hardware_gpio hardware_gpio
2223
* \defgroup hardware_i2c hardware_i2c

src/rp2_common/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pico_add_subdirectory(hardware_adc)
1010
pico_add_subdirectory(hardware_clocks)
1111
pico_add_subdirectory(hardware_dma)
1212
pico_add_subdirectory(hardware_divider)
13+
pico_add_subdirectory(hardware_exception)
1314
pico_add_subdirectory(hardware_flash)
1415
pico_add_subdirectory(hardware_gpio)
1516
pico_add_subdirectory(hardware_i2c)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pico_simple_hardware_target(exception)
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3+
*
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
#include "hardware/exception.h"
8+
#include "hardware/regs/m0plus.h"
9+
#include "hardware/platform_defs.h"
10+
#include "hardware/structs/scb.h"
11+
12+
#include "pico/mutex.h"
13+
#include "pico/assert.h"
14+
15+
#ifndef exception_is_compile_time_default
16+
static bool exception_is_compile_time_default(exception_handler_t handler) {
17+
extern char __default_isrs_start;
18+
extern char __default_isrs_end;
19+
return ((uintptr_t)handler) >= (uintptr_t)&__default_isrs_start &&
20+
((uintptr_t)handler) < (uintptr_t)&__default_isrs_end;
21+
}
22+
#endif
23+
24+
static inline exception_handler_t *get_vtable(void) {
25+
return (exception_handler_t *) scb_hw->vtor;
26+
}
27+
28+
static void set_raw_exception_handler_and_restore_interrupts(enum exception_number num, exception_handler_t handler, uint32_t save) {
29+
// update vtable (vtable_handler may be same or updated depending on cases, but we do it anyway for compactness)
30+
get_vtable()[16 + num] = handler;
31+
__dmb();
32+
restore_interrupts(save);
33+
}
34+
35+
static inline void check_exception_param(__unused enum exception_number num) {
36+
invalid_params_if(EXCEPTION, num < NMI_EXCEPTION || num >=0);
37+
}
38+
39+
exception_handler_t exception_get_vtable_handler(enum exception_number num) {
40+
check_exception_param(num);
41+
return get_vtable()[16 + num];
42+
}
43+
44+
exception_handler_t exception_set_exclusive_handler(enum exception_number num, exception_handler_t handler) {
45+
check_exception_param(num);
46+
#if !PICO_NO_RAM_VECTOR_TABLE
47+
uint32_t save = save_and_disable_interrupts();
48+
exception_handler_t current = exception_get_vtable_handler(num);
49+
hard_assert(exception_is_compile_time_default(current));
50+
set_raw_exception_handler_and_restore_interrupts(num, handler, save);
51+
#else
52+
panic_unsupported();
53+
#endif
54+
return current;
55+
}
56+
57+
void exception_restore_handler(enum exception_number num, exception_handler_t original_handler) {
58+
hard_assert(exception_is_compile_time_default(original_handler));
59+
#if !PICO_NO_RAM_VECTOR_TABLE
60+
uint32_t save = save_and_disable_interrupts();
61+
set_raw_exception_handler_and_restore_interrupts(num, original_handler, save);
62+
#else
63+
panic_unsupported();
64+
#endif
65+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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+
#include "hardware/regs/m0plus.h"
13+
14+
/** \file exception.h
15+
* \defgroup hardware_exception hardware_exception
16+
*
17+
* Methods for setting processor exception handlers
18+
*
19+
* Exceptions are identified by a \ref exception_num which is a number from -15 to -1; these are the numbers relative to
20+
* the index of the first IRQ vector in the vector table. (i.e. vector table index is exception_num plus 16)
21+
*
22+
* There is one set of exception handlers per core, so the exception handlers for each core as set by these methods are independent.
23+
*
24+
* \note That all exception APIs affect the executing core only (i.e. the core calling the function).
25+
*/
26+
27+
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_EXCEPTION, Enable/disable assertions in the exception module, type=bool, default=0, group=hardware_exception
28+
#ifndef PARAM_ASSERTIONS_ENABLED_EXCEPTION
29+
#define PARAM_ASSERTIONS_ENABLED_EXCEPTION 0
30+
#endif
31+
32+
#ifdef __cplusplus
33+
extern "C" {
34+
#endif
35+
36+
/*! \brief Exception number definitions
37+
*
38+
* Note for consistency with irq numbers, these numbers are defined to be negative. The VTABLE index is
39+
* the number here plus 16.
40+
*
41+
* Name | Value | Exception
42+
* ---------------------|-------|----------
43+
* NMI_EXCEPTION | -14 | Non Maskable Interrupt
44+
* HARDFAULT_EXCEPTION | -13 | HardFault
45+
* SVCALL_EXCEPTION | -5 | SV Call
46+
* PENDSV_EXCEPTION | -2 | Pend SV
47+
* SYSTICK_EXCEPTION | -1 | System Tick
48+
*
49+
* \ingroup hardware_exception
50+
*/
51+
enum exception_number {
52+
NMI_EXCEPTION = -14, /* Non Maskable Interrupt */
53+
HARDFAULT_EXCEPTION = -13, /* HardFault Interrupt */
54+
SVCALL_EXCEPTION = -5, /* SV Call Interrupt */
55+
PENDSV_EXCEPTION = -2, /* Pend SV Interrupt */
56+
SYSTICK_EXCEPTION = -1, /* System Tick Interrupt */
57+
};
58+
59+
/*! \brief Exception handler function type
60+
* \ingroup hardware_exception
61+
*
62+
* All exceptions handlers should be of this type, and follow normal ARM EABI register saving conventions
63+
*/
64+
typedef void (*exception_handler_t)(void);
65+
66+
/*! \brief Set the exception handler for an exception on the executing core.
67+
* \ingroup hardware_exception
68+
*
69+
* This method will assert if an exception handler has been set for this exception number on this core via
70+
* this method, without an intervening restore via exception_restore_handler.
71+
*
72+
* \note this method may not be used to override an exception handler that was specified at link time by
73+
* providing a strong replacement for the weakly defined stub exception handlers. It will assert in this case too.
74+
*
75+
* \param num Exception number
76+
* \param handler The handler to set
77+
* \see exception_number
78+
*/
79+
exception_handler_t exception_set_exclusive_handler(enum exception_number num, exception_handler_t handler);
80+
81+
/*! \brief Restore the original exception handler for an exception on this core
82+
* \ingroup hardware_exception
83+
*
84+
* This method may be used to restore the exception handler for an exception on this core to the state
85+
* prior to the call to exception_set_exclusive_handler(), so that exception_set_exclusive_handler()
86+
* may be called again in the future.
87+
*
88+
* \param num Exception number \ref exception_nums
89+
* \param original_handler The original handler returned from \ref exception_set_exclusive_handler
90+
* \see exception_set_exclusive_handler()
91+
*/
92+
void exception_restore_handler(enum exception_number, exception_handler_t original_handler);
93+
94+
/*! \brief Get the current exception handler for the specified exception from the currently installed vector table
95+
* of the execution core
96+
* \ingroup hardware_exception
97+
*
98+
* \param num Exception number
99+
* \return the address stored in the VTABLE for the given exception number
100+
*/
101+
exception_handler_t exception_get_vtable_handler(enum exception_number num);
102+
#ifdef __cplusplus
103+
}
104+
#endif
105+
106+
#endif

src/rp2_common/hardware_irq/include/hardware/irq.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ static inline void irq_clear(uint int_num) {
255255
void irq_set_pending(uint num);
256256

257257

258-
/*! \brief Perform IRQ priority intiialization for the current core
258+
/*! \brief Perform IRQ priority initialization for the current core
259259
*
260260
* \note This is an internal method and user should generally not call it.
261261
*/

src/rp2_common/pico_standard_link/crt0.S

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ __vectors:
7474
.word isr_irq30
7575
.word isr_irq31
7676

77+
// all default exception handlers do nothing, and we can check for them being set to our
78+
// default values by them pointing to between __defaults_isrs_start and __default_isrs_end
79+
.global __default_isrs_start
80+
__default_isrs_start:
81+
7782
// Declare a weak symbol for each ISR.
7883
// By default, they will fall through to the undefined IRQ handler below (breakpoint),
7984
// but can be overridden by C functions with correct name.
@@ -94,6 +99,9 @@ decl_isr_bkpt isr_svcall
9499
decl_isr_bkpt isr_pendsv
95100
decl_isr_bkpt isr_systick
96101

102+
.global __default_isrs_end
103+
__default_isrs_end:
104+
97105
.macro decl_isr name
98106
.weak \name
99107
.type \name,%function

test/kitchen_sink/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ target_link_libraries(kitchen_sink_libs INTERFACE
66
hardware_adc
77
hardware_clocks
88
hardware_divider
9+
hardware_exception
910
hardware_dma
1011
hardware_flash
1112
hardware_gpio

test/kitchen_sink/kitchen_sink.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "hardware/clocks.h"
1212
#include "hardware/divider.h"
1313
#include "hardware/dma.h"
14+
#include "hardware/exception.h"
1415
#include "hardware/flash.h"
1516
#include "hardware/gpio.h"
1617
#include "hardware/i2c.h"

0 commit comments

Comments
 (0)