Skip to content

Commit b3a04e3

Browse files
committed
add an initial baremetal trial target
just prints hello world for now!
1 parent 2433fe9 commit b3a04e3

File tree

12 files changed

+580
-0
lines changed

12 files changed

+580
-0
lines changed

baremetal/Cargo.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "baremetal"
3+
version = "0.1.0"
4+
authors = ["bunnie <[email protected]>"]
5+
edition = "2018"
6+
description = "Baremetal target"
7+
8+
[dependencies]
9+
xous = "0.9.66"
10+
utralib = { version = "0.1.25", optional = true, default-features = false }
11+
cramium-hal = { path = "../libs/cramium-hal", optional = true, default-features = false }
12+
cramium-api = { path = "../libs/cramium-api", optional = true, default-features = false }
13+
riscv = { version = "0.5.6", package = "xous-riscv" }
14+
linked_list_allocator = { version = "0.10.5", optional = true }
15+
16+
[features]
17+
artybio = ["utralib/artybio", "linked_list_allocator"]
18+
cramium-soc = ["utralib/cramium-soc"]
19+
20+
verilator-only = []
21+
debug-print = []
22+
default = ["artybio", "debug-print"]

baremetal/build.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// NOTE: Adapted from cortex-m/build.rs
2+
use std::env;
3+
use std::fs;
4+
use std::io::Write;
5+
use std::path::PathBuf;
6+
7+
fn main() {
8+
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
9+
let target = env::var("TARGET").unwrap();
10+
11+
let linker_file_path = if target.starts_with("riscv") {
12+
println!("cargo:rustc-link-search={}", out_dir.display());
13+
#[cfg(feature = "cramium-soc")]
14+
let p = PathBuf::from("src/platform/cramium/link.x");
15+
#[cfg(feature = "artybio")]
16+
let p = PathBuf::from("src/platform/artybio/link.x");
17+
18+
println!("cargo:rerun-if-changed={}", p.clone().into_os_string().into_string().unwrap());
19+
println!("cargo:rustc-link-arg=-Tlink.x");
20+
21+
p
22+
} else {
23+
unreachable!("unsupported target");
24+
};
25+
26+
println!("{}", out_dir.join("link.x").display());
27+
// Put the linker script somewhere the linker can find it
28+
std::fs::OpenOptions::new()
29+
.create(true)
30+
.write(true)
31+
.truncate(true)
32+
.open(out_dir.join("link.x"))
33+
.unwrap()
34+
.write_all(fs::read_to_string(linker_file_path).expect("linker file read").as_bytes())
35+
.unwrap();
36+
println!("cargo:rustc-link-search={}", out_dir.display());
37+
38+
println!("cargo:rerun-if-changed=build.rs");
39+
println!("cargo:rerun-if-changed=link.x");
40+
}

baremetal/src/asm.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use core::arch::asm;
2+
3+
use crate::platform;
4+
// Assembly stubs for entering into the loader, and exiting it.
5+
6+
// Note: inline constants are not yet stable in Rust: https://github.com/rust-lang/rust/pull/104087
7+
#[link_section = ".text.init"]
8+
#[export_name = "_start"]
9+
pub extern "C" fn _start() {
10+
unsafe {
11+
#[rustfmt::skip]
12+
asm! (
13+
// Place the stack pointer at the end of RAM
14+
"mv sp, {ram_top}",
15+
// subtract four from sp to make room for a DMA "gutter"
16+
"addi sp, sp, -4",
17+
18+
// Install a machine mode trap handler
19+
"la t0, abort",
20+
"csrw mtvec, t0",
21+
22+
// Start Rust
23+
"j rust_entry",
24+
25+
ram_top = in(reg) (platform::RAM_BASE + platform::RAM_SIZE),
26+
options(noreturn)
27+
);
28+
}
29+
}
30+
31+
#[link_section = ".text.init"]
32+
#[export_name = "abort"]
33+
/// This is only used in debug mode
34+
pub extern "C" fn abort() -> ! {
35+
unsafe {
36+
#[rustfmt::skip]
37+
asm!(
38+
"300:", // abort
39+
"j 300b",
40+
options(noreturn)
41+
);
42+
}
43+
}

baremetal/src/main.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#![cfg_attr(not(test), no_main)]
2+
#![cfg_attr(not(test), no_std)]
3+
4+
// contains runtime setup
5+
mod asm;
6+
7+
mod platform;
8+
use platform::*;
9+
10+
/// Entrypoint
11+
/// This makes the program self-sufficient by setting up memory page assignment
12+
/// and copying the arguments to RAM.
13+
/// Assume the bootloader has already set up the stack to point to the end of RAM.
14+
///
15+
/// # Safety
16+
///
17+
/// This function is safe to call exactly once.
18+
#[export_name = "rust_entry"]
19+
pub unsafe extern "C" fn rust_entry() -> ! {
20+
let mut count = 0;
21+
loop {
22+
crate::println!("hello world {}!\n", count);
23+
count += 1;
24+
}
25+
}
26+
27+
// Install a panic handler when not running tests.
28+
#[cfg(all(not(test)))]
29+
mod panic_handler {
30+
use core::panic::PanicInfo;
31+
#[panic_handler]
32+
fn handle_panic(_arg: &PanicInfo) -> ! {
33+
crate::println!("{}", _arg);
34+
loop {}
35+
}
36+
}

