cortex_m_rt/lib.rs
1//! Startup code and minimal runtime for Cortex-M microcontrollers
2//!
3//! This crate contains all the required parts to build a `no_std` application (binary crate) that
4//! targets a Cortex-M microcontroller.
5//!
6//! # Features
7//!
8//! This crates takes care of:
9//!
10//! - The memory layout of the program. In particular, it populates the vector table so the device
11//! can boot correctly, and properly dispatch exceptions and interrupts.
12//!
13//! - Initializing `static` variables before the program entry point.
14//!
15//! - Enabling the FPU before the program entry point if the target is `-eabihf`.
16//!
17//! This crate also provides the following attributes:
18//!
19//! - [`#[entry]`][attr-entry] to declare the entry point of the program
20//! - [`#[exception]`][attr-exception] to override an exception handler. If not overridden all
21//! exception handlers default to an infinite loop.
22//!
23//! This crate also implements a related attribute called `#[interrupt]`, which allows you
24//! to define interrupt handlers. However, since which interrupts are available depends on the
25//! microcontroller in use, this attribute should be re-exported and used from a peripheral
26//! access crate (PAC).
27//!
28//! A [`#[pre_init]`][attr-pre_init] macro is also provided to run a function before RAM
29//! initialisation, but its use is deprecated as it is not defined behaviour to execute Rust
30//! code before initialisation. It is still possible to create a custom `pre_init` function
31//! using assembly.
32//!
33//! The documentation for these attributes can be found in the [Attribute Macros](#attributes)
34//! section.
35//!
36//! # Requirements
37//!
38//! ## `memory.x`
39//!
40//! This crate expects the user, or some other crate, to provide the memory layout of the target
41//! device via a linker script named `memory.x`, described in this section. The `memory.x` file is
42//! used during linking by the `link.x` script provided by this crate. If you are using a custom
43//! linker script, you do not need a `memory.x` file.
44//!
45//! ### `MEMORY`
46//!
47//! The linker script must specify the memory available in the device as, at least, two `MEMORY`
48//! regions: one named `FLASH` and one named `RAM`. The `.text` and `.rodata` sections of the
49//! program will be placed in the `FLASH` region, whereas the `.bss` and `.data` sections, as well
50//! as the heap, will be placed in the `RAM` region.
51//!
52//! ```text
53//! /* Linker script for the STM32F103C8T6 */
54//! MEMORY
55//! {
56//! FLASH : ORIGIN = 0x08000000, LENGTH = 64K
57//! RAM : ORIGIN = 0x20000000, LENGTH = 20K
58//! }
59//! ```
60//!
61//! ### `_stack_start` / `_stack_end`
62//!
63//! The `_stack_start` optional symbol can be used to indicate where the call stack of the program
64//! should be placed. If this symbol is not used then the stack will be placed at the *end* of the
65//! `RAM` region -- the stack grows downwards towards smaller address. This is generally a sensible
66//! default and most applications will not need to specify `_stack_start`. The same goes for
67//! `_stack_end` which is automatically placed after the end of statically allocated RAM.
68//!
69//! **NOTE:** If you change `_stack_start`, make sure to also set `_stack_end` correctly to match
70//! new stack area if you are using it, e.g for MSPLIM.
71//!
72//! The `_stack_end` is checked by linker script to be less than or equal to `_stack_start` and is
73//! used as a bound in `paint-stack` feature.
74//!
75//! For Cortex-M, the `_stack_start` must always be aligned to 8 bytes, which is enforced by
76//! the linker script. If you override it, ensure that whatever value you set is a multiple
77//! of 8 bytes. The `_stack_end` is aligned to 4 bytes.
78//!
79//! This symbol can be used to place the stack in a different memory region, for example:
80//!
81//! ```text
82//! /* Linker script for the STM32F303VCT6 with stack in CCM */
83//! MEMORY
84//! {
85//! FLASH : ORIGIN = 0x08000000, LENGTH = 256K
86//!
87//! /* .bss, .data and the heap go in this region */
88//! RAM : ORIGIN = 0x20000000, LENGTH = 40K
89//!
90//! /* Core coupled (faster) RAM dedicated to hold the stack */
91//! CCRAM : ORIGIN = 0x10000000, LENGTH = 8K
92//! }
93//!
94//! _stack_start = ORIGIN(CCRAM) + LENGTH(CCRAM);
95//! _stack_end = ORIGIN(CCRAM); /* Optional, add if used by the application */
96//! ```
97//!
98//! ### `_stext`
99//!
100//! This optional symbol can be used to control where the `.text` section is placed. If omitted the
101//! `.text` section will be placed right after the vector table, which is placed at the beginning of
102//! `FLASH`. Some devices store settings like Flash configuration right after the vector table;
103//! for these devices one must place the `.text` section after this configuration section --
104//! `_stext` can be used for this purpose.
105//!
106//! ```text
107//! MEMORY
108//! {
109//! /* .. */
110//! }
111//!
112//! /* The device stores Flash configuration in 0x400-0x40C so we place .text after that */
113//! _stext = ORIGIN(FLASH) + 0x40C;
114//! ```
115//!
116//! # An example
117//!
118//! This section presents a minimal application built on top of `cortex-m-rt`. Apart from the
119//! mandatory `memory.x` linker script describing the memory layout of the device, the hard fault
120//! handler and the default exception handler must also be defined somewhere in the dependency
121//! graph (see [`#[exception]`]). In this example we define them in the binary crate:
122//!
123//! ```no_run
124//! #![no_main]
125//! #![no_std]
126//!
127//! // Some panic handler needs to be included. This one halts the processor on panic.
128//! use panic_halt as _;
129//!
130//! use cortex_m_rt::entry;
131//!
132//! // Use `main` as the entry point of this application, which may not return.
133//! #[entry]
134//! fn main() -> ! {
135//! // initialization
136//!
137//! loop {
138//! // application logic
139//! }
140//! }
141//! ```
142//!
143//! To actually build this program you need to place a `memory.x` linker script somewhere the linker
144//! can find it, e.g. in the current directory; and then link the program using `cortex-m-rt`'s
145//! linker script: `link.x`. The required steps are shown below:
146//!
147//! ```text
148//! $ cat > memory.x <<EOF
149//! MEMORY
150//! {
151//! FLASH : ORIGIN = 0x08000000, LENGTH = 64K
152//! RAM : ORIGIN = 0x20000000, LENGTH = 20K
153//! }
154//! EOF
155//!
156//! $ RUSTFLAGS="-C link-arg=-Tlink.x" cargo build --target thumbv7m-none-eabi
157//! $ file target/thumbv7m-none-eabi/debug/app
158//! app: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, (..)
159//! ```
160//!
161//! To avoid typing the long command, you can create a `.cargo/config.toml` file:
162//!
163//! ```toml
164//! [target.thumbv7m-none-eabi]
165//! rustflags = ["-C", "link-arg=-Tlink.x"]
166//!
167//! [build]
168//! target = "thumbv7m-none-eabi"
169//! ```
170//!
171//! With this configuration, a simple `cargo build` is enough.
172//!
173//! For Cortex-M4 devices, use the target thumbv7em-none-eabi instead.
174//!
175//! # Optional features
176//!
177//! ## `device`
178//!
179//! If this feature is disabled then this crate populates the whole vector table. All the interrupts
180//! in the vector table, even the ones unused by the target device, will be bound to the default
181//! exception handler. This makes the final application device agnostic: you will be able to run it
182//! on any Cortex-M device -- provided that you correctly specified its memory layout in `memory.x`
183//! -- without hitting undefined behavior.
184//!
185//! If this feature is enabled then the interrupts section of the vector table is left unpopulated
186//! and some other crate, or the user, will have to populate it. This mode is meant to be used in
187//! conjunction with crates generated using `svd2rust`. Those peripheral access crates, or PACs,
188//! will populate the missing part of the vector table when their `"rt"` feature is enabled.
189//!
190//! ## `set-sp`
191//!
192//! If this feature is enabled, the stack pointer (SP) is initialised in the reset handler to the
193//! `_stack_start` value from the linker script. This is not usually required, but some debuggers
194//! do not initialise SP when performing a soft reset, which can lead to stack corruption.
195//!
196//! ## `set-vtor`
197//!
198//! If this feature is enabled, the vector table offset register (VTOR) is initialised in the reset
199//! handler to the start of the vector table defined in the linker script. This is not usually
200//! required, but some bootloaders do not set VTOR before jumping to application code, leading to
201//! your main function executing but interrupt handlers not being used.
202//!
203//! ## `set-msplim`
204//!
205//! If this feature is enabled, the main stack pointer limit register (MSPLIM) is initialized in
206//! the reset handler to the `_stack_end` value from the linker script. This feature is only
207//! available on ARMv8-M Mainline and helps enforce stack limits by defining the lowest valid
208//! stack address.
209//!
210//! ## `zero-init-ram`
211//!
212//! If this feature is enabled, RAM is initialized with zeros during startup from the `_ram_start`
213//! value to the `_ram_end` value from the linker script. This is not usually required, but might be
214//! necessary to properly initialize memory integrity measures on some hardware.
215//!
216//! ## `paint-stack`
217//!
218//! Everywhere between `_stack_end` and `_stack_start` is painted with the fixed value
219//! `STACK_PAINT_VALUE`, which is `0xCCCC_CCCC`.
220//! You can then inspect memory during debugging to determine how much of the stack has been used -
221//! where the stack has been used the 'paint' will have been 'scrubbed off' and the memory will
222//! have a value other than `STACK_PAINT_VALUE`.
223//!
224//! ## `skip-data-copy`
225//!
226//! Skips copying the .data section (containing the initial values for static variables) when a bootloader
227//! (or other mechanism) is responsible for initializing the section. Use when the code is loaded from a location
228//! that's invalid after the bootloader runs (e.g. copy-from-XIP or copy-from-network boot). For example,
229//! rp2040-boot2 with `BOOT_LOADER_RAM_MEMCPY` (not the default of boot2!) set, which copies the code out
230//! of the XIP flash memory and then disables the XIP peripheral afterwards.
231//!
232//! # Inspection
233//!
234//! This section covers how to inspect a binary that builds on top of `cortex-m-rt`.
235//!
236//! ## Sections (`size`)
237//!
238//! `cortex-m-rt` uses standard sections like `.text`, `.rodata`, `.bss` and `.data` as one would
239//! expect. `cortex-m-rt` separates the vector table in its own section, named `.vector_table`. This
240//! lets you distinguish how much space is taking the vector table in Flash vs how much is being
241//! used by actual instructions (`.text`) and constants (`.rodata`).
242//!
243//! ```text
244//! $ size -Ax target/thumbv7m-none-eabi/examples/app
245//! target/thumbv7m-none-eabi/release/examples/app :
246//! section size addr
247//! .vector_table 0x400 0x8000000
248//! .text 0x88 0x8000400
249//! .rodata 0x0 0x8000488
250//! .data 0x0 0x20000000
251//! .bss 0x0 0x20000000
252//! ```
253//!
254//! Without the `-A` argument `size` reports the sum of the sizes of `.text`, `.rodata` and
255//! `.vector_table` under "text".
256//!
257//! ```text
258//! $ size target/thumbv7m-none-eabi/examples/app
259//! text data bss dec hex filename
260//! 1160 0 0 1660 67c target/thumbv7m-none-eabi/release/app
261//! ```
262//!
263//! ## Symbols (`objdump`, `nm`)
264//!
265//! One will always find the following (unmangled) symbols in `cortex-m-rt` applications:
266//!
267//! - `Reset`. This is the reset handler. The microcontroller will execute this function upon
268//! booting. This function will call the user program entry point (cf. [`#[entry]`][attr-entry])
269//! using the `main` symbol so you will also find that symbol in your program.
270//!
271//! - `DefaultHandler`. This is the default handler. If not overridden using `#[exception] fn
272//! DefaultHandler(..` this will be an infinite loop.
273//!
274//! - `HardFault` and `_HardFault`. These function handle the hard fault handling and what they
275//! do depends on whether the hard fault is overridden and whether the trampoline is enabled (which it is by default).
276//! - No override: Both are the same function. The function is an infinite loop defined in the cortex-m-rt crate.
277//! - Trampoline enabled: `HardFault` is the real hard fault handler defined in assembly. This function is simply a
278//! trampoline that jumps into the rust defined `_HardFault` function. This second function jumps to the user-defined
279//! handler with the exception frame as parameter. This second jump is usually optimised away with inlining.
280//! - Trampoline disabled: `HardFault` is the user defined function. This means the user function is called directly
281//! from the vector table. `_HardFault` still exists, but is an empty function that is purely there for compiler
282//! diagnostics.
283//!
284//! - `__STACK_START`. This is the first entry in the `.vector_table` section. This symbol contains
285//! the initial value of the stack pointer; this is where the stack will be located -- the stack
286//! grows downwards towards smaller addresses.
287//!
288//! - `__RESET_VECTOR`. This is the reset vector, a pointer to the `Reset` function. This vector
289//! is located in the `.vector_table` section after `__STACK_START`.
290//!
291//! - `__EXCEPTIONS`. This is the core exceptions portion of the vector table; it's an array of 14
292//! exception vectors, which includes exceptions like `HardFault` and `SysTick`. This array is
293//! located after `__RESET_VECTOR` in the `.vector_table` section.
294//!
295//! - `__INTERRUPTS`. This is the device specific interrupt portion of the vector table; its exact
296//! size depends on the target device but if the `"device"` feature has not been enabled it will
297//! have a size of 32 vectors (on ARMv6-M), 240 vectors (on ARMv7-M, ARMv8-M Baseline) or 480
298//! vectors (on ARMv8-M Mainline).
299//! This array is located after `__EXCEPTIONS` in the `.vector_table` section.
300//!
301//! - `__pre_init`. This is a function to be run before RAM is initialized. It defaults to an empty
302//! function. As this runs before RAM is initialised, it is not sound to use a Rust function for
303//! `pre_init`, and instead it should typically be written in assembly using `global_asm` or an
304//! external assembly file.
305//!
306//! If you override any exception handler you'll find it as an unmangled symbol, e.g. `SysTick` or
307//! `SVCall`, in the output of `objdump`,
308//!
309//! # Advanced usage
310//!
311//! ## Custom linker script
312//!
313//! To use your own linker script, ensure it is placed in the linker search path (for example in
314//! the crate root or in Cargo's `OUT_DIR`) and use it with `-C link-arg=-Tmy_script.ld` instead
315//! of the normal `-C link-arg=-Tlink.x`. The provided `link.x` may be used as a starting point
316//! for customisation.
317//!
318//! ## Setting the program entry point
319//!
320//! This section describes how [`#[entry]`][attr-entry] is implemented. This information is useful
321//! to developers who want to provide an alternative to [`#[entry]`][attr-entry] that provides extra
322//! guarantees.
323//!
324//! The `Reset` handler will call a symbol named `main` (unmangled) *after* initializing `.bss` and
325//! `.data`, and enabling the FPU (if the target has an FPU). A function with the `entry` attribute
326//! will be set to have the export name "`main`"; in addition, its mutable statics are turned into
327//! safe mutable references (see [`#[entry]`][attr-entry] for details).
328//!
329//! The unmangled `main` symbol must have signature `extern "C" fn() -> !` or its invocation from
330//! `Reset` will result in undefined behavior.
331//!
332//! ## Incorporating device specific interrupts
333//!
334//! This section covers how an external crate can insert device specific interrupt handlers into the
335//! vector table. Most users don't need to concern themselves with these details, but if you are
336//! interested in how PACs generated using `svd2rust` integrate with `cortex-m-rt` read on.
337//!
338//! The information in this section applies when the `"device"` feature has been enabled.
339//!
340//! ### `__INTERRUPTS`
341//!
342//! The external crate must provide the interrupts portion of the vector table via a `static`
343//! variable named`__INTERRUPTS` (unmangled) that must be placed in the `.vector_table.interrupts`
344//! section of its object file.
345//!
346//! This `static` variable will be placed at `ORIGIN(FLASH) + 0x40`. This address corresponds to the
347//! spot where IRQ0 (IRQ number 0) is located.
348//!
349//! To conform to the Cortex-M ABI `__INTERRUPTS` must be an array of function pointers; some spots
350//! in this array may need to be set to 0 if they are marked as *reserved* in the data sheet /
351//! reference manual. We recommend using a `union` to set the reserved spots to `0`; `None`
352//! (`Option<fn()>`) may also work but it's not guaranteed that the `None` variant will *always* be
353//! represented by the value `0`.
354//!
355//! Let's illustrate with an artificial example where a device only has two interrupt: `Foo`, with
356//! IRQ number = 2, and `Bar`, with IRQ number = 4.
357//!
358//! ```no_run
359//! pub union Vector {
360//! handler: unsafe extern "C" fn(),
361//! reserved: usize,
362//! }
363//!
364//! unsafe extern "C" {
365//! fn Foo();
366//! fn Bar();
367//! }
368//!
369//! #[unsafe(link_section = ".vector_table.interrupts")]
370//! #[unsafe(no_mangle)]
371//! pub static __INTERRUPTS: [Vector; 5] = [
372//! // 0-1: Reserved
373//! Vector { reserved: 0 },
374//! Vector { reserved: 0 },
375//!
376//! // 2: Foo
377//! Vector { handler: Foo },
378//!
379//! // 3: Reserved
380//! Vector { reserved: 0 },
381//!
382//! // 4: Bar
383//! Vector { handler: Bar },
384//! ];
385//! ```
386//!
387//! ### `device.x`
388//!
389//! Linking in `__INTERRUPTS` creates a bunch of undefined references. If the user doesn't set a
390//! handler for *all* the device specific interrupts then linking will fail with `"undefined
391//! reference"` errors.
392//!
393//! We want to provide a default handler for all the interrupts while still letting the user
394//! individually override each interrupt handler. In C projects, this is usually accomplished using
395//! weak aliases declared in external assembly files. We use a similar solution via the `PROVIDE`
396//! command in the linker script: when the `"device"` feature is enabled, `cortex-m-rt`'s linker
397//! script (`link.x`) includes a linker script named `device.x`, which must be provided by
398//! whichever crate provides `__INTERRUPTS`.
399//!
400//! For our running example the `device.x` linker script looks like this:
401//!
402//! ```text
403//! /* device.x */
404//! PROVIDE(Foo = DefaultHandler);
405//! PROVIDE(Bar = DefaultHandler);
406//! ```
407//!
408//! This weakly aliases both `Foo` and `Bar`. `DefaultHandler` is the default exception handler and
409//! that the core exceptions use unless overridden.
410//!
411//! Because this linker script is provided by a dependency of the final application the dependency
412//! must contain a build script that puts `device.x` somewhere the linker can find. An example of
413//! such build script is shown below:
414//!
415//! ```ignore
416//! use std::env;
417//! use std::fs::File;
418//! use std::io::Write;
419//! use std::path::PathBuf;
420//!
421//! fn main() {
422//! // Put the linker script somewhere the linker can find it
423//! let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
424//! File::create(out.join("device.x"))
425//! .unwrap()
426//! .write_all(include_bytes!("device.x"))
427//! .unwrap();
428//! println!("cargo:rustc-link-search={}", out.display());
429//! }
430//! ```
431//!
432//! ## Uninitialized static variables
433//!
434//! The `.uninit` linker section can be used to leave `static mut` variables uninitialized. One use
435//! case of unitialized static variables is to avoid zeroing large statically allocated buffers (say
436//! to be used as thread stacks) -- this can considerably reduce initialization time on devices that
437//! operate at low frequencies.
438//!
439//! The only correct way to use this section is with [`MaybeUninit`] types.
440//!
441//! [`MaybeUninit`]: https://doc.rust-lang.org/core/mem/union.MaybeUninit.html
442//!
443//! ```no_run
444//! # extern crate core;
445//! use core::mem::MaybeUninit;
446//!
447//! const STACK_SIZE: usize = 8 * 1024;
448//! const NTHREADS: usize = 4;
449//!
450//! #[unsafe(link_section = ".uninit.STACKS")]
451//! static mut STACKS: MaybeUninit<[[u8; STACK_SIZE]; NTHREADS]> = MaybeUninit::uninit();
452//! ```
453//!
454//! Be very careful with the `link_section` attribute because it's easy to misuse in ways that cause
455//! undefined behavior.
456//!
457//! ## Extra Sections
458//!
459//! Some microcontrollers provide additional memory regions beyond RAM and FLASH. For example,
460//! some STM32 devices provide "CCM" or core-coupled RAM that is only accessible from the core. In
461//! order to place variables in these sections using [`link_section`] attributes from your code,
462//! you need to modify `memory.x` to declare the additional sections:
463//!
464//! [`link_section`]: https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute
465//!
466//! ```text
467//! MEMORY
468//! {
469//! FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
470//! RAM (rw) : ORIGIN = 0x20000000, LENGTH = 128K
471//! CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
472//! }
473//!
474//! SECTIONS
475//! {
476//! .ccmram (NOLOAD) : ALIGN(4)
477//! {
478//! *(.ccmram .ccmram.*);
479//! . = ALIGN(4);
480//! } > CCMRAM
481//! }
482//! ```
483//!
484//! You can then use something like this to place a variable into this specific section of memory:
485//!
486//! ```no_run
487//! # extern crate core;
488//! # use core::mem::MaybeUninit;
489//! #[unsafe(link_section=".ccmram.BUFFERS")]
490//! static mut BUF: MaybeUninit<[u8; 1024]> = MaybeUninit::uninit();
491//! ```
492//!
493//! However, note that these sections are not initialised by cortex-m-rt, and so must be used
494//! either with `MaybeUninit` types or you must otherwise arrange for them to be initialised
495//! yourself, such as in `pre_init`.
496//!
497//! [attr-entry]: attr.entry.html
498//! [attr-exception]: attr.exception.html
499//! [attr-pre_init]: attr.pre_init.html
500//!
501//! # Minimum Supported Rust Version (MSRV)
502//!
503//! The MSRV of this release is Rust 1.85.
504
505// # Developer notes
506//
507// - `link_section` is used to place symbols in specific places of the final binary. The names used
508// here will appear in the linker script (`link.x`) in conjunction with the `KEEP` command.
509
510#![deny(missing_docs)]
511#![no_std]
512
513extern crate cortex_m_rt_macros as macros;
514
515/// The 32-bit value the stack is painted with before the program runs.
516// Note: keep this value in-sync with the start-up assembly code, as we can't
517// use const values in `global_asm!` yet.
518#[cfg(feature = "paint-stack")]
519pub const STACK_PAINT_VALUE: u32 = 0xcccc_cccc;
520
521#[cfg(cortex_m)]
522use core::arch::global_asm;
523use core::fmt;
524
525/// Parse cfg attributes inside a global_asm call.
526#[cfg(cortex_m)]
527macro_rules! cfg_global_asm {
528 {@inner, [$($x:tt)*], } => {
529 global_asm!{$($x)*}
530 };
531 (@inner, [$($x:tt)*], #[cfg($meta:meta)] $asm:literal, $($rest:tt)*) => {
532 #[cfg($meta)]
533 cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
534 #[cfg(not($meta))]
535 cfg_global_asm!{@inner, [$($x)*], $($rest)*}
536 };
537 {@inner, [$($x:tt)*], $asm:literal, $($rest:tt)*} => {
538 cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
539 };
540 {$($asms:tt)*} => {
541 cfg_global_asm!{@inner, [], $($asms)*}
542 };
543}
544
545// This reset vector is the initial entry point after a system reset.
546// Calls an optional user-provided __pre_init and then initialises RAM.
547// If the target has an FPU, it is enabled.
548// Finally jumps to the user main function.
549#[cfg(cortex_m)]
550cfg_global_asm! {
551 ".cfi_sections .debug_frame
552 .section .Reset, \"ax\"
553 .global Reset
554 .type Reset,%function
555 .thumb_func",
556 ".cfi_startproc
557 Reset:",
558
559 // If enabled, initialise the SP. This is normally initialised by the CPU itself or by a
560 // bootloader, but some debuggers fail to set it when resetting the target, leading to
561 // stack corruptions.
562 #[cfg(feature = "set-sp")]
563 "ldr r0, =_stack_start
564 msr msp, r0",
565
566 // If enabled, initialise VTOR to the start of the vector table. This is normally initialised
567 // by a bootloader when the non-reset value is required, but some bootloaders do not set it,
568 // leading to frustrating issues where everything seems to work but interrupts are never
569 // handled. The VTOR register is optional on ARMv6-M, but when not present is RAZ,WI and
570 // therefore safe to write to.
571 #[cfg(feature = "set-vtor")]
572 "ldr r0, =0xe000ed08
573 ldr r1, =__vector_table
574 str r1, [r0]",
575
576 // If enabled, set the Main Stack Pointer Limit (MSPLIM) to the end of the stack.
577 // This feature is only available on ARMv8-M Mainline, where it helps enforce stack limits
578 // by defining the lowest valid stack address.
579 #[cfg(all(armv8m_main, feature = "set-msplim"))]
580 "ldr r0, =_stack_end
581 msr MSPLIM, r0",
582
583 // Run user pre-init code which must be executed immediately after startup, before the
584 // potentially time-consuming memory initialisation takes place.
585 // Example use cases include disabling default watchdogs or enabling RAM.
586 "bl __pre_init",
587
588 // If enabled, initialize RAM with zeros. This is not usually required, but might be necessary
589 // to properly initialize checksum-based memory integrity measures on safety-critical hardware.
590 #[cfg(feature = "zero-init-ram")]
591 "ldr r0, =_ram_start
592 ldr r1, =_ram_end
593 movs r2, #0
594 0:
595 cmp r1, r0
596 beq 1f
597 stm r0!, {{r2}}
598 b 0b
599 1:",
600
601 // Initialise .bss memory. `__sbss` and `__ebss` come from the linker script.
602 #[cfg(not(feature = "zero-init-ram"))]
603 "ldr r0, =__sbss
604 ldr r1, =__ebss
605 movs r2, #0
606 0:
607 cmp r1, r0
608 beq 1f
609 stm r0!, {{r2}}
610 b 0b
611 1:",
612
613 // If enabled, paint stack/heap RAM with 0xcccccccc.
614 // `_stack_end` and `_stack_start` come from the linker script.
615 #[cfg(feature = "paint-stack")]
616 "ldr r0, =_stack_end
617 ldr r1, =_stack_start
618 ldr r2, =0xcccccccc // This must match STACK_PAINT_VALUE
619 0:
620 cmp r1, r0
621 beq 1f
622 stm r0!, {{r2}}
623 b 0b
624 1:",
625
626 // Initialise .data memory. `__sdata`, `__sidata`, and `__edata` come from the linker script.
627 #[cfg(not(feature = "skip-data-copy"))]
628 "ldr r0, =__sdata
629 ldr r1, =__edata
630 ldr r2, =__sidata
631 0:
632 cmp r1, r0
633 beq 1f
634 ldm r2!, {{r3}}
635 stm r0!, {{r3}}
636 b 0b
637 1:",
638
639 // Potentially enable an FPU.
640 // SCB.CPACR is 0xE000_ED88.
641 // We enable access to CP10 and CP11 from priviliged and unprivileged mode.
642 #[cfg(has_fpu)]
643 "ldr r0, =0xE000ED88
644 ldr r1, =(0b1111 << 20)
645 ldr r2, [r0]
646 orr r2, r2, r1
647 str r2, [r0]
648 dsb
649 isb",
650
651 // Jump to user main function.
652 // `bl` is used for the extended range, but the user main function should not return,
653 // so trap on any unexpected return.
654 "bl main
655 udf #0",
656
657 ".cfi_endproc
658 .size Reset, . - Reset",
659}
660
661/// Attribute to declare an interrupt (AKA device-specific exception) handler
662///
663/// **NOTE**: This attribute is exposed by `cortex-m-rt` only when the `device` feature is enabled.
664/// However, that export is not meant to be used directly -- using it will result in a compilation
665/// error. You should instead use the PAC (usually generated using `svd2rust`) re-export of
666/// that attribute. You need to use the re-export to have the compiler check that the interrupt
667/// exists on the target device.
668///
669/// # Syntax
670///
671/// ``` ignore
672/// extern crate device;
673///
674/// // the attribute comes from the PAC not from cortex-m-rt
675/// use device::interrupt;
676///
677/// #[interrupt]
678/// fn USART1() {
679/// // ..
680/// }
681/// ```
682///
683/// where the name of the function must be one of the device interrupts.
684///
685/// # Usage
686///
687/// `#[interrupt] fn Name(..` overrides the default handler for the interrupt with the given `Name`.
688/// These handlers must have signature `[unsafe] fn() [-> !]`. It's possible to add state to these
689/// handlers by declaring `static mut` variables at the beginning of the body of the function. These
690/// variables will be safe to access from the function body.
691///
692/// If the interrupt handler has not been overridden it will be dispatched by the default exception
693/// handler (`DefaultHandler`).
694///
695/// # Properties
696///
697/// Interrupts handlers can only be called by the hardware. Other parts of the program can't refer
698/// to the interrupt handlers, much less invoke them as if they were functions.
699///
700/// `static mut` variables declared within an interrupt handler are safe to access and can be used
701/// to preserve state across invocations of the handler. The compiler can't prove this is safe so
702/// the attribute will help by making a transformation to the source code: for this reason a
703/// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`.
704///
705/// # Examples
706///
707/// - Using state within an interrupt handler
708///
709/// ``` ignore
710/// extern crate device;
711///
712/// use device::interrupt;
713///
714/// #[interrupt]
715/// fn TIM2() {
716/// static mut COUNT: i32 = 0;
717///
718/// // `COUNT` is safe to access and has type `&mut i32`
719/// *COUNT += 1;
720///
721/// println!("{}", COUNT);
722/// }
723/// ```
724#[cfg(feature = "device")]
725pub use macros::interrupt;
726
727/// Attribute to declare the entry point of the program
728///
729/// The specified function will be called by the reset handler *after* RAM has been initialized. In
730/// the case of the `thumbv7em-none-eabihf` target the FPU will also be enabled before the function
731/// is called.
732///
733/// The type of the specified function must be `[unsafe] fn() -> !` (never ending function)
734///
735/// # Properties
736///
737/// The entry point will be called by the reset handler. The program can't reference to the entry
738/// point, much less invoke it.
739///
740/// `static mut` variables declared within the entry point are safe to access. The compiler can't
741/// prove this is safe so the attribute will help by making a transformation to the source code: for
742/// this reason a variable like `static mut FOO: u32` will become `let FOO: &'static mut u32;`. Note
743/// that `&'static mut` references have move semantics.
744///
745/// # Examples
746///
747/// - Simple entry point
748///
749/// ``` no_run
750/// # #![no_main]
751/// # use cortex_m_rt::entry;
752/// #[entry]
753/// fn main() -> ! {
754/// loop {
755/// /* .. */
756/// }
757/// }
758/// ```
759///
760/// - `static mut` variables local to the entry point are safe to modify.
761///
762/// ``` no_run
763/// # #![no_main]
764/// # use cortex_m_rt::entry;
765/// #[entry]
766/// fn main() -> ! {
767/// static mut FOO: u32 = 0;
768///
769/// let foo: &'static mut u32 = FOO;
770/// assert_eq!(*foo, 0);
771/// *foo = 1;
772/// assert_eq!(*foo, 1);
773///
774/// loop {
775/// /* .. */
776/// }
777/// }
778/// ```
779pub use macros::entry;
780
781/// Attribute to declare an exception handler
782///
783/// # Syntax
784///
785/// ```
786/// # use cortex_m_rt::exception;
787/// #[exception]
788/// fn SysTick() {
789/// // ..
790/// }
791///
792/// # fn main() {}
793/// ```
794///
795/// where the name of the function must be one of:
796///
797/// - `DefaultHandler`
798/// - `NonMaskableInt`
799/// - `HardFault`
800/// - `MemoryManagement` (a)
801/// - `BusFault` (a)
802/// - `UsageFault` (a)
803/// - `SecureFault` (b)
804/// - `SVCall`
805/// - `DebugMonitor` (a)
806/// - `PendSV`
807/// - `SysTick`
808///
809/// (a) Not available on Cortex-M0 variants (`thumbv6m-none-eabi`)
810///
811/// (b) Only available on ARMv8-M
812///
813/// # Usage
814///
815/// ## HardFault handler
816///
817/// `#[exception(trampoline = true)] unsafe fn HardFault(..` sets the hard fault handler.
818/// If the trampoline parameter is set to true, the handler must have signature `unsafe fn(&ExceptionFrame) -> !`.
819/// If set to false, the handler must have signature `unsafe fn() -> !`.
820///
821/// This handler is not allowed to return as that can cause undefined behavior.
822///
823/// To maintain backwards compatibility the attribute can be used without trampoline parameter (`#[exception]`),
824/// which sets the trampoline to true.
825///
826/// ## Default handler
827///
828/// `#[exception] unsafe fn DefaultHandler(..` sets the *default* handler. All exceptions which have
829/// not been assigned a handler will be serviced by this handler. This handler must have signature
830/// `unsafe fn(irqn: i16) [-> !]`. `irqn` is the IRQ number (See CMSIS); `irqn` will be a negative
831/// number when the handler is servicing a core exception; `irqn` will be a positive number when the
832/// handler is servicing a device specific exception (interrupt).
833///
834/// ## Other handlers
835///
836/// `#[exception] fn Name(..` overrides the default handler for the exception with the given `Name`.
837/// These handlers must have signature `[unsafe] fn() [-> !]`. When overriding these other exception
838/// it's possible to add state to them by declaring `static mut` variables at the beginning of the
839/// body of the function. These variables will be safe to access from the function body.
840///
841/// # Properties
842///
843/// Exception handlers can only be called by the hardware. Other parts of the program can't refer to
844/// the exception handlers, much less invoke them as if they were functions.
845///
846/// `static mut` variables declared within an exception handler are safe to access and can be used
847/// to preserve state across invocations of the handler. The compiler can't prove this is safe so
848/// the attribute will help by making a transformation to the source code: for this reason a
849/// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`.
850///
851/// # Safety
852///
853/// It is not generally safe to register handlers for non-maskable interrupts. On Cortex-M,
854/// `HardFault` is non-maskable (at least in general), and there is an explicitly non-maskable
855/// interrupt `NonMaskableInt`.
856///
857/// The reason for that is that non-maskable interrupts will preempt any currently running function,
858/// even if that function executes within a critical section. Thus, if it was safe to define NMI
859/// handlers, critical sections wouldn't work safely anymore.
860///
861/// This also means that defining a `DefaultHandler` must be unsafe, as that will catch
862/// `NonMaskableInt` and `HardFault` if no handlers for those are defined.
863///
864/// The safety requirements on those handlers is as follows: The handler must not access any data
865/// that is protected via a critical section and shared with other interrupts that may be preempted
866/// by the NMI while holding the critical section. As long as this requirement is fulfilled, it is
867/// safe to handle NMIs.
868///
869/// # Examples
870///
871/// - Setting the default handler
872///
873/// ```
874/// use cortex_m_rt::exception;
875///
876/// #[exception]
877/// unsafe fn DefaultHandler(irqn: i16) {
878/// println!("IRQn = {}", irqn);
879/// }
880///
881/// # fn main() {}
882/// ```
883///
884/// - Overriding the `SysTick` handler
885///
886/// ```
887/// use cortex_m_rt::exception;
888///
889/// #[exception]
890/// fn SysTick() {
891/// static mut COUNT: i32 = 0;
892///
893/// // `COUNT` is safe to access and has type `&mut i32`
894/// *COUNT += 1;
895///
896/// println!("{}", COUNT);
897/// }
898///
899/// # fn main() {}
900/// ```
901pub use macros::exception;
902
903/// Attribute to mark which function will be called at the beginning of the reset handler.
904///
905/// **IMPORTANT**: This attribute can appear at most *once* in the dependency graph.
906///
907/// The function must have the signature of `unsafe fn()`.
908///
909/// # Safety
910///
911/// The function will be called before memory is initialized, as soon as possible after reset. Any
912/// access of memory, including any static variables, will result in undefined behavior.
913///
914/// **Warning**: Due to [rvalue static promotion][rfc1414] static variables may be accessed whenever
915/// taking a reference to a constant. This means that even trivial expressions such as `&1` in the
916/// `#[pre_init]` function *or any code called by it* will cause **immediate undefined behavior**.
917///
918/// Users are advised to only use the `#[pre_init]` feature when absolutely necessary as these
919/// constraints make safe usage difficult.
920///
921/// # Examples
922///
923/// ```
924/// # use cortex_m_rt::pre_init;
925/// #[pre_init]
926/// unsafe fn before_main() {
927/// // do something here
928/// }
929///
930/// # fn main() {}
931/// ```
932///
933/// [rfc1414]: https://github.com/rust-lang/rfcs/blob/master/text/1414-rvalue_static_promotion.md
934pub use macros::pre_init;
935
936// We export this static with an informative name so that if an application attempts to link
937// two copies of cortex-m-rt together, linking will fail. We also declare a links key in
938// Cargo.toml which is the more modern way to solve the same problem, but we have to keep
939// __ONCE__ around to prevent linking with versions before the links key was added.
940#[unsafe(export_name = "error: cortex-m-rt appears more than once in the dependency graph")]
941#[doc(hidden)]
942pub static __ONCE__: () = ();
943
944/// Registers stacked (pushed onto the stack) during an exception.
945#[derive(Clone, Copy)]
946#[repr(C)]
947#[allow(dead_code)]
948pub struct ExceptionFrame {
949 r0: u32,
950 r1: u32,
951 r2: u32,
952 r3: u32,
953 r12: u32,
954 lr: u32,
955 pc: u32,
956 xpsr: u32,
957}
958
959impl ExceptionFrame {
960 /// Returns the value of (general purpose) register 0.
961 #[inline(always)]
962 pub fn r0(&self) -> u32 {
963 self.r0
964 }
965
966 /// Returns the value of (general purpose) register 1.
967 #[inline(always)]
968 pub fn r1(&self) -> u32 {
969 self.r1
970 }
971
972 /// Returns the value of (general purpose) register 2.
973 #[inline(always)]
974 pub fn r2(&self) -> u32 {
975 self.r2
976 }
977
978 /// Returns the value of (general purpose) register 3.
979 #[inline(always)]
980 pub fn r3(&self) -> u32 {
981 self.r3
982 }
983
984 /// Returns the value of (general purpose) register 12.
985 #[inline(always)]
986 pub fn r12(&self) -> u32 {
987 self.r12
988 }
989
990 /// Returns the value of the Link Register.
991 #[inline(always)]
992 pub fn lr(&self) -> u32 {
993 self.lr
994 }
995
996 /// Returns the value of the Program Counter.
997 #[inline(always)]
998 pub fn pc(&self) -> u32 {
999 self.pc
1000 }
1001
1002 /// Returns the value of the Program Status Register.
1003 #[inline(always)]
1004 pub fn xpsr(&self) -> u32 {
1005 self.xpsr
1006 }
1007
1008 /// Sets the stacked value of (general purpose) register 0.
1009 ///
1010 /// # Safety
1011 ///
1012 /// This affects the `r0` register of the preempted code, which must not rely on it getting
1013 /// restored to its previous value.
1014 #[inline(always)]
1015 pub unsafe fn set_r0(&mut self, value: u32) {
1016 self.r0 = value;
1017 }
1018
1019 /// Sets the stacked value of (general purpose) register 1.
1020 ///
1021 /// # Safety
1022 ///
1023 /// This affects the `r1` register of the preempted code, which must not rely on it getting
1024 /// restored to its previous value.
1025 #[inline(always)]
1026 pub unsafe fn set_r1(&mut self, value: u32) {
1027 self.r1 = value;
1028 }
1029
1030 /// Sets the stacked value of (general purpose) register 2.
1031 ///
1032 /// # Safety
1033 ///
1034 /// This affects the `r2` register of the preempted code, which must not rely on it getting
1035 /// restored to its previous value.
1036 #[inline(always)]
1037 pub unsafe fn set_r2(&mut self, value: u32) {
1038 self.r2 = value;
1039 }
1040
1041 /// Sets the stacked value of (general purpose) register 3.
1042 ///
1043 /// # Safety
1044 ///
1045 /// This affects the `r3` register of the preempted code, which must not rely on it getting
1046 /// restored to its previous value.
1047 #[inline(always)]
1048 pub unsafe fn set_r3(&mut self, value: u32) {
1049 self.r3 = value;
1050 }
1051
1052 /// Sets the stacked value of (general purpose) register 12.
1053 ///
1054 /// # Safety
1055 ///
1056 /// This affects the `r12` register of the preempted code, which must not rely on it getting
1057 /// restored to its previous value.
1058 #[inline(always)]
1059 pub unsafe fn set_r12(&mut self, value: u32) {
1060 self.r12 = value;
1061 }
1062
1063 /// Sets the stacked value of the Link Register.
1064 ///
1065 /// # Safety
1066 ///
1067 /// This affects the `lr` register of the preempted code, which must not rely on it getting
1068 /// restored to its previous value.
1069 #[inline(always)]
1070 pub unsafe fn set_lr(&mut self, value: u32) {
1071 self.lr = value;
1072 }
1073
1074 /// Sets the stacked value of the Program Counter.
1075 ///
1076 /// # Safety
1077 ///
1078 /// This affects the `pc` register of the preempted code, which must not rely on it getting
1079 /// restored to its previous value.
1080 #[inline(always)]
1081 pub unsafe fn set_pc(&mut self, value: u32) {
1082 self.pc = value;
1083 }
1084
1085 /// Sets the stacked value of the Program Status Register.
1086 ///
1087 /// # Safety
1088 ///
1089 /// This affects the `xPSR` registers (`IPSR`, `APSR`, and `EPSR`) of the preempted code, which
1090 /// must not rely on them getting restored to their previous value.
1091 #[inline(always)]
1092 pub unsafe fn set_xpsr(&mut self, value: u32) {
1093 self.xpsr = value;
1094 }
1095}
1096
1097impl fmt::Debug for ExceptionFrame {
1098 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1099 struct Hex(u32);
1100 impl fmt::Debug for Hex {
1101 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1102 write!(f, "0x{:08x}", self.0)
1103 }
1104 }
1105 f.debug_struct("ExceptionFrame")
1106 .field("r0", &Hex(self.r0))
1107 .field("r1", &Hex(self.r1))
1108 .field("r2", &Hex(self.r2))
1109 .field("r3", &Hex(self.r3))
1110 .field("r12", &Hex(self.r12))
1111 .field("lr", &Hex(self.lr))
1112 .field("pc", &Hex(self.pc))
1113 .field("xpsr", &Hex(self.xpsr))
1114 .finish()
1115 }
1116}
1117
1118/// Returns a pointer to the start of the heap
1119///
1120/// The returned pointer is guaranteed to be 4-byte aligned.
1121#[inline]
1122pub fn heap_start() -> *mut u32 {
1123 unsafe extern "C" {
1124 static mut __sheap: u32;
1125 }
1126
1127 #[allow(unused_unsafe)] // no longer unsafe since rust 1.82.0
1128 unsafe {
1129 core::ptr::addr_of_mut!(__sheap)
1130 }
1131}
1132
1133// Entry point is Reset.
1134#[doc(hidden)]
1135#[cfg_attr(cortex_m, unsafe(link_section = ".vector_table.reset_vector"))]
1136#[unsafe(no_mangle)]
1137pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset;
1138
1139#[doc(hidden)]
1140#[cfg_attr(cortex_m, unsafe(link_section = ".HardFault.default"))]
1141#[unsafe(no_mangle)]
1142pub unsafe extern "C" fn HardFault_() -> ! {
1143 #[allow(clippy::empty_loop)]
1144 loop {}
1145}
1146
1147#[doc(hidden)]
1148#[unsafe(no_mangle)]
1149pub unsafe extern "C" fn DefaultHandler_() -> ! {
1150 #[allow(clippy::empty_loop)]
1151 loop {}
1152}
1153
1154#[doc(hidden)]
1155#[unsafe(no_mangle)]
1156pub unsafe extern "C" fn DefaultPreInit() {}
1157
1158/* Exceptions */
1159#[doc(hidden)]
1160pub enum Exception {
1161 NonMaskableInt,
1162
1163 // Not overridable
1164 // HardFault,
1165 #[cfg(not(armv6m))]
1166 MemoryManagement,
1167
1168 #[cfg(not(armv6m))]
1169 BusFault,
1170
1171 #[cfg(not(armv6m))]
1172 UsageFault,
1173
1174 #[cfg(armv8m)]
1175 SecureFault,
1176
1177 SVCall,
1178
1179 #[cfg(not(armv6m))]
1180 DebugMonitor,
1181
1182 PendSV,
1183
1184 SysTick,
1185}
1186
1187#[doc(hidden)]
1188pub use self::Exception as exception;
1189
1190unsafe extern "C" {
1191 fn Reset() -> !;
1192
1193 fn NonMaskableInt();
1194
1195 fn HardFault();
1196
1197 #[cfg(not(armv6m))]
1198 fn MemoryManagement();
1199
1200 #[cfg(not(armv6m))]
1201 fn BusFault();
1202
1203 #[cfg(not(armv6m))]
1204 fn UsageFault();
1205
1206 #[cfg(armv8m)]
1207 fn SecureFault();
1208
1209 fn SVCall();
1210
1211 #[cfg(not(armv6m))]
1212 fn DebugMonitor();
1213
1214 fn PendSV();
1215
1216 fn SysTick();
1217}
1218
1219#[doc(hidden)]
1220#[repr(C)]
1221pub union Vector {
1222 handler: unsafe extern "C" fn(),
1223 reserved: usize,
1224}
1225
1226#[doc(hidden)]
1227#[cfg_attr(cortex_m, unsafe(link_section = ".vector_table.exceptions"))]
1228#[unsafe(no_mangle)]
1229pub static __EXCEPTIONS: [Vector; 14] = [
1230 // Exception 2: Non Maskable Interrupt.
1231 Vector {
1232 handler: NonMaskableInt,
1233 },
1234 // Exception 3: Hard Fault Interrupt.
1235 Vector { handler: HardFault },
1236 // Exception 4: Memory Management Interrupt [not on Cortex-M0 variants].
1237 #[cfg(not(armv6m))]
1238 Vector {
1239 handler: MemoryManagement,
1240 },
1241 #[cfg(armv6m)]
1242 Vector { reserved: 0 },
1243 // Exception 5: Bus Fault Interrupt [not on Cortex-M0 variants].
1244 #[cfg(not(armv6m))]
1245 Vector { handler: BusFault },
1246 #[cfg(armv6m)]
1247 Vector { reserved: 0 },
1248 // Exception 6: Usage Fault Interrupt [not on Cortex-M0 variants].
1249 #[cfg(not(armv6m))]
1250 Vector {
1251 handler: UsageFault,
1252 },
1253 #[cfg(armv6m)]
1254 Vector { reserved: 0 },
1255 // Exception 7: Secure Fault Interrupt [only on Armv8-M].
1256 #[cfg(armv8m)]
1257 Vector {
1258 handler: SecureFault,
1259 },
1260 #[cfg(not(armv8m))]
1261 Vector { reserved: 0 },
1262 // 8-10: Reserved
1263 Vector { reserved: 0 },
1264 Vector { reserved: 0 },
1265 Vector { reserved: 0 },
1266 // Exception 11: SV Call Interrupt.
1267 Vector { handler: SVCall },
1268 // Exception 12: Debug Monitor Interrupt [not on Cortex-M0 variants].
1269 #[cfg(not(armv6m))]
1270 Vector {
1271 handler: DebugMonitor,
1272 },
1273 #[cfg(armv6m)]
1274 Vector { reserved: 0 },
1275 // 13: Reserved
1276 Vector { reserved: 0 },
1277 // Exception 14: Pend SV Interrupt [not on Cortex-M0 variants].
1278 Vector { handler: PendSV },
1279 // Exception 15: System Tick Interrupt.
1280 Vector { handler: SysTick },
1281];
1282
1283// If we are not targeting a specific device we bind all the potential device specific interrupts
1284// to the default handler
1285#[cfg(all(any(not(feature = "device"), test), not(armv6m), not(armv8m_main)))]
1286#[doc(hidden)]
1287#[cfg_attr(cortex_m, unsafe(link_section = ".vector_table.interrupts"))]
1288#[unsafe(no_mangle)]
1289pub static __INTERRUPTS: [unsafe extern "C" fn(); 240] = [{
1290 unsafe extern "C" {
1291 fn DefaultHandler();
1292 }
1293
1294 DefaultHandler
1295}; 240];
1296
1297// ARMv8-M Mainline can have up to 480 device specific interrupts
1298#[cfg(all(not(feature = "device"), armv8m_main))]
1299#[doc(hidden)]
1300#[cfg_attr(cortex_m, unsafe(link_section = ".vector_table.interrupts"))]
1301#[unsafe(no_mangle)]
1302pub static __INTERRUPTS: [unsafe extern "C" fn(); 480] = [{
1303 unsafe extern "C" {
1304 fn DefaultHandler();
1305 }
1306
1307 DefaultHandler
1308}; 480];
1309
1310// ARMv6-M can only have a maximum of 32 device specific interrupts
1311#[cfg(all(not(feature = "device"), armv6m))]
1312#[doc(hidden)]
1313#[unsafe(link_section = ".vector_table.interrupts")]
1314#[unsafe(no_mangle)]
1315pub static __INTERRUPTS: [unsafe extern "C" fn(); 32] = [{
1316 unsafe extern "C" {
1317 fn DefaultHandler();
1318 }
1319
1320 DefaultHandler
1321}; 32];