Skip to content

Commit

Permalink
Merge pull request #227 from mekosko/master
Browse files Browse the repository at this point in the history
Make support for u-boot
  • Loading branch information
romancardenas authored Aug 27, 2024
2 parents 51fb773 + 86a3ebf commit a4d6961
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 31 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/riscv-rt.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ jobs:
run: RUSTFLAGS="-C link-arg=-Triscv-rt/examples/device.x" cargo build --package riscv-rt --target ${{ matrix.target }} --example ${{ matrix.example }} --features=single-hart
- name : Build (v-trap)
run: RUSTFLAGS="-C link-arg=-Triscv-rt/examples/device.x" cargo build --package riscv-rt --target ${{ matrix.target }} --example ${{ matrix.example }} --features=v-trap
- name: Build (all features)
run: RUSTFLAGS="-C link-arg=-Triscv-rt/examples/device.x" cargo build --package riscv-rt --target ${{ matrix.target }} --example ${{ matrix.example }} --all-features
- name : Build (all features except u-boot)
run: RUSTFLAGS="-C link-arg=-Triscv-rt/examples/device.x" cargo build --package riscv-rt --target ${{ matrix.target }} --example ${{ matrix.example }} --features=s-mode,single-hart,v-trap
- name : Build (u-boot)
run: RUSTFLAGS="-C link-arg=-Triscv-rt/examples/device.x" cargo build --package riscv-rt --target ${{ matrix.target }} --example empty --features=u-boot

# Job to check that all the builds succeeded
build-check:
Expand Down
2 changes: 2 additions & 0 deletions riscv-rt/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Add `v-trap` feature to enable interrupt handling in vectored mode.
- Add `interrupt` proc macro to help defining interrupt handlers.
If `v-trap` feature is enabled, this macro also generates its corresponding trap.
- Add `u-boot` feature, so that you can start your elf binary with u-boot and
work with passed arguments.

### Changed

Expand Down
1 change: 1 addition & 0 deletions riscv-rt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ panic-halt = "0.2.0"
s-mode = ["riscv-rt-macros/s-mode"]
single-hart = []
v-trap = ["riscv-rt-macros/v-trap"]
u-boot = ["riscv-rt-macros/u-boot", "single-hart"]
1 change: 1 addition & 0 deletions riscv-rt/macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ syn = { version = "2.0", features = ["extra-traits", "full"] }
[features]
s-mode = []
v-trap = []
u-boot = []
108 changes: 79 additions & 29 deletions riscv-rt/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ extern crate syn;
use proc_macro2::Span;
use syn::{
parse::{self, Parse},
punctuated::Punctuated,
spanned::Spanned,
FnArg, ItemFn, LitInt, LitStr, PathArguments, ReturnType, Type, Visibility,
FnArg, ItemFn, LitInt, LitStr, PatType, ReturnType, Type, Visibility,
};

use proc_macro::TokenStream;
Expand Down Expand Up @@ -52,29 +53,57 @@ use proc_macro::TokenStream;
pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
let f = parse_macro_input!(input as ItemFn);

#[cfg(not(feature = "u-boot"))]
let arguments_limit = 3;
#[cfg(feature = "u-boot")]
let arguments_limit = 2;

