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//! # 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];