Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

feat(prototyper): refactor code and add jump firmware #54

Merged
merged 1 commit into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions prototyper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ forced-target = "riscv64imac-unknown-none-elf"
[dependencies]
aclint = "0.0.0"
log = "0.4.21"
panic-halt = "0.2.0"
panic-halt = "1.0.0"
riscv = "0.11.1"
rustsbi = { version = "0.4.0", features = ["machine"] }
sbi-spec = { version = "0.0.7", features = ["legacy"] }
sbi-spec = { version = "0.0.8", features = ["legacy"] }
serde = { version = "1.0.202", default-features = false, features = ["derive"] }
serde-device-tree = { git = "https://github.com/rustsbi/serde-device-tree", default-features = false }
sifive-test-device = "0.0.0"
Expand All @@ -24,6 +24,7 @@ riscv-decode = "0.2.1"
fast-trap = { version = "0.0.1", features = ["riscv-m"] }
uart_xilinx = { git = "https://github.com/duskmoon314/uart-rs/" }
xuantie-riscv = { git= "https://github.com/rustsbi/xuantie" }
cfg-if = "1.0.0"

[[bin]]
name = "rustsbi-prototyper"
Expand All @@ -33,4 +34,5 @@ bench = false
[features]
nemu = []
payload = []
jump = []
fdt = []
13 changes: 13 additions & 0 deletions prototyper/src/cfg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/// Maximum number of supported harts.
pub const NUM_HART_MAX: usize = 8;
/// Stack size per hart (hardware thread) in bytes.
pub const LEN_STACK_PER_HART: usize = 16 * 1024;
/// Page size
pub const PAGE_SIZE: usize = 4096;
/// TLB_FLUSH_LIMIT defines the TLB refresh range limit.
/// If the TLB refresh range is greater than TLB_FLUSH_LIMIT, the entire TLB is refreshed.
pub const TLB_FLUSH_LIMIT: usize = 4 * PAGE_SIZE;


#[cfg(feature = "jump")]
pub const JUMP_ADDRESS: usize = 0x80200000;
File renamed without changes.
141 changes: 71 additions & 70 deletions prototyper/src/fail.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
use serde_device_tree::Dtb;

use crate::dt;
use crate::devicetree;

#[cfg(not(feature = "payload"))]
use crate::firmware::dynamic;
#[cfg(not(feature = "payload"))]
use crate::sbi::reset;
#[cfg(not(feature = "payload"))]
use riscv::register::mstatus;
#[cfg(all(feature = "payload", feature = "jump"))]
compile_error!("feature \"payload\" and feature \"jump\" cannot be enabled at the same time");

// TODO: Need a better way to handle device tree parsing errors

/// Handles device tree format parsing errors by logging and resetting.
#[cold]
pub fn device_tree_format(_err: dt::ParseDeviceTreeError) -> Dtb {
pub fn device_tree_format(_err: devicetree::ParseDeviceTreeError) -> Dtb {
loop {
core::hint::spin_loop()
}
Expand All @@ -28,72 +23,78 @@ pub fn device_tree_deserialize_root<'a>(
}
}

/// Handles invalid dynamic information data by logging details and resetting.
#[cold]
#[cfg(not(feature = "payload"))]
pub fn invalid_dynamic_data(err: dynamic::DynamicError) -> (mstatus::MPP, usize) {
error!("Invalid data in dynamic information:");
if err.invalid_mpp {
error!("* dynamic information contains invalid privilege mode");
}
if err.invalid_next_addr {
error!("* dynamic information contains invalid next jump address");
}
let explain_next_mode = match err.bad_info.next_mode {
3 => "Machine",
1 => "Supervisor",
0 => "User",
_ => "Invalid",
};
error!(
"@ help: dynamic information contains magic value 0x{:x}, version {}, next jump address 0x{:x}, next privilege mode {} ({}), options {:x}, boot hart ID {}",
err.bad_info.magic, err.bad_info.version, err.bad_info.next_addr, err.bad_info.next_mode, explain_next_mode, err.bad_info.options, err.bad_info.boot_hart
);
reset::fail()
}