baremetal/src/platform.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#[cfg(any(feature = "cramium-soc"))]
2+
mod cramium;
3+
#[cfg(any(feature = "cramium-soc"))]
4+
pub use cramium::*;
5+
6+
#[cfg(any(feature = "artybio"))]
7+
mod artybio;
8+
#[cfg(any(feature = "artybio"))]
9+
pub use artybio::*;

baremetal/src/platform/artybio.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub mod artybio;
2+
pub use artybio::*;
3+
pub mod debug;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#[global_allocator]
2+
static ALLOCATOR: linked_list_allocator::LockedHeap = linked_list_allocator::LockedHeap::empty();
3+
4+
pub const RAM_SIZE: usize = utralib::generated::HW_MAIN_RAM_MEM_LEN;
5+
pub const RAM_BASE: usize = utralib::generated::HW_MAIN_RAM_MEM;
6+
7+
#[cfg(all(feature = "cramium-soc", not(feature = "verilator-only")))]
8+
pub fn early_init() {}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use utralib::generated::*;
2+
pub struct Uart {
3+
// pub base: *mut u32,
4+
}
5+
6+
impl Uart {
7+
pub fn putc(&self, c: u8) {
8+
let base = utra::uart::HW_UART_BASE as *mut u32;
9+
let mut uart = CSR::new(base);
10+
// Wait until TXFULL is `0`
11+
while uart.r(utra::uart::TXFULL) != 0 {}
12+
uart.wo(utra::uart::RXTX, c as u32)
13+
}
14+
}
15+
16+
use core::fmt::{Error, Write};
17+
impl Write for Uart {
18+
fn write_str(&mut self, s: &str) -> Result<(), Error> {
19+
for c in s.bytes() {
20+
self.putc(c);
21+
}
22+
Ok(())
23+
}
24+
}
25+
26+
#[macro_use]
27+
pub mod debug_print_hardware {
28+
#[macro_export]
29+
macro_rules! print
30+
{
31+
($($args:tt)+) => ({
32+
use core::fmt::Write;
33+
let _ = write!(crate::debug::Uart {}, $($args)+);
34+
});
35+
}
36+
}
37+
38+
#[macro_export]
39+
macro_rules! println
40+
{
41+
() => ({
42+
$crate::print!("\r\n")
43+
});
44+
($fmt:expr) => ({
45+
$crate::print!(concat!($fmt, "\r\n"))
46+
});
47+
($fmt:expr, $($args:tt)+) => ({
48+
$crate::print!(concat!($fmt, "\r\n"), $($args)+)
49+
});
50+
}