// check the function arguments
if f.sig.inputs.len() > 3 {
if f.sig.inputs.len() > arguments_limit {
return parse::Error::new(
f.sig.inputs.last().unwrap().span(),
"`#[entry]` function has too many arguments",
)
.to_compile_error()
.into();
}
for arg in &f.sig.inputs {
match arg {
FnArg::Receiver(_) => {
return parse::Error::new(arg.span(), "invalid argument")
.to_compile_error()
.into();
}
FnArg::Typed(t) => {
if !is_simple_type(&t.ty, "usize") {
return parse::Error::new(t.ty.span(), "argument type must be usize")
.to_compile_error()
.into();
}
}

fn check_correct_type(argument: &PatType, ty: &str) -> Option<TokenStream> {
let inv_type_message = format!("argument type must be {}", ty);

if !is_correct_type(&argument.ty, ty) {
let error = parse::Error::new(argument.ty.span(), inv_type_message);

Some(error.to_compile_error().into())
} else {
None
}
}
fn check_argument_type(argument: &FnArg, ty: &str) -> Option<TokenStream> {
let argument_error = parse::Error::new(argument.span(), "invalid argument");
let argument_error = argument_error.to_compile_error().into();

match argument {
FnArg::Typed(argument) => check_correct_type(argument, ty),
FnArg::Receiver(_) => Some(argument_error),
}
}
#[cfg(not(feature = "u-boot"))]
for argument in f.sig.inputs.iter() {
if let Some(message) = check_argument_type(argument, "usize") {
return message;
};
}
#[cfg(feature = "u-boot")]
if let Some(argument) = f.sig.inputs.get(0) {
if let Some(message) = check_argument_type(argument, "c_int") {
return message;
}
}
#[cfg(feature = "u-boot")]
if let Some(argument) = f.sig.inputs.get(1) {
if let Some(message) = check_argument_type(argument, "*const *const c_char") {
return message;
}
}

Expand Down Expand Up @@ -123,17 +152,32 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
.into()
}

#[allow(unused)]
fn is_simple_type(ty: &Type, name: &str) -> bool {
if let Type::Path(p) = ty {
if p.qself.is_none() && p.path.leading_colon.is_none() && p.path.segments.len() == 1 {
let segment = p.path.segments.first().unwrap();
if segment.ident == name && segment.arguments == PathArguments::None {
return true;
}
fn strip_type_path(ty: &Type) -> Option<Type> {
match ty {
Type::Ptr(ty) => {
let mut ty = ty.clone();
ty.elem = Box::new(strip_type_path(&ty.elem)?);
Some(Type::Ptr(ty))
}
Type::Path(ty) => {
let mut ty = ty.clone();
let last_segment = ty.path.segments.last().unwrap().clone();
ty.path.segments = Punctuated::new();
ty.path.segments.push_value(last_segment);
Some(Type::Path(ty))
}
_ => None,
}
}

#[allow(unused)]
fn is_correct_type(ty: &Type, name: &str) -> bool {
let correct: Type = syn::parse_str(name).unwrap();
if let Some(ty) = strip_type_path(ty) {
ty == correct
} else {
false
}
false
}

/// Attribute to mark which function will be called at the beginning of the reset handler.
Expand Down Expand Up @@ -505,15 +549,21 @@ _continue_interrupt_trap:
}

#[proc_macro_attribute]
/// Attribute to declare an interrupt handler. The function must have the signature `[unsafe] fn() [-> !]`.
/// If the `v-trap` feature is enabled, this macro generates the interrupt trap handler in assembly for RISCV-32 targets.
/// Attribute to declare an interrupt handler.
///
/// The function must have the signature `[unsafe] fn() [-> !]`.
/// If the `v-trap` feature is enabled, this macro generates the
/// interrupt trap handler in assembly for RISCV-32 targets.
pub fn interrupt_riscv32(args: TokenStream, input: TokenStream) -> TokenStream {
interrupt(args, input, RiscvArch::Rv32)
}

#[proc_macro_attribute]
/// Attribute to declare an interrupt handler. The function must have the signature `[unsafe] fn() [-> !]`.
/// If the `v-trap` feature is enabled, this macro generates the interrupt trap handler in assembly for RISCV-32 targets.
/// Attribute to declare an interrupt handler.
///
/// The function must have the signature `[unsafe] fn() [-> !]`.
/// If the `v-trap` feature is enabled, this macro generates the
/// interrupt trap handler in assembly for RISCV-64 targets.
pub fn interrupt_riscv64(args: TokenStream, input: TokenStream) -> TokenStream {
interrupt(args, input, RiscvArch::Rv64)
}
Expand Down
13 changes: 13 additions & 0 deletions riscv-rt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,19 @@
//! ```
//!
//! This will generate a function named `_start_MachineTimer_trap` that calls the interrupt handler `MachineTimer`.
//!
//! ## `u-boot`
//!
//! The u-boot support feature (`u-boot`) can be activated via [Cargo features](https://doc.rust-lang.org/cargo/reference/features.html).
//!
//! For example:
//! ``` text
//! [dependencies]
//! riscv-rt = { features = ["u-boot"] }
//! ```
//! When the u-boot feature is enabled, acceptable signature for `#[entry]` macros is changed. This is required
//! because when booting from elf, u-boot passes `argc` and `argv`. This feature also implies `single-hart`.
//! The only way to get boot-hart is through fdt, so other harts initialization is up to you.

// NOTE: Adapted from cortex-m/src/lib.rs
#![no_std]
Expand Down
1 change: 1 addition & 0 deletions riscv/src/interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ pub mod supervisor {
}

/// Execute closure `f` with interrupts enabled in the current hart (supervisor mode).
///
/// This method is assumed to be called within an interrupt handler, and allows
/// nested interrupts to occur. After the closure `f` is executed, the [`sstatus`]
/// and [`sepc`] registers are properly restored to their previous values.
Expand Down

0 comments on commit a4d6961

Please sign in to comment.