/// Handles case where dynamic information is not available by logging details and resetting.
#[cold]
#[cfg(not(feature = "payload"))]
pub fn no_dynamic_info_available(err: dynamic::DynamicReadError) -> dynamic::DynamicInfo {
if let Some(bad_paddr) = err.bad_paddr {
error!(
"No dynamic information available at address 0x{:x}",
bad_paddr
);
cfg_if::cfg_if! {
if #[cfg(feature = "payload")] {
} else if #[cfg(feature = "jump")] {
} else {
error!("No valid dynamic information available:");
if let Some(bad_magic) = err.bad_magic {
use crate::firmware::dynamic;
use crate::sbi::reset;
use riscv::register::mstatus;
/// Handles invalid dynamic information data by logging details and resetting.
#[cold]
pub fn invalid_dynamic_data(err: dynamic::DynamicError) -> (mstatus::MPP, usize) {
error!("Invalid data in dynamic information:");
if err.invalid_mpp {
error!("* dynamic information contains invalid privilege mode");
}
if err.invalid_next_addr {
error!("* dynamic information contains invalid next jump address");
}
let explain_next_mode = match err.bad_info.next_mode {
3 => "Machine",
1 => "Supervisor",
0 => "User",
_ => "Invalid",
};
error!(
"* tried to identify dynamic information, but found invalid magic number 0x{:x}",
bad_magic
"@ help: dynamic information contains magic value 0x{:x}, version {}, next jump address 0x{:x}, next privilege mode {} ({}), options {:x}, boot hart ID {}",
err.bad_info.magic, err.bad_info.version, err.bad_info.next_addr, err.bad_info.next_mode, explain_next_mode, err.bad_info.options, err.bad_info.boot_hart
);
reset::fail()
}
if let Some(bad_version) = err.bad_version {
error!("* tries to identify version of dynamic information, but the version number {} is not supported", bad_version);
}
if err.bad_magic.is_none() {
error!("@ help: magic number is valid")
}
if err.bad_version.is_none() {
error!("@ help: dynamic information version is valid")

/// Handles case where dynamic information is not available by logging details and resetting.
#[cold]
pub fn no_dynamic_info_available(err: dynamic::DynamicReadError) -> dynamic::DynamicInfo {
if let Some(bad_paddr) = err.bad_paddr {
error!(
"No dynamic information available at address 0x{:x}",
bad_paddr
);
} else {
error!("No valid dynamic information available:");
if let Some(bad_magic) = err.bad_magic {
error!(
"* tried to identify dynamic information, but found invalid magic number 0x{:x}",
bad_magic
);
}
if let Some(bad_version) = err.bad_version {
error!("* tries to identify version of dynamic information, but the version number {} is not supported", bad_version);
}
if err.bad_magic.is_none() {
error!("@ help: magic number is valid")
}
if err.bad_version.is_none() {
error!("@ help: dynamic information version is valid")
}
}
reset::fail()
}
}
reset::fail()
}

/// Fallback function that returns default dynamic info with boot_hart set to MAX.
///
/// Used when dynamic info read fails but execution should continue.
#[cold]
#[cfg(not(feature = "payload"))]
pub fn use_lottery(_err: dynamic::DynamicReadError) -> dynamic::DynamicInfo {
dynamic::DynamicInfo {
magic: 0,
version: 0,
next_addr: 0,
next_mode: 0,
options: 0,
boot_hart: usize::MAX,
/// Fallback function that returns default dynamic info with boot_hart set to MAX.
///
/// Used when dynamic info read fails but execution should continue.
#[cold]
pub fn use_lottery(_err: dynamic::DynamicReadError) -> dynamic::DynamicInfo {
dynamic::DynamicInfo {
magic: 0,
version: 0,
next_addr: 0,
next_mode: 0,
options: 0,
boot_hart: usize::MAX,
}
}
}
}
2 changes: 1 addition & 1 deletion prototyper/src/firmware/dynamic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use core::sync::atomic::{AtomicBool, Ordering};

use super::BootInfo;
use crate::fail;
use crate::riscv_spec::current_hartid;
use crate::riscv::current_hartid;

use riscv::register::mstatus;

Expand Down
20 changes: 20 additions & 0 deletions prototyper/src/firmware/jump.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use core::sync::atomic::{AtomicBool, Ordering};
use riscv::register::mstatus;

use super::BootInfo;
use crate::cfg::JUMP_ADDRESS;

/// Determine whether the current hart is boot hart.
///
/// Return true if the current hart is boot hart.
pub fn is_boot_hart(_nonstandard_a2: usize) -> bool {
static GENESIS: AtomicBool = AtomicBool::new(true);
GENESIS.swap(false, Ordering::AcqRel)
}

pub fn get_boot_info(_nonstandard_a2: usize) -> BootInfo {
BootInfo {
next_address: JUMP_ADDRESS,
mpp: mstatus::MPP::Supervisor,
}
}
20 changes: 12 additions & 8 deletions prototyper/src/firmware/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
#[cfg(not(feature = "payload"))]
pub mod dynamic;
#[cfg(feature = "payload")]
pub mod payload;
cfg_if::cfg_if! {
if #[cfg(feature = "payload")] {
pub mod payload;
pub use payload::{get_boot_info, is_boot_hart};
} else if #[cfg(feature = "jump")] {
pub mod jump;
pub use jump::{get_boot_info, is_boot_hart};
} else {
pub mod dynamic;
pub use dynamic::{get_boot_info, is_boot_hart};
}
}

