diff --git a/Cargo.lock b/Cargo.lock
index 1b89223c8be..c4704fb0dd5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -444,7 +444,7 @@ dependencies = [
  "directories",
  "rustc-build-sysroot",
  "rustc-workspace-hack",
- "rustc_tools_util 0.2.1",
+ "rustc_tools_util",
  "rustc_version",
  "serde",
  "serde_json",
@@ -738,7 +738,7 @@ dependencies = [
  "regex",
  "rustc-semver",
  "rustc-workspace-hack",
- "rustc_tools_util 0.3.0",
+ "rustc_tools_util",
  "semver",
  "serde",
  "syn",
@@ -4725,12 +4725,6 @@ dependencies = [
  "tracing",
 ]
 
-[[package]]
-name = "rustc_tools_util"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "598f48ce2a421542b3e64828aa742b687cc1b91d2f96591cfdb7ac5988cd6366"
-
 [[package]]
 name = "rustc_tools_util"
 version = "0.3.0"
diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md
index 5b538691de1..476075e9c91 100644
--- a/src/tools/miri/CONTRIBUTING.md
+++ b/src/tools/miri/CONTRIBUTING.md
@@ -242,6 +242,13 @@ josh-proxy --local=$HOME/.cache/josh --remote=https://github.com --no-background
 
 This uses a directory `$HOME/.cache/josh` as a cache, to speed up repeated pulling/pushing.
 
+To make josh push via ssh instead of https, you can add the following to your `.gitconfig`:
+
+```toml
+[url "git@github.com:"]
+    pushInsteadOf = https://github.com/
+```
+
 ### Importing changes from the rustc repo
 
 Josh needs to be running, as described above.
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 48581f6bbff..1086d0481c8 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -213,7 +213,9 @@ degree documented below):
 - The best-supported target is `x86_64-unknown-linux-gnu`. Miri releases are
   blocked on things working with this target. Most other Linux targets should
   also work well; we do run the test suite on `i686-unknown-linux-gnu` as a
-  32bit target and `mips64-unknown-linux-gnuabi64` as a big-endian target.
+  32bit target and `mips64-unknown-linux-gnuabi64` as a big-endian target, as
+  well as the ARM targets `aarch64-unknown-linux-gnu` and
+  `arm-unknown-linux-gnueabi`.
 - `x86_64-apple-darwin` should work basically as well as Linux. We also test
   `aarch64-apple-darwin`. However, we might ship Miri with a nightly even when
   some features on these targets regress.
@@ -590,7 +592,7 @@ extern "Rust" {
     /// `out` must point to at least `out_size` many bytes, and the result will be stored there
     /// with a null terminator.
     /// Returns 0 if the `out` buffer was large enough, and the required size otherwise.
-    fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
+    fn miri_host_to_target_path(path: *const std::ffi::c_char, out: *mut std::ffi::c_char, out_size: usize) -> usize;
 }
 ```
 
diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock
index 37926db0166..76badcf94af 100644
--- a/src/tools/miri/cargo-miri/Cargo.lock
+++ b/src/tools/miri/cargo-miri/Cargo.lock
@@ -193,9 +193,9 @@ checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb"
 
 [[package]]
 name = "rustc_tools_util"
-version = "0.2.1"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "598f48ce2a421542b3e64828aa742b687cc1b91d2f96591cfdb7ac5988cd6366"
+checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f"
 
 [[package]]
 name = "rustc_version"
diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml
index 2197160bc9d..09079dbb818 100644
--- a/src/tools/miri/cargo-miri/Cargo.toml
+++ b/src/tools/miri/cargo-miri/Cargo.toml
@@ -30,4 +30,4 @@ rustc-workspace-hack = "1.0.0"
 serde = { version = "*", features = ["derive"] }
 
 [build-dependencies]
-rustc_tools_util = "0.2"
+rustc_tools_util = "0.3"
diff --git a/src/tools/miri/cargo-miri/build.rs b/src/tools/miri/cargo-miri/build.rs
index c1110115455..52e2a083512 100644
--- a/src/tools/miri/cargo-miri/build.rs
+++ b/src/tools/miri/cargo-miri/build.rs
@@ -2,12 +2,5 @@ fn main() {
     // Don't rebuild miri when nothing changed.
     println!("cargo:rerun-if-changed=build.rs");
     // gather version info
-    println!(
-        "cargo:rustc-env=GIT_HASH={}",
-        rustc_tools_util::get_commit_hash().unwrap_or_default()
-    );
-    println!(
-        "cargo:rustc-env=COMMIT_DATE={}",
-        rustc_tools_util::get_commit_date().unwrap_or_default()
-    );
+    rustc_tools_util::setup_version_info!();
 }
diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh
index e01bfbc74d9..60450d09815 100755
--- a/src/tools/miri/ci.sh
+++ b/src/tools/miri/ci.sh
@@ -104,6 +104,7 @@ run_tests
 case $HOST_TARGET in
   x86_64-unknown-linux-gnu)
     MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
+    MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
     MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
     MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests
     MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var
@@ -118,6 +119,7 @@ case $HOST_TARGET in
     MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests
     ;;
   i686-pc-windows-msvc)
+    MIRI_TEST_TARGET=arm-unknown-linux-gnueabi run_tests
     MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests
     MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests
     ;;
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index cf6d9c28080..53ec1ba0821 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-c54c8cbac882e149e04a9e1f2d146fd548ae30ae
+c4e0cd966062ca67daed20775f4e8a60c28e57df
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index cf1ff603281..b766916402e 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -148,8 +148,7 @@ impl NewPermission {
             NewPermission::Uniform {
                 perm: Permission::Unique,
                 access: Some(AccessKind::Write),
-                protector: (kind == RetagKind::FnEntry)
-                    .then_some(ProtectorKind::WeakProtector),
+                protector: (kind == RetagKind::FnEntry).then_some(ProtectorKind::WeakProtector),
             }
         } else {
             // `!Unpin` boxes do not get `noalias` nor `dereferenceable`.
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 7024927b205..f64f216520f 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -13,6 +13,7 @@
 #![allow(
     clippy::collapsible_else_if,
     clippy::collapsible_if,
+    clippy::if_same_then_else,
     clippy::comparison_chain,
     clippy::enum_variant_names,
     clippy::field_reassign_with_default,
@@ -21,7 +22,7 @@
     clippy::single_match,
     clippy::useless_format,
     clippy::derive_partial_eq_without_eq,
-    clippy::derive_hash_xor_eq,
+    clippy::derived_hash_with_manual_eq,
     clippy::too_many_arguments,
     clippy::type_complexity,
     clippy::single_element_loop,
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 8bd1e802f8a..8bbf9f87b43 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -477,7 +477,8 @@ pub struct MiriMachine<'mir, 'tcx> {
 
 impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
     pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self {
-        let local_crates = helpers::get_local_crates(layout_cx.tcx);
+        let tcx = layout_cx.tcx;
+        let local_crates = helpers::get_local_crates(tcx);
         let layouts =
             PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types");
         let profiler = config.measureme_out.as_ref().map(|out| {
@@ -486,10 +487,13 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
         let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0));
         let borrow_tracker = config.borrow_tracker.map(|bt| bt.instanciate_global_state(config));
         let data_race = config.data_race_detector.then(|| data_race::GlobalState::new(config));
+        // Determinine page size, stack address, and stack size.
+        // These values are mostly meaningless, but the stack address is also where we start
+        // allocating physical integer addresses for all allocations.
         let page_size = if let Some(page_size) = config.page_size {
             page_size
         } else {
-            let target = &layout_cx.tcx.sess.target;
+            let target = &tcx.sess.target;
             match target.arch.as_ref() {
                 "wasm32" | "wasm64" => 64 * 1024, // https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances
                 "aarch64" =>
@@ -504,10 +508,12 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
                 _ => 4 * 1024,
             }
         };
-        let stack_addr = page_size * 32;
-        let stack_size = page_size * 16;
+        // On 16bit targets, 32 pages is more than the entire address space!
+        let stack_addr = if tcx.pointer_size().bits() < 32 { page_size } else { page_size * 32 };
+        let stack_size =
+            if tcx.pointer_size().bits() < 32 { page_size * 4 } else { page_size * 16 };
         MiriMachine {
-            tcx: layout_cx.tcx,
+            tcx,
             borrow_tracker,
             data_race,
             intptrcast: RefCell::new(intptrcast::GlobalStateInner::new(config, stack_addr)),
@@ -902,8 +908,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
             };
             let (shim_size, shim_align, _kind) = ecx.get_alloc_info(alloc_id);
             let def_ty = ecx.tcx.type_of(def_id).subst_identity();
-            let extern_decl_layout =
-                ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap();
+            let extern_decl_layout = ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap();
             if extern_decl_layout.size != shim_size || extern_decl_layout.align.abi != shim_align {
                 throw_unsup_format!(
                     "`extern` static `{name}` from crate `{krate}` has been declared \
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 2d9eb37a258..03275ed4ed1 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -885,6 +885,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     }
                 }
             }
+            "llvm.arm.hint" if this.tcx.sess.target.arch == "arm" => {
+                let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?;
+                let arg = this.read_scalar(arg)?.to_i32()?;
+                match arg {
+                    // YIELD
+                    1 => {
+                        this.yield_active_thread();
+                    }
+                    _ => {
+                        throw_unsup_format!("unsupported llvm.arm.hint argument {}", arg);
+                    }
+                }
+            }
 
             // Platform-specific shims
             _ =>
diff --git a/src/tools/miri/src/shims/unix/linux/fd.rs b/src/tools/miri/src/shims/unix/linux/fd.rs
index 212b7936341..fd4927fa10c 100644
--- a/src/tools/miri/src/shims/unix/linux/fd.rs
+++ b/src/tools/miri/src/shims/unix/linux/fd.rs
@@ -7,6 +7,8 @@ use socketpair::SocketPair;
 
 use shims::unix::fs::EvalContextExt as _;
 
+use std::cell::Cell;
+
 pub mod epoll;
 pub mod event;
 pub mod socketpair;
@@ -101,6 +103,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         }
     }
 
+    /// The `epoll_wait()` system call waits for events on the `Epoll`
+    /// instance referred to by the file descriptor `epfd`. The buffer
+    /// pointed to by `events` is used to return information from the ready
+    /// list about file descriptors in the interest list that have some
+    /// events available. Up to `maxevents` are returned by `epoll_wait()`.
+    /// The `maxevents` argument must be greater than zero.
+
+    /// The `timeout` argument specifies the number of milliseconds that
+    /// `epoll_wait()` will block. Time is measured against the
+    /// CLOCK_MONOTONIC clock.
+
+    /// A call to `epoll_wait()` will block until either:
+    /// • a file descriptor delivers an event;
+    /// • the call is interrupted by a signal handler; or
+    /// • the timeout expires.
+
+    /// Note that the timeout interval will be rounded up to the system
+    /// clock granularity, and kernel scheduling delays mean that the
+    /// blocking interval may overrun by a small amount. Specifying a
+    /// timeout of -1 causes `epoll_wait()` to block indefinitely, while
+    /// specifying a timeout equal to zero cause `epoll_wait()` to return
+    /// immediately, even if no events are available.
+    ///
+    /// On success, `epoll_wait()` returns the number of file descriptors
+    /// ready for the requested I/O, or zero if no file descriptor became
+    /// ready during the requested timeout milliseconds. On failure,
+    /// `epoll_wait()` returns -1 and errno is set to indicate the error.
+    ///
+    /// <https://man7.org/linux/man-pages/man2/epoll_wait.2.html>
+    fn epoll_wait(
+        &mut self,
+        epfd: &OpTy<'tcx, Provenance>,
+        events: &OpTy<'tcx, Provenance>,
+        maxevents: &OpTy<'tcx, Provenance>,
+        timeout: &OpTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx, Scalar<Provenance>> {
+        let this = self.eval_context_mut();
+
+        let epfd = this.read_scalar(epfd)?.to_i32()?;
+        let _events = this.read_scalar(events)?.to_pointer(this)?;
+        let _maxevents = this.read_scalar(maxevents)?.to_i32()?;
+        let _timeout = this.read_scalar(timeout)?.to_i32()?;
+
+        let numevents = 0;
+        if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) {
+            let _epfd = epfd.as_epoll_handle()?;
+
+            // FIXME return number of events ready when scheme for marking events ready exists
+            Ok(Scalar::from_i32(numevents))
+        } else {
+            Ok(Scalar::from_i32(this.handle_not_found()?))
+        }
+    }
+
     /// This function creates an `Event` that is used as an event wait/notify mechanism by
     /// user-space applications, and by the kernel to notify user-space applications of events.
     /// The `Event` contains an `u64` counter maintained by the kernel. The counter is initialized
@@ -142,7 +198,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         }
 
         let fh = &mut this.machine.file_handler;
-        let fd = fh.insert_fd(Box::new(Event { val }));
+        let fd = fh.insert_fd(Box::new(Event { val: Cell::new(val.into()) }));
         Ok(Scalar::from_i32(fd))
     }
 
diff --git a/src/tools/miri/src/shims/unix/linux/fd/event.rs b/src/tools/miri/src/shims/unix/linux/fd/event.rs
index 239eb462a1d..b28a6e0c56e 100644
--- a/src/tools/miri/src/shims/unix/linux/fd/event.rs
+++ b/src/tools/miri/src/shims/unix/linux/fd/event.rs
@@ -2,6 +2,7 @@ use crate::shims::unix::fs::FileDescriptor;
 
 use rustc_const_eval::interpret::InterpResult;
 
+use std::cell::Cell;
 use std::io;
 
 /// A kind of file descriptor created by `eventfd`.
@@ -13,7 +14,9 @@ use std::io;
 /// <https://man.netbsd.org/eventfd.2>
 #[derive(Debug)]
 pub struct Event {
-    pub val: u32,
+    /// The object contains an unsigned 64-bit integer (uint64_t) counter that is maintained by the
+    /// kernel. This counter is initialized with the value specified in the argument initval.
+    pub val: Cell<u64>,
 }
 
 impl FileDescriptor for Event {
@@ -22,7 +25,7 @@ impl FileDescriptor for Event {
     }
 
     fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
-        Ok(Box::new(Event { val: self.val }))
+        Ok(Box::new(Event { val: self.val.clone() }))
     }
 
     fn is_tty(&self) -> bool {
@@ -35,4 +38,32 @@ impl FileDescriptor for Event {
     ) -> InterpResult<'tcx, io::Result<i32>> {
         Ok(Ok(0))
     }
+
+    /// A write call adds the 8-byte integer value supplied in
+    /// its buffer to the counter.  The maximum value that may be
+    /// stored in the counter is the largest unsigned 64-bit value
+    /// minus 1 (i.e., 0xfffffffffffffffe).  If the addition would
+    /// cause the counter's value to exceed the maximum, then the
+    /// write either blocks until a read is performed on the
+    /// file descriptor, or fails with the error EAGAIN if the
+    /// file descriptor has been made nonblocking.
+
+    /// A write fails with the error EINVAL if the size of the
+    /// supplied buffer is less than 8 bytes, or if an attempt is
+    /// made to write the value 0xffffffffffffffff.
+    ///
+    /// FIXME: use endianness
+    fn write<'tcx>(
+        &self,
+        _communicate_allowed: bool,
+        bytes: &[u8],
+    ) -> InterpResult<'tcx, io::Result<usize>> {
+        let v1 = self.val.get();
+        // FIXME handle blocking when addition results in exceeding the max u64 value
+        // or fail with EAGAIN if the file descriptor is nonblocking.
+        let v2 = v1.checked_add(u64::from_be_bytes(bytes.try_into().unwrap())).unwrap();
+        self.val.set(v2);
+        assert_eq!(8, bytes.len());
+        Ok(Ok(8))
+    }
 }
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index 9f6938424fb..f4e7824d91d 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -55,6 +55,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let result = this.epoll_ctl(epfd, op, fd, event)?;
                 this.write_scalar(result, dest)?;
             }
+            "epoll_wait" => {
+                let [epfd, events, maxevents, timeout] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let result = this.epoll_wait(epfd, events, maxevents, timeout)?;
+                this.write_scalar(result, dest)?;
+            }
             "eventfd" => {
                 let [val, flag] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
diff --git a/src/tools/miri/test-cargo-miri/src/main.rs b/src/tools/miri/test-cargo-miri/src/main.rs
index 048dbbbaa0f..048577ef15a 100644
--- a/src/tools/miri/test-cargo-miri/src/main.rs
+++ b/src/tools/miri/test-cargo-miri/src/main.rs
@@ -23,7 +23,7 @@ fn main() {
     // (We rely on the test runner to always disable isolation when passing no arguments.)
     if std::env::args().len() <= 1 {
         fn host_to_target_path(path: String) -> PathBuf {
-            use std::ffi::{CStr, CString};
+            use std::ffi::{c_char, CStr, CString};
 
             let path = CString::new(path).unwrap();
             let mut out = Vec::with_capacity(1024);
@@ -31,8 +31,8 @@ fn main() {
             unsafe {
                 extern "Rust" {
                     fn miri_host_to_target_path(
-                        path: *const i8,
-                        out: *mut i8,
+                        path: *const c_char,
+                        out: *mut c_char,
                         out_size: usize,
                     ) -> usize;
                 }
diff --git a/src/tools/miri/test-cargo-miri/subcrate/main.rs b/src/tools/miri/test-cargo-miri/subcrate/main.rs
index 1cb8091f877..52161098788 100644
--- a/src/tools/miri/test-cargo-miri/subcrate/main.rs
+++ b/src/tools/miri/test-cargo-miri/subcrate/main.rs
@@ -5,7 +5,7 @@ fn main() {
     println!("subcrate running");
 
     fn host_to_target_path(path: String) -> PathBuf {
-        use std::ffi::{CStr, CString};
+        use std::ffi::{c_char, CStr, CString};
 
         let path = CString::new(path).unwrap();
         let mut out = Vec::with_capacity(1024);
@@ -13,8 +13,8 @@ fn main() {
         unsafe {
             extern "Rust" {
                 fn miri_host_to_target_path(
-                    path: *const i8,
-                    out: *mut i8,
+                    path: *const c_char,
+                    out: *mut c_char,
                     out_size: usize,
                 ) -> usize;
             }
diff --git a/src/tools/miri/test-cargo-miri/subcrate/test.rs b/src/tools/miri/test-cargo-miri/subcrate/test.rs
index 619d8c72fd0..1681c721dc2 100644
--- a/src/tools/miri/test-cargo-miri/subcrate/test.rs
+++ b/src/tools/miri/test-cargo-miri/subcrate/test.rs
@@ -8,7 +8,7 @@ fn main() {
     println!("subcrate testing");
 
     fn host_to_target_path(path: String) -> PathBuf {
-        use std::ffi::{CStr, CString};
+        use std::ffi::{c_char, CStr, CString};
 
         let path = CString::new(path).unwrap();
         let mut out = Vec::with_capacity(1024);
@@ -16,8 +16,8 @@ fn main() {
         unsafe {
             extern "Rust" {
                 fn miri_host_to_target_path(
-                    path: *const i8,
-                    out: *mut i8,
+                    path: *const c_char,
+                    out: *mut c_char,
                     out_size: usize,
                 ) -> usize;
             }
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index a84ed859763..8be1ee54672 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -292,9 +292,9 @@ dependencies = [
 
 [[package]]
 name = "tokio"
-version = "1.23.1"
+version = "1.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38a54aca0c15d014013256222ba0ebed095673f89345dd79119d912eb561b7a8"
+checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb"
 dependencies = [
  "autocfg",
  "bytes",
diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml
index f5ab6acf008..d1ff33379e4 100644
--- a/src/tools/miri/test_dependencies/Cargo.toml
+++ b/src/tools/miri/test_dependencies/Cargo.toml
@@ -18,6 +18,6 @@ rand = { version = "0.8", features = ["small_rng"] }
 
 [target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
 page_size = "0.5"
-tokio = { version = "1.23", features = ["full"] }
+tokio = { version = "1.24", features = ["full"] }
 
 [workspace]
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs
index 816b6ab9fb3..4a43db0aac5 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs
@@ -3,7 +3,7 @@
 
 #![allow(dead_code, unused_variables)]
 
-use std::{ptr, mem};
+use std::{mem, ptr};
 
 #[repr(packed)]
 struct Foo {
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs.rs b/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
index ba5b269f652..cd071a7f32a 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
@@ -5,7 +5,7 @@
 #![feature(io_error_uncategorized)]
 
 use std::convert::TryInto;
-use std::ffi::{CStr, CString};
+use std::ffi::{c_char, CStr, CString};
 use std::fs::{canonicalize, remove_dir_all, remove_file, File};
 use std::io::{Error, ErrorKind, Write};
 use std::os::unix::ffi::OsStrExt;
@@ -31,7 +31,11 @@ fn tmp() -> PathBuf {
 
     unsafe {
         extern "Rust" {
-            fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
+            fn miri_host_to_target_path(
+                path: *const c_char,
+                out: *mut c_char,
+                out_size: usize,
+            ) -> usize;
         }
         let ret = miri_host_to_target_path(path.as_ptr(), out.as_mut_ptr(), out.capacity());
         assert_eq!(ret, 0);
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
index 20e96a92c7c..98e1c3a0adb 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
+++ b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
@@ -7,7 +7,7 @@ use std::os::unix::io::AsRawFd;
 use std::path::PathBuf;
 
 fn tmp() -> PathBuf {
-    use std::ffi::{CStr, CString};
+    use std::ffi::{c_char, CStr, CString};
 
     let path = std::env::var("MIRI_TEMP")
         .unwrap_or_else(|_| std::env::temp_dir().into_os_string().into_string().unwrap());
@@ -17,7 +17,11 @@ fn tmp() -> PathBuf {
 
     unsafe {
         extern "Rust" {
-            fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
+            fn miri_host_to_target_path(
+                path: *const c_char,
+                out: *mut c_char,
+                out_size: usize,
+            ) -> usize;
         }
         let ret = miri_host_to_target_path(path.as_ptr(), out.as_mut_ptr(), out.capacity());
         assert_eq!(ret, 0);
diff --git a/src/tools/miri/tests/pass-dep/tokio/sleep.rs b/src/tools/miri/tests/pass-dep/tokio/sleep.rs
new file mode 100644
index 00000000000..1341484dda4
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/tokio/sleep.rs
@@ -0,0 +1,14 @@
+//@compile-flags: -Zmiri-disable-isolation -Zmiri-permissive-provenance -Zmiri-backtrace=full
+//@only-target-x86_64-unknown-linux: support for tokio only on linux and x86
+
+use tokio::time::{sleep, Duration, Instant};
+
+#[tokio::main]
+async fn main() {
+    let start = Instant::now();
+    sleep(Duration::from_secs(1)).await;
+    // It takes 96 millisecond to sleep for 1 millisecond
+    // It takes 1025 millisecond to sleep for 1 second
+    let time_elapsed = &start.elapsed().as_millis();
+    assert!(time_elapsed > &1000, "{}", time_elapsed);
+}
diff --git a/src/tools/miri/tests/pass-dep/tokio_mvp.rs b/src/tools/miri/tests/pass-dep/tokio/tokio_mvp.rs
similarity index 88%
rename from src/tools/miri/tests/pass-dep/tokio_mvp.rs
rename to src/tools/miri/tests/pass-dep/tokio/tokio_mvp.rs
index 642168253c2..0bca7cc069a 100644
--- a/src/tools/miri/tests/pass-dep/tokio_mvp.rs
+++ b/src/tools/miri/tests/pass-dep/tokio/tokio_mvp.rs
@@ -1,5 +1,5 @@
 // Need to disable preemption to stay on the supported MVP codepath in mio.
-//@compile-flags: -Zmiri-disable-isolation -Zmiri-permissive-provenance -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-disable-isolation -Zmiri-permissive-provenance
 //@only-target-x86_64-unknown-linux: support for tokio exists only on linux and x86
 
 #[tokio::main]
diff --git a/src/tools/miri/tests/pass/dyn-star.rs b/src/tools/miri/tests/pass/dyn-star.rs
index 16a8cec6cda..1fac16352a4 100644
--- a/src/tools/miri/tests/pass/dyn-star.rs
+++ b/src/tools/miri/tests/pass/dyn-star.rs
@@ -1,5 +1,8 @@
 #![feature(dyn_star)]
 #![allow(incomplete_features)]
+#![feature(custom_inner_attributes)]
+// rustfmt destroys `dyn* Trait` syntax
+#![rustfmt::skip]
 
 use std::fmt::{Debug, Display};
 
diff --git a/src/tools/miri/tests/pass/move-data-across-await-point.rs b/src/tools/miri/tests/pass/move-data-across-await-point.rs
new file mode 100644
index 00000000000..489fae66ffb
--- /dev/null
+++ b/src/tools/miri/tests/pass/move-data-across-await-point.rs
@@ -0,0 +1,81 @@
+use std::future::Future;
+use std::ptr;
+
+// This test:
+// - Compares addresses of non-Copy data before and after moving it
+// - Writes to the pointer after it has moved across the await point
+//
+// This is only meant to assert current behavior, not guarantee that this is
+// how it should work in the future. In fact, upcoming changes to rustc
+// *should* break these tests.
+// See: https://github.com/rust-lang/rust/issues/62958
+async fn data_moved_async() {
+    async fn helper(mut data: Vec<u8>, raw_pointer: *mut Vec<u8>) {
+        let raw_pointer2 = ptr::addr_of_mut!(data);
+        // `raw_pointer` points to the original location where the Vec was stored in the caller.
+        // `data` is where that Vec (to be precise, its ptr+capacity+len on-stack data)
+        // got moved to. Those will usually not be the same since the Vec got moved twice
+        // (into the function call, and then into the generator upvar).
+        assert_ne!(raw_pointer, raw_pointer2);
+        unsafe {
+            // This writes into the `x` in `data_moved_async`, re-initializing it.
+            std::ptr::write(raw_pointer, vec![3]);
+        }
+    }
+    // Vec<T> is not Copy
+    let mut x: Vec<u8> = vec![2];
+    let raw_pointer = ptr::addr_of_mut!(x);
+    helper(x, raw_pointer).await;
+    unsafe {
+        assert_eq!(*raw_pointer, vec![3]);
+        // Drop to prevent leak.
+        std::ptr::drop_in_place(raw_pointer);
+    }
+}
+
+// Same thing as above, but non-async.
+fn data_moved() {
+    fn helper(mut data: Vec<u8>, raw_pointer: *mut Vec<u8>) {
+        let raw_pointer2 = ptr::addr_of_mut!(data);
+        assert_ne!(raw_pointer, raw_pointer2);
+        unsafe {
+            std::ptr::write(raw_pointer, vec![3]);
+        }
+    }
+
+    let mut x: Vec<u8> = vec![2];
+    let raw_pointer = ptr::addr_of_mut!(x);
+    helper(x, raw_pointer);
+    unsafe {
+        assert_eq!(*raw_pointer, vec![3]);
+        std::ptr::drop_in_place(raw_pointer);
+    }
+}
+
+fn run_fut<T>(fut: impl Future<Output = T>) -> T {
+    use std::sync::Arc;
+    use std::task::{Context, Poll, Wake, Waker};
+
+    struct MyWaker;
+    impl Wake for MyWaker {
+        fn wake(self: Arc<Self>) {
+            unimplemented!()
+        }
+    }
+
+    let waker = Waker::from(Arc::new(MyWaker));
+    let mut context = Context::from_waker(&waker);
+
+    let mut pinned = Box::pin(fut);
+    loop {
+        match pinned.as_mut().poll(&mut context) {
+            Poll::Pending => continue,
+            Poll::Ready(v) => return v,
+        }
+    }
+}
+
+fn main() {
+    run_fut(data_moved_async());
+    data_moved();
+}
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index a7d4800faec..7a9974f3938 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -6,7 +6,7 @@
 #![feature(is_terminal)]
 
 use std::collections::HashMap;
-use std::ffi::OsString;
+use std::ffi::{c_char, OsString};
 use std::fs::{
     canonicalize, create_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, rename,
     File, OpenOptions,
@@ -39,7 +39,11 @@ fn host_to_target_path(path: String) -> PathBuf {
 
     unsafe {
         extern "Rust" {
-            fn miri_host_to_target_path(path: *const i8, out: *mut i8, out_size: usize) -> usize;
+            fn miri_host_to_target_path(
+                path: *const c_char,
+                out: *mut c_char,
+                out_size: usize,
+            ) -> usize;
         }
         let ret = miri_host_to_target_path(path.as_ptr(), out.as_mut_ptr(), out.capacity());
         assert_eq!(ret, 0);