Skip to content
This repository has been archived by the owner on Nov 28, 2023. It is now read-only.

Commit

Permalink
Merge pull request #123 from coastalwhite/r0-in-asm
Browse files Browse the repository at this point in the history
Implement r0 crate in assembly
  • Loading branch information
romancardenas authored Oct 2, 2023
2 parents 8bda5c2 + 738baf9 commit a4fd9fa
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Use inline assembly instead of pre-compiled blobs
- Removed bors in favor of GitHub Merge Queue
- `start_trap_rust` is now marked as `unsafe`
- Implement `r0` as inline assembly

## [v0.11.0] - 2023-01-18

Expand Down
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ s-mode = []
single-hart = []

[dependencies]
r0 = "1.0.0"
riscv = "0.10"
riscv-rt-macros = { path = "macros", version = "0.2.0" }

Expand Down
17 changes: 11 additions & 6 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,17 @@ use std::env;
use std::fs;
use std::path::PathBuf;

fn add_linker_script(bytes: &[u8]) {
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());

// Put the linker script somewhere the linker can find it
fs::write(out_dir.join("link.x"), bytes).unwrap();
println!("cargo:rustc-link-search={}", out_dir.display());
println!("cargo:rerun-if-changed=link.x");
}

fn main() {
let target = env::var("TARGET").unwrap();
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let _name = env::var("CARGO_PKG_NAME").unwrap();

// set configuration flags depending on the target
Expand All @@ -17,19 +25,16 @@ fn main() {
match target.bits {
32 => {
println!("cargo:rustc-cfg=riscv32");
add_linker_script(include_bytes!("link-rv32.x"));
}
64 => {
println!("cargo:rustc-cfg=riscv64");
add_linker_script(include_bytes!("link-rv64.x"));
}
_ => panic!("Unsupported bit width"),
}
if target.has_extension('m') {
println!("cargo:rustc-cfg=riscvm"); // we can expose extensions this way
}
}

// Put the linker script somewhere the linker can find it
fs::write(out_dir.join("link.x"), include_bytes!("link.x")).unwrap();
println!("cargo:rustc-link-search={}", out_dir.display());
println!("cargo:rerun-if-changed=link.x");
}
2 changes: 1 addition & 1 deletion link.x → link-rv32.x
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ SECTIONS
_edata = .;
} > REGION_DATA AT > REGION_RODATA

.bss (NOLOAD) :
.bss (NOLOAD) : ALIGN(4)
{
_sbss = .;
*(.sbss .sbss.* .bss .bss.*);
Expand Down
174 changes: 174 additions & 0 deletions link-rv64.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
PROVIDE(_stext = ORIGIN(REGION_TEXT));
PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK));
PROVIDE(_max_hart_id = 0);
PROVIDE(_hart_stack_size = 2K);
PROVIDE(_heap_size = 0);

PROVIDE(UserSoft = DefaultHandler);
PROVIDE(SupervisorSoft = DefaultHandler);
PROVIDE(MachineSoft = DefaultHandler);
PROVIDE(UserTimer = DefaultHandler);
PROVIDE(SupervisorTimer = DefaultHandler);
PROVIDE(MachineTimer = DefaultHandler);
PROVIDE(UserExternal = DefaultHandler);
PROVIDE(SupervisorExternal = DefaultHandler);
PROVIDE(MachineExternal = DefaultHandler);

PROVIDE(DefaultHandler = DefaultInterruptHandler);
PROVIDE(ExceptionHandler = DefaultExceptionHandler);

/* # Pre-initialization function */
/* If the user overrides this using the `#[pre_init]` attribute or by creating a `__pre_init` function,
then the function this points to will be called before the RAM is initialized. */
PROVIDE(__pre_init = default_pre_init);

/* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */
PROVIDE(_setup_interrupts = default_setup_interrupts);

/* # Multi-processing hook function
fn _mp_hook() -> bool;

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).
*/
PROVIDE(_mp_hook = default_mp_hook);

/* # Start trap function override
By default uses the riscv crates default trap handler
but by providing the `_start_trap` symbol external crates can override.
*/
PROVIDE(_start_trap = default_start_trap);

SECTIONS
{
.text.dummy (NOLOAD) :
{
/* This section is intended to make _stext address work */
. = ABSOLUTE(_stext);
} > REGION_TEXT

.text _stext :
{
/* Put reset handler first in .text section so it ends up as the entry */
/* point of the program. */
KEEP(*(.init));
KEEP(*(.init.rust));
. = ALIGN(4);
*(.trap);
*(.trap.rust);
*(.text.abort);
*(.text .text.*);
} > REGION_TEXT

.rodata : ALIGN(4)
{
*(.srodata .srodata.*);
*(.rodata .rodata.*);

/* 4-byte align the end (VMA) of this section.
This is required by LLD to ensure the LMA of the following .data
section will have the correct alignment. */
. = ALIGN(4);
} > REGION_RODATA

.data : ALIGN(8)
{
_sidata = LOADADDR(.data);
_sdata = .;
/* Must be called __global_pointer$ for linker relaxations to work. */
PROVIDE(__global_pointer$ = . + 0x800);
*(.sdata .sdata.* .sdata2 .sdata2.*);
*(.data .data.*);
. = ALIGN(8);
_edata = .;
} > REGION_DATA AT > REGION_RODATA

.bss (NOLOAD) : ALIGN(8)
{
_sbss = .;
*(.sbss .sbss.* .bss .bss.*);
. = ALIGN(8);
_ebss = .;
} > REGION_BSS

/* fictitious region that represents the memory available for the heap */
.heap (NOLOAD) :
{
_sheap = .;
. += _heap_size;
. = ALIGN(4);
_eheap = .;
} > REGION_HEAP

/* fictitious region that represents the memory available for the stack */
.stack (NOLOAD) :
{
_estack = .;
. = ABSOLUTE(_stack_start);
_sstack = .;
} > REGION_STACK

/* fake output .got section */
/* Dynamic relocations are unsupported. This section is only used to detect
relocatable code in the input files and raise an error if relocatable code
is found */
.got (INFO) :
{
KEEP(*(.got .got.*));
}

.eh_frame (INFO) : { KEEP(*(.eh_frame)) }
.eh_frame_hdr (INFO) : { *(.eh_frame_hdr) }
}

