From fd67ccf9cdfb1816db440147905e8231b73a860c Mon Sep 17 00:00:00 2001 From: yuyang <96557710+yuyang-ok@users.noreply.github.com> Date: Fri, 3 Feb 2023 08:11:24 +0800 Subject: [PATCH] Perform I-Cache Maintenance on RISC-V (#5698) * re modify this. * fix compile failure. * fix unused warning. --- crates/jit-icache-coherence/Cargo.toml | 8 +++++ crates/jit-icache-coherence/src/libc.rs | 43 ++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/crates/jit-icache-coherence/Cargo.toml b/crates/jit-icache-coherence/Cargo.toml index 3741e6e60b..5fdb5bf42f 100644 --- a/crates/jit-icache-coherence/Cargo.toml +++ b/crates/jit-icache-coherence/Cargo.toml @@ -21,3 +21,11 @@ features = [ [target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "freebsd", target_os = "android"))'.dependencies] libc = "0.2.42" + +[features] +# Most modern CPUs are SMP (multicore). However, when only one core is present, +# some aspects of coherence are much cheaper. For example, RISC-V can use +# one instruction `fence.i` rather than a syscall that invokes all other cores. +# This feature enables such optimizations, but the resulting program will *only* +# be safe to run on one-core systems. +one-core = [] \ No newline at end of file diff --git a/crates/jit-icache-coherence/src/libc.rs b/crates/jit-icache-coherence/src/libc.rs index 001e9251f6..557cd06921 100644 --- a/crates/jit-icache-coherence/src/libc.rs +++ b/crates/jit-icache-coherence/src/libc.rs @@ -91,6 +91,46 @@ mod details { Ok(()) } } +#[cfg(all(target_arch = "riscv64", target_os = "linux"))] +fn riscv_flush_icache(start: u64, end: u64) -> Result<()> { + cfg_if::cfg_if! { + if #[cfg(feature = "one-core")] { + use std::arch::asm; + unsafe { + asm!("fence.i"); + }; + Ok(()) + } else { + match unsafe { + libc::syscall( + { + // The syscall isn't defined in `libc`, so we definfe the syscall number here. + // https://github.com/torvalds/linux/search?q=__NR_arch_specific_syscall + #[allow(non_upper_case_globals)] + const __NR_arch_specific_syscall :i64 = 244; + // https://github.com/torvalds/linux/blob/5bfc75d92efd494db37f5c4c173d3639d4772966/tools/arch/riscv/include/uapi/asm/unistd.h#L40 + #[allow(non_upper_case_globals)] + const sys_riscv_flush_icache :i64 = __NR_arch_specific_syscall + 15; + sys_riscv_flush_icache + }, + // Currently these parameters are not used, but they are still defined. + start, // start + end, // end + { + #[allow(non_snake_case)] + const SYS_RISCV_FLUSH_ICACHE_LOCAL :i64 = 1; + #[allow(non_snake_case)] + const SYS_RISCV_FLUSH_ICACHE_ALL :i64 = SYS_RISCV_FLUSH_ICACHE_LOCAL; + SYS_RISCV_FLUSH_ICACHE_ALL + }, // flags + ) + } { + 0 => { Ok(()) } + _ => Err(std::io::Error::last_os_error()), + } + } + } +} pub(crate) use details::*; @@ -103,6 +143,7 @@ pub(crate) fn clear_cache(_ptr: *const c_void, _len: usize) -> Result<()> { // We should call some implementation of `clear_cache` here. // // See: https://github.com/bytecodealliance/wasmtime/issues/3310 - + #[cfg(all(target_arch = "riscv64", target_os = "linux"))] + riscv_flush_icache(_ptr as u64, (_ptr as u64) + (_len as u64))?; Ok(()) }