use core::arch::asm;
use core::ops::Range;
Expand Down Expand Up @@ -34,10 +42,6 @@ fn get_fdt_address() -> usize {
raw_fdt as usize
}

#[cfg(not(feature = "payload"))]
pub use dynamic::{get_boot_info, is_boot_hart};
#[cfg(feature = "payload")]
pub use payload::{get_boot_info, is_boot_hart};

/// Gets boot hart information based on opaque and nonstandard_a2 parameters.
///
Expand Down
14 changes: 8 additions & 6 deletions prototyper/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@ extern crate log;
#[macro_use]
mod macros;

mod dt;
mod cfg;
mod devicetree;
mod fail;
mod firmware;
mod platform;
mod riscv_spec;
mod riscv;
mod sbi;

use core::arch::asm;

use crate::platform::PLATFORM;
use crate::riscv_spec::{current_hartid, menvcfg};
use crate::riscv::csr::menvcfg;
use crate::riscv::current_hartid;
use crate::sbi::extensions::{
hart_extension_probe, hart_privileged_version, privileged_version_detection, Extension,
PrivilegedVersion,
Expand Down Expand Up @@ -98,7 +100,7 @@ extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
asm!("csrw medeleg, {}", in(reg) !0);
asm!("csrw mcounteren, {}", in(reg) !0);
asm!("csrw scounteren, {}", in(reg) !0);
use riscv::register::{medeleg, mtvec};
use ::riscv::register::{medeleg, mtvec};
// Keep supervisor environment calls and illegal instructions in M-mode.
medeleg::clear_supervisor_env_call();
medeleg::clear_illegal_instruction();
Expand Down Expand Up @@ -199,8 +201,8 @@ unsafe extern "C" fn relocation_update() {

#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
use riscv::register::*;
error!("Hart {} {info}", riscv::register::mhartid::read());
use ::riscv::register::*;
error!("Hart {} {info}", current_hartid());
error!("-----------------------------");
error!("mcause: {:?}", mcause::read().cause());
error!("mepc: {:#018x}", mepc::read());
Expand Down
Loading