|
@@ -13,14 +13,14 @@
|
|
|
//!
|
|
|
//! - Before main initialization of the `.bss` and `.data` sections.
|
|
|
//!
|
|
|
-//! - Before main initialization of the FPU (for targets that have a FPU).
|
|
|
-//!
|
|
|
//! - `#[entry]` to declare the entry point of the program
|
|
|
//! - `#[pre_init]` to run code *before* `static` variables are initialized
|
|
|
//!
|
|
|
//! - A linker script that encodes the memory layout of a generic RISC-V
|
|
|
//! microcontroller. This linker script is missing some information that must
|
|
|
-//! be supplied through a `memory.x` file (see example below).
|
|
|
+//! be supplied through a `memory.x` file (see example below). This file
|
|
|
+//! must be supplied using rustflags and listed *before* `link.x`. Arbitrary
|
|
|
+//! filename can be use instead of `memory.x`.
|
|
|
//!
|
|
|
//! - A `_sheap` symbol at whose address you can locate a heap.
|
|
|
//!
|
|
@@ -37,11 +37,17 @@
|
|
|
//! $ edit memory.x && cat $_
|
|
|
//! MEMORY
|
|
|
//! {
|
|
|
-//! /* NOTE K = KiBi = 1024 bytes */
|
|
|
-//! FLASH : ORIGIN = 0x20000000, LENGTH = 16M
|
|
|
//! RAM : ORIGIN = 0x80000000, LENGTH = 16K
|
|
|
+//! FLASH : ORIGIN = 0x20000000, LENGTH = 16M
|
|
|
//! }
|
|
|
//!
|
|
|
+//! REGION_ALIAS("REGION_TEXT", FLASH);
|
|
|
+//! REGION_ALIAS("REGION_RODATA", FLASH);
|
|
|
+//! REGION_ALIAS("REGION_DATA", RAM);
|
|
|
+//! REGION_ALIAS("REGION_BSS", RAM);
|
|
|
+//! REGION_ALIAS("REGION_HEAP", RAM);
|
|
|
+//! REGION_ALIAS("REGION_STACK", RAM);
|
|
|
+//!
|
|
|
//! $ edit src/main.rs && cat $_
|
|
|
//! ```
|
|
|
//!
|
|
@@ -66,7 +72,8 @@
|
|
|
//! $ mkdir .cargo && edit .cargo/config && cat $_
|
|
|
//! [target.riscv32imac-unknown-none-elf]
|
|
|
//! rustflags = [
|
|
|
-//! "-C", "link-arg=-Tlink.x"
|
|
|
+//! "-C", "link-arg=-Tmemory.x",
|
|
|
+//! "-C", "link-arg=-Tlink.x",
|
|
|
//! ]
|
|
|
//!
|
|
|
//! [build]
|
|
@@ -124,14 +131,27 @@
|
|
|
//!
|
|
|
//! The main information that this file must provide is the memory layout of
|
|
|
//! the device in the form of the `MEMORY` command. The command is documented
|
|
|
-//! [here][2], but at a minimum you'll want to create two memory regions: one
|
|
|
-//! for Flash memory and another for RAM.
|
|
|
+//! [here][2], but at a minimum you'll want to create at least one memory region.
|
|
|
//!
|
|
|
//! [2]: https://sourceware.org/binutils/docs/ld/MEMORY.html
|
|
|
//!
|
|
|
-//! The program instructions (the `.text` section) will be stored in the memory
|
|
|
-//! region named FLASH, and the program `static` variables (the sections `.bss`
|
|
|
-//! and `.data`) will be allocated in the memory region named RAM.
|
|
|
+//! To support different relocation models (RAM-only, FLASH+RAM) multiple regions are used:
|
|
|
+//!
|
|
|
+//! - `REGION_TEXT` - for `.init`, `.trap` and `.text` sections
|
|
|
+//! - `REGION_RODATA` - for `.rodata` section and storing initial values for `.data` section
|
|
|
+//! - `REGION_DATA` - for `.data` section
|
|
|
+//! - `REGION_BSS` - for `.bss` section
|
|
|
+//! - `REGION_HEAP` - for the heap area
|
|
|
+//! - `REGION_STACK` - for hart stacks
|
|
|
+//!
|
|
|
+//! Specific aliases for these regions must be defined in `memory.x` file (see example below).
|
|
|
+//!
|
|
|
+//! ### `_stext`
|
|
|
+//!
|
|
|
+//! This symbol provides the loading address of `.text` section. This value can be changed
|
|
|
+//! to override the loading address of the firmware (for example, in case of bootloader present).
|
|
|
+//!
|
|
|
+//! If omitted this symbol value will default to `ORIGIN(REGION_TEXT)`.
|
|
|
//!
|
|
|
//! ### `_stack_start`
|
|
|
//!
|
|
@@ -140,25 +160,49 @@
|
|
|
//! valid RAM address plus one (this *is* an invalid address but the processor
|
|
|
//! will decrement the stack pointer *before* using its value as an address).
|
|
|
//!
|
|
|
-//! If omitted this symbol value will default to `ORIGIN(RAM) + LENGTH(RAM)`.
|
|
|
+//! In case of multiple harts present, this address defines the initial stack pointer for hart 0.
|
|
|
+//! Stack pointer for hart `N` is calculated as `_stack_start - N * _hart_stack_size`.
|
|
|
+//!
|
|
|
+//! If omitted this symbol value will default to `ORIGIN(REGION_STACK) + LENGTH(REGION_STACK)`.
|
|
|
//!
|
|
|
//! #### Example
|
|
|
//!
|
|
|
//! Allocating the call stack on a different RAM region.
|
|
|
//!
|
|
|
-//! ```
|
|
|
+//! ``` text
|
|
|
//! MEMORY
|
|
|
//! {
|
|
|
-//! /* call stack will go here */
|
|
|
-//! CCRAM : ORIGIN = 0x10000000, LENGTH = 8K
|
|
|
-//! FLASH : ORIGIN = 0x08000000, LENGTH = 256K
|
|
|
-//! /* static variables will go here */
|
|
|
-//! RAM : ORIGIN = 0x20000000, LENGTH = 40K
|
|
|
+//! L2_LIM : ORIGIN = 0x08000000, LENGTH = 1M
|
|
|
+//! RAM : ORIGIN = 0x80000000, LENGTH = 16K
|
|
|
+//! FLASH : ORIGIN = 0x20000000, LENGTH = 16M
|
|
|
//! }
|
|
|
//!
|
|
|
-//! _stack_start = ORIGIN(CCRAM) + LENGTH(CCRAM);
|
|
|
+//! REGION_ALIAS("REGION_TEXT", FLASH);
|
|
|
+//! REGION_ALIAS("REGION_RODATA", FLASH);
|
|
|
+//! REGION_ALIAS("REGION_DATA", RAM);
|
|
|
+//! REGION_ALIAS("REGION_BSS", RAM);
|
|
|
+//! REGION_ALIAS("REGION_HEAP", RAM);
|
|
|
+//! REGION_ALIAS("REGION_STACK", L2_LIM);
|
|
|
+//!
|
|
|
+//! _stack_start = ORIGIN(L2_LIM) + LENGTH(L2_LIM);
|
|
|
//! ```
|
|
|
//!
|
|
|
+//! ### `_max_hart_id`
|
|
|
+//!
|
|
|
+//! This symbol defines the maximum hart id suppoted. All harts with id
|
|
|
+//! greater than `_max_hart_id` will be redirected to `abort()`.
|
|
|
+//!
|
|
|
+//! This symbol is supposed to be redefined in platform support crates for
|
|
|
+//! multi-core targets.
|
|
|
+//!
|
|
|
+//! If omitted this symbol value will default to 0 (single core).
|
|
|
+//!
|
|
|
+//! ### `_hart_stack_size`
|
|
|
+//!
|
|
|
+//! This symbol defines stack area size for *one* hart.
|
|
|
+//!
|
|
|
+//! If omitted this symbol value will default to 2K.
|
|
|
+//!
|
|
|
//! ### `_heap_size`
|
|
|
//!
|
|
|
//! This symbol provides the size of a heap region. The default value is 0. You can set `_heap_size`
|
|
@@ -172,7 +216,7 @@
|
|
|
//!
|
|
|
//! #### Example
|
|
|
//!
|
|
|
-//! ```
|
|
|
+//! ``` no_run
|
|
|
//! extern crate some_allocator;
|
|
|
//!
|
|
|
//! extern "C" {
|
|
@@ -189,13 +233,22 @@
|
|
|
//! }
|
|
|
//! ```
|
|
|
//!
|
|
|
-//! ## `pre_init!`
|
|
|
+//! ### `_mp_hook`
|
|
|
+//!
|
|
|
+//! This function is called from all the harts and must return true only for one hart,
|
|
|
+//! which will perform memory initialization. For other harts it must return false
|
|
|
+//! and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt).
|
|
|
//!
|
|
|
-//! A user-defined function can be run at the start of the reset handler, before RAM is
|
|
|
-//! initialized. The macro `pre_init!` can be called to set the function to be run. The function is
|
|
|
-//! intended to perform actions that cannot wait the time it takes for RAM to be initialized, such
|
|
|
-//! as disabling a watchdog. As the function is called before RAM is initialized, any access of
|
|
|
-//! static variables will result in undefined behavior.
|
|
|
+//! This function can be redefined in the following way:
|
|
|
+//!
|
|
|
+//! ``` no_run
|
|
|
+//! #[export_name = "_mp_hook"]
|
|
|
+//! pub extern "Rust" fn mp_hook() -> bool {
|
|
|
+//! // ...
|
|
|
+//! }
|
|
|
+//! ```
|
|
|
+//!
|
|
|
+//! Default implementation of this function wakes hart 0 and busy-loops all the other harts.
|
|
|
|
|
|
// NOTE: Adapted from cortex-m/src/lib.rs
|
|
|
#![no_std]
|
|
@@ -281,7 +334,7 @@ pub extern "C" fn start_trap_rust() {
|
|
|
}
|
|
|
|
|
|
|
|
|
-/// Default Trap Handler
|
|
|
+#[doc(hidden)]
|
|
|
#[no_mangle]
|
|
|
pub fn default_trap_handler() {}
|
|
|
|