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:
Dániel Buga 2025-09-17 09:57:23 +02:00 committed by GitHub
parent 3a4b7c6ded
commit 321ae5ef1b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 320 additions and 208 deletions

View File

@ -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",

View File

@ -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 */

View File

@ -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
}

View File

@ -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 */

View File

@ -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

View File

@ -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 {

View File

@ -1,6 +1,3 @@
/* override entry point */
ENTRY(ESP32Reset)
#IF ESP_HAL_CONFIG_INSTRUCTION_CACHE_SIZE_32KB
/* reserved for ICACHE */
RESERVE_ICACHE = 0x8000;

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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
}

View File

@ -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