Skip to content

Commit a4d6961

Browse files
Merge pull request #227 from mekosko/master
Make support for u-boot
2 parents 51fb773 + 86a3ebf commit a4d6961

File tree

7 files changed

+101
-31
lines changed

7 files changed

+101
-31
lines changed

.github/workflows/riscv-rt.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ jobs:
4141
run: RUSTFLAGS="-C link-arg=-Triscv-rt/examples/device.x" cargo build --package riscv-rt --target ${{ matrix.target }} --example ${{ matrix.example }} --features=single-hart
4242
- name : Build (v-trap)
4343
run: RUSTFLAGS="-C link-arg=-Triscv-rt/examples/device.x" cargo build --package riscv-rt --target ${{ matrix.target }} --example ${{ matrix.example }} --features=v-trap
44-
- name: Build (all features)
45-
run: RUSTFLAGS="-C link-arg=-Triscv-rt/examples/device.x" cargo build --package riscv-rt --target ${{ matrix.target }} --example ${{ matrix.example }} --all-features
44+
- name : Build (all features except u-boot)
45+
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
46+
- name : Build (u-boot)
47+
run: RUSTFLAGS="-C link-arg=-Triscv-rt/examples/device.x" cargo build --package riscv-rt --target ${{ matrix.target }} --example empty --features=u-boot
4648

4749
# Job to check that all the builds succeeded
4850
build-check:

riscv-rt/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1313
- Add `v-trap` feature to enable interrupt handling in vectored mode.
1414
- Add `interrupt` proc macro to help defining interrupt handlers.
1515
If `v-trap` feature is enabled, this macro also generates its corresponding trap.
16+
- Add `u-boot` feature, so that you can start your elf binary with u-boot and
17+
work with passed arguments.
1618

1719
### Changed
1820

riscv-rt/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ panic-halt = "0.2.0"
2323
s-mode = ["riscv-rt-macros/s-mode"]
2424
single-hart = []
2525
v-trap = ["riscv-rt-macros/v-trap"]
26+
u-boot = ["riscv-rt-macros/u-boot", "single-hart"]

riscv-rt/macros/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ syn = { version = "2.0", features = ["extra-traits", "full"] }
2323
[features]
2424
s-mode = []
2525
v-trap = []
26+
u-boot = []

riscv-rt/macros/src/lib.rs

Lines changed: 79 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ extern crate syn;
1111
use proc_macro2::Span;
1212
use syn::{
1313
parse::{self, Parse},
14+
punctuated::Punctuated,
1415
spanned::Spanned,
15-
FnArg, ItemFn, LitInt, LitStr, PathArguments, ReturnType, Type, Visibility,
16+
FnArg, ItemFn, LitInt, LitStr, PatType, ReturnType, Type, Visibility,
1617
};
1718

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

