mirror of
https://github.com/micropython/micropython.git
synced 2025-07-21 13:01:10 +02:00
Since the very beginning, the stm32 port (first called stm, then stmhal now stm32) has had a special keyboard interrupt feature which works by using PendSV to break out of any running code. This preemptive ctrl-C was added long ago in commit01156d510c
. The stm32 port still uses that code, and current does this: - If ctrl-C is received on UART or USB then `mp_sched_keyboard_interrupt()` is called (like all other ports) to set a flag for the VM to see, and then the VM (or any loop calling `mp_handle_pending(true)`) will eventually handle the `KeyboardInterrupt` exception, raising it via NLR. - If another ctrl-C is received while the existing scheduled keyboard interrupt is still pending (ie the VM has not yet processed it) then a special hard NLR jump will activate, that preempts the calling code. Within the PendSV interrupt the stack is adjusted and an NLR jump is made to the most recent `nlr_push()` location. This is like a normal NLR except it is called from an interrupt context and completely annihilates the code that was interrupted by the IRQ. The reason for the preemptive interrupt was to handle ctrl-C before the VM was able to handle it. Eventually a mechanism (that's in use today by all ports) was added to the VM and runtime to be able to check for pending interrupts. Then the stm32 port was updated to use this mechanism, with a fallback to the old preemptive way if a second ctrl-C was received (without the first one being processed). This preemptive NLR jump is problematic because it can interrupt long-running instructions (eg store multiple, usually used at the end of a function to restore registers and return). If such an instruction is interrupted the CPU remembers that with some flags, and can resume the long-running instruction when the interrupt finishes. But the preemptive NLR does a long jump to different code at thread level and so the long-running interrupt is never resumed. This leads to a CPU fault. This fault has been previously reported in issues #3807 and #3842 (see also issue #294). It's now possible to easily reproduce this problem, since commit69c25ea865
. Running the test suite over and over again on any stm32 board will eventually crash the board (it can happen on a PYBv1.x, but it happens more regularly on PYBD-SF2/6). The point is, a skipped test now soft resets the board and so the board must run `boot.py` again. The test runner may then interrupt the execution of `boot.py` with the double-ctrl-C that it sends (in `tools/pyboard.py`, `enter_raw_repl()`) in order to get the board into a known good state for the next test. If the timing is right, this can trigger the preemptive PendSV in an unfortunate location and hard fault the board. The fix in this commit is to just remove the preemptive NLR jump feature. No other port has this feature and it's not needed, ctrl-C works very well on those ports. Preemptive NLR jump is a very dangerous thing (eg it may interrupt and break out of an external SPI flash operation when reading code from a filesystem) and is obviously buggy. With this commit, stm32 borads no longer hard fault when running the test suite (but it does leave an issue, the tests can still interrupt `boot.py` with a single ctrl-C; that will be fixed separately). An alternative to this commit would be to clear the CPU state for the long-running instruction as suggested in issue #3842. But it's much simpler to just remove this code, which is now unnecessary and can have other problems as per issue #294. Signed-off-by: Damien George <damien@micropython.org>
57 lines
2.0 KiB
C
57 lines
2.0 KiB
C
/*
|
|
* This file is part of the MicroPython project, http://micropython.org/
|
|
*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2013, 2014 Damien P. George
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
#ifndef MICROPY_INCLUDED_STM32_PENDSV_H
|
|
#define MICROPY_INCLUDED_STM32_PENDSV_H
|
|
|
|
#include "boardctrl.h"
|
|
|
|
enum {
|
|
PENDSV_DISPATCH_SOFT_TIMER,
|
|
#if MICROPY_PY_NETWORK && MICROPY_PY_LWIP
|
|
PENDSV_DISPATCH_LWIP,
|
|
#if MICROPY_PY_NETWORK_CYW43
|
|
PENDSV_DISPATCH_CYW43,
|
|
#endif
|
|
#if MICROPY_PY_NETWORK_WIZNET5K
|
|
PENDSV_DISPATCH_WIZNET,
|
|
#endif
|
|
#endif
|
|
#if MICROPY_PY_BLUETOOTH && !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
|
PENDSV_DISPATCH_BLUETOOTH_HCI,
|
|
#endif
|
|
MICROPY_BOARD_PENDSV_ENTRIES
|
|
PENDSV_DISPATCH_MAX
|
|
};
|
|
|
|
#define PENDSV_DISPATCH_NUM_SLOTS PENDSV_DISPATCH_MAX
|
|
|
|
typedef void (*pendsv_dispatch_t)(void);
|
|
|
|
void pendsv_init(void);
|
|
void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f);
|
|
|
|
#endif // MICROPY_INCLUDED_STM32_PENDSV_H
|