diff --git a/src/lib.rs b/src/lib.rs index 1c870b5..cabb2cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,10 +55,15 @@ //! //! ``` ignore,no_run //! #![no_std] +//! #![no_main] //! +//! #[macro_use(entry)] //! extern crate riscv_rt; //! -//! fn main() { +//! // use `main` as the entry point of this application +//! entry!(main); +//! +//! fn main() -> ! { //! // do something here //! } //! ``` @@ -174,13 +179,9 @@ extern crate r0; mod lang_items; -use riscv::asm; use riscv::register::{mcause, mstatus}; extern "C" { - // NOTE `rustc` forces this signature on us. See `src/lang_items.rs` - fn main() -> isize; - // Boundaries of the .bss section static mut _ebss: u32; static mut _sbss: u32; @@ -234,6 +235,11 @@ _start: #[link_section = ".init.rust"] #[export_name = "_start_rust"] pub extern "C" fn start_rust() -> ! { + extern "C" { + // This symbol will be provided by the user via the `entry!` macro + fn main() -> !; + } + unsafe { r0::zero_bss(&mut _sbss, &mut _ebss); r0::init_data(&mut _sdata, &mut _edata, &_sidata); @@ -252,17 +258,34 @@ pub extern "C" fn start_rust() -> ! { : "volatile"); } - // Neither `argc` or `argv` make sense in bare metal context so we - // just stub them unsafe { main(); } +} - // If `main` returns, then we go into "reactive" mode and simply attend - // interrupts as they occur. - loop { - asm::wfi(); - } + +/// Macro to define the entry point of the program +/// +/// **NOTE** This macro must be invoked once and must be invoked from an accessible module, ideally +/// from the root of the crate. +/// +/// Usage: `entry!(path::to::entry::point)` +/// +/// The specified function will be called by the reset handler *after* RAM has been initialized. +/// +/// The signature of the specified function must be `fn() -> !` (never ending function). +#[macro_export] +macro_rules! entry { + ($path:expr) => { + #[inline(never)] + #[export_name = "main"] + pub extern "C" fn __impl_main() -> ! { + // validate the signature of the program entry point + let f: fn() -> ! = $path; + + f() + } + }; }