#![no_std]
#![no_main]
extern crate panic_halt;
use riscv_rt::entry;
use hifive1::hal::prelude::*;
use hifive1::hal::DeviceResources;
use hifive1::{sprintln, pin};
//use core::mem;
use riscv::register::{mepc,mstatus,mcause,mtvec,misa};
// Function to use as entry for user mode
fn user_mode(){
//sprintln!("User Mode Entered!"); // Verify that user mode has been entered
let _attempt = mepc::read();
loop{};
}
// This function handles machine traps from user mode due to interrupts or exceptions
fn trap_handler(){
sprintln!("Machine Trap Occurred!");
//let reason = mcause::read();
let ext = misa::read();
sprintln!("{:032b}", ext.map_or(0, |v| v.bits()));
}
#[entry]
fn main() -> ! {
let dr = DeviceResources::take().unwrap();
let p = dr.peripherals;
let pins = dr.pins;
// Configure clocks
let clocks = hifive1::clock::configure(p.PRCI, p.AONCLK, 320.mhz().into());
// Configure UART for stdoutcar
hifive1::stdout::configure(p.UART0, pin!(pins, uart0_tx), pin!(pins, uart0_rx), 115_200.bps(), clocks);
// Top of stack using all 16k of ram
let stack_ptr: usize = 0x80004000;
// Setup machine trap vector
let trap_address = trap_handler as *const();
unsafe{mtvec::write(trap_address as usize,mtvec::TrapMode::Direct)};
// prepare to entry user mode
let user_entry = user_mode as *const();
mepc::write(user_entry as usize); // Entry point for user mode
unsafe{mstatus::set_mpp(mstatus::MPP::User)}; // Set MPP bit to enter user mode (00)
//Set return address to 0, set stack pointer, mret to enter user mode
#[cfg(all(riscv, feature = "inline-asm"))]
unsafe{
asm!("mov ra, 0",
"mov sp, $0" : "=r" (stack_ptr) ,
"mret");
}
loop{};
}
Did you compile it ?
The more-up-to-date documentation for asm!
is https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html .
Yeah I started to think that I was using older syntax, I changed my inline to this
asm!("mov ra, 0",
"mov sp, {0}",
"mret",
in(reg) stack_ptr);
I don't have any issues building the program, but I do get a warning that stack_ptr
is unused?
Is the instruction valid ?
You could quick compile here: Compiler Explorer
Seems like there are some mistakes: Compiler Explorer
Very nice, I had heard of godbolt, but I have never tried to use it. Looks like it can be very useful, thank you for the links. I will give the new syntax a try.
EDIT:
Also, do I need to add the #[no_mangle] and pub unsafe fn, or was that just for godbolt?
Yeah, just for godbolt.
Any ideas on the syntax for using modules, I cannot figure it out.
I've tried
let cause = mcause::read();
let cause = mcause::Mcause::Trap();
let cause = mcause::Mcause::code();
let cause = mcause::Mcause.code();
etc
Just trying to get the exception enum result
I think I figured it out, LOL.
mcause::read().code()
My inline assembly isn't working. The SiFive guys suggested I use the assembly I have setup in godbolt. It compiles fine on godbolt, but I get an error when I try to build the program
error: linking with rust-lld failed: exit code: 1 ....
undefined symbol a0
When I try
#![no_std]
#![feature(asm, start)]
#[no_mangle]
pub unsafe fn foo() {
let stack_ptr: usize = 0x80003b80;
// #[cfg(all(riscv, feature = "inline-asm"))]
asm!(
"mv ra, zero",
"la t0, {0}",
"lw sp, 0(t0)",
"mret",
in(reg) stack_ptr ,
);
}
#[panic_handler]
fn panic_handler(_: &core::panic::PanicInfo) -> ! {
loop {}
}
#[start]
fn start(_: isize, _: *const *const u8) -> isize {
unsafe { foo(); }
0
}
with -Clinker=rust-lld
on godbolt it compiles without problem. (you have to enable the "compile to binary" option under "output")
Still getting that same error when I try to build on my laptop. I see that it compiles on godbolt with -Clinker=rust-lld
. I'm using the riscv_rt crate
which uses link.x as a link argument, but I'm not sure that has anything to do with it.
"/home/dkhayes117/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/riscv32imac-unknown-none-elf/lib/libcompiler_builtins-a966de93028a50b8.rlib" "-Tmachine-memory.x" "-Tlink.x" "-Bdynamic"
= note: rust-lld: error: undefined symbol: a0
>>> referenced by user_stack.rs:98 (examples/user_stack.rs:98)
>>>
Does riscv have other linkers?
The error is weird because a0 is a valid register.
I'm not sure, I thought it was strange as well, but any assembly that expands into something with a0 fails. I based the project off of the rust-riscv-quickstart template on github, which is the only setup I know of to use Rust with the HiFive1 Rev B microcontroller. I modified the link files and arguments but even using the template defaults I get the same error.
EDIT: Maybe I can precompile the assembly portion and include it as a module or something in my code. The riscv
crate that I am using does this, but I have no idea on how to do this
What is even weirder is that the original assembly I used expands to use a0 and builds fine
asm!(
"mv ra, zero",
"mv sp, {0}",
"mret",
in(reg) stack_ptr ,
);
foo:
lui a0, 524292
addi a0, a0, -1152
mv ra, zero
add sp, zero, a0
mret
j .LBB0_1
.LBB0_1:
ret
what is your lld version, also did you try rust-lld ?
https://github.com/riscv/riscv-lld is a forked of LLD, but I expect most patches are merged back upstream.
I don't think the assembly was correct for my operation. I determined my original assembly that you helped me with was correct and was not the issue. It turns out that when going into user mode any memory accesses have to match one of the physical memory protection (PMP) registers. I never configured them because they were all turned off, but this doesn't matter, while in u-mode PMPs are always checked. Once I fixed that, all went well
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.