baremetal/src/platform/artybio/link.x

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
MEMORY
2+
{
3+
FLASH : ORIGIN = 0x40000000, LENGTH = 4M
4+
RAM : ORIGIN = 0x40400000, LENGTH = 4M
5+
}
6+
7+
REGION_ALIAS("REGION_TEXT", FLASH);
8+
REGION_ALIAS("REGION_RODATA", FLASH);
9+
REGION_ALIAS("REGION_DATA", RAM);
10+
REGION_ALIAS("REGION_BSS", RAM);
11+
REGION_ALIAS("REGION_STACK", RAM);
12+
REGION_ALIAS("REGION_HEAP", RAM);
13+
14+
/* Size of the main kernel stack */
15+
_stack_size = 16K;
16+
_eheap = ORIGIN(RAM) + LENGTH(RAM);
17+
18+
19+
PROVIDE(_stext = ORIGIN(REGION_TEXT));
20+
PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK));
21+
PROVIDE(_max_hart_id = 0);
22+
PROVIDE(_hart_stack_size = 2K);
23+
PROVIDE(_heap_size = 0);
24+
25+
PROVIDE(trap_handler = default_trap_handler);
26+
27+
/* # Pre-initialization function */
28+
/* If the user overrides this using the `#[pre_init]` attribute or by creating a `__pre_init` function,
29+
then the function this points to will be called before the RAM is initialized. */
30+
PROVIDE(__pre_init = default_pre_init);
31+
32+
/* # Multi-processing hook function
33+
fn _mp_hook() -> bool;
34+
35+
This function is called from all the harts and must return true only for one hart,
36+
which will perform memory initialization. For other harts it must return false
37+
and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt).
38+
*/
39+
PROVIDE(_mp_hook = default_mp_hook);
40+
41+
ENTRY(_start)
42+
43+
SECTIONS
44+
{
45+
.text.dummy (NOLOAD) :
46+
{
47+
/* This section is intended to make _stext address work */
48+
. = ABSOLUTE(_stext);
49+
} > REGION_TEXT
50+
51+
.text _stext :
52+
{
53+
/* Put reset handler first in .text section so it ends up as the entry */
54+
/* point of the program. */
55+
KEEP(*(.text.init));
56+
KEEP(*(.init));
57+
KEEP(*(.init.rust));
58+
. = ALIGN(4);
59+
KEEP(*(.trap));
60+
KEEP(*(.trap.rust));
61+
62+
*(.text .text.*);
63+
} > REGION_TEXT
64+
65+
.rodata : ALIGN(4)
66+
{
67+
*(.rodata .rodata.*);
68+
69+
/* 4-byte align the end (VMA) of this section.
70+
This is required by LLD to ensure the LMA of the following .data
71+
section will have the correct alignment. */
72+
. = ALIGN(4);
73+
_etext = .;
74+
} > REGION_RODATA
75+
76+
.data : ALIGN(4)
77+
{
78+
_sidata = LOADADDR(.data);
79+
_sdata = .;
80+
/* Must be called __global_pointer$ for linker relaxations to work. */
81+
PROVIDE(__global_pointer$ = . + 0x800);
82+
*(.sdata .sdata.* .sdata2 .sdata2.*);
83+
*(.data .data.*);
84+
. = ALIGN(4);
85+
_edata = .;
86+
} > REGION_DATA AT > REGION_RODATA
87+
88+
.bss (NOLOAD) :
89+
{
90+
_sbss = .;
91+
*(.sbss .sbss.* .bss .bss.*);
92+
. = ALIGN(4);
93+
_ebss = .;
94+
} > REGION_BSS
95+
96+
/* fictitious region that represents the memory available for the stack */
97+
.stack (NOLOAD) :
98+
{
99+
_sstack = .;
100+
. += _stack_size;
101+
. = ALIGN(4096);
102+
_estack = .;
103+
} > REGION_STACK
104+
105+
/* fictitious region that represents the memory available for the heap */
106+
.heap (NOLOAD) :
107+
{
108+
. = ALIGN(4);
109+
_sheap = .;
110+
/* _eheap is defined elsewhere and is the remainder of RAM */
111+
} > REGION_HEAP
112+
113+
/* fake output .got section */
114+
/* Dynamic relocations are unsupported. This section is only used to detect
115+
relocatable code in the input files and raise an error if relocatable code
116+
is found */
117+
.got (INFO) :
118+
{
119+
KEEP(*(.got .got.*));
120+
}
121+
122+
/* Discard .eh_frame, we are not doing unwind on panic so it is not needed */
123+
/DISCARD/ :
124+
{
125+
*(.eh_frame);
126+
*(.eh_frame_hdr);
127+
}
128+
}
129+
130+
/* Do not exceed this mark in the error messages above | */
131+
ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
132+
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
133+
134+
ASSERT(ORIGIN(REGION_RODATA) % 4 == 0, "
135+
ERROR(riscv-rt): the start of the REGION_RODATA must be 4-byte aligned");
136+
137+
ASSERT(ORIGIN(REGION_DATA) % 4 == 0, "
138+
ERROR(riscv-rt): the start of the REGION_DATA must be 4-byte aligned");
139+
140+
ASSERT(ORIGIN(REGION_HEAP) % 4 == 0, "
141+
ERROR(riscv-rt): the start of the REGION_HEAP must be 4-byte aligned");
142+
143+
ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
144+
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
145+
146+
ASSERT(ORIGIN(REGION_STACK) % 4 == 0, "
147+
ERROR(riscv-rt): the start of the REGION_STACK must be 4-byte aligned");
148+
149+
ASSERT(_stext % 4 == 0, "
150+
ERROR(riscv-rt): `_stext` must be 4-byte aligned");
151+
152+
ASSERT(_sdata % 4 == 0 && _edata % 4 == 0, "
153+
BUG(riscv-rt): .data is not 4-byte aligned");
154+
155+
ASSERT(_sidata % 4 == 0, "
156+
BUG(riscv-rt): the LMA of .data is not 4-byte aligned");
157+
158+
ASSERT(_sbss % 4 == 0 && _ebss % 4 == 0, "
159+
BUG(riscv-rt): .bss is not 4-byte aligned");
160+
161+
ASSERT(_sheap % 4 == 0, "
162+
BUG(riscv-rt): start of .heap is not 4-byte aligned");
163+
164+
ASSERT(_stext + SIZEOF(.text) < ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT), "
165+
ERROR(riscv-rt): The .text section must be placed inside the REGION_TEXT region.
166+
Set _stext to an address smaller than 'ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT)'");
167+
168+
ASSERT(SIZEOF(.stack) > (_max_hart_id + 1) * _hart_stack_size, "
169+
ERROR(riscv-rt): .stack section is too small for allocating stacks for all the harts.
170+
Consider changing `_max_hart_id` or `_hart_stack_size`.");
171+
172+
ASSERT(SIZEOF(.got) == 0, "
173+
.got section detected in the input files. Dynamic relocations are not
174+
supported. If you are linking to C code compiled using the `gcc` crate
175+
then modify your build script to compile the C code _without_ the
176+
-fPIC flag. See the documentation of the `gcc::Config.fpic` method for
177+
details.");
178+
179+
/* Do not exceed this mark in the error messages above | */

0 commit comments

Comments
 (0)