Path: blob/main/crates/jit-icache-coherence/src/lib.rs
1692 views
//! This crate provides utilities for instruction cache maintenance for JIT authors.1//!2//! > **⚠️ Warning ⚠️**: this crate is an internal-only crate for the Wasmtime3//! > project and is not intended for general use. APIs are not strictly4//! > reviewed for safety and usage outside of Wasmtime may have bugs. If5//! > you're interested in using this feel free to file an issue on the6//! > Wasmtime repository to start a discussion about doing so, but otherwise7//! > be aware that your usage of this crate is not supported.8//!9//! In self modifying codes such as when writing a JIT, special care must be taken when marking the10//! code as ready for execution. On fully coherent architectures (X86, S390X) the data cache (D-Cache)11//! and the instruction cache (I-Cache) are always in sync. However this is not guaranteed for all12//! architectures such as AArch64 where these caches are not coherent with each other.13//!14//! When writing new code there may be a I-cache entry for that same address which causes the15//! processor to execute whatever was in the cache instead of the new code.16//!17//! See the [ARM Community - Caches and Self-Modifying Code] blog post that contains a great18//! explanation of the above. (It references AArch32 but it has a high level overview of this problem).19//!20//! ## Usage21//!22//! You should call [clear_cache] on any pages that you write with the new code that you're intending23//! to execute. You can do this at any point in the code from the moment that you write the page up to24//! the moment where the code is executed.25//!26//! You also need to call [pipeline_flush_mt] to ensure that there isn't any invalid instruction currently27//! in the pipeline if you are running in a multi threaded environment.28//!29//! For single threaded programs you are free to omit [pipeline_flush_mt], otherwise you need to30//! call both [clear_cache] and [pipeline_flush_mt] in that order.31//!32//! ### Example:33//! ```34//! # use std::ffi::c_void;35//! # use std::io;36//! # use wasmtime_internal_jit_icache_coherence::*;37//! #38//! # struct Page {39//! # addr: *const c_void,40//! # len: usize,41//! # }42//! #43//! # fn main() -> anyhow::Result<()> {44//! #45//! # let run_code = || {};46//! # let code = vec![0u8; 64];47//! # let newly_written_pages = vec![Page {48//! # addr: &code[0] as *const u8 as *const c_void,49//! # len: code.len(),50//! # }];51//! # unsafe {52//! // Invalidate the cache for all the newly written pages where we wrote our new code.53//! for page in newly_written_pages {54//! clear_cache(page.addr, page.len)?;55//! }56//!57//! // Once those are invalidated we also need to flush the pipeline58//! pipeline_flush_mt()?;59//!60//! // We can now safely execute our new code.61//! run_code();62//! # }63//! # Ok(())64//! # }65//! ```66//!67//! <div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;">68//!69//! **Warning**: In order to correctly use this interface you should always call [clear_cache].70//! A followup call to [pipeline_flush_mt] is required if you are running in a multi-threaded environment.71//!72//! </pre></div>73//!74//! [ARM Community - Caches and Self-Modifying Code]: https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/caches-and-self-modifying-code7576use std::ffi::c_void;7778cfg_if::cfg_if! {79if #[cfg(target_os = "windows")] {80mod win;81use win as imp;82} else if #[cfg(miri)] {83mod miri;84use crate::miri as imp;85} else {86mod libc;87use crate::libc as imp;88}89}9091/// Flushes instructions in the processor pipeline92///93/// This pipeline flush is broadcast to all processors that are executing threads in the current process.94///95/// Calling [pipeline_flush_mt] is only required for multi-threaded programs and it *must* be called96/// after all calls to [clear_cache].97///98/// If the architecture does not require a pipeline flush, this function does nothing.99pub fn pipeline_flush_mt() -> imp::Result<()> {100imp::pipeline_flush_mt()101}102103/// Flushes the instruction cache for a region of memory.104///105/// If the architecture does not require an instruction cache flush, this function does nothing.106///107/// # Unsafe108///109/// It is necessary to call [pipeline_flush_mt] after this function if you are running in a multi-threaded110/// environment.111pub unsafe fn clear_cache(ptr: *const c_void, len: usize) -> imp::Result<()> {112imp::clear_cache(ptr, len)113}114115116