Skip to main content

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