xtensa_lx_rt/
lib.rs

1//! Minimal startup/runtime for Xtensa LX CPUs.
2//!
3//! ## Feature Flags
4#![doc = document_features::document_features!()]
5#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
6#![allow(asm_sub_register, named_asm_labels)]
7#![feature(asm_experimental_arch)]
8#![no_std]
9
10use core::{
11    arch::asm,
12    ptr::{addr_of, addr_of_mut},
13};
14
15pub use macros::{entry, exception, interrupt, pre_init};
16pub use r0::{init_data, zero_bss};
17pub use xtensa_lx;
18
19pub mod exception;
20pub mod interrupt;
21
22#[doc(hidden)]
23#[unsafe(no_mangle)]
24pub unsafe extern "C" fn DefaultPreInit() {}
25
26#[doc(hidden)]
27#[unsafe(no_mangle)]
28pub unsafe extern "C" fn Reset() -> ! {
29    unsafe {
30        // These symbols come from `link.x`
31        unsafe extern "C" {
32            static mut _bss_start: u32;
33            static mut _bss_end: u32;
34
35            static mut _data_start: u32;
36            static mut _data_end: u32;
37            static _sidata: u32;
38
39            static mut _init_start: u32;
40
41        }
42
43        unsafe extern "Rust" {
44            // This symbol will be provided by the user via `#[entry]`
45            fn main() -> !;
46
47            // This symbol will be provided by the user via `#[pre_init]`
48            fn __pre_init();
49
50            fn __post_init();
51
52            fn __zero_bss() -> bool;
53
54            fn __init_data() -> bool;
55        }
56
57        __pre_init();
58
59        if __zero_bss() {
60            r0::zero_bss(addr_of_mut!(_bss_start), addr_of_mut!(_bss_end));
61        }
62
63        if __init_data() {
64            r0::init_data(addr_of_mut!(_data_start), addr_of_mut!(_data_end), &_sidata);
65        }
66
67        // Copy of data segment is done by bootloader
68
69        // According to 4.4.6.2 of the xtensa isa, ccount and compare are undefined on
70        // reset, set all values to zero to disable
71        reset_internal_timers();
72
73        // move vec table
74        set_vecbase(addr_of!(_init_start));
75
76        __post_init();
77
78        main();
79    }
80}
81
82#[doc(hidden)]
83#[unsafe(no_mangle)]
84#[rustfmt::skip]
85pub unsafe extern "Rust" fn default_post_init() {}
86
87// We redefine these functions to avoid pulling in `xtensa-lx` as a dependency:
88
89#[doc(hidden)]
90#[inline]
91unsafe fn reset_internal_timers() {
92    unsafe {
93        #[cfg(any(
94            XCHAL_HAVE_TIMER0,
95            XCHAL_HAVE_TIMER1,
96            XCHAL_HAVE_TIMER2,
97            XCHAL_HAVE_TIMER3
98        ))]
99        {
100            let value = 0;
101            cfg_asm!(
102        {
103            #[cfg(XCHAL_HAVE_TIMER0)]
104            "wsr.ccompare0 {0}",
105            #[cfg(XCHAL_HAVE_TIMER1)]
106            "wsr.ccompare1 {0}",
107            #[cfg(XCHAL_HAVE_TIMER2)]
108            "wsr.ccompare2 {0}",
109            #[cfg(XCHAL_HAVE_TIMER3)]
110            "wsr.ccompare3 {0}",
111            "isync",
112        }, in(reg) value, options(nostack));
113        }
114    }
115}
116
117// CPU Interrupts
118unsafe extern "C" {
119    #[cfg(XCHAL_HAVE_TIMER0)]
120    pub fn Timer0(save_frame: &mut crate::exception::Context);
121    #[cfg(XCHAL_HAVE_TIMER1)]
122    pub fn Timer1(save_frame: &mut crate::exception::Context);
123    #[cfg(XCHAL_HAVE_TIMER2)]
124    pub fn Timer2(save_frame: &mut crate::exception::Context);
125    #[cfg(XCHAL_HAVE_TIMER3)]
126    pub fn Timer3(save_frame: &mut crate::exception::Context);
127
128    #[cfg(XCHAL_HAVE_PROFILING)]
129    pub fn Profiling(save_frame: &mut crate::exception::Context);
130
131    #[cfg(XCHAL_HAVE_SOFTWARE0)]
132    pub fn Software0(save_frame: &mut crate::exception::Context);
133    #[cfg(XCHAL_HAVE_SOFTWARE1)]
134    pub fn Software1(save_frame: &mut crate::exception::Context);
135
136    #[cfg(XCHAL_HAVE_NMI)]
137    pub fn NMI(save_frame: &mut crate::exception::Context);
138}
139
140#[doc(hidden)]
141#[inline]
142unsafe fn set_vecbase(base: *const u32) {
143    unsafe {
144        asm!("wsr.vecbase {0}", in(reg) base, options(nostack));
145    }
146}
147
148#[doc(hidden)]
149#[unsafe(no_mangle)]
150#[rustfmt::skip]
151pub extern "Rust" fn default_mem_hook() -> bool {
152    true // default to zeroing bss & initializing data
153}
154
155#[doc(hidden)]
156#[macro_export]
157macro_rules! cfg_asm {
158    (@inner, [$($x:tt)*], [$($opts:tt)*], ) => {
159        asm!($($x)* $($opts)*)
160    };
161    (@inner, [$($x:tt)*], [$($opts:tt)*], #[cfg($meta:meta)] $asm:literal, $($rest:tt)*) => {
162        #[cfg($meta)]
163        cfg_asm!(@inner, [$($x)* $asm,], [$($opts)*], $($rest)*);
164        #[cfg(not($meta))]
165        cfg_asm!(@inner, [$($x)*], [$($opts)*], $($rest)*)
166    };
167    (@inner, [$($x:tt)*], [$($opts:tt)*], $asm:literal, $($rest:tt)*) => {
168        cfg_asm!(@inner, [$($x)* $asm,], [$($opts)*], $($rest)*)
169    };
170    ({$($asms:tt)*}, $($opts:tt)*) => {
171        cfg_asm!(@inner, [], [$($opts)*], $($asms)*)
172    };
173}
174
175#[doc(hidden)]
176#[macro_export]
177macro_rules! cfg_global_asm {
178    {@inner, [$($x:tt)*], } => {
179        global_asm!{$($x)*}
180    };
181    (@inner, [$($x:tt)*], #[cfg($meta:meta)] $asm:literal, $($rest:tt)*) => {
182        #[cfg($meta)]
183        cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
184        #[cfg(not($meta))]
185        cfg_global_asm!{@inner, [$($x)*], $($rest)*}
186    };
187    {@inner, [$($x:tt)*], $asm:literal, $($rest:tt)*} => {
188        cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
189    };
190    {$($asms:tt)*} => {
191        cfg_global_asm!{@inner, [], $($asms)*}
192    };
193}