-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add hardware_exception for setting exception handlers at runtime #380
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| pico_simple_hardware_target(exception) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| /* | ||
| * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. | ||
| * | ||
| * SPDX-License-Identifier: BSD-3-Clause | ||
| */ | ||
|
|
||
| #include "hardware/exception.h" | ||
| #include "hardware/regs/m0plus.h" | ||
| #include "hardware/platform_defs.h" | ||
| #include "hardware/structs/scb.h" | ||
|
|
||
| #include "pico/mutex.h" | ||
| #include "pico/assert.h" | ||
|
|
||
| #ifndef exception_is_compile_time_default | ||
| static bool exception_is_compile_time_default(exception_handler_t handler) { | ||
| extern char __default_isrs_start; | ||
| extern char __default_isrs_end; | ||
| return ((uintptr_t)handler) >= (uintptr_t)&__default_isrs_start && | ||
| ((uintptr_t)handler) < (uintptr_t)&__default_isrs_end; | ||
| } | ||
| #endif | ||
|
|
||
| static inline exception_handler_t *get_vtable(void) { | ||
| return (exception_handler_t *) scb_hw->vtor; | ||
| } | ||
|
|
||
| static void set_raw_exception_handler_and_restore_interrupts(enum exception_number num, exception_handler_t handler, uint32_t save) { | ||
| // update vtable (vtable_handler may be same or updated depending on cases, but we do it anyway for compactness) | ||
| get_vtable()[16 + num] = handler; | ||
| __dmb(); | ||
| restore_interrupts(save); | ||
| } | ||
|
|
||
| static inline void check_exception_param(__unused enum exception_number num) { | ||
| invalid_params_if(EXCEPTION, num < NMI_EXCEPTION || num >=0); | ||
| } | ||
|
|
||
| exception_handler_t exception_get_vtable_handler(enum exception_number num) { | ||
| check_exception_param(num); | ||
| return get_vtable()[16 + num]; | ||
| } | ||
|
|
||
| exception_handler_t exception_set_exclusive_handler(enum exception_number num, exception_handler_t handler) { | ||
| check_exception_param(num); | ||
| #if !PICO_NO_RAM_VECTOR_TABLE | ||
| uint32_t save = save_and_disable_interrupts(); | ||
| exception_handler_t current = exception_get_vtable_handler(num); | ||
| hard_assert(exception_is_compile_time_default(current)); | ||
| set_raw_exception_handler_and_restore_interrupts(num, handler, save); | ||
| #else | ||
| panic_unsupported(); | ||
| #endif | ||
| return current; | ||
| } | ||
|
|
||
| void exception_restore_handler(enum exception_number num, exception_handler_t original_handler) { | ||
| hard_assert(exception_is_compile_time_default(original_handler)); | ||
| #if !PICO_NO_RAM_VECTOR_TABLE | ||
| uint32_t save = save_and_disable_interrupts(); | ||
| set_raw_exception_handler_and_restore_interrupts(num, original_handler, save); | ||
| #else | ||
| panic_unsupported(); | ||
| #endif | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| /* | ||
| * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. | ||
| * | ||
| * SPDX-License-Identifier: BSD-3-Clause | ||
| */ | ||
|
|
||
| #ifndef _HARDWARE_EXCEPTION_H_ | ||
| #define _HARDWARE_EXCEPTION_H_ | ||
|
|
||
| #include "pico.h" | ||
| #include "hardware/address_mapped.h" | ||
| #include "hardware/regs/m0plus.h" | ||
|
|
||
| /** \file exception.h | ||
| * \defgroup hardware_exception hardware_exception | ||
| * | ||
| * Methods for setting processor exception handlers | ||
| * | ||
| * Exceptions are identified by a \ref exception_num which is a number from -15 to -1; these are the numbers relative to | ||
| * the index of the first IRQ vector in the vector table. (i.e. vector table index is exception_num plus 16) | ||
| * | ||
| * There is one set of exception handlers per core, so the exception handlers for each core as set by these methods are independent. | ||
| * | ||
| * \note That all exception APIs affect the executing core only (i.e. the core calling the function). | ||
| */ | ||
|
|
||
| // PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_EXCEPTION, Enable/disable assertions in the exception module, type=bool, default=0, group=hardware_exception | ||
| #ifndef PARAM_ASSERTIONS_ENABLED_EXCEPTION | ||
| #define PARAM_ASSERTIONS_ENABLED_EXCEPTION 0 | ||
| #endif | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /*! \brief Exception number definitions | ||
| * | ||
| * Note for consistency with irq numbers, these numbers are defined to be negative. The VTABLE index is | ||
| * the number here plus 16. | ||
| * | ||
| * Name | Value | Exception | ||
| * ---------------------|-------|---------- | ||
| * NMI_EXCEPTION | -14 | Non Maskable Interrupt | ||
| * HARDFAULT_EXCEPTION | -13 | HardFault | ||
| * SVCALL_EXCEPTION | -5 | SV Call | ||
| * PENDSV_EXCEPTION | -2 | Pend SV | ||
| * SYSTICK_EXCEPTION | -1 | System Tick | ||
| * | ||
| * \ingroup hardware_exception | ||
| */ | ||
| enum exception_number { | ||
| NMI_EXCEPTION = -14, /* Non Maskable Interrupt */ | ||
| HARDFAULT_EXCEPTION = -13, /* HardFault Interrupt */ | ||
| SVCALL_EXCEPTION = -5, /* SV Call Interrupt */ | ||
| PENDSV_EXCEPTION = -2, /* Pend SV Interrupt */ | ||
| SYSTICK_EXCEPTION = -1, /* System Tick Interrupt */ | ||
| }; | ||
|
Comment on lines
+51
to
+57
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens for numbers outside of this list, e.g. -3 ?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. they continue to exist you can set handlers for them, but there is no point |
||
|
|
||
| /*! \brief Exception handler function type | ||
| * \ingroup hardware_exception | ||
| * | ||
| * All exceptions handlers should be of this type, and follow normal ARM EABI register saving conventions | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "exceptions handlers" -> "exception handlers" |
||
| */ | ||
| typedef void (*exception_handler_t)(void); | ||
|
|
||
| /*! \brief Set the exception handler for an exception on the executing core. | ||
| * \ingroup hardware_exception | ||
| * | ||
| * This method will assert if an exception handler has been set for this exception number on this core via | ||
| * this method, without an intervening restore via exception_restore_handler. | ||
| * | ||
| * \note this method may not be used to override an exception handler that was specified at link time by | ||
| * providing a strong replacement for the weakly defined stub exception handlers. It will assert in this case too. | ||
| * | ||
| * \param num Exception number | ||
| * \param handler The handler to set | ||
| * \see exception_number | ||
| */ | ||
| exception_handler_t exception_set_exclusive_handler(enum exception_number num, exception_handler_t handler); | ||
|
|
||
| /*! \brief Restore the original exception handler for an exception on this core | ||
| * \ingroup hardware_exception | ||
| * | ||
| * This method may be used to restore the exception handler for an exception on this core to the state | ||
| * prior to the call to exception_set_exclusive_handler(), so that exception_set_exclusive_handler() | ||
| * may be called again in the future. | ||
| * | ||
| * \param num Exception number \ref exception_nums | ||
| * \param original_handler The original handler returned from \ref exception_set_exclusive_handler | ||
| * \see exception_set_exclusive_handler() | ||
| */ | ||
| void exception_restore_handler(enum exception_number, exception_handler_t original_handler); | ||
|
|
||
| /*! \brief Get the current exception handler for the specified exception from the currently installed vector table | ||
| * of the execution core | ||
| * \ingroup hardware_exception | ||
| * | ||
| * \param num Exception number | ||
| * \return the address stored in the VTABLE for the given exception number | ||
| */ | ||
| exception_handler_t exception_get_vtable_handler(enum exception_number num); | ||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,6 +74,11 @@ __vectors: | |
| .word isr_irq30 | ||
| .word isr_irq31 | ||
|
|
||
| // all default exception handlers do nothing, and we can check for them being set to our | ||
| // default values by them pointing to between __defaults_isrs_start and __default_isrs_end | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I initially thought "by them pointing to" was a typo for "by pointing them to", but then I reread it a couple of times and figured out what it actually meant 😉 |
||
| .global __default_isrs_start | ||
| __default_isrs_start: | ||
|
|
||
| // Declare a weak symbol for each ISR. | ||
| // By default, they will fall through to the undefined IRQ handler below (breakpoint), | ||
| // but can be overridden by C functions with correct name. | ||
|
|
@@ -94,6 +99,9 @@ decl_isr_bkpt isr_svcall | |
| decl_isr_bkpt isr_pendsv | ||
| decl_isr_bkpt isr_systick | ||
|
|
||
| .global __default_isrs_end | ||
| __default_isrs_end: | ||
|
|
||
| .macro decl_isr name | ||
| .weak \name | ||
| .type \name,%function | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only a minor nit-pick, but this is already included in hardware/exception.h