mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-26 20:00:32 +00:00
Rewrite Xtensa startup code in assembly (#4117)
* Initialize rtc RAM in xtensa-lx-rt * Rewrite CPU reset handler in ASM
This commit is contained in:
parent
3a4b7c6ded
commit
321ae5ef1b
@ -87,7 +87,7 @@ esp32s2 = { version = "0.29.0", features = ["critical-section", "rt"], optional
|
||||
esp32s3 = { version = "0.33.0", features = ["critical-section", "rt"], optional = true, git = "https://github.com/esp-rs/esp-pacs", rev = "aaacac954c30c19debd1c86fd6bbecf3ae554581" }
|
||||
|
||||
[target.'cfg(target_arch = "riscv32")'.dependencies]
|
||||
riscv = { version = "0.15.0", optional = true }
|
||||
riscv = { version = "0.15.0" }
|
||||
esp-riscv-rt = { version = "0.12.0", path = "../esp-riscv-rt", optional = true }
|
||||
|
||||
[target.'cfg(target_arch = "xtensa")'.dependencies]
|
||||
@ -136,7 +136,6 @@ esp32 = [
|
||||
# Target the ESP32-C2.
|
||||
esp32c2 = [
|
||||
"dep:esp32c2",
|
||||
"dep:riscv",
|
||||
"esp-riscv-rt/no-mie-mip",
|
||||
"portable-atomic/unsafe-assume-single-core",
|
||||
"esp-rom-sys/esp32c2",
|
||||
@ -146,7 +145,6 @@ esp32c2 = [
|
||||
# Target the ESP32-C3.
|
||||
esp32c3 = [
|
||||
"dep:esp32c3",
|
||||
"dep:riscv",
|
||||
"esp-riscv-rt/no-mie-mip",
|
||||
"esp-riscv-rt/rtc-ram",
|
||||
"portable-atomic/unsafe-assume-single-core",
|
||||
@ -157,7 +155,6 @@ esp32c3 = [
|
||||
# Target the ESP32-C6.
|
||||
esp32c6 = [
|
||||
"dep:esp32c6",
|
||||
"dep:riscv",
|
||||
"esp-riscv-rt/rtc-ram",
|
||||
"procmacros/has-lp-core",
|
||||
"esp-rom-sys/esp32c6",
|
||||
@ -167,7 +164,6 @@ esp32c6 = [
|
||||
# Target the ESP32-H2.
|
||||
esp32h2 = [
|
||||
"dep:esp32h2",
|
||||
"dep:riscv",
|
||||
"esp-riscv-rt/rtc-ram",
|
||||
"esp-rom-sys/esp32h2",
|
||||
"esp-sync/esp32h2",
|
||||
|
@ -1,13 +1,3 @@
|
||||
|
||||
/* before memory.x to allow override */
|
||||
ENTRY(ESP32Reset)
|
||||
|
||||
/* after memory.x to allow override */
|
||||
PROVIDE(__pre_init = DefaultPreInit);
|
||||
PROVIDE(__zero_bss = default_mem_hook);
|
||||
PROVIDE(__init_data = default_mem_hook);
|
||||
PROVIDE(__post_init = default_post_init);
|
||||
|
||||
INCLUDE exception.x
|
||||
|
||||
/* ESP32 fixups */
|
||||
|
@ -5,9 +5,6 @@
|
||||
for details
|
||||
*/
|
||||
|
||||
/* override entry point */
|
||||
ENTRY(ESP32Reset)
|
||||
|
||||
INCLUDE "memory_extras.x"
|
||||
|
||||
/* Specify main memory areas */
|
||||
@ -59,4 +56,3 @@ MEMORY
|
||||
/* RTC slow memory (data accessible). Persists over deep sleep. */
|
||||
rtc_slow_seg(RW) : ORIGIN = 0x50000000, len = 8k
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,3 @@
|
||||
|
||||
/* before memory.x to allow override */
|
||||
ENTRY(ESP32Reset)
|
||||
|
||||
/* after memory.x to allow override */
|
||||
PROVIDE(__pre_init = DefaultPreInit);
|
||||
PROVIDE(__zero_bss = default_mem_hook);
|
||||
PROVIDE(__init_data = default_mem_hook);
|
||||
PROVIDE(__post_init = default_post_init);
|
||||
|
||||
INCLUDE exception.x
|
||||
|
||||
/* This represents .rwtext but in .data */
|
||||
|
@ -1,13 +1,10 @@
|
||||
/* This memory map assumes the flash cache is on;
|
||||
the blocks used are excluded from the various memory ranges
|
||||
|
||||
/* This memory map assumes the flash cache is on;
|
||||
the blocks used are excluded from the various memory ranges
|
||||
|
||||
see: https://github.com/espressif/esp-idf/blob/5b1189570025ba027f2ff6c2d91f6ffff3809cc2/components/heap/port/esp32s2/memory_layout.c
|
||||
for details
|
||||
*/
|
||||
|
||||
/* override entry point */
|
||||
ENTRY(ESP32Reset)
|
||||
|
||||
INCLUDE "memory_extras.x"
|
||||
|
||||
VECTORS_SIZE = 0x400;
|
||||
@ -23,7 +20,7 @@ MEMORY
|
||||
/* memory available after the 2nd stage bootloader is finished */
|
||||
dram2_seg ( RW ) : ORIGIN = ORIGIN(dram_seg) + LENGTH(dram_seg), len = 136K
|
||||
|
||||
/* external flash
|
||||
/* external flash
|
||||
The 0x20 offset is a convenience for the app binary image generation.
|
||||
Flash cache has 64KB pages. The .bin file which is flashed to the chip
|
||||
has a 0x18 byte file header, and each segment has a 0x08 byte segment
|
||||
|
@ -1,12 +1,3 @@
|
||||
/* before memory.x to allow override */
|
||||
ENTRY(ESP32Reset)
|
||||
|
||||
/* after memory.x to allow override */
|
||||
PROVIDE(__pre_init = DefaultPreInit);
|
||||
PROVIDE(__zero_bss = default_mem_hook);
|
||||
PROVIDE(__init_data = default_mem_hook);
|
||||
PROVIDE(__post_init = default_post_init);
|
||||
|
||||
INCLUDE exception.x
|
||||
|
||||
SECTIONS {
|
||||
|
@ -1,6 +1,3 @@
|
||||
/* override entry point */
|
||||
ENTRY(ESP32Reset)
|
||||
|
||||
#IF ESP_HAL_CONFIG_INSTRUCTION_CACHE_SIZE_32KB
|
||||
/* reserved for ICACHE */
|
||||
RESERVE_ICACHE = 0x8000;
|
||||
|
@ -6,7 +6,7 @@ SECTIONS {
|
||||
*(.rtc_fast.literal .rtc_fast.text .rtc_fast.literal.* .rtc_fast.text.*)
|
||||
. = ALIGN(4);
|
||||
} > RTC_FAST_RWTEXT AT > RODATA
|
||||
|
||||
|
||||
.rtc_fast.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
@ -16,6 +16,9 @@ SECTIONS {
|
||||
. = ALIGN(4);
|
||||
} > RTC_FAST_RWDATA AT > RODATA
|
||||
|
||||
/* LMA of .data */
|
||||
_rtc_fast_sidata = LOADADDR(.rtc_fast.data);
|
||||
|
||||
.rtc_fast.bss (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
@ -33,4 +36,4 @@ SECTIONS {
|
||||
_rtc_fast_persistent_end = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
} > RTC_FAST_RWDATA
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,9 @@ SECTIONS {
|
||||
. = ALIGN(4);
|
||||
} > rtc_slow_seg AT > RODATA
|
||||
|
||||
/* LMA of .data */
|
||||
_rtc_slow_sidata = LOADADDR(.rtc_slow.data);
|
||||
|
||||
.rtc_slow.bss (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
@ -33,4 +36,4 @@ SECTIONS {
|
||||
_rtc_slow_persistent_end = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
} > rtc_slow_seg
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,10 @@
|
||||
ENTRY(Reset)
|
||||
|
||||
PROVIDE(__zero_bss = default_mem_hook);
|
||||
PROVIDE(__init_data = default_mem_hook);
|
||||
PROVIDE(__init_persistent = default_mem_hook);
|
||||
PROVIDE(__post_init = no_init_hook);
|
||||
|
||||
PROVIDE(DefaultHandler = EspDefaultHandler);
|
||||
|
||||
PROVIDE(level1_interrupt = DefaultHandler);
|
||||
|
@ -78,82 +78,150 @@ fn hal_main(a0: usize, a1: usize, a2: usize) -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(xtensa)]
|
||||
#[cfg(feature = "rt")]
|
||||
#[unsafe(no_mangle)]
|
||||
#[cfg_attr(esp32s3, unsafe(link_section = ".rwtext"))]
|
||||
unsafe extern "C" fn ESP32Reset() -> ! {
|
||||
unsafe {
|
||||
configure_cpu_caches();
|
||||
}
|
||||
#[cfg(all(xtensa, feature = "rt"))]
|
||||
mod xtensa {
|
||||
use core::arch::{global_asm, naked_asm};
|
||||
|
||||
/// The ESP32 has a first stage bootloader that handles loading program data
|
||||
/// into the right place therefore we skip loading it again. This function
|
||||
/// is called by xtensa-lx-rt in Reset.
|
||||
#[doc(hidden)]
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "Rust" fn __init_data() -> bool {
|
||||
#[unsafe(export_name = "__init_data")]
|
||||
extern "C" fn __init_data() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
// These symbols come from `memory.x`
|
||||
extern "C" fn __init_persistent() -> bool {
|
||||
matches!(
|
||||
crate::system::reset_reason(),
|
||||
None | Some(crate::rtc_cntl::SocResetReason::ChipPowerOn)
|
||||
)
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
static mut _rtc_fast_bss_start: u32;
|
||||
static mut _rtc_fast_bss_end: u32;
|
||||
static mut _rtc_fast_persistent_start: u32;
|
||||
static mut _rtc_fast_persistent_end: u32;
|
||||
static _rtc_fast_bss_start: u32;
|
||||
static _rtc_fast_bss_end: u32;
|
||||
static _rtc_fast_persistent_end: u32;
|
||||
static _rtc_fast_persistent_start: u32;
|
||||
|
||||
static mut _rtc_slow_bss_start: u32;
|
||||
static mut _rtc_slow_bss_end: u32;
|
||||
static mut _rtc_slow_persistent_start: u32;
|
||||
static mut _rtc_slow_persistent_end: u32;
|
||||
static _rtc_slow_bss_start: u32;
|
||||
static _rtc_slow_bss_end: u32;
|
||||
static _rtc_slow_persistent_end: u32;
|
||||
static _rtc_slow_persistent_start: u32;
|
||||
|
||||
static mut _stack_start_cpu0: u32;
|
||||
fn _xtensa_lx_rt_zero_fill(s: *mut u32, e: *mut u32);
|
||||
|
||||
static mut __stack_chk_guard: u32;
|
||||
}
|
||||
|
||||
// set stack pointer to end of memory: no need to retain stack up to this point
|
||||
unsafe {
|
||||
xtensa_lx::set_stack_pointer(core::ptr::addr_of_mut!(_stack_start_cpu0));
|
||||
global_asm!(
|
||||
"
|
||||
.literal sym_init_persistent, {__init_persistent}
|
||||
.literal sym_xtensa_lx_rt_zero_fill, {_xtensa_lx_rt_zero_fill}
|
||||
|
||||
.literal sym_rtc_fast_bss_start, {_rtc_fast_bss_start}
|
||||
.literal sym_rtc_fast_bss_end, {_rtc_fast_bss_end}
|
||||
.literal sym_rtc_fast_persistent_end, {_rtc_fast_persistent_end}
|
||||
.literal sym_rtc_fast_persistent_start, {_rtc_fast_persistent_start}
|
||||
|
||||
.literal sym_rtc_slow_bss_start, {_rtc_slow_bss_start}
|
||||
.literal sym_rtc_slow_bss_end, {_rtc_slow_bss_end}
|
||||
.literal sym_rtc_slow_persistent_end, {_rtc_slow_persistent_end}
|
||||
.literal sym_rtc_slow_persistent_start, {_rtc_slow_persistent_start}
|
||||
",
|
||||
__init_persistent = sym __init_persistent,
|
||||
_xtensa_lx_rt_zero_fill = sym _xtensa_lx_rt_zero_fill,
|
||||
|
||||
_rtc_fast_bss_end = sym _rtc_fast_bss_end,
|
||||
_rtc_fast_bss_start = sym _rtc_fast_bss_start,
|
||||
_rtc_fast_persistent_end = sym _rtc_fast_persistent_end,
|
||||
_rtc_fast_persistent_start = sym _rtc_fast_persistent_start,
|
||||
|
||||
_rtc_slow_bss_end = sym _rtc_slow_bss_end,
|
||||
_rtc_slow_bss_start = sym _rtc_slow_bss_start,
|
||||
_rtc_slow_persistent_end = sym _rtc_slow_persistent_end,
|
||||
_rtc_slow_persistent_start = sym _rtc_slow_persistent_start,
|
||||
);
|
||||
|
||||
#[unsafe(export_name = "__post_init")]
|
||||
#[unsafe(naked)]
|
||||
#[allow(named_asm_labels)]
|
||||
extern "C" fn post_init() {
|
||||
naked_asm!(
|
||||
"
|
||||
entry a1, 0
|
||||
|
||||
l32r a6, sym_xtensa_lx_rt_zero_fill // Pre-load address of zero-fill function
|
||||
|
||||
l32r a10, sym_rtc_fast_bss_start // Set input range to .rtc_fast.bss
|
||||
l32r a11, sym_rtc_fast_bss_end //
|
||||
callx8 a6 // Zero-fill
|
||||
|
||||
l32r a10, sym_rtc_slow_bss_start // Set input range to .rtc_slow.bss
|
||||
l32r a11, sym_rtc_slow_bss_end //
|
||||
callx8 a6 // Zero-fill
|
||||
|
||||
l32r a5, sym_init_persistent // Do we need to initialize persistent data?
|
||||
callx8 a5
|
||||
beqz a10, .Lpost_init_return // If not, skip initialization
|
||||
|
||||
l32r a10, sym_rtc_fast_persistent_start // Set input range to .rtc_fast.persistent
|
||||
l32r a11, sym_rtc_fast_persistent_end //
|
||||
callx8 a6 // Zero-fill
|
||||
|
||||
l32r a10, sym_rtc_slow_persistent_start // Set input range to .rtc_slow.persistent
|
||||
l32r a11, sym_rtc_slow_persistent_end //
|
||||
callx8 a6 // Zero-fill
|
||||
|
||||
.Lpost_init_return:
|
||||
retw.n
|
||||
",
|
||||
)
|
||||
}
|
||||
|
||||
// copying data from flash to various data segments is done by the bootloader
|
||||
// initialization to zero needs to be done by the application
|
||||
#[cfg(esp32s3)]
|
||||
global_asm!(".section .rwtext,\"ax\",@progbits");
|
||||
global_asm!(
|
||||
"
|
||||
.literal sym_stack_chk_guard, {__stack_chk_guard}
|
||||
.literal stack_guard_value, {stack_guard_value}
|
||||
",
|
||||
__stack_chk_guard = sym __stack_chk_guard,
|
||||
stack_guard_value = const esp_config::esp_config_int!(
|
||||
u32,
|
||||
"ESP_HAL_CONFIG_STACK_GUARD_VALUE"
|
||||
)
|
||||
);
|
||||
|
||||
// Initialize RTC RAM
|
||||
unsafe {
|
||||
xtensa_lx_rt::zero_bss(
|
||||
core::ptr::addr_of_mut!(_rtc_fast_bss_start),
|
||||
core::ptr::addr_of_mut!(_rtc_fast_bss_end),
|
||||
);
|
||||
xtensa_lx_rt::zero_bss(
|
||||
core::ptr::addr_of_mut!(_rtc_slow_bss_start),
|
||||
core::ptr::addr_of_mut!(_rtc_slow_bss_end),
|
||||
);
|
||||
}
|
||||
if matches!(
|
||||
crate::system::reset_reason(),
|
||||
None | Some(crate::rtc_cntl::SocResetReason::ChipPowerOn)
|
||||
) {
|
||||
unsafe {
|
||||
xtensa_lx_rt::zero_bss(
|
||||
core::ptr::addr_of_mut!(_rtc_fast_persistent_start),
|
||||
core::ptr::addr_of_mut!(_rtc_fast_persistent_end),
|
||||
);
|
||||
xtensa_lx_rt::zero_bss(
|
||||
core::ptr::addr_of_mut!(_rtc_slow_persistent_start),
|
||||
core::ptr::addr_of_mut!(_rtc_slow_persistent_end),
|
||||
);
|
||||
#[cfg_attr(esp32s3, unsafe(link_section = ".rwtext"))]
|
||||
#[unsafe(export_name = "__pre_init")]
|
||||
#[unsafe(naked)]
|
||||
unsafe extern "C" fn esp32_reset() {
|
||||
// Set up stack protector value before jumping to a rust function
|
||||
naked_asm! {
|
||||
"
|
||||
entry a1, 0x20
|
||||
|
||||
// Set up the stack protector value
|
||||
l32r a2, sym_stack_chk_guard
|
||||
l32r a3, stack_guard_value
|
||||
s32i.n a3, a2, 0
|
||||
|
||||
call8 {esp32_init}
|
||||
|
||||
retw.n
|
||||
",
|
||||
esp32_init = sym esp32_init
|
||||
}
|
||||
}
|
||||
|
||||
setup_stack_guard();
|
||||
#[cfg_attr(esp32s3, unsafe(link_section = ".rwtext"))]
|
||||
fn esp32_init() {
|
||||
unsafe {
|
||||
super::configure_cpu_caches();
|
||||
}
|
||||
|
||||
crate::interrupt::setup_interrupts();
|
||||
|
||||
// continue with default reset handler
|
||||
unsafe { xtensa_lx_rt::Reset() }
|
||||
crate::interrupt::setup_interrupts();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rt")]
|
||||
@ -162,7 +230,7 @@ unsafe extern "C" fn stack_chk_fail() {
|
||||
panic!("Stack corruption detected");
|
||||
}
|
||||
|
||||
#[cfg(feature = "rt")]
|
||||
#[cfg(all(feature = "rt", riscv))]
|
||||
fn setup_stack_guard() {
|
||||
unsafe extern "C" {
|
||||
static mut __stack_chk_guard: u32;
|
||||
|
@ -429,6 +429,8 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
},
|
||||
};
|
||||
|
||||
// TODO: require `unsafe(naked)` as no Rust code should run before statics are initialized
|
||||
|
||||
if !valid_signature {
|
||||
return parse::Error::new(
|
||||
f.span(),
|
||||
@ -453,7 +455,7 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let block = f.block;
|
||||
|
||||
quote!(
|
||||
#[export_name = "__pre_init"]
|
||||
#[unsafe(export_name = "__pre_init")]
|
||||
#[allow(missing_docs)] // we make a private fn public, which can trigger this lint
|
||||
#(#attrs)*
|
||||
pub unsafe fn #ident() #block
|
||||
|
@ -11,9 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- A new feature `defmt` which implements `defmt::Format` on `Context` (#3887)
|
||||
|
||||
|
||||
### Changed
|
||||
|
||||
- Removed the `r0` dependency (#4117)
|
||||
|
||||
### Fixed
|
||||
|
||||
@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Removed
|
||||
|
||||
|
||||
|
||||
## [v0.20.0] - 2025-07-16
|
||||
|
||||
### Changed
|
||||
|
@ -19,7 +19,6 @@ test = false
|
||||
document-features = "0.2.11"
|
||||
defmt = {version = "1.0.1", optional = true}
|
||||
macros = { version = "0.4.0", package = "xtensa-lx-rt-proc-macros", path = "../xtensa-lx-rt-proc-macros" }
|
||||
r0 = "1.0.0"
|
||||
xtensa-lx = { version = "0.12.0", path = "../xtensa-lx" }
|
||||
|
||||
[build-dependencies]
|
||||
|
@ -7,13 +7,9 @@
|
||||
#![feature(asm_experimental_arch)]
|
||||
#![no_std]
|
||||
|
||||
use core::{
|
||||
arch::asm,
|
||||
ptr::{addr_of, addr_of_mut},
|
||||
};
|
||||
use core::arch::global_asm;
|
||||
|
||||
pub use macros::{entry, exception, interrupt, pre_init};
|
||||
pub use r0::{init_data, zero_bss};
|
||||
pub use xtensa_lx;
|
||||
|
||||
pub mod exception;
|
||||
@ -21,99 +17,183 @@ pub mod interrupt;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn DefaultPreInit() {}
|
||||
pub unsafe extern "C" fn no_init_hook() {}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn Reset() -> ! {
|
||||
unsafe {
|
||||
// These symbols come from `link.x`
|
||||
unsafe extern "C" {
|
||||
static mut _bss_start: u32;
|
||||
static mut _bss_end: u32;
|
||||
unsafe extern "C" {
|
||||
fn __pre_init();
|
||||
fn __post_init();
|
||||
|
||||
static mut _data_start: u32;
|
||||
static mut _data_end: u32;
|
||||
static _sidata: u32;
|
||||
fn __zero_bss() -> bool;
|
||||
fn __init_data() -> bool;
|
||||
|
||||
static mut _init_start: u32;
|
||||
fn main() -> !;
|
||||
|
||||
}
|
||||
static _bss_start: u32;
|
||||
static _bss_end: u32;
|
||||
|
||||
unsafe extern "Rust" {
|
||||
// This symbol will be provided by the user via `#[entry]`
|
||||
fn main() -> !;
|
||||
static _data_start: u32;
|
||||
static _data_end: u32;
|
||||
static _sidata: u32;
|
||||
|
||||
// This symbol will be provided by the user via `#[pre_init]`
|
||||
fn __pre_init();
|
||||
static _init_start: u32;
|
||||
|
||||
fn __post_init();
|
||||
|
||||
fn __zero_bss() -> bool;
|
||||
|
||||
fn __init_data() -> bool;
|
||||
}
|
||||
|
||||
__pre_init();
|
||||
|
||||
if __zero_bss() {
|
||||
r0::zero_bss(addr_of_mut!(_bss_start), addr_of_mut!(_bss_end));
|
||||
}
|
||||
|
||||
if __init_data() {
|
||||
r0::init_data(addr_of_mut!(_data_start), addr_of_mut!(_data_end), &_sidata);
|
||||
}
|
||||
|
||||
// Copy of data segment is done by bootloader
|
||||
|
||||
// According to 4.4.6.2 of the xtensa isa, ccount and compare are undefined on
|
||||
// reset, set all values to zero to disable
|
||||
reset_internal_timers();
|
||||
|
||||
// move vec table
|
||||
set_vecbase(addr_of!(_init_start));
|
||||
|
||||
__post_init();
|
||||
|
||||
main();
|
||||
}
|
||||
static _stack_start_cpu0: u32;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unsafe(no_mangle)]
|
||||
#[rustfmt::skip]
|
||||
pub unsafe extern "Rust" fn default_post_init() {}
|
||||
global_asm!(
|
||||
"
|
||||
.section .rwtext,\"ax\",@progbits
|
||||
.literal sym__pre_init, {__pre_init}
|
||||
.literal sym__post_init, {__post_init}
|
||||
.literal sym__zero_bss, {__zero_bss}
|
||||
.literal sym_main, {main}
|
||||
|
||||
.literal sym_stack_start_cpu0, {_stack_start_cpu0}
|
||||
|
||||
.literal sym_init_start, {_init_start}
|
||||
.literal sym_bss_end, {_bss_end}
|
||||
.literal sym_bss_start, {_bss_start}
|
||||
.literal sym__init_data, {__init_data}
|
||||
.literal sym_data_start, {_data_start}
|
||||
.literal sym_data_end, {_data_end}
|
||||
.literal sym_sidata, {_sidata}
|
||||
",
|
||||
__pre_init = sym __pre_init,
|
||||
__post_init = sym __post_init,
|
||||
__zero_bss = sym __zero_bss,
|
||||
|
||||
_stack_start_cpu0 = sym _stack_start_cpu0,
|
||||
|
||||
_bss_end = sym _bss_end,
|
||||
_bss_start = sym _bss_start,
|
||||
__init_data = sym __init_data,
|
||||
_data_start = sym _data_start,
|
||||
_data_end = sym _data_end,
|
||||
_sidata = sym _sidata,
|
||||
|
||||
_init_start = sym _init_start,
|
||||
main = sym main,
|
||||
);
|
||||
|
||||
global_asm!(
|
||||
"
|
||||
// _xtensa_lx_rt_zero_fill
|
||||
//
|
||||
// Input arguments:
|
||||
// a2: start address (used as a cursor)
|
||||
// a3: end address
|
||||
|
||||
.section .rwtext,\"ax\",@progbits
|
||||
.global _xtensa_lx_rt_zero_fill
|
||||
.p2align 2
|
||||
.type _xtensa_lx_rt_zero_fill,@function
|
||||
_xtensa_lx_rt_zero_fill:
|
||||
entry a1, 0
|
||||
bgeu a2, a3, .Lfill_done // If start >= end, skip zeroing
|
||||
movi.n a5, 0
|
||||
|
||||
.Lfill_loop:
|
||||
s32i.n a5, a2, 0 // Store the zero at the current cursor
|
||||
addi.n a2, a2, 4 // Increment the cursor by 4 bytes
|
||||
bltu a2, a3, .Lfill_loop // If cursor < end, repeat
|
||||
.Lfill_done:
|
||||
retw.n
|
||||
|
||||
// _xtensa_lx_rt_copy
|
||||
//
|
||||
// Input arguments:
|
||||
// a2: source address
|
||||
// a3: destination start address (used as a cursor)
|
||||
// a4: destination end address
|
||||
|
||||
.section .rwtext,\"ax\",@progbits
|
||||
.global _xtensa_lx_rt_copy
|
||||
.p2align 2
|
||||
.type _xtensa_lx_rt_copy,@function
|
||||
_xtensa_lx_rt_copy:
|
||||
entry a1, 0
|
||||
bgeu a3, a4, .Lcopy_done // If start >= end, skip copying
|
||||
.Lcopy_loop:
|
||||
l32i.n a5, a2, 0 // Load word from source pointer
|
||||
s32i.n a5, a3, 0 // Store word at destination pointer
|
||||
addi.n a3, a3, 4 // Increment destination pointer by 4 bytes
|
||||
addi.n a2, a2, 4 // Increment source pointer by 4 bytes
|
||||
bltu a3, a4, .Lcopy_loop // If cursor < end, repeat
|
||||
.Lcopy_done:
|
||||
retw.n
|
||||
|
||||
.section .rwtext,\"ax\",@progbits
|
||||
.global Reset
|
||||
.p2align 2
|
||||
.type Reset,@function
|
||||
Reset:
|
||||
entry a1, 0
|
||||
movi a0, 0 // Trash the return address. Debuggers may use this to stop unwinding.
|
||||
l32r a5, sym_stack_start_cpu0 // a5 is our temporary value register
|
||||
mov sp, a5 // Set the stack pointer.
|
||||
|
||||
l32r a5, sym__pre_init
|
||||
callx8 a5 // Call the pre-initialization function.
|
||||
|
||||
.Linit_bss:
|
||||
l32r a5, sym__zero_bss // Do we need to zero-initialize memory?
|
||||
callx8 a5
|
||||
beqz a10, .Linit_data // No -> skip to copying initialized data
|
||||
|
||||
l32r a10, sym_bss_start // Set input range to .bss
|
||||
l32r a11, sym_bss_end //
|
||||
call8 _xtensa_lx_rt_zero_fill // Zero-fill
|
||||
|
||||
.Linit_data:
|
||||
l32r a5, sym__init_data // Do we need to initialize data sections?
|
||||
callx8 a5
|
||||
beqz a10, .Linit_data_done // If not, skip initialization
|
||||
|
||||
l32r a10, sym_sidata // Arguments - source data pointer
|
||||
l32r a11, sym_data_start // - destination pointer
|
||||
l32r a12, sym_data_end // - destination end pointer
|
||||
call8 _xtensa_lx_rt_copy // Copy .data section
|
||||
|
||||
.Linit_data_done:
|
||||
memw // Make sure all writes are completed before proceeding. At this point, all static variables have been initialized.
|
||||
"
|
||||
);
|
||||
|
||||
// According to 4.4.7.2 of the xtensa isa, ccount and compare are undefined on
|
||||
// reset, set all values to zero to disable. ("timer interupts are cleared by writing CCOMPARE[i]")
|
||||
#[cfg(any(
|
||||
XCHAL_HAVE_TIMER0,
|
||||
XCHAL_HAVE_TIMER1,
|
||||
XCHAL_HAVE_TIMER2,
|
||||
XCHAL_HAVE_TIMER3
|
||||
))]
|
||||
cfg_global_asm!(
|
||||
#[cfg(XCHAL_HAVE_TIMER0)]
|
||||
"wsr.ccompare0 a0",
|
||||
#[cfg(XCHAL_HAVE_TIMER1)]
|
||||
"wsr.ccompare1 a0",
|
||||
#[cfg(XCHAL_HAVE_TIMER2)]
|
||||
"wsr.ccompare2 a0",
|
||||
#[cfg(XCHAL_HAVE_TIMER3)]
|
||||
"wsr.ccompare3 a0",
|
||||
"isync",
|
||||
);
|
||||
|
||||
global_asm!(
|
||||
"
|
||||
l32r a5, sym_init_start // vector table address
|
||||
wsr.vecbase a5
|
||||
|
||||
l32r a5, sym__post_init
|
||||
callx8 a5
|
||||
|
||||
l32r a5, sym_main // program entry point
|
||||
callx8 a5
|
||||
",
|
||||
);
|
||||
|
||||
// We redefine these functions to avoid pulling in `xtensa-lx` as a dependency:
|
||||
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
unsafe fn reset_internal_timers() {
|
||||
unsafe {
|
||||
#[cfg(any(
|
||||
XCHAL_HAVE_TIMER0,
|
||||
XCHAL_HAVE_TIMER1,
|
||||
XCHAL_HAVE_TIMER2,
|
||||
XCHAL_HAVE_TIMER3
|
||||
))]
|
||||
{
|
||||
let value = 0;
|
||||
cfg_asm!(
|
||||
{
|
||||
#[cfg(XCHAL_HAVE_TIMER0)]
|
||||
"wsr.ccompare0 {0}",
|
||||
#[cfg(XCHAL_HAVE_TIMER1)]
|
||||
"wsr.ccompare1 {0}",
|
||||
#[cfg(XCHAL_HAVE_TIMER2)]
|
||||
"wsr.ccompare2 {0}",
|
||||
#[cfg(XCHAL_HAVE_TIMER3)]
|
||||
"wsr.ccompare3 {0}",
|
||||
"isync",
|
||||
}, in(reg) value, options(nostack));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CPU Interrupts
|
||||
unsafe extern "C" {
|
||||
#[cfg(XCHAL_HAVE_TIMER0)]
|
||||
@ -137,18 +217,9 @@ unsafe extern "C" {
|
||||
pub fn NMI(save_frame: &mut crate::exception::Context);
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
unsafe fn set_vecbase(base: *const u32) {
|
||||
unsafe {
|
||||
asm!("wsr.vecbase {0}", in(reg) base, options(nostack));
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unsafe(no_mangle)]
|
||||
#[rustfmt::skip]
|
||||
pub extern "Rust" fn default_mem_hook() -> bool {
|
||||
pub extern "C" fn default_mem_hook() -> bool {
|
||||
true // default to zeroing bss & initializing data
|
||||
}
|
||||
|
||||
|
@ -5,10 +5,11 @@ ENTRY(Reset)
|
||||
INCLUDE memory.x
|
||||
|
||||
/* after memory.x to allow override */
|
||||
PROVIDE(__pre_init = DefaultPreInit);
|
||||
PROVIDE(__pre_init = no_init_hook);
|
||||
PROVIDE(__zero_bss = default_mem_hook);
|
||||
PROVIDE(__init_data = default_mem_hook);
|
||||
PROVIDE(__post_init = default_post_init);
|
||||
PROVIDE(__init_persistent = default_mem_hook);
|
||||
PROVIDE(__post_init = no_init_hook);
|
||||
|
||||
INCLUDE exception.x
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user