Browse Source

Merge pull request #54 from guttatus/jump

feat(prototyper): refactor code and add jump firmware
guttatus 2 tháng trước cách đây
mục cha
commit
9a8667df69

+ 13 - 6
Cargo.lock

@@ -212,9 +212,9 @@ dependencies = [
 
 [[package]]
 name = "panic-halt"
-version = "0.2.0"
+version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
+checksum = "a513e167849a384b7f9b746e517604398518590a9142f4846a32e3c2a4de7b11"
 
 [[package]]
 name = "paste"
@@ -308,7 +308,7 @@ dependencies = [
  "log",
  "rcore-console",
  "riscv 0.11.1",
- "sbi-spec 0.0.8",
+ "sbi-spec 0.0.8 (git+https://github.com/rustsbi/rustsbi?rev=4821073)",
  "sbi-testing 0.0.3-alpha.2 (git+https://github.com/rustsbi/rustsbi?rev=4821073)",
  "serde",
  "serde-device-tree",
@@ -332,13 +332,14 @@ name = "rustsbi-prototyper"
 version = "0.0.0"
 dependencies = [
  "aclint",
+ "cfg-if",
  "fast-trap",
  "log",
  "panic-halt",
  "riscv 0.11.1",
  "riscv-decode",
  "rustsbi",
- "sbi-spec 0.0.7",
+ "sbi-spec 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde",
  "serde-device-tree",
  "sifive-test-device",
@@ -383,7 +384,7 @@ name = "sbi-rt"
 version = "0.0.3"
 source = "git+https://github.com/rustsbi/rustsbi?rev=4821073#4821073b56a7223781c11a49aba743785d89d3ea"
 dependencies = [
- "sbi-spec 0.0.8",
+ "sbi-spec 0.0.8 (git+https://github.com/rustsbi/rustsbi?rev=4821073)",
 ]
 
 [[package]]
@@ -392,6 +393,12 @@ version = "0.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e6e36312fb5ddc10d08ecdc65187402baba4ac34585cb9d1b78522ae2358d890"
 
+[[package]]
+name = "sbi-spec"
+version = "0.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8309630ab2b300d4fe52b6757e53a7cbb6672f55aa08b50e28b1952c06dd994d"
+
 [[package]]
 name = "sbi-spec"
 version = "0.0.8"
@@ -420,7 +427,7 @@ dependencies = [
  "log",
  "riscv 0.12.1",
  "sbi-rt 0.0.3 (git+https://github.com/rustsbi/rustsbi?rev=4821073)",
- "sbi-spec 0.0.8",
+ "sbi-spec 0.0.8 (git+https://github.com/rustsbi/rustsbi?rev=4821073)",
 ]
 
 [[package]]

+ 4 - 2
prototyper/Cargo.toml

@@ -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"
@@ -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"
@@ -33,4 +34,5 @@ bench = false
 [features]
 nemu = []
 payload = []
+jump = []
 fdt = []

+ 13 - 0
prototyper/src/cfg.rs

@@ -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;

+ 0 - 0
prototyper/src/dt.rs → prototyper/src/devicetree.rs


+ 71 - 70
prototyper/src/fail.rs

@@ -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()
     }
@@ -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,
+            }
+        }
     }
 }

+ 1 - 1
prototyper/src/firmware/dynamic.rs

@@ -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;
 

+ 20 - 0
prototyper/src/firmware/jump.rs

@@ -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,
+    }
+}

+ 12 - 8
prototyper/src/firmware/mod.rs

@@ -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;
@@ -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.
 ///

+ 8 - 6
prototyper/src/main.rs

@@ -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,
@@ -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();
@@ -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());

+ 11 - 11
prototyper/src/platform/mod.rs

