瀏覽代碼

Merge #95

95: Pass a0..a2 to main() r=almindor a=Disasm

This PR delivers arguments stored in a0..a2 to `main`.

Fixes https://github.com/rust-embedded/riscv-rt/issues/92

Tested with:
* build the `empty` example for `riscv64imac-unknown-none-elf` with a memory file which puts everything to `0x80000000`
* run `qemu-system-riscv64 -nographic -machine virt -bios target/riscv64imac-unknown-none-elf/release/examples/empty -s -S`
* connect to qemu with gdb (`target remote :1234`)
* set breakpoint to main (`b main`)
* resume execution (`continue`)
* inspect registers (`info registers`)
```
a0             0x0	0
a1             0x87000000	2264924160
a2             0x1028	4136
```
* check header (`x/xw 0x87000000`)
```
0x87000000:	0xedfe0dd0
```

Co-authored-by: Vadim Kaushan <admin@disasm.info>
bors[bot] 2 年之前
父節點
當前提交
4b98bd4e49
共有 29 個文件被更改,包括 57 次插入23 次删除
  1. 1 1
      riscv-rt/Cargo.toml
  2. 8 10
      riscv-rt/asm.S
  3. 二進制
      riscv-rt/bin/riscv32i-unknown-none-elf.a
  4. 二進制
      riscv-rt/bin/riscv32ic-unknown-none-elf.a
  5. 二進制
      riscv-rt/bin/riscv32if-unknown-none-elf.a
  6. 二進制
      riscv-rt/bin/riscv32ifc-unknown-none-elf.a
  7. 二進制
      riscv-rt/bin/riscv32ifd-unknown-none-elf.a
  8. 二進制
      riscv-rt/bin/riscv32ifdc-unknown-none-elf.a
  9. 二進制
      riscv-rt/bin/riscv32im-unknown-none-elf.a
  10. 二進制
      riscv-rt/bin/riscv32imc-unknown-none-elf.a
  11. 二進制
      riscv-rt/bin/riscv32imf-unknown-none-elf.a
  12. 二進制
      riscv-rt/bin/riscv32imfc-unknown-none-elf.a
  13. 二進制
      riscv-rt/bin/riscv32imfd-unknown-none-elf.a
  14. 二進制
      riscv-rt/bin/riscv32imfdc-unknown-none-elf.a
  15. 二進制
      riscv-rt/bin/riscv64i-unknown-none-elf.a
  16. 二進制
      riscv-rt/bin/riscv64ic-unknown-none-elf.a
  17. 二進制
      riscv-rt/bin/riscv64if-unknown-none-elf.a
  18. 二進制
      riscv-rt/bin/riscv64ifc-unknown-none-elf.a
  19. 二進制
      riscv-rt/bin/riscv64ifd-unknown-none-elf.a
  20. 二進制
      riscv-rt/bin/riscv64ifdc-unknown-none-elf.a
  21. 二進制
      riscv-rt/bin/riscv64im-unknown-none-elf.a
  22. 二進制
      riscv-rt/bin/riscv64imc-unknown-none-elf.a
  23. 二進制
      riscv-rt/bin/riscv64imf-unknown-none-elf.a
  24. 二進制
      riscv-rt/bin/riscv64imfc-unknown-none-elf.a
  25. 二進制
      riscv-rt/bin/riscv64imfd-unknown-none-elf.a
  26. 二進制
      riscv-rt/bin/riscv64imfdc-unknown-none-elf.a
  27. 1 1
      riscv-rt/macros/Cargo.toml
  28. 44 8
      riscv-rt/macros/src/lib.rs
  29. 3 3
      riscv-rt/src/lib.rs

+ 1 - 1
riscv-rt/Cargo.toml

@@ -12,7 +12,7 @@ license = "ISC"
 [dependencies]
 r0 = "1.0.0"
 riscv = "0.8"
-riscv-rt-macros = { path = "macros", version = "0.1.6" }
+riscv-rt-macros = { path = "macros", version = "0.2.0" }
 
 [dev-dependencies]
 panic-halt = "0.2.0"

+ 8 - 10
riscv-rt/asm.S

@@ -58,9 +58,7 @@ _abs_start:
     li  x7, 0
     li  x8, 0
     li  x9, 0
-    li  x10,0
-    li  x11,0
-    li  x12,0
+    // a0..a2 (x10..x12) skipped
     li  x13,0
     li  x14,0
     li  x15,0
@@ -87,23 +85,23 @@ _abs_start:
     .option pop
 
     // Check hart id
-    csrr a2, mhartid
+    csrr t2, mhartid
     lui t0, %hi(_max_hart_id)
     add t0, t0, %lo(_max_hart_id)
-    bgtu a2, t0, abort
+    bgtu t2, t0, abort
 
     // Allocate stacks
     la sp, _stack_start
     lui t0, %hi(_hart_stack_size)
     add t0, t0, %lo(_hart_stack_size)
 #ifdef __riscv_mul
-    mul t0, a2, t0
+    mul t0, t2, t0
 #else
-    beqz a2, 2f  // Jump if single-hart
-    mv t1, a2
-    mv t2, t0
+    beqz t2, 2f  // Jump if single-hart
+    mv t1, t2
+    mv t3, t0
 1:
-    add t0, t0, t2
+    add t0, t0, t3
     addi t1, t1, -1
     bnez t1, 1b
 2:

二進制
riscv-rt/bin/riscv32i-unknown-none-elf.a


二進制
riscv-rt/bin/riscv32ic-unknown-none-elf.a