/* Do not exceed this mark in the error messages above | */
ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");

ASSERT(ORIGIN(REGION_RODATA) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_RODATA must be 4-byte aligned");

ASSERT(ORIGIN(REGION_DATA) % 8 == 0, "
ERROR(riscv-rt): the start of the REGION_DATA must be 8-byte aligned");

ASSERT(ORIGIN(REGION_HEAP) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_HEAP must be 4-byte aligned");

ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");

ASSERT(ORIGIN(REGION_STACK) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_STACK must be 4-byte aligned");

ASSERT(_stext % 4 == 0, "
ERROR(riscv-rt): `_stext` must be 4-byte aligned");

ASSERT(_sdata % 8 == 0 && _edata % 8 == 0, "
BUG(riscv-rt): .data is not 8-byte aligned");

ASSERT(_sidata % 8 == 0, "
BUG(riscv-rt): the LMA of .data is not 8-byte aligned");

ASSERT(_sbss % 8 == 0 && _ebss % 8 == 0, "
BUG(riscv-rt): .bss is not 8-byte aligned");

ASSERT(_sheap % 4 == 0, "
BUG(riscv-rt): start of .heap is not 4-byte aligned");

ASSERT(_stext + SIZEOF(.text) < ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT), "
ERROR(riscv-rt): The .text section must be placed inside the REGION_TEXT region.
Set _stext to an address smaller than 'ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT)'");

ASSERT(SIZEOF(.stack) > (_max_hart_id + 1) * _hart_stack_size, "
ERROR(riscv-rt): .stack section is too small for allocating stacks for all the harts.
Consider changing `_max_hart_id` or `_hart_stack_size`.");

ASSERT(SIZEOF(.got) == 0, "
.got section detected in the input files. Dynamic relocations are not
supported. If you are linking to C code compiled using the `gcc` crate
then modify your build script to compile the C code _without_ the
-fPIC flag. See the documentation of the `gcc::Config.fpic` method for
details.");

/* Do not exceed this mark in the error messages above | */
104 changes: 89 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,8 @@
#[cfg(riscv)]
mod asm;

use core::sync::atomic::{compiler_fence, Ordering};

#[cfg(feature = "s-mode")]
use riscv::register::{scause as xcause, stvec as xtvec, stvec::TrapMode as xTrapMode};

Expand All @@ -378,19 +380,6 @@ pub use riscv_rt_macros::{entry, pre_init};
#[doc(hidden)]
pub static __ONCE__: () = ();

extern "C" {
// Boundaries of the .bss section
static mut _ebss: u32;
static mut _sbss: u32;

// Boundaries of the .data section
static mut _edata: u32;
static mut _sdata: u32;

// Initial values of the .data section (stored in Flash)
static _sidata: u32;
}

/// Rust entry point (_start_rust)
///
/// Zeros bss section, initializes data section and calls main. This function never returns.
Expand Down Expand Up @@ -424,8 +413,93 @@ pub unsafe extern "C" fn start_rust(a0: usize, a1: usize, a2: usize) -> ! {
if _mp_hook(hartid) {
__pre_init();

r0::zero_bss(&mut _sbss, &mut _ebss);
r0::init_data(&mut _sdata, &mut _edata, &_sidata);
// Initialize RAM
// 1. Copy over .data from flash to RAM
// 2. Zero out .bss

#[cfg(target_arch = "riscv32")]
core::arch::asm!(
"
// Copy over .data
la {start},_sdata
la {end},_edata
la {input},_sidata
bgeu {start},{end},2f
1:
lw {a},0({input})
addi {input},{input},4
sw {a},0({start})
addi {start},{start},4
bltu {start},{end},1b
2:
li {a},0
li {input},0
// Zero out .bss
la {start},_sbss
la {end},_ebss
bgeu {start},{end},3f
2:
sw zero,0({start})
addi {start},{start},4
bltu {start},{end},2b
3:
li {start},0
li {end},0
",
start = out(reg) _,
end = out(reg) _,
input = out(reg) _,
a = out(reg) _,
);

#[cfg(target_arch = "riscv64")]
core::arch::asm!(
"
// Copy over .data
la {start},_sdata
la {end},_edata
la {input},_sidata
bgeu {start},{end},2f
1: // .data Main Loop
ld {a},0({input})
addi {input},{input},8
sd {a},0({start})
addi {start},{start},8
bltu {start},{end},1b
2: // .data zero registers
li {a},0
li {input},0
la {start},_sbss
la {end},_ebss
bgeu {start},{end},4f
3: // .bss main loop
sd zero,0({start})
addi {start},{start},8
bltu {start},{end},3b
4: // .bss zero registers
// Zero out used registers
li {start},0
li {end},0
",
start = out(reg) _,
end = out(reg) _,
input = out(reg) _,
a = out(reg) _,
);

compiler_fence(Ordering::SeqCst);
}

// TODO: Enable FPU when available
Expand Down

0 comments on commit a4fd9fa

Please sign in to comment.