@@ -1,3 +1,5 @@
+use crate::cfg::NUM_HART_MAX;
+use crate::devicetree::*;
 use crate::fail;
 use crate::platform::clint::{MachineClint, MachineClintType, CLINT_COMPATIBLE};
 use crate::platform::console::{
@@ -11,10 +13,9 @@ use crate::sbi::hsm::SbiHsm;
 use crate::sbi::ipi::SbiIpi;
 use crate::sbi::logger;
 use crate::sbi::reset::SbiReset;
+use crate::sbi::rfence::SbiRFence;
 use crate::sbi::trap_stack;
-use crate::sbi::trap_stack::NUM_HART_MAX;
 use crate::sbi::SBI;
-use crate::{dt, sbi::rfence::SbiRFence};
 use core::{
     fmt::{Display, Formatter, Result},
     ops::Range,
@@ -40,7 +41,7 @@ impl<const N: usize> Display for StringInline<N> {
     }
 }
 
-type CpuEnableList = [bool; trap_stack::NUM_HART_MAX];
+type CpuEnableList = [bool; NUM_HART_MAX];
 
 pub struct BoardInfo {
     pub memory_range: Option<Range<usize>>,
@@ -90,17 +91,17 @@ impl Platform {
     }
 
     fn info_init(&mut self, fdt_address: usize) {
-        let dtb = dt::parse_device_tree(fdt_address).unwrap_or_else(fail::device_tree_format);
+        let dtb = parse_device_tree(fdt_address).unwrap_or_else(fail::device_tree_format);
         let dtb = dtb.share();
 
         let root: serde_device_tree::buildin::Node = serde_device_tree::from_raw_mut(&dtb)
             .unwrap_or_else(fail::device_tree_deserialize_root);
-        let tree: dt::Tree = root.deserialize();
+        let tree: Tree = root.deserialize();
 
         //  Get console device info
         for console_path in tree.chosen.stdout_path.iter() {
             if let Some(node) = root.find(console_path) {
-                let info = dt::get_compatible_and_range(&node);
+                let info = get_compatible_and_range(&node);
                 let result = info.is_some_and(|info| {
                     let (compatible, regs) = info;
                     for device_id in compatible.iter() {
@@ -128,7 +129,7 @@ impl Platform {
 
         // Get ipi and reset device info
         let mut find_device = |node: &serde_device_tree::buildin::Node| {
-            let info = dt::get_compatible_and_range(node);
+            let info = get_compatible_and_range(node);
             if let Some(info) = info {
                 let (compatible, regs) = info;
                 let base_address = regs.start;
@@ -157,7 +158,7 @@ impl Platform {
             .iter()
             .next()
             .unwrap()
-            .deserialize::<dt::Memory>()
+            .deserialize::<Memory>()
             .reg;
         let memory_range = memory_reg.iter().next().unwrap().0;
         self.info.memory_range = Some(memory_range);
@@ -180,9 +181,8 @@ impl Platform {
         extensions::init(&tree.cpus.cpu);
 
         // Find which hart is enabled by fdt
-        let mut cpu_list: CpuEnableList = [false; trap_stack::NUM_HART_MAX];
+        let mut cpu_list: CpuEnableList = [false; NUM_HART_MAX];
         for cpu_iter in tree.cpus.cpu.iter() {
-            use dt::Cpu;
             let cpu = cpu_iter.deserialize::<Cpu>();
             let hart_id = cpu.reg.iter().next().unwrap().0.start;
             if let Some(x) = cpu_list.get_mut(hart_id) {
@@ -281,7 +281,7 @@ impl Platform {
         );
 
         if let Some(cpu_enabled) = &self.info.cpu_enabled {
-            let mut enabled_harts = [0; trap_stack::NUM_HART_MAX];
+            let mut enabled_harts = [0; NUM_HART_MAX];
             let mut count = 0;
             for (i, &enabled) in cpu_enabled.iter().enumerate() {
                 if enabled {

+ 0 - 6
prototyper/src/riscv_spec.rs → prototyper/src/riscv/csr.rs

@@ -61,9 +61,3 @@ pub mod stimecmp {
         }
     }
 }
-
-/// Returns the current hart (hardware thread) ID.
-#[inline]
-pub fn current_hartid() -> usize {
-    riscv::register::mhartid::read()
-}

+ 7 - 0
prototyper/src/riscv/mod.rs

@@ -0,0 +1,7 @@
+pub mod csr;
+
+/// Returns the current hart (hardware thread) ID.
+#[inline]
+pub fn current_hartid() -> usize {
+    riscv::register::mhartid::read()
+}

+ 2 - 2
prototyper/src/sbi/extensions.rs

@@ -1,6 +1,6 @@
 use serde_device_tree::buildin::NodeSeq;
 
-use crate::riscv_spec::current_hartid;
+use crate::riscv::current_hartid;
 use crate::sbi::trap_stack::ROOT_STACK;
 
 pub struct HartFeatures {
@@ -57,7 +57,7 @@ pub fn hart_privileged_version(hart_id: usize) -> PrivilegedVersion {
 
 #[cfg(not(feature = "nemu"))]
 pub fn init(cpus: &NodeSeq) {
-    use crate::dt::Cpu;
+    use crate::devicetree::Cpu;
     for cpu_iter in cpus.iter() {
         let cpu = cpu_iter.deserialize::<Cpu>();
         let hart_id = cpu.reg.iter().next().unwrap().0.start;

+ 1 - 1
prototyper/src/sbi/hsm.rs

@@ -7,7 +7,7 @@ use riscv::register::mstatus::MPP;
 use rustsbi::{spec::hsm::hart_state, SbiRet};
 
 use crate::platform::PLATFORM;
-use crate::riscv_spec::current_hartid;
+use crate::riscv::current_hartid;
 use crate::sbi::hart_context::NextStage;
 use crate::sbi::trap_stack::ROOT_STACK;
 

+ 2 - 1
prototyper/src/sbi/ipi.rs

@@ -1,5 +1,6 @@
 use crate::platform::PLATFORM;
-use crate::riscv_spec::{current_hartid, stimecmp};
+use crate::riscv::csr::stimecmp;
+use crate::riscv::current_hartid;
 use crate::sbi::extensions::{hart_extension_probe, Extension};
 use crate::sbi::hsm::remote_hsm;
 use crate::sbi::rfence;

+ 1 - 1
prototyper/src/sbi/rfence.rs

@@ -2,7 +2,7 @@ use rustsbi::{HartMask, SbiRet};
 use spin::Mutex;
 
 use crate::platform::PLATFORM;
-use crate::riscv_spec::current_hartid;
+use crate::riscv::current_hartid;
 use crate::sbi::fifo::{Fifo, FifoError};
 use crate::sbi::trap;
 use crate::sbi::trap_stack::ROOT_STACK;

+ 3 - 6
prototyper/src/sbi/trap.rs

@@ -6,18 +6,15 @@ use riscv::register::{
 };
 use rustsbi::RustSBI;
 
+use crate::cfg::{PAGE_SIZE, TLB_FLUSH_LIMIT};
 use crate::platform::PLATFORM;
-use crate::riscv_spec::{current_hartid, CSR_TIME, CSR_TIMEH};
+use crate::riscv::csr::{CSR_TIME, CSR_TIMEH};
+use crate::riscv::current_hartid;
 use crate::sbi::console;
 use crate::sbi::hsm::local_hsm;
 use crate::sbi::ipi;
 use crate::sbi::rfence::{self, local_rfence, RFenceType};
 
-// Constants for page and TLB management
-const PAGE_SIZE: usize = 4096;
-// TODO: `TLB_FLUSH_LIMIT` is a platform-dependent parameter
-const TLB_FLUSH_LIMIT: usize = 4 * PAGE_SIZE;
-
 /// Trap vector table entry point. Maps different trap types to their handlers.
 #[naked]
 pub(crate) unsafe extern "C" fn trap_vec() {

+ 2 - 6
prototyper/src/sbi/trap_stack.rs

@@ -1,13 +1,9 @@
-use crate::riscv_spec::current_hartid;
+use crate::riscv::current_hartid;
 use crate::sbi::hart_context::HartContext;
 use crate::sbi::trap::fast_handler;
 use core::mem::forget;
 use fast_trap::FreeTrapStack;
-
-/// Stack size per hart (hardware thread) in bytes.
-const LEN_STACK_PER_HART: usize = 16 * 1024;
-/// Maximum number of supported harts.
-pub const NUM_HART_MAX: usize = 8;
+use crate::cfg::{NUM_HART_MAX, LEN_STACK_PER_HART};
 
 /// Root stack array for all harts, placed in uninitialized BSS section.
 #[link_section = ".bss.uninit"]

+ 20 - 0
xtask/src/prototyper.rs

@@ -19,6 +19,9 @@ pub struct PrototyperArg {
     #[clap(long, env = "PROTOTYPER_PAYLOAD_PATH")]
     pub payload: Option<String>,
 
+    #[clap(long)]
+    pub jump: bool,
+
     #[clap(long, default_value = "INFO")]
     pub log_level: String,
 }
@@ -29,6 +32,7 @@ pub fn run(arg: &PrototyperArg) -> Option<ExitStatus> {
     let arch = "riscv64imac-unknown-none-elf";
     let fdt = arg.fdt.clone();
     let payload = arg.payload.clone();
+    let jump = arg.jump;
     let current_dir = env::current_dir();
     let target_dir = current_dir
         .as_ref()
@@ -52,6 +56,9 @@ pub fn run(arg: &PrototyperArg) -> Option<ExitStatus> {
             cargo.env("PROTOTYPER_PAYLOAD_PATH", payload.as_ref().unwrap());
             cargo.features(["payload".to_string()])
         })
+        .optional(jump, |cargo| {
+            cargo.features(["jump".to_string()])
+        })
         .env("RUST_LOG", &arg.log_level)
         .release()
         .status()
@@ -82,6 +89,18 @@ pub fn run(arg: &PrototyperArg) -> Option<ExitStatus> {
             target_dir.join("rustsbi-prototyper-payload.bin"),
         )
         .ok()?;
+    } else if arg.jump {
+        info!("Copy for jump mode");
+        fs::copy(
+            target_dir.join("rustsbi-prototyper"),
+            target_dir.join("rustsbi-prototyper-jump.elf"),
+        )
+        .ok()?;
+        fs::copy(
+            target_dir.join("rustsbi-prototyper.bin"),
+            target_dir.join("rustsbi-prototyper-jump.bin"),
+        )
+        .ok()?;
     } else {
         info!("Copy for dynamic mode");
         fs::copy(
@@ -94,6 +113,7 @@ pub fn run(arg: &PrototyperArg) -> Option<ExitStatus> {
             target_dir.join("rustsbi-prototyper-dynamic.bin"),
         )
         .ok()?;
+
     }
 
     Some(exit_status)