二進制
riscv-rt/bin/riscv32if-unknown-none-elf.a


二進制
riscv-rt/bin/riscv32ifc-unknown-none-elf.a


二進制
riscv-rt/bin/riscv32ifd-unknown-none-elf.a


二進制
riscv-rt/bin/riscv32ifdc-unknown-none-elf.a


二進制
riscv-rt/bin/riscv32im-unknown-none-elf.a


二進制
riscv-rt/bin/riscv32imc-unknown-none-elf.a


二進制
riscv-rt/bin/riscv32imf-unknown-none-elf.a


二進制
riscv-rt/bin/riscv32imfc-unknown-none-elf.a


二進制
riscv-rt/bin/riscv32imfd-unknown-none-elf.a


二進制
riscv-rt/bin/riscv32imfdc-unknown-none-elf.a


二進制
riscv-rt/bin/riscv64i-unknown-none-elf.a


二進制
riscv-rt/bin/riscv64ic-unknown-none-elf.a


二進制
riscv-rt/bin/riscv64if-unknown-none-elf.a


二進制
riscv-rt/bin/riscv64ifc-unknown-none-elf.a


二進制
riscv-rt/bin/riscv64ifd-unknown-none-elf.a


二進制
riscv-rt/bin/riscv64ifdc-unknown-none-elf.a


二進制
riscv-rt/bin/riscv64im-unknown-none-elf.a


二進制
riscv-rt/bin/riscv64imc-unknown-none-elf.a


二進制
riscv-rt/bin/riscv64imf-unknown-none-elf.a


二進制
riscv-rt/bin/riscv64imfc-unknown-none-elf.a


二進制
riscv-rt/bin/riscv64imfd-unknown-none-elf.a


二進制
riscv-rt/bin/riscv64imfdc-unknown-none-elf.a


+ 1 - 1
riscv-rt/macros/Cargo.toml

@@ -10,7 +10,7 @@ keywords = ["riscv", "runtime", "startup"]
 license = "MIT OR Apache-2.0"
 name = "riscv-rt-macros"
 repository = "https://github.com/rust-embedded/riscv-rt"
-version = "0.1.6"
+version = "0.2.0"
 
 [lib]
 proc-macro = true

+ 44 - 8
riscv-rt/macros/src/lib.rs

@@ -9,7 +9,7 @@ extern crate proc_macro2;
 extern crate syn;
 
 use proc_macro2::Span;
-use syn::{parse, spanned::Spanned, ItemFn, ReturnType, Type, Visibility};
+use syn::{parse, spanned::Spanned, FnArg, ItemFn, PathArguments, ReturnType, Type, Visibility};
 
 use proc_macro::TokenStream;
 
@@ -48,27 +48,49 @@ use proc_macro::TokenStream;
 pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
     let f = parse_macro_input!(input as ItemFn);
 
+    // check the function arguments
+    if f.sig.inputs.len() > 3 {
+        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();
+                }
+            }
+        }
+    }
+
     // check the function signature
     let valid_signature = f.sig.constness.is_none()
         && f.sig.asyncness.is_none()
         && f.vis == Visibility::Inherited
         && f.sig.abi.is_none()
-        && f.sig.inputs.is_empty()
         && f.sig.generics.params.is_empty()
         && f.sig.generics.where_clause.is_none()
         && f.sig.variadic.is_none()
         && match f.sig.output {
             ReturnType::Default => false,
-            ReturnType::Type(_, ref ty) => match **ty {
-                Type::Never(_) => true,
-                _ => false,
-            },
+            ReturnType::Type(_, ref ty) => matches!(**ty, Type::Never(_)),
         };
 
     if !valid_signature {
         return parse::Error::new(
             f.span(),
-            "`#[entry]` function must have signature `[unsafe] fn() -> !`",
+            "`#[entry]` function must have signature `[unsafe] fn([arg0: usize, ...]) -> !`",
         )
         .to_compile_error()
         .into();
@@ -83,18 +105,32 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
     // XXX should we blacklist other attributes?
     let attrs = f.attrs;
     let unsafety = f.sig.unsafety;
+    let args = f.sig.inputs;
     let stmts = f.block.stmts;
 
     quote!(
         #[export_name = "main"]
         #(#attrs)*
-        pub #unsafety fn __risc_v_rt__main() -> ! {
+        pub #unsafety fn __risc_v_rt__main(#args) -> ! {
             #(#stmts)*
         }
     )
     .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;
+            }
+        }
+    }
+    false
+}
+
 /// Attribute to mark which function will be called at the beginning of the reset handler.
 ///
 /// **IMPORTANT**: This attribute can appear at most *once* in the dependency graph. Also, if you

+ 3 - 3
riscv-rt/src/lib.rs

@@ -361,11 +361,11 @@ extern "C" {
 /// never returns.
 #[link_section = ".init.rust"]
 #[export_name = "_start_rust"]
-pub unsafe extern "C" fn start_rust() -> ! {
+pub unsafe extern "C" fn start_rust(a0: usize, a1: usize, a2: usize) -> ! {
     #[rustfmt::skip]
     extern "Rust" {
         // This symbol will be provided by the user via `#[entry]`
-        fn main() -> !;
+        fn main(a0: usize, a1: usize, a2: usize) -> !;
 
         // This symbol will be provided by the user via `#[pre_init]`
         fn __pre_init();
@@ -386,7 +386,7 @@ pub unsafe extern "C" fn start_rust() -> ! {
 
     _setup_interrupts();
 
-    main();
+    main(a0, a1, a2);
 }
 
 /// Registers saved in trap handler