56+
#[cfg(not(feature = "u-boot"))]
57+
let arguments_limit = 3;
58+
#[cfg(feature = "u-boot")]
59+
let arguments_limit = 2;
60+
5561
// check the function arguments
56-
if f.sig.inputs.len() > 3 {
62+
if f.sig.inputs.len() > arguments_limit {
5763
return parse::Error::new(
5864
f.sig.inputs.last().unwrap().span(),
5965
"`#[entry]` function has too many arguments",
6066
)
6167
.to_compile_error()
6268
.into();
6369
}
64-
for arg in &f.sig.inputs {
65-
match arg {
66-
FnArg::Receiver(_) => {
67-
return parse::Error::new(arg.span(), "invalid argument")
68-
.to_compile_error()
69-
.into();
70-
}
71-
FnArg::Typed(t) => {
72-
if !is_simple_type(&t.ty, "usize") {
73-
return parse::Error::new(t.ty.span(), "argument type must be usize")
74-
.to_compile_error()
75-
.into();
76-
}
77-
}
70+
71+
fn check_correct_type(argument: &PatType, ty: &str) -> Option<TokenStream> {
72+
let inv_type_message = format!("argument type must be {}", ty);
73+
74+
if !is_correct_type(&argument.ty, ty) {
75+
let error = parse::Error::new(argument.ty.span(), inv_type_message);
76+
77+
Some(error.to_compile_error().into())
78+
} else {
79+
None
80+
}
81+
}
82+
fn check_argument_type(argument: &FnArg, ty: &str) -> Option<TokenStream> {
83+
let argument_error = parse::Error::new(argument.span(), "invalid argument");
84+
let argument_error = argument_error.to_compile_error().into();
85+
86+
match argument {
87+
FnArg::Typed(argument) => check_correct_type(argument, ty),
88+
FnArg::Receiver(_) => Some(argument_error),
89+
}
90+
}
91+
#[cfg(not(feature = "u-boot"))]
92+
for argument in f.sig.inputs.iter() {
93+
if let Some(message) = check_argument_type(argument, "usize") {
94+
return message;
95+
};
96+
}
97+
#[cfg(feature = "u-boot")]
98+
if let Some(argument) = f.sig.inputs.get(0) {
99+
if let Some(message) = check_argument_type(argument, "c_int") {
100+
return message;
101+
}
102+
}
103+
#[cfg(feature = "u-boot")]
104+
if let Some(argument) = f.sig.inputs.get(1) {
105+
if let Some(message) = check_argument_type(argument, "*const *const c_char") {
106+
return message;
78107
}
79108
}
80109

@@ -123,17 +152,32 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
123152
.into()
124153
}
125154

126-
#[allow(unused)]
127-
fn is_simple_type(ty: &Type, name: &str) -> bool {
128-
if let Type::Path(p) = ty {
129-
if p.qself.is_none() && p.path.leading_colon.is_none() && p.path.segments.len() == 1 {
130-
let segment = p.path.segments.first().unwrap();
131-
if segment.ident == name && segment.arguments == PathArguments::None {
132-
return true;
133-
}
155+
fn strip_type_path(ty: &Type) -> Option<Type> {
156+
match ty {
157+
Type::Ptr(ty) => {
158+
let mut ty = ty.clone();
159+
ty.elem = Box::new(strip_type_path(&ty.elem)?);
160+
Some(Type::Ptr(ty))
161+
}
162+
Type::Path(ty) => {
163+
let mut ty = ty.clone();
164+
let last_segment = ty.path.segments.last().unwrap().clone();
165+
ty.path.segments = Punctuated::new();
166+
ty.path.segments.push_value(last_segment);
167+
Some(Type::Path(ty))
134168
}
169+
_ => None,
170+
}
171+
}
172+
173+
#[allow(unused)]
174+
fn is_correct_type(ty: &Type, name: &str) -> bool {
175+
let correct: Type = syn::parse_str(name).unwrap();
176+
if let Some(ty) = strip_type_path(ty) {
177+
ty == correct
178+
} else {
179+
false
135180
}
136-
false
137181
}
138182

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

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

514561
#[proc_macro_attribute]
515-
/// Attribute to declare an interrupt handler. The function must have the signature `[unsafe] fn() [-> !]`.
516-
/// If the `v-trap` feature is enabled, this macro generates the interrupt trap handler in assembly for RISCV-32 targets.
562+
/// Attribute to declare an interrupt handler.
563+
///
564+
/// The function must have the signature `[unsafe] fn() [-> !]`.
565+
/// If the `v-trap` feature is enabled, this macro generates the
566+
/// interrupt trap handler in assembly for RISCV-64 targets.
517567
pub fn interrupt_riscv64(args: TokenStream, input: TokenStream) -> TokenStream {
518568
interrupt(args, input, RiscvArch::Rv64)
519569
}

riscv-rt/src/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,19 @@
452452
//! ```
453453
//!
454454
//! This will generate a function named `_start_MachineTimer_trap` that calls the interrupt handler `MachineTimer`.
455+
//!
456+
//! ## `u-boot`
457+
//!
458+
//! The u-boot support feature (`u-boot`) can be activated via [Cargo features](https://doc.rust-lang.org/cargo/reference/features.html).
459+
//!
460+
//! For example:
461+
//! ``` text
462+
//! [dependencies]
463+
//! riscv-rt = { features = ["u-boot"] }
464+
//! ```
465+
//! When the u-boot feature is enabled, acceptable signature for `#[entry]` macros is changed. This is required
466+
//! because when booting from elf, u-boot passes `argc` and `argv`. This feature also implies `single-hart`.
467+
//! The only way to get boot-hart is through fdt, so other harts initialization is up to you.
455468
456469
// NOTE: Adapted from cortex-m/src/lib.rs
457470
#![no_std]

riscv/src/interrupt.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ pub mod supervisor {
142142
}
143143

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

0 commit comments

Comments
 (0)