about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--modules/nixos-apple-silicon/README.md2
-rw-r--r--modules/nixos-apple-silicon/apple-silicon-support/modules/kernel/default.nix2
-rw-r--r--modules/nixos-apple-silicon/apple-silicon-support/modules/sound/default.nix68
-rw-r--r--modules/nixos-apple-silicon/apple-silicon-support/packages/asahi-audio/default.nix18
-rw-r--r--modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/0001-check-in-new-alloc-for-1.75.0.patch1345
-rw-r--r--modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/config5
-rw-r--r--modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/default.nix26
-rw-r--r--modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/rust_1_76_0.patch426
-rw-r--r--modules/nixos-apple-silicon/apple-silicon-support/packages/m1n1/default.nix4
-rw-r--r--modules/nixos-apple-silicon/apple-silicon-support/packages/uboot-asahi/default.nix6
-rw-r--r--modules/nixos-apple-silicon/docs/release-notes.md51
-rw-r--r--modules/nixos-apple-silicon/docs/uefi-standalone.md14
-rw-r--r--modules/nixos-apple-silicon/flake.lock8
-rw-r--r--modules/nixos-apple-silicon/flake.nix2
-rw-r--r--modules/nixos-apple-silicon/iso-configuration/installer-configuration.nix12
-rw-r--r--sys/mbp.nix10
16 files changed, 98 insertions, 1901 deletions
diff --git a/modules/nixos-apple-silicon/README.md b/modules/nixos-apple-silicon/README.md
index 97c3938a42fe..e8c1a0e59a3f 100644
--- a/modules/nixos-apple-silicon/README.md
+++ b/modules/nixos-apple-silicon/README.md
@@ -9,7 +9,7 @@ Please see the documentation and guide below to get started.
 ## Documentation
 
 * [Release Notes](docs/release-notes.md)
-* [Setup, Installation, and Maintenance Guide (2024-04-04)](docs/uefi-standalone.md)
+* [Setup, Installation, and Maintenance Guide (2024-05-17)](docs/uefi-standalone.md)
 
 ## Credits
 
diff --git a/modules/nixos-apple-silicon/apple-silicon-support/modules/kernel/default.nix b/modules/nixos-apple-silicon/apple-silicon-support/modules/kernel/default.nix
index 619a02634e93..aeb6d62dc0fa 100644
--- a/modules/nixos-apple-silicon/apple-silicon-support/modules/kernel/default.nix
+++ b/modules/nixos-apple-silicon/apple-silicon-support/modules/kernel/default.nix
@@ -25,7 +25,7 @@
       "pinctrl-apple-gpio"
       "macsmc"
       "macsmc-rtkit"
-      "i2c-apple"
+      "i2c-pasemi-platform"
       "tps6598x"
       "apple-dart"
       "dwc3"
diff --git a/modules/nixos-apple-silicon/apple-silicon-support/modules/sound/default.nix b/modules/nixos-apple-silicon/apple-silicon-support/modules/sound/default.nix
index d0928b0ca348..d68ba9b3c646 100644
--- a/modules/nixos-apple-silicon/apple-silicon-support/modules/sound/default.nix
+++ b/modules/nixos-apple-silicon/apple-silicon-support/modules/sound/default.nix
@@ -26,19 +26,7 @@
 
     lsp-plugins = pkgs.lsp-plugins; # the lsp-plugins we use
 
-    lsp-plugins-is-patched = (lsp-plugins.overrideAttrs (old: {
-      passthru = (old.passthru or {}) // {
-        lsp-plugins-is-patched = builtins.elem "58c3f985f009c84347fa91236f164a9e47aafa93.patch"
-          (builtins.map (p: p.name) (old.patches or []));
-      };
-    })).lsp-plugins-is-patched;
-
-    lsp-plugins-is-safe = (pkgs.lib.versionAtLeast lsp-plugins.version "1.2.14") || lsp-plugins-is-patched;
-
-    # https://github.com/NixOS/nixpkgs/pull/282377
-    # options is the set of all module option declarations, rather than their
-    # values, to prevent infinite recursion
-    newHotness = builtins.hasAttr "configPackages" options.services.pipewire;
+    lsp-plugins-is-safe = (pkgs.lib.versionAtLeast lsp-plugins.version "1.2.14");
 
     lv2Path = lib.makeSearchPath "lib/lv2" [ lsp-plugins pkgs.bankstown-lv2 ];
   in lib.mkIf (cfg.setupAsahiSound && cfg.enable) (lib.mkMerge [
@@ -49,10 +37,18 @@
       # and asahi-audio configs and plugins
       services.pipewire = {
         enable = true;
-
         alsa.enable = true;
         pulse.enable = true;
-        wireplumber.enable = true;
+
+        configPackages = [ asahi-audio ];
+        extraLv2Packages = [ lsp-plugins pkgs.bankstown-lv2 ];
+
+        wireplumber = {
+          enable = true;
+
+          configPackages = [ asahi-audio ];
+          extraLv2Packages = [ lsp-plugins pkgs.bankstown-lv2 ];
+        };
       };
 
       # set up enivronment so that UCM configs are used as well
@@ -66,40 +62,14 @@
         [ pkgs.speakersafetyd ];
       services.udev.packages = [ pkgs.speakersafetyd ];
 
-      # downgrade wireplumber to a version compatible with the asahi-audio configs
-      nixpkgs.overlays = [(final: prev: {
-        wireplumber = prev.wireplumber.overrideAttrs (old:
-          lib.optionalAttrs (lib.versionAtLeast old.version "0.5.0") rec {
-            version = "0.4.17";
-            src = final.fetchFromGitLab {
-              domain = "gitlab.freedesktop.org";
-              owner = "pipewire";
-              repo = "wireplumber";
-              rev = version;
-              hash = "sha256-vhpQT67+849WV1SFthQdUeFnYe/okudTQJoL3y+wXwI=";
-            };
-          });
-      })];
+      # asahi-sound requires wireplumber 0.5.2 or above
+      # https://github.com/AsahiLinux/asahi-audio/commit/29ec1056c18193ffa09a990b1b61ed273e97fee6
+      assertions = [
+        {
+          assertion = lib.versionAtLeast pkgs.wireplumber.version "0.5.2";
+          message = "wireplumber >= 0.5.2 is required for sound with nixos-apple-silicon.";
+        }
+      ];
     }
-    (lib.optionalAttrs newHotness {
-      # use configPackages and friends to install asahi-audio and plugins
-      services.pipewire = {
-        configPackages = [ asahi-audio ];
-        extraLv2Packages = [ lsp-plugins pkgs.bankstown-lv2 ];
-        wireplumber = {
-          configPackages = [ asahi-audio ];
-          extraLv2Packages = [ lsp-plugins pkgs.bankstown-lv2 ];
-        };
-      };
-    })
-    (lib.optionalAttrs (!newHotness) {
-      # use environment.etc and environment variables to install asahi-audio and plugins
-      environment.etc = builtins.listToAttrs (builtins.map
-        (f: { name = f; value = { source = "${asahi-audio}/share/${f}"; }; })
-        asahi-audio.providedConfigFiles);
-
-      systemd.user.services.pipewire.environment.LV2_PATH = lv2Path;
-      systemd.user.services.wireplumber.environment.LV2_PATH = lv2Path;
-    })
   ]);
 }
diff --git a/modules/nixos-apple-silicon/apple-silicon-support/packages/asahi-audio/default.nix b/modules/nixos-apple-silicon/apple-silicon-support/packages/asahi-audio/default.nix
index 4ccbcc5d066c..c051cb94cfd9 100644
--- a/modules/nixos-apple-silicon/apple-silicon-support/packages/asahi-audio/default.nix
+++ b/modules/nixos-apple-silicon/apple-silicon-support/packages/asahi-audio/default.nix
@@ -6,14 +6,13 @@
 stdenv.mkDerivation rec {
   pname = "asahi-audio";
   # tracking: https://src.fedoraproject.org/rpms/asahi-audio
-  # note: ensure that the providedConfigFiles list below is current!
-  version = "1.6";
+  version = "2.2";
 
   src = fetchFromGitHub {
     owner = "AsahiLinux";
     repo = "asahi-audio";
     rev = "v${version}";
-    hash = "sha256-NxTQD742U2FUZNmw7RHuOruMuTRLtAh1HDlMV9EzQkg=";
+    hash = "sha256-5YBQibt/dfJb9/TzF6rczeQE3ySm0SeewhZrgublu2E=";
   };
 
   preBuild = ''
@@ -35,17 +34,4 @@ stdenv.mkDerivation rec {
     # no need to link the asahi-audio dir globally
     mv $out/share/asahi-audio $out
   '';
-
-  # list of config files installed in $out/share/ and destined for
-  # /etc/, from the `install -pm0644 conf/` lines in the Makefile. note
-  # that the contents of asahi-audio/ stay in $out/ and the config files
-  # are modified to point to them.
-  passthru.providedConfigFiles = [
-    "wireplumber/wireplumber.conf.d/99-asahi.conf"
-    "wireplumber/policy.lua.d/85-asahi-policy.lua"
-    "wireplumber/main.lua.d/85-asahi.lua"
-    "wireplumber/scripts/policy-asahi.lua"
-    "pipewire/pipewire.conf.d/99-asahi.conf"
-    "pipewire/pipewire-pulse.conf.d/99-asahi.conf"
-  ];
 }
diff --git a/modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/0001-check-in-new-alloc-for-1.75.0.patch b/modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/0001-check-in-new-alloc-for-1.75.0.patch
deleted file mode 100644
index 3c03bf913610..000000000000
--- a/modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/0001-check-in-new-alloc-for-1.75.0.patch
+++ /dev/null
@@ -1,1345 +0,0 @@
-From 568b4e71264f2c636c65da0671e80d3c734489c6 Mon Sep 17 00:00:00 2001
-From: Yureka <yuka@yuka.dev>
-Date: Tue, 16 Jan 2024 09:58:27 +0100
-Subject: [PATCH] check in new alloc for 1.75.0
-
----
- rust/alloc/alloc.rs            |  63 +++++-----
- rust/alloc/boxed.rs            |  74 +++++++-----
- rust/alloc/lib.rs              |  27 +++--
- rust/alloc/raw_vec.rs          |  49 +++++---
- rust/alloc/slice.rs            |   2 +-
- rust/alloc/vec/drain_filter.rs | 199 -------------------------------
- rust/alloc/vec/extract_if.rs   | 115 ++++++++++++++++++
- rust/alloc/vec/mod.rs          | 209 +++++++++++++++++++++++----------
- rust/alloc/vec/spec_extend.rs  |   8 +-
- 9 files changed, 389 insertions(+), 357 deletions(-)
- delete mode 100644 rust/alloc/vec/drain_filter.rs
- create mode 100644 rust/alloc/vec/extract_if.rs
-
-diff --git a/rust/alloc/alloc.rs b/rust/alloc/alloc.rs
-index 08eafb3de807..8a6be8c98173 100644
---- a/rust/alloc/alloc.rs
-+++ b/rust/alloc/alloc.rs
-@@ -6,9 +6,7 @@
- 
- #[cfg(not(test))]
- use core::intrinsics;
--use core::intrinsics::{min_align_of_val, size_of_val};
- 
--use core::ptr::Unique;
- #[cfg(not(test))]
- use core::ptr::{self, NonNull};
- 
-@@ -40,7 +38,6 @@
-     #[rustc_nounwind]
-     fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
- 
--    #[cfg(not(bootstrap))]
-     static __rust_no_alloc_shim_is_unstable: u8;
- }
- 
-@@ -98,7 +95,6 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 {
-     unsafe {
-         // Make sure we don't accidentally allow omitting the allocator shim in
-         // stable code until it is actually stabilized.
--        #[cfg(not(bootstrap))]
-         core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable);
- 
-         __rust_alloc(layout.size(), layout.align())
-@@ -339,23 +335,6 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
-     }
- }
- 
--#[cfg(not(version("1.72")))]
--#[cfg_attr(not(test), lang = "box_free")]
--#[inline]
--// This signature has to be the same as `Box`, otherwise an ICE will happen.
--// When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as
--// well.
--// For example if `Box` is changed to  `struct Box<T: ?Sized, A: Allocator>(Unique<T>, A)`,
--// this function has to be changed to `fn box_free<T: ?Sized, A: Allocator>(Unique<T>, A)` as well.
--pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A) {
--    unsafe {
--        let size = size_of_val(ptr.as_ref());
--        let align = min_align_of_val(ptr.as_ref());
--        let layout = Layout::from_size_align_unchecked(size, align);
--        alloc.deallocate(From::from(ptr.cast()), layout)
--    }
--}
--
- // # Allocation error handler
- 
- #[cfg(not(no_global_oom_handling))]
-@@ -366,18 +345,31 @@ pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A)
-     fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
- }
- 
--/// Abort on memory allocation error or failure.
-+/// Signal a memory allocation error.
- ///
--/// Callers of memory allocation APIs wishing to abort computation
-+/// Callers of memory allocation APIs wishing to cease execution
- /// in response to an allocation error are encouraged to call this function,
--/// rather than directly invoking `panic!` or similar.
-+/// rather than directly invoking [`panic!`] or similar.
-+///
-+/// This function is guaranteed to diverge (not return normally with a value), but depending on
-+/// global configuration, it may either panic (resulting in unwinding or aborting as per
-+/// configuration for all panics), or abort the process (with no unwinding).
- ///
--/// The default behavior of this function is to print a message to standard error
--/// and abort the process.
--/// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`].
-+/// The default behavior is:
-+///
-+///  * If the binary links against `std` (typically the case), then
-+///   print a message to standard error and abort the process.
-+///   This behavior can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`].
-+///   Future versions of Rust may panic by default instead.
-+///
-+/// * If the binary does not link against `std` (all of its crates are marked
-+///   [`#![no_std]`][no_std]), then call [`panic!`] with a message.
-+///   [The panic handler] applies as to any panic.
- ///
- /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
- /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
-+/// [The panic handler]: https://doc.rust-lang.org/reference/runtime.html#the-panic_handler-attribute
-+/// [no_std]: https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute
- #[stable(feature = "global_alloc", since = "1.28.0")]
- #[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
- #[cfg(all(not(no_global_oom_handling), not(test)))]
-@@ -387,13 +379,20 @@ const fn ct_error(_: Layout) -> ! {
-         panic!("allocation failed");
-     }
- 
-+    #[inline]
-     fn rt_error(layout: Layout) -> ! {
-         unsafe {
-             __rust_alloc_error_handler(layout.size(), layout.align());
-         }
-     }
- 
--    unsafe { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) }
-+    #[cfg(not(feature = "panic_immediate_abort"))]
-+    unsafe {
-+        core::intrinsics::const_eval_select((layout,), ct_error, rt_error)
-+    }
-+
-+    #[cfg(feature = "panic_immediate_abort")]
-+    ct_error(layout)
- }
- 
- // For alloc test `std::alloc::handle_alloc_error` can be used directly.
-@@ -415,13 +414,13 @@ pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
-             static __rust_alloc_error_handler_should_panic: u8;
-         }
- 
--        #[allow(unused_unsafe)]
-         if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
-             panic!("memory allocation of {size} bytes failed")
-         } else {
--            core::panicking::panic_nounwind_fmt(format_args!(
--                "memory allocation of {size} bytes failed"
--            ))
-+            core::panicking::panic_nounwind_fmt(
-+                format_args!("memory allocation of {size} bytes failed"),
-+                /* force_no_backtrace */ false,
-+            )
-         }
-     }
- }
-diff --git a/rust/alloc/boxed.rs b/rust/alloc/boxed.rs
-index ed7e2f666178..f5f40778a193 100644
---- a/rust/alloc/boxed.rs
-+++ b/rust/alloc/boxed.rs
-@@ -159,12 +159,12 @@
- use core::iter::FusedIterator;
- use core::marker::Tuple;
- use core::marker::Unsize;
--use core::mem;
-+use core::mem::{self, SizedTypeProperties};
- use core::ops::{
--    CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Generator, GeneratorState, Receiver,
-+    CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, DispatchFromDyn, Receiver,
- };
- use core::pin::Pin;
--use core::ptr::{self, Unique};
-+use core::ptr::{self, NonNull, Unique};
- use core::task::{Context, Poll};
- 
- #[cfg(not(no_global_oom_handling))]
-@@ -211,7 +211,7 @@ impl<T> Box<T> {
-     /// ```
-     /// let five = Box::new(5);
-     /// ```
--    #[cfg(all(not(no_global_oom_handling)))]
-+    #[cfg(not(no_global_oom_handling))]
-     #[inline(always)]
-     #[stable(feature = "rust1", since = "1.0.0")]
-     #[must_use]
-@@ -483,8 +483,12 @@ pub fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocE
-     where
-         A: Allocator,
-     {
--        let layout = Layout::new::<mem::MaybeUninit<T>>();
--        let ptr = alloc.allocate(layout)?.cast();
-+        let ptr = if T::IS_ZST {
-+            NonNull::dangling()
-+        } else {
-+            let layout = Layout::new::<mem::MaybeUninit<T>>();
-+            alloc.allocate(layout)?.cast()
-+        };
-         unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
-     }
- 
-@@ -553,8 +557,12 @@ pub fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocE
-     where
-         A: Allocator,
-     {
--        let layout = Layout::new::<mem::MaybeUninit<T>>();
--        let ptr = alloc.allocate_zeroed(layout)?.cast();
-+        let ptr = if T::IS_ZST {
-+            NonNull::dangling()
-+        } else {
-+            let layout = Layout::new::<mem::MaybeUninit<T>>();
-+            alloc.allocate_zeroed(layout)?.cast()
-+        };
-         unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
-     }
- 
-@@ -679,14 +687,16 @@ pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
-     #[unstable(feature = "allocator_api", issue = "32838")]
-     #[inline]
-     pub fn try_new_uninit_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, AllocError> {
--        unsafe {
-+        let ptr = if T::IS_ZST || len == 0 {
-+            NonNull::dangling()
-+        } else {
-             let layout = match Layout::array::<mem::MaybeUninit<T>>(len) {
-                 Ok(l) => l,
-                 Err(_) => return Err(AllocError),
-             };
--            let ptr = Global.allocate(layout)?;
--            Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len))
--        }
-+            Global.allocate(layout)?.cast()
-+        };
-+        unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) }
-     }
- 
-     /// Constructs a new boxed slice with uninitialized contents, with the memory
-@@ -711,14 +721,16 @@ pub fn try_new_uninit_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, Al
-     #[unstable(feature = "allocator_api", issue = "32838")]
-     #[inline]
-     pub fn try_new_zeroed_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, AllocError> {
--        unsafe {
-+        let ptr = if T::IS_ZST || len == 0 {
-+            NonNull::dangling()
-+        } else {
-             let layout = match Layout::array::<mem::MaybeUninit<T>>(len) {
-                 Ok(l) => l,
-                 Err(_) => return Err(AllocError),
-             };
--            let ptr = Global.allocate_zeroed(layout)?;
--            Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len))
--        }
-+            Global.allocate_zeroed(layout)?.cast()
-+        };
-+        unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) }
-     }
- }
- 
-@@ -1215,12 +1227,6 @@ pub const fn into_pin(boxed: Self) -> Pin<Self>
- 
- #[stable(feature = "rust1", since = "1.0.0")]
- unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
--    #[cfg(not(version("1.72")))]
--    fn drop(&mut self) {
--        // FIXME: Do nothing, drop is currently performed by compiler.
--    }
--
--    #[cfg(version("1.72"))]
-     #[inline]
-     fn drop(&mut self) {
-         // the T in the Box is dropped by the compiler before the destructor is run
-@@ -1229,7 +1235,9 @@ fn drop(&mut self) {
- 
-         unsafe {
-             let layout = Layout::for_value_raw(ptr.as_ptr());
--            self.1.deallocate(From::from(ptr.cast()), layout)
-+            if layout.size() != 0 {
-+                self.1.deallocate(From::from(ptr.cast()), layout);
-+            }
-         }
-     }
- }
-@@ -2102,28 +2110,28 @@ fn as_mut(&mut self) -> &mut T {
- #[stable(feature = "pin", since = "1.33.0")]
- impl<T: ?Sized, A: Allocator> Unpin for Box<T, A> where A: 'static {}
- 
--#[unstable(feature = "generator_trait", issue = "43122")]
--impl<G: ?Sized + Generator<R> + Unpin, R, A: Allocator> Generator<R> for Box<G, A>
-+#[unstable(feature = "coroutine_trait", issue = "43122")]
-+impl<G: ?Sized + Coroutine<R> + Unpin, R, A: Allocator> Coroutine<R> for Box<G, A>
- where
-     A: 'static,
- {
-     type Yield = G::Yield;
-     type Return = G::Return;
- 
--    fn resume(mut self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return> {
-+    fn resume(mut self: Pin<&mut Self>, arg: R) -> CoroutineState<Self::Yield, Self::Return> {
-         G::resume(Pin::new(&mut *self), arg)
-     }
- }
- 
--#[unstable(feature = "generator_trait", issue = "43122")]
--impl<G: ?Sized + Generator<R>, R, A: Allocator> Generator<R> for Pin<Box<G, A>>
-+#[unstable(feature = "coroutine_trait", issue = "43122")]
-+impl<G: ?Sized + Coroutine<R>, R, A: Allocator> Coroutine<R> for Pin<Box<G, A>>
- where
-     A: 'static,
- {
-     type Yield = G::Yield;
-     type Return = G::Return;
- 
--    fn resume(mut self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return> {
-+    fn resume(mut self: Pin<&mut Self>, arg: R) -> CoroutineState<Self::Yield, Self::Return> {
-         G::resume((*self).as_mut(), arg)
-     }
- }
-@@ -2179,7 +2187,7 @@ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn E
-         let err: Box<dyn Error> = self;
-         <dyn Error>::downcast(err).map_err(|s| unsafe {
-             // Reapply the `Send` marker.
--            mem::transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
-+            Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send))
-         })
-     }
- }
-@@ -2193,7 +2201,7 @@ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>
-         let err: Box<dyn Error> = self;
-         <dyn Error>::downcast(err).map_err(|s| unsafe {
-             // Reapply the `Send + Sync` marker.
--            mem::transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
-+            Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send + Sync))
-         })
-     }
- }
-@@ -2440,4 +2448,8 @@ fn cause(&self) -> Option<&dyn core::error::Error> {
-     fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
-         core::error::Error::source(&**self)
-     }
-+
-+    fn provide<'b>(&'b self, request: &mut core::error::Request<'b>) {
-+        core::error::Error::provide(&**self, request);
-+    }
- }
-diff --git a/rust/alloc/lib.rs b/rust/alloc/lib.rs
-index 65b7a02d0956..345cf5c9cf92 100644
---- a/rust/alloc/lib.rs
-+++ b/rust/alloc/lib.rs
-@@ -57,8 +57,12 @@
- //! [`Cell`]: core::cell
- //! [`Rc`]: rc
- //! [`RefCell`]: core::cell
--#![feature(doc_cfg_hide)]
- 
-+// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
-+// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
-+// rustc itself never sets the feature, so this line has no effect there.
-+#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
-+//
- #![allow(unused_attributes)]
- #![stable(feature = "alloc", since = "1.36.0")]
- #![doc(
-@@ -76,13 +80,10 @@
-     not(no_sync),
-     target_has_atomic = "ptr"
- ))]
-+#![cfg_attr(not(bootstrap), doc(rust_logo))]
-+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
- #![no_std]
- #![needs_allocator]
--// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
--// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
--// rustc itself never sets the feature, so this line has no affect there.
--#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
--//
- // Lints:
- #![deny(unsafe_op_in_unsafe_fn)]
- #![deny(fuzzy_provenance_casts)]
-@@ -91,6 +92,8 @@
- #![warn(missing_docs)]
- #![allow(explicit_outlives_requirements)]
- #![warn(multiple_supertrait_upcastable)]
-+#![allow(internal_features)]
-+#![allow(rustdoc::redundant_explicit_links)]
- //
- // Library features:
- // tidy-alphabetical-start
-@@ -107,21 +110,20 @@
- #![feature(ascii_char)]
- #![feature(assert_matches)]
- #![feature(async_iterator)]
--#![feature(cfg_version)]
- #![feature(coerce_unsized)]
- #![feature(const_align_of_val)]
--#![cfg_attr(not(version("1.73")), feature(const_box))]
-+#![feature(const_box)]
- #![cfg_attr(not(no_borrow), feature(const_cow_is_borrowed))]
- #![feature(const_eval_select)]
- #![feature(const_maybe_uninit_as_mut_ptr)]
- #![feature(const_maybe_uninit_write)]
--#![feature(const_maybe_uninit_zeroed)]
- #![feature(const_pin)]
- #![feature(const_refs_to_cell)]
- #![feature(const_size_of_val)]
- #![feature(const_waker)]
- #![feature(core_intrinsics)]
- #![feature(core_panic)]
-+#![feature(deprecated_suggestion)]
- #![feature(dispatch_from_dyn)]
- #![feature(error_generic_member_access)]
- #![feature(error_in_core)]
-@@ -140,13 +142,11 @@
- #![feature(maybe_uninit_uninit_array)]
- #![feature(maybe_uninit_uninit_array_transpose)]
- #![feature(pattern)]
--#![feature(pointer_byte_offsets)]
--#![cfg_attr(not(version("1.73")), feature(provide_any))]
-+#![feature(ptr_addr_eq)]
- #![feature(ptr_internals)]
- #![feature(ptr_metadata)]
- #![feature(ptr_sub_ptr)]
- #![feature(receiver_trait)]
--#![feature(saturating_int_impl)]
- #![feature(set_ptr_value)]
- #![feature(sized_type_properties)]
- #![feature(slice_from_ptr_range)]
-@@ -169,7 +169,7 @@
- //
- // Language features:
- // tidy-alphabetical-start
--#![cfg_attr(not(test), feature(generator_trait))]
-+#![cfg_attr(not(test), feature(coroutine_trait))]
- #![cfg_attr(test, feature(panic_update_hook))]
- #![cfg_attr(test, feature(test))]
- #![feature(allocator_internals)]
-@@ -204,6 +204,7 @@
- //
- // Rustdoc features:
- #![feature(doc_cfg)]
-+#![feature(doc_cfg_hide)]
- // Technically, this is a bug in rustdoc: rustdoc sees the documentation on `#[lang = slice_alloc]`
- // blocks is for `&[T]`, which also has documentation using this feature in `core`, and gets mad
- // that the feature-gate isn't enabled. Ideally, it wouldn't check for the feature gate for docs
-diff --git a/rust/alloc/raw_vec.rs b/rust/alloc/raw_vec.rs
-index 65d5ce15828e..f1b8cec8cc62 100644
---- a/rust/alloc/raw_vec.rs
-+++ b/rust/alloc/raw_vec.rs
-@@ -338,10 +338,13 @@ pub fn reserve_for_push(&mut self, len: usize) {
-     /// The same as `reserve`, but returns on errors instead of panicking or aborting.
-     pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
-         if self.needs_to_grow(len, additional) {
--            self.grow_amortized(len, additional)
--        } else {
--            Ok(())
-+            self.grow_amortized(len, additional)?;
-+        }
-+        unsafe {
-+            // Inform the optimizer that the reservation has succeeded or wasn't needed
-+            core::intrinsics::assume(!self.needs_to_grow(len, additional));
-         }
-+        Ok(())
-     }
- 
-     /// The same as `reserve_for_push`, but returns on errors instead of panicking or aborting.
-@@ -378,7 +381,14 @@ pub fn try_reserve_exact(
-         len: usize,
-         additional: usize,
-     ) -> Result<(), TryReserveError> {
--        if self.needs_to_grow(len, additional) { self.grow_exact(len, additional) } else { Ok(()) }
-+        if self.needs_to_grow(len, additional) {
-+            self.grow_exact(len, additional)?;
-+        }
-+        unsafe {
-+            // Inform the optimizer that the reservation has succeeded or wasn't needed
-+            core::intrinsics::assume(!self.needs_to_grow(len, additional));
-+        }
-+        Ok(())
-     }
- 
-     /// Shrinks the buffer down to the specified capacity. If the given amount
-@@ -471,16 +481,26 @@ fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> {
-         let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) };
-         // See current_memory() why this assert is here
-         let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
--        let ptr = unsafe {
--            // `Layout::array` cannot overflow here because it would have
--            // overflowed earlier when capacity was larger.
--            let new_size = mem::size_of::<T>().unchecked_mul(cap);
--            let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
--            self.alloc
--                .shrink(ptr, layout, new_layout)
--                .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
--        };
--        self.set_ptr_and_cap(ptr, cap);
-+
-+        // If shrinking to 0, deallocate the buffer. We don't reach this point
-+        // for the T::IS_ZST case since current_memory() will have returned
-+        // None.
-+        if cap == 0 {
-+            unsafe { self.alloc.deallocate(ptr, layout) };
-+            self.ptr = Unique::dangling();
-+            self.cap = 0;
-+        } else {
-+            let ptr = unsafe {
-+                // `Layout::array` cannot overflow here because it would have
-+                // overflowed earlier when capacity was larger.
-+                let new_size = mem::size_of::<T>().unchecked_mul(cap);
-+                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
-+                self.alloc
-+                    .shrink(ptr, layout, new_layout)
-+                    .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
-+            };
-+            self.set_ptr_and_cap(ptr, cap);
-+        }
-         Ok(())
-     }
- }
-@@ -559,6 +579,7 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
- // ensure that the code generation related to these panics is minimal as there's
- // only one location which panics rather than a bunch throughout the module.
- #[cfg(not(no_global_oom_handling))]
-+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
- fn capacity_overflow() -> ! {
-     panic!("capacity overflow");
- }
-diff --git a/rust/alloc/slice.rs b/rust/alloc/slice.rs
-index 6ac463bd3edc..1181836da5f4 100644
---- a/rust/alloc/slice.rs
-+++ b/rust/alloc/slice.rs
-@@ -594,7 +594,7 @@ pub fn join<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Outp
-     /// ```
-     #[rustc_allow_incoherent_impl]
-     #[stable(feature = "rust1", since = "1.0.0")]
--    #[deprecated(since = "1.3.0", note = "renamed to join")]
-+    #[deprecated(since = "1.3.0", note = "renamed to join", suggestion = "join")]
-     pub fn connect<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output
-     where
-         Self: Join<Separator>,
-diff --git a/rust/alloc/vec/drain_filter.rs b/rust/alloc/vec/drain_filter.rs
-deleted file mode 100644
-index 09efff090e42..000000000000
---- a/rust/alloc/vec/drain_filter.rs
-+++ /dev/null
-@@ -1,199 +0,0 @@
--// SPDX-License-Identifier: Apache-2.0 OR MIT
--
--use crate::alloc::{Allocator, Global};
--use core::mem::{ManuallyDrop, SizedTypeProperties};
--use core::ptr;
--use core::slice;
--
--use super::Vec;
--
--/// An iterator which uses a closure to determine if an element should be removed.
--///
--/// This struct is created by [`Vec::drain_filter`].
--/// See its documentation for more.
--///
--/// # Example
--///
--/// ```
--/// #![feature(drain_filter)]
--///
--/// let mut v = vec![0, 1, 2];
--/// let iter: std::vec::DrainFilter<'_, _, _> = v.drain_filter(|x| *x % 2 == 0);
--/// ```
--#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
--#[derive(Debug)]
--pub struct DrainFilter<
--    'a,
--    T,
--    F,
--    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
--> where
--    F: FnMut(&mut T) -> bool,
--{
--    pub(super) vec: &'a mut Vec<T, A>,
--    /// The index of the item that will be inspected by the next call to `next`.
--    pub(super) idx: usize,
--    /// The number of items that have been drained (removed) thus far.
--    pub(super) del: usize,
--    /// The original length of `vec` prior to draining.
--    pub(super) old_len: usize,
--    /// The filter test predicate.
--    pub(super) pred: F,
--    /// A flag that indicates a panic has occurred in the filter test predicate.
--    /// This is used as a hint in the drop implementation to prevent consumption
--    /// of the remainder of the `DrainFilter`. Any unprocessed items will be
--    /// backshifted in the `vec`, but no further items will be dropped or
--    /// tested by the filter predicate.
--    pub(super) panic_flag: bool,
--}
--
--impl<T, F, A: Allocator> DrainFilter<'_, T, F, A>
--where
--    F: FnMut(&mut T) -> bool,
--{
--    /// Returns a reference to the underlying allocator.
--    #[unstable(feature = "allocator_api", issue = "32838")]
--    #[inline]
--    pub fn allocator(&self) -> &A {
--        self.vec.allocator()
--    }
--
--    /// Keep unyielded elements in the source `Vec`.
--    ///
--    /// # Examples
--    ///
--    /// ```
--    /// #![feature(drain_filter)]
--    /// #![feature(drain_keep_rest)]
--    ///
--    /// let mut vec = vec!['a', 'b', 'c'];
--    /// let mut drain = vec.drain_filter(|_| true);
--    ///
--    /// assert_eq!(drain.next().unwrap(), 'a');
--    ///
--    /// // This call keeps 'b' and 'c' in the vec.
--    /// drain.keep_rest();
--    ///
--    /// // If we wouldn't call `keep_rest()`,
--    /// // `vec` would be empty.
--    /// assert_eq!(vec, ['b', 'c']);
--    /// ```
--    #[unstable(feature = "drain_keep_rest", issue = "101122")]
--    pub fn keep_rest(self) {
--        // At this moment layout looks like this:
--        //
--        //  _____________________/-- old_len
--        // /                     \
--        // [kept] [yielded] [tail]
--        //        \_______/ ^-- idx
--        //                \-- del
--        //
--        // Normally `Drop` impl would drop [tail] (via .for_each(drop), ie still calling `pred`)
--        //
--        // 1. Move [tail] after [kept]
--        // 2. Update length of the original vec to `old_len - del`
--        //    a. In case of ZST, this is the only thing we want to do
--        // 3. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
--        let mut this = ManuallyDrop::new(self);
--
--        unsafe {
--            // ZSTs have no identity, so we don't need to move them around.
--            if !T::IS_ZST && this.idx < this.old_len && this.del > 0 {
--                let ptr = this.vec.as_mut_ptr();
--                let src = ptr.add(this.idx);
--                let dst = src.sub(this.del);
--                let tail_len = this.old_len - this.idx;
--                src.copy_to(dst, tail_len);
--            }
--
--            let new_len = this.old_len - this.del;
--            this.vec.set_len(new_len);
--        }
--    }
--}
--
--#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
--impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A>
--where
--    F: FnMut(&mut T) -> bool,
--{
--    type Item = T;
--
--    fn next(&mut self) -> Option<T> {
--        unsafe {
--            while self.idx < self.old_len {
--                let i = self.idx;
--                let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
--                self.panic_flag = true;
--                let drained = (self.pred)(&mut v[i]);
--                self.panic_flag = false;
--                // Update the index *after* the predicate is called. If the index
--                // is updated prior and the predicate panics, the element at this
--                // index would be leaked.
--                self.idx += 1;
--                if drained {
--                    self.del += 1;
--                    return Some(ptr::read(&v[i]));
--                } else if self.del > 0 {
--                    let del = self.del;
--                    let src: *const T = &v[i];
--                    let dst: *mut T = &mut v[i - del];
--                    ptr::copy_nonoverlapping(src, dst, 1);
--                }
--            }
--            None
--        }
--    }
--
--    fn size_hint(&self) -> (usize, Option<usize>) {
--        (0, Some(self.old_len - self.idx))
--    }
--}
--
--#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
--impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
--where
--    F: FnMut(&mut T) -> bool,
--{
--    fn drop(&mut self) {
--        struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator>
--        where
--            F: FnMut(&mut T) -> bool,
--        {
--            drain: &'b mut DrainFilter<'a, T, F, A>,
--        }
--
--        impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A>
--        where
--            F: FnMut(&mut T) -> bool,
--        {
--            fn drop(&mut self) {
--                unsafe {
--                    if self.drain.idx < self.drain.old_len && self.drain.del > 0 {
--                        // This is a pretty messed up state, and there isn't really an
--                        // obviously right thing to do. We don't want to keep trying
--                        // to execute `pred`, so we just backshift all the unprocessed
--                        // elements and tell the vec that they still exist. The backshift
--                        // is required to prevent a double-drop of the last successfully
--                        // drained item prior to a panic in the predicate.
--                        let ptr = self.drain.vec.as_mut_ptr();
--                        let src = ptr.add(self.drain.idx);
--                        let dst = src.sub(self.drain.del);
--                        let tail_len = self.drain.old_len - self.drain.idx;
--                        src.copy_to(dst, tail_len);
--                    }
--                    self.drain.vec.set_len(self.drain.old_len - self.drain.del);
--                }
--            }
--        }
--
--        let backshift = BackshiftOnDrop { drain: self };
--
--        // Attempt to consume any remaining elements if the filter predicate
--        // has not yet panicked. We'll backshift any remaining elements
--        // whether we've already panicked or if the consumption here panics.
--        if !backshift.drain.panic_flag {
--            backshift.drain.for_each(drop);
--        }
--    }
--}
-diff --git a/rust/alloc/vec/extract_if.rs b/rust/alloc/vec/extract_if.rs
-new file mode 100644
-index 000000000000..f314a51d4d3d
---- /dev/null
-+++ b/rust/alloc/vec/extract_if.rs
-@@ -0,0 +1,115 @@
-+// SPDX-License-Identifier: Apache-2.0 OR MIT
-+
-+use crate::alloc::{Allocator, Global};
-+use core::ptr;
-+use core::slice;
-+
-+use super::Vec;
-+
-+/// An iterator which uses a closure to determine if an element should be removed.
-+///
-+/// This struct is created by [`Vec::extract_if`].
-+/// See its documentation for more.
-+///
-+/// # Example
-+///
-+/// ```
-+/// #![feature(extract_if)]
-+///
-+/// let mut v = vec![0, 1, 2];
-+/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(|x| *x % 2 == 0);
-+/// ```
-+#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
-+#[derive(Debug)]
-+#[must_use = "iterators are lazy and do nothing unless consumed"]
-+pub struct ExtractIf<
-+    'a,
-+    T,
-+    F,
-+    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
-+> where
-+    F: FnMut(&mut T) -> bool,
-+{
-+    pub(super) vec: &'a mut Vec<T, A>,
-+    /// The index of the item that will be inspected by the next call to `next`.
-+    pub(super) idx: usize,
-+    /// The number of items that have been drained (removed) thus far.
-+    pub(super) del: usize,
-+    /// The original length of `vec` prior to draining.
-+    pub(super) old_len: usize,
-+    /// The filter test predicate.
-+    pub(super) pred: F,
-+}
-+
-+impl<T, F, A: Allocator> ExtractIf<'_, T, F, A>
-+where
-+    F: FnMut(&mut T) -> bool,
-+{
-+    /// Returns a reference to the underlying allocator.
-+    #[unstable(feature = "allocator_api", issue = "32838")]
-+    #[inline]
-+    pub fn allocator(&self) -> &A {
-+        self.vec.allocator()
-+    }
-+}
-+
-+#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
-+impl<T, F, A: Allocator> Iterator for ExtractIf<'_, T, F, A>
-+where
-+    F: FnMut(&mut T) -> bool,
-+{
-+    type Item = T;
-+
-+    fn next(&mut self) -> Option<T> {
-+        unsafe {
-+            while self.idx < self.old_len {
-+                let i = self.idx;
-+                let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
-+                let drained = (self.pred)(&mut v[i]);
-+                // Update the index *after* the predicate is called. If the index
-+                // is updated prior and the predicate panics, the element at this
-+                // index would be leaked.
-+                self.idx += 1;
-+                if drained {
-+                    self.del += 1;
-+                    return Some(ptr::read(&v[i]));
-+                } else if self.del > 0 {
-+                    let del = self.del;
-+                    let src: *const T = &v[i];
-+                    let dst: *mut T = &mut v[i - del];
-+                    ptr::copy_nonoverlapping(src, dst, 1);
-+                }
-+            }
-+            None
-+        }
-+    }
-+
-+    fn size_hint(&self) -> (usize, Option<usize>) {
-+        (0, Some(self.old_len - self.idx))
-+    }
-+}
-+
-+#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
-+impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A>
-+where
-+    F: FnMut(&mut T) -> bool,
-+{
-+    fn drop(&mut self) {
-+        unsafe {
-+            if self.idx < self.old_len && self.del > 0 {
-+                // This is a pretty messed up state, and there isn't really an
-+                // obviously right thing to do. We don't want to keep trying
-+                // to execute `pred`, so we just backshift all the unprocessed
-+                // elements and tell the vec that they still exist. The backshift
-+                // is required to prevent a double-drop of the last successfully
-+                // drained item prior to a panic in the predicate.
-+                let ptr = self.vec.as_mut_ptr();
-+                let src = ptr.add(self.idx);
-+                let dst = src.sub(self.del);
-+                let tail_len = self.old_len - self.idx;
-+                src.copy_to(dst, tail_len);
-+            }
-+            self.vec.set_len(self.old_len - self.del);
-+        }
-+    }
-+}
-diff --git a/rust/alloc/vec/mod.rs b/rust/alloc/vec/mod.rs
-index 05c70de0227e..0d95fd7ef337 100644
---- a/rust/alloc/vec/mod.rs
-+++ b/rust/alloc/vec/mod.rs
-@@ -74,10 +74,10 @@
- use crate::collections::{TryReserveError, TryReserveErrorKind};
- use crate::raw_vec::RawVec;
- 
--#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
--pub use self::drain_filter::DrainFilter;
-+#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
-+pub use self::extract_if::ExtractIf;
- 
--mod drain_filter;
-+mod extract_if;
- 
- #[cfg(not(no_global_oom_handling))]
- #[stable(feature = "vec_splice", since = "1.21.0")]
-@@ -216,7 +216,7 @@
- ///
- /// # Indexing
- ///
--/// The `Vec` type allows to access values by index, because it implements the
-+/// The `Vec` type allows access to values by index, because it implements the
- /// [`Index`] trait. An example will be more explicit:
- ///
- /// ```
-@@ -618,22 +618,20 @@ pub fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError> {
-     /// Using memory that was allocated elsewhere:
-     ///
-     /// ```rust
--    /// #![feature(allocator_api)]
--    ///
--    /// use std::alloc::{AllocError, Allocator, Global, Layout};
-+    /// use std::alloc::{alloc, Layout};
-     ///
-     /// fn main() {
-     ///     let layout = Layout::array::<u32>(16).expect("overflow cannot happen");
-     ///
-     ///     let vec = unsafe {
--    ///         let mem = match Global.allocate(layout) {
--    ///             Ok(mem) => mem.cast::<u32>().as_ptr(),
--    ///             Err(AllocError) => return,
--    ///         };
-+    ///         let mem = alloc(layout).cast::<u32>();
-+    ///         if mem.is_null() {
-+    ///             return;
-+    ///         }
-     ///
-     ///         mem.write(1_000_000);
-     ///
--    ///         Vec::from_raw_parts_in(mem, 1, 16, Global)
-+    ///         Vec::from_raw_parts(mem, 1, 16)
-     ///     };
-     ///
-     ///     assert_eq!(vec, &[1_000_000]);
-@@ -876,19 +874,22 @@ pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserv
-     /// Using memory that was allocated elsewhere:
-     ///
-     /// ```rust
--    /// use std::alloc::{alloc, Layout};
-+    /// #![feature(allocator_api)]
-+    ///
-+    /// use std::alloc::{AllocError, Allocator, Global, Layout};
-     ///
-     /// fn main() {
-     ///     let layout = Layout::array::<u32>(16).expect("overflow cannot happen");
-+    ///
-     ///     let vec = unsafe {
--    ///         let mem = alloc(layout).cast::<u32>();
--    ///         if mem.is_null() {
--    ///             return;
--    ///         }
-+    ///         let mem = match Global.allocate(layout) {
-+    ///             Ok(mem) => mem.cast::<u32>().as_ptr(),
-+    ///             Err(AllocError) => return,
-+    ///         };
-     ///
-     ///         mem.write(1_000_000);
-     ///
--    ///         Vec::from_raw_parts(mem, 1, 16)
-+    ///         Vec::from_raw_parts_in(mem, 1, 16, Global)
-     ///     };
-     ///
-     ///     assert_eq!(vec, &[1_000_000]);
-@@ -1227,8 +1228,8 @@ pub fn into_boxed_slice(mut self) -> Box<[T], A> {
-     /// Shortens the vector, keeping the first `len` elements and dropping
-     /// the rest.
-     ///
--    /// If `len` is greater than the vector's current length, this has no
--    /// effect.
-+    /// If `len` is greater or equal to the vector's current length, this has
-+    /// no effect.
-     ///
-     /// The [`drain`] method can emulate `truncate`, but causes the excess
-     /// elements to be returned instead of dropped.
-@@ -1335,6 +1336,15 @@ pub fn as_mut_slice(&mut self) -> &mut [T] {
-     /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
-     /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
-     ///
-+    /// This method guarantees that for the purpose of the aliasing model, this method
-+    /// does not materialize a reference to the underlying slice, and thus the returned pointer
-+    /// will remain valid when mixed with other calls to [`as_ptr`] and [`as_mut_ptr`].
-+    /// Note that calling other methods that materialize mutable references to the slice,
-+    /// or mutable references to specific elements you are planning on accessing through this pointer,
-+    /// as well as writing to those elements, may still invalidate this pointer.
-+    /// See the second example below for how this guarantee can be used.
-+    ///
-+    ///
-     /// # Examples
-     ///
-     /// ```
-@@ -1348,8 +1358,25 @@ pub fn as_mut_slice(&mut self) -> &mut [T] {
-     /// }
-     /// ```
-     ///
-+    /// Due to the aliasing guarantee, the following code is legal:
-+    ///
-+    /// ```rust
-+    /// unsafe {
-+    ///     let mut v = vec![0, 1, 2];
-+    ///     let ptr1 = v.as_ptr();
-+    ///     let _ = ptr1.read();
-+    ///     let ptr2 = v.as_mut_ptr().offset(2);
-+    ///     ptr2.write(2);
-+    ///     // Notably, the write to `ptr2` did *not* invalidate `ptr1`
-+    ///     // because it mutated a different element:
-+    ///     let _ = ptr1.read();
-+    /// }
-+    /// ```
-+    ///
-     /// [`as_mut_ptr`]: Vec::as_mut_ptr
-+    /// [`as_ptr`]: Vec::as_ptr
-     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
-+    #[rustc_never_returns_null_ptr]
-     #[inline]
-     pub fn as_ptr(&self) -> *const T {
-         // We shadow the slice method of the same name to avoid going through
-@@ -1365,6 +1392,15 @@ pub fn as_ptr(&self) -> *const T {
-     /// Modifying the vector may cause its buffer to be reallocated,
-     /// which would also make any pointers to it invalid.
-     ///
-+    /// This method guarantees that for the purpose of the aliasing model, this method
-+    /// does not materialize a reference to the underlying slice, and thus the returned pointer
-+    /// will remain valid when mixed with other calls to [`as_ptr`] and [`as_mut_ptr`].
-+    /// Note that calling other methods that materialize references to the slice,
-+    /// or references to specific elements you are planning on accessing through this pointer,
-+    /// may still invalidate this pointer.
-+    /// See the second example below for how this guarantee can be used.
-+    ///
-+    ///
-     /// # Examples
-     ///
-     /// ```
-@@ -1382,7 +1418,25 @@ pub fn as_ptr(&self) -> *const T {
-     /// }
-     /// assert_eq!(&*x, &[0, 1, 2, 3]);
-     /// ```
-+    ///
-+    /// Due to the aliasing guarantee, the following code is legal:
-+    ///
-+    /// ```rust
-+    /// unsafe {
-+    ///     let mut v = vec![0];
-+    ///     let ptr1 = v.as_mut_ptr();
-+    ///     ptr1.write(1);
-+    ///     let ptr2 = v.as_mut_ptr();
-+    ///     ptr2.write(2);
-+    ///     // Notably, the write to `ptr2` did *not* invalidate `ptr1`:
-+    ///     ptr1.write(3);
-+    /// }
-+    /// ```
-+    ///
-+    /// [`as_mut_ptr`]: Vec::as_mut_ptr
-+    /// [`as_ptr`]: Vec::as_ptr
-     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
-+    #[rustc_never_returns_null_ptr]
-     #[inline]
-     pub fn as_mut_ptr(&mut self) -> *mut T {
-         // We shadow the slice method of the same name to avoid going through
-@@ -1511,7 +1565,8 @@ pub unsafe fn set_len(&mut self, new_len: usize) {
-     #[stable(feature = "rust1", since = "1.0.0")]
-     pub fn swap_remove(&mut self, index: usize) -> T {
-         #[cold]
--        #[inline(never)]
-+        #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
-+        #[track_caller]
-         fn assert_failed(index: usize, len: usize) -> ! {
-             panic!("swap_remove index (is {index}) should be < len (is {len})");
-         }
-@@ -1552,7 +1607,8 @@ fn assert_failed(index: usize, len: usize) -> ! {
-     #[stable(feature = "rust1", since = "1.0.0")]
-     pub fn insert(&mut self, index: usize, element: T) {
-         #[cold]
--        #[inline(never)]
-+        #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
-+        #[track_caller]
-         fn assert_failed(index: usize, len: usize) -> ! {
-             panic!("insertion index (is {index}) should be <= len (is {len})");
-         }
-@@ -1613,7 +1669,7 @@ fn assert_failed(index: usize, len: usize) -> ! {
-     #[track_caller]
-     pub fn remove(&mut self, index: usize) -> T {
-         #[cold]
--        #[inline(never)]
-+        #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
-         #[track_caller]
-         fn assert_failed(index: usize, len: usize) -> ! {
-             panic!("removal index (is {index}) should be < len (is {len})");
-@@ -2043,6 +2099,7 @@ pub fn pop(&mut self) -> Option<T> {
-         } else {
-             unsafe {
-                 self.len -= 1;
-+                core::intrinsics::assume(self.len < self.capacity());
-                 Some(ptr::read(self.as_ptr().add(self.len())))
-             }
-         }
-@@ -2245,7 +2302,8 @@ pub fn split_off(&mut self, at: usize) -> Self
-         A: Clone,
-     {
-         #[cold]
--        #[inline(never)]
-+        #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
-+        #[track_caller]
-         fn assert_failed(at: usize, len: usize) -> ! {
-             panic!("`at` split index (is {at}) should be <= len (is {len})");
-         }
-@@ -2507,7 +2565,7 @@ pub fn resize(&mut self, new_len: usize, value: T) {
-         let len = self.len();
- 
-         if new_len > len {
--            self.extend_with(new_len - len, ExtendElement(value))
-+            self.extend_with(new_len - len, value)
-         } else {
-             self.truncate(new_len);
-         }
-@@ -2545,7 +2603,7 @@ pub fn try_resize(&mut self, new_len: usize, value: T) -> Result<(), TryReserveE
-         let len = self.len();
- 
-         if new_len > len {
--            self.try_extend_with(new_len - len, ExtendElement(value))
-+            self.try_extend_with(new_len - len, value)
-         } else {
-             self.truncate(new_len);
-             Ok(())
-@@ -2684,26 +2742,10 @@ pub fn into_flattened(self) -> Vec<T, A> {
-     }
- }
- 
--// This code generalizes `extend_with_{element,default}`.
--trait ExtendWith<T> {
--    fn next(&mut self) -> T;
--    fn last(self) -> T;
--}
--
--struct ExtendElement<T>(T);
--impl<T: Clone> ExtendWith<T> for ExtendElement<T> {
--    fn next(&mut self) -> T {
--        self.0.clone()
--    }
--    fn last(self) -> T {
--        self.0
--    }
--}
--
--impl<T, A: Allocator> Vec<T, A> {
-+impl<T: Clone, A: Allocator> Vec<T, A> {
-     #[cfg(not(no_global_oom_handling))]
--    /// Extend the vector by `n` values, using the given generator.
--    fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) {
-+    /// Extend the vector by `n` clones of value.
-+    fn extend_with(&mut self, n: usize, value: T) {
-         self.reserve(n);
- 
-         unsafe {
-@@ -2715,15 +2757,15 @@ fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) {
- 
-             // Write all elements except the last one
-             for _ in 1..n {
--                ptr::write(ptr, value.next());
-+                ptr::write(ptr, value.clone());
-                 ptr = ptr.add(1);
--                // Increment the length in every step in case next() panics
-+                // Increment the length in every step in case clone() panics
-                 local_len.increment_len(1);
-             }
- 
-             if n > 0 {
-                 // We can write the last element directly without cloning needlessly
--                ptr::write(ptr, value.last());
-+                ptr::write(ptr, value);
-                 local_len.increment_len(1);
-             }
- 
-@@ -2731,8 +2773,8 @@ fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) {
-         }
-     }
- 
--    /// Try to extend the vector by `n` values, using the given generator.
--    fn try_extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) -> Result<(), TryReserveError> {
-+    /// Try to extend the vector by `n` clones of value.
-+    fn try_extend_with(&mut self, n: usize, value: T) -> Result<(), TryReserveError> {
-         self.try_reserve(n)?;
- 
-         unsafe {
-@@ -2744,15 +2786,15 @@ fn try_extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) -> Resul
- 
-             // Write all elements except the last one
-             for _ in 1..n {
--                ptr::write(ptr, value.next());
-+                ptr::write(ptr, value.clone());
-                 ptr = ptr.add(1);
--                // Increment the length in every step in case next() panics
-+                // Increment the length in every step in case clone() panics
-                 local_len.increment_len(1);
-             }
- 
-             if n > 0 {
-                 // We can write the last element directly without cloning needlessly
--                ptr::write(ptr, value.last());
-+                ptr::write(ptr, value);
-                 local_len.increment_len(1);
-             }
- 
-@@ -3210,6 +3252,12 @@ pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoI
-     /// If the closure returns false, the element will remain in the vector and will not be yielded
-     /// by the iterator.
-     ///
-+    /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
-+    /// or the iteration short-circuits, then the remaining elements will be retained.
-+    /// Use [`retain`] with a negated predicate if you do not need the returned iterator.
-+    ///
-+    /// [`retain`]: Vec::retain
-+    ///
-     /// Using this method is equivalent to the following code:
-     ///
-     /// ```
-@@ -3228,10 +3276,10 @@ pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoI
-     /// # assert_eq!(vec, vec![1, 4, 5]);
-     /// ```
-     ///
--    /// But `drain_filter` is easier to use. `drain_filter` is also more efficient,
-+    /// But `extract_if` is easier to use. `extract_if` is also more efficient,
-     /// because it can backshift the elements of the array in bulk.
-     ///
--    /// Note that `drain_filter` also lets you mutate every element in the filter closure,
-+    /// Note that `extract_if` also lets you mutate every element in the filter closure,
-     /// regardless of whether you choose to keep or remove it.
-     ///
-     /// # Examples
-@@ -3239,17 +3287,17 @@ pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoI
-     /// Splitting an array into evens and odds, reusing the original allocation:
-     ///
-     /// ```
--    /// #![feature(drain_filter)]
-+    /// #![feature(extract_if)]
-     /// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
-     ///
--    /// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
-+    /// let evens = numbers.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
-     /// let odds = numbers;
-     ///
-     /// assert_eq!(evens, vec![2, 4, 6, 8, 14]);
-     /// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
-     /// ```
--    #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
--    pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
-+    #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
-+    pub fn extract_if<F>(&mut self, filter: F) -> ExtractIf<'_, T, F, A>
-     where
-         F: FnMut(&mut T) -> bool,
-     {
-@@ -3260,7 +3308,7 @@ pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
-             self.set_len(0);
-         }
- 
--        DrainFilter { vec: self, idx: 0, del: 0, old_len, pred: filter, panic_flag: false }
-+        ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter }
-     }
- }
- 
-@@ -3272,7 +3320,7 @@ pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
- /// [`copy_from_slice`]: slice::copy_from_slice
- #[cfg(not(no_global_oom_handling))]
- #[stable(feature = "extend_ref", since = "1.2.0")]
--impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec<T, A> {
-+impl<'a, T: Copy + 'a, A: Allocator> Extend<&'a T> for Vec<T, A> {
-     fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
-         self.spec_extend(iter.into_iter())
-     }
-@@ -3290,9 +3338,14 @@ fn extend_reserve(&mut self, additional: usize) {
- 
- /// Implements comparison of vectors, [lexicographically](Ord#lexicographical-comparison).
- #[stable(feature = "rust1", since = "1.0.0")]
--impl<T: PartialOrd, A: Allocator> PartialOrd for Vec<T, A> {
-+impl<T, A1, A2> PartialOrd<Vec<T, A2>> for Vec<T, A1>
-+where
-+    T: PartialOrd,
-+    A1: Allocator,
-+    A2: Allocator,
-+{
-     #[inline]
--    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-+    fn partial_cmp(&self, other: &Vec<T, A2>) -> Option<Ordering> {
-         PartialOrd::partial_cmp(&**self, &**other)
-     }
- }
-@@ -3407,6 +3460,36 @@ fn from(s: &mut [T]) -> Vec<T> {
-     }
- }
- 
-+#[cfg(not(no_global_oom_handling))]
-+#[stable(feature = "vec_from_array_ref", since = "1.74.0")]
-+impl<T: Clone, const N: usize> From<&[T; N]> for Vec<T> {
-+    /// Allocate a `Vec<T>` and fill it by cloning `s`'s items.
-+    ///
-+    /// # Examples
-+    ///
-+    /// ```
-+    /// assert_eq!(Vec::from(&[1, 2, 3]), vec![1, 2, 3]);
-+    /// ```
-+    fn from(s: &[T; N]) -> Vec<T> {
-+        Self::from(s.as_slice())
-+    }
-+}
-+
-+#[cfg(not(no_global_oom_handling))]
-+#[stable(feature = "vec_from_array_ref", since = "1.74.0")]
-+impl<T: Clone, const N: usize> From<&mut [T; N]> for Vec<T> {
-+    /// Allocate a `Vec<T>` and fill it by cloning `s`'s items.
-+    ///
-+    /// # Examples
-+    ///
-+    /// ```
-+    /// assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]);
-+    /// ```
-+    fn from(s: &mut [T; N]) -> Vec<T> {
-+        Self::from(s.as_mut_slice())
-+    }
-+}
-+
- #[cfg(not(no_global_oom_handling))]
- #[stable(feature = "vec_from_array", since = "1.44.0")]
- impl<T, const N: usize> From<[T; N]> for Vec<T> {
-diff --git a/rust/alloc/vec/spec_extend.rs b/rust/alloc/vec/spec_extend.rs
-index a6a735201e59..ada919537446 100644
---- a/rust/alloc/vec/spec_extend.rs
-+++ b/rust/alloc/vec/spec_extend.rs
-@@ -77,7 +77,7 @@ fn try_spec_extend(&mut self, mut iterator: IntoIter<T>) -> Result<(), TryReserv
- }
- 
- #[cfg(not(no_global_oom_handling))]
--impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec<T, A>
-+impl<'a, T: 'a, I, A: Allocator> SpecExtend<&'a T, I> for Vec<T, A>
- where
-     I: Iterator<Item = &'a T>,
-     T: Clone,
-@@ -87,7 +87,7 @@ impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec<T, A>
-     }
- }
- 
--impl<'a, T: 'a, I, A: Allocator + 'a> TrySpecExtend<&'a T, I> for Vec<T, A>
-+impl<'a, T: 'a, I, A: Allocator> TrySpecExtend<&'a T, I> for Vec<T, A>
- where
-     I: Iterator<Item = &'a T>,
-     T: Clone,
-@@ -98,7 +98,7 @@ impl<'a, T: 'a, I, A: Allocator + 'a> TrySpecExtend<&'a T, I> for Vec<T, A>
- }
- 
- #[cfg(not(no_global_oom_handling))]
--impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
-+impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
- where
-     T: Copy,
- {
-@@ -108,7 +108,7 @@ fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) {
-     }
- }
- 
--impl<'a, T: 'a, A: Allocator + 'a> TrySpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
-+impl<'a, T: 'a, A: Allocator> TrySpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
- where
-     T: Copy,
- {
--- 
-2.42.0
-
diff --git a/modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/config b/modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/config
index 18639f02111b..12faa5e4eded 100644
--- a/modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/config
+++ b/modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/config
@@ -7803,7 +7803,7 @@ CONFIG_RUST=y
 CONFIG_RUST_OVERFLOW_CHECKS=y
 # CONFIG_SPI_HID_APPLE_OF is not set
 # CONFIG_USB_XHCI_PCI_ASMEDIA is not set
-# CONFIG_APPLE_MAILBOX is not set
+CONFIG_APPLE_MAILBOX=y
 # CONFIG_APPLE_PMGR_MISC is not set
 CONFIG_ARM64_MEMORY_MODEL_CONTROL=y
 # CONFIG_ARM_APPLE_CPUIDLE is not set
@@ -7813,7 +7813,6 @@ CONFIG_USB_XHCI_PCI_ASMEDIA=y
 CONFIG_SND_SOC_CS42L84=m
 CONFIG_TOUCHSCREEN_APPLE_Z2=m
 CONFIG_APPLE_DOCKCHANNEL=m
-CONFIG_APPLE_MBOX=y
 CONFIG_APPLE_PLATFORMS=y
 CONFIG_APPLE_PMGR_MISC=y
 CONFIG_APPLE_RTKIT=y
@@ -7824,6 +7823,7 @@ CONFIG_ARM_APPLE_CPUIDLE=y
 CONFIG_CHARGER_MACSMC=m
 CONFIG_DRM_ADP=m
 CONFIG_DRM_APPLE=m
+CONFIG_DRM_APPLE_AUDIO=y
 CONFIG_DRM_ASAHI=m
 # CONFIG_DRM_ASAHI_DEBUG_ALLOCATOR is not set
 CONFIG_GPIO_MACSMC=m
@@ -7843,3 +7843,4 @@ CONFIG_SPI_HID_APPLE_OF=m
 CONFIG_SPMI_APPLE=m
 CONFIG_VIDEO_APPLE_ISP=m
 CONFIG_SND_SOC_CS42L84=m
+CONFIG_APPLE_SIO=m
diff --git a/modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/default.nix b/modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/default.nix
index 2f1d490277be..917e67c286ca 100644
--- a/modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/default.nix
+++ b/modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/default.nix
@@ -3,7 +3,6 @@
 , callPackage
 , writeShellScriptBin
 , writeText
-, removeReferencesTo
 , linuxPackagesFor
 , withRust ? false
 , _kernelPatches ? [ ]
@@ -87,16 +86,16 @@ let
     (linuxKernel.manualConfig rec {
       inherit stdenv lib;
 
-      version = "6.6.0-asahi";
+      version = "6.8.9-asahi";
       modDirVersion = version;
-      extraMeta.branch = "6.6";
+      extraMeta.branch = "6.8";
 
       src = fetchFromGitHub {
         # tracking: https://github.com/AsahiLinux/linux/tree/asahi-wip (w/ fedora verification)
         owner = "AsahiLinux";
         repo = "linux";
-        rev = "asahi-6.6-16";
-        hash = "sha256-73ye5JE3YKRgrxGfdQN0+YMIVO1QAJeDuUjTcFhcwI0=";
+        rev = "asahi-6.8.9-6";
+        hash = "sha256-qDxO6gXHTNcUWfa1YnoqZz1/eOg26JLnTTvTrxSbDAc=";
       };
 
       kernelPatches = [
@@ -117,14 +116,6 @@ let
             hash = "sha256-wn5x2hN42/kCp/XHBvLWeNLfwlOBB+T6UeeMt2tSg3o=";
           };
         }
-      ] ++ lib.optionals (rustAtLeast "1.75.0") [
-        { name = "rustc-1.75.0";
-          patch = ./0001-check-in-new-alloc-for-1.75.0.patch;
-        }
-      ] ++ lib.optionals (rustAtLeast "1.76.0") [
-        { name = "rustc-1.76.0";
-          patch = ./rust_1_76_0.patch;
-        }
       ] ++ _kernelPatches;
 
       inherit configfile;
@@ -136,16 +127,7 @@ let
         rust-bindgen
         rustfmt
         rustc
-        removeReferencesTo
       ];
-      # HACK: references shouldn't have been there in the first place
-      # TODO: remove once 23.05 is obsolete
-      postFixup = (old.postFixup or "") + ''
-        if [ -f $dev/lib/modules/${old.version}/build/vmlinux ]; then
-          remove-references-to -t $out $dev/lib/modules/${old.version}/build/vmlinux
-        fi
-        remove-references-to -t $dev $out/Image
-      '';
       RUST_LIB_SRC = rustPlatform.rustLibSrc;
     } else {});
 
diff --git a/modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/rust_1_76_0.patch b/modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/rust_1_76_0.patch
deleted file mode 100644
index 0ede15025298..000000000000
--- a/modules/nixos-apple-silicon/apple-silicon-support/packages/linux-asahi/rust_1_76_0.patch
+++ /dev/null
@@ -1,426 +0,0 @@
-diff --git a/rust/alloc/alloc.rs b/rust/alloc/alloc.rs
-index 08eafb3de807..7cf4edb8b786 100644
---- a/rust/alloc/alloc.rs
-+++ b/rust/alloc/alloc.rs
-@@ -426,12 +426,14 @@ pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
-     }
- }
- 
-+#[cfg(not(no_global_oom_handling))]
- /// Specialize clones into pre-allocated, uninitialized memory.
- /// Used by `Box::clone` and `Rc`/`Arc::make_mut`.
- pub(crate) trait WriteCloneIntoRaw: Sized {
-     unsafe fn write_clone_into_raw(&self, target: *mut Self);
- }
- 
-+#[cfg(not(no_global_oom_handling))]
- impl<T: Clone> WriteCloneIntoRaw for T {
-     #[inline]
-     default unsafe fn write_clone_into_raw(&self, target: *mut Self) {
-@@ -441,6 +443,7 @@ impl<T: Clone> WriteCloneIntoRaw for T {
-     }
- }
- 
-+#[cfg(not(no_global_oom_handling))]
- impl<T: Copy> WriteCloneIntoRaw for T {
-     #[inline]
-     unsafe fn write_clone_into_raw(&self, target: *mut Self) {
-diff --git a/rust/alloc/boxed.rs b/rust/alloc/boxed.rs
-index ed7e2f666178..359b8bcdb7a2 100644
---- a/rust/alloc/boxed.rs
-+++ b/rust/alloc/boxed.rs
-@@ -1030,10 +1030,18 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
-     /// use std::ptr;
-     ///
-     /// let x = Box::new(String::from("Hello"));
--    /// let p = Box::into_raw(x);
-+    /// let ptr = Box::into_raw(x);
-+    /// unsafe {
-+    ///     ptr::drop_in_place(ptr);
-+    ///     dealloc(ptr as *mut u8, Layout::new::<String>());
-+    /// }
-+    /// ```
-+    /// Note: This is equivalent to the following:
-+    /// ```
-+    /// let x = Box::new(String::from("Hello"));
-+    /// let ptr = Box::into_raw(x);
-     /// unsafe {
--    ///     ptr::drop_in_place(p);
--    ///     dealloc(p as *mut u8, Layout::new::<String>());
-+    ///     drop(Box::from_raw(ptr));
-     /// }
-     /// ```
-     ///
-diff --git a/rust/alloc/collections/mod.rs b/rust/alloc/collections/mod.rs
-index 2506065d158a..00ffb3b97365 100644
---- a/rust/alloc/collections/mod.rs
-+++ b/rust/alloc/collections/mod.rs
-@@ -150,6 +150,7 @@ fn fmt(
- 
- /// An intermediate trait for specialization of `Extend`.
- #[doc(hidden)]
-+#[cfg(not(no_global_oom_handling))]
- trait SpecExtend<I: IntoIterator> {
-     /// Extends `self` with the contents of the given iterator.
-     fn spec_extend(&mut self, iter: I);
-diff --git a/rust/alloc/lib.rs b/rust/alloc/lib.rs
-index 65b7a02d0956..6cddaf298118 100644
---- a/rust/alloc/lib.rs
-+++ b/rust/alloc/lib.rs
-@@ -157,6 +157,7 @@
- #![feature(std_internals)]
- #![feature(str_internals)]
- #![feature(strict_provenance)]
-+#![feature(trusted_fused)]
- #![feature(trusted_len)]
- #![feature(trusted_random_access)]
- #![feature(try_trait_v2)]
-@@ -276,7 +277,7 @@ pub(crate) mod test_helpers {
-     /// seed not being the same for every RNG invocation too.
-     pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
-         use std::hash::{BuildHasher, Hash, Hasher};
--        let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
-+        let mut hasher = std::hash::RandomState::new().build_hasher();
-         std::panic::Location::caller().hash(&mut hasher);
-         let hc64 = hasher.finish();
-         let seed_vec =
-diff --git a/rust/alloc/raw_vec.rs b/rust/alloc/raw_vec.rs
-index 65d5ce15828e..3fb1ee104cff 100644
---- a/rust/alloc/raw_vec.rs
-+++ b/rust/alloc/raw_vec.rs
-@@ -27,6 +27,16 @@ enum AllocInit {
-     Zeroed,
- }
- 
-+#[repr(transparent)]
-+#[cfg_attr(target_pointer_width = "16", rustc_layout_scalar_valid_range_end(0x7fff))]
-+#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0x7fff_ffff))]
-+#[cfg_attr(target_pointer_width = "64", rustc_layout_scalar_valid_range_end(0x7fff_ffff_ffff_ffff))]
-+struct Cap(usize);
-+
-+impl Cap {
-+    const ZERO: Cap = unsafe { Cap(0) };
-+}
-+
- /// A low-level utility for more ergonomically allocating, reallocating, and deallocating
- /// a buffer of memory on the heap without having to worry about all the corner cases
- /// involved. This type is excellent for building your own data structures like Vec and VecDeque.
-@@ -52,7 +62,12 @@ enum AllocInit {
- #[allow(missing_debug_implementations)]
- pub(crate) struct RawVec<T, A: Allocator = Global> {
-     ptr: Unique<T>,
--    cap: usize,
-+    /// Never used for ZSTs; it's `capacity()`'s responsibility to return usize::MAX in that case.
-+    ///
-+    /// # Safety
-+    ///
-+    /// `cap` must be in the `0..=isize::MAX` range.
-+    cap: Cap,
-     alloc: A,
- }
- 
-@@ -121,7 +136,7 @@ impl<T, A: Allocator> RawVec<T, A> {
-     /// the returned `RawVec`.
-     pub const fn new_in(alloc: A) -> Self {
-         // `cap: 0` means "unallocated". zero-sized types are ignored.
--        Self { ptr: Unique::dangling(), cap: 0, alloc }
-+        Self { ptr: Unique::dangling(), cap: Cap::ZERO, alloc }
-     }
- 
-     /// Like `with_capacity`, but parameterized over the choice of
-@@ -203,7 +218,7 @@ fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self {
-             // here should change to `ptr.len() / mem::size_of::<T>()`.
-             Self {
-                 ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) },
--                cap: capacity,
-+                cap: unsafe { Cap(capacity) },
-                 alloc,
-             }
-         }
-@@ -228,7 +243,7 @@ fn try_allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Result<Self, T
-         // here should change to `ptr.len() / mem::size_of::<T>()`.
-         Ok(Self {
-             ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) },
--            cap: capacity,
-+            cap: unsafe { Cap(capacity) },
-             alloc,
-         })
-     }
-@@ -240,12 +255,13 @@ fn try_allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Result<Self, T
-     /// The `ptr` must be allocated (via the given allocator `alloc`), and with the given
-     /// `capacity`.
-     /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit
--    /// systems). ZST vectors may have a capacity up to `usize::MAX`.
-+    /// systems). For ZSTs capacity is ignored.
-     /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is
-     /// guaranteed.
-     #[inline]
-     pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self {
--        Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap: capacity, alloc }
-+        let cap = if T::IS_ZST { Cap::ZERO } else { unsafe { Cap(capacity) } };
-+        Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap, alloc }
-     }
- 
-     /// Gets a raw pointer to the start of the allocation. Note that this is
-@@ -261,7 +277,7 @@ pub fn ptr(&self) -> *mut T {
-     /// This will always be `usize::MAX` if `T` is zero-sized.
-     #[inline(always)]
-     pub fn capacity(&self) -> usize {
--        if T::IS_ZST { usize::MAX } else { self.cap }
-+        if T::IS_ZST { usize::MAX } else { self.cap.0 }
-     }
- 
-     /// Returns a shared reference to the allocator backing this `RawVec`.
-@@ -270,7 +286,7 @@ pub fn allocator(&self) -> &A {
-     }
- 
-     fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
--        if T::IS_ZST || self.cap == 0 {
-+        if T::IS_ZST || self.cap.0 == 0 {
-             None
-         } else {
-             // We could use Layout::array here which ensures the absence of isize and usize overflows
-@@ -280,7 +296,7 @@ fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
-             let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
-             unsafe {
-                 let align = mem::align_of::<T>();
--                let size = mem::size_of::<T>().unchecked_mul(self.cap);
-+                let size = mem::size_of::<T>().unchecked_mul(self.cap.0);
-                 let layout = Layout::from_size_align_unchecked(size, align);
-                 Some((self.ptr.cast().into(), layout))
-             }
-@@ -404,12 +420,15 @@ fn needs_to_grow(&self, len: usize, additional: usize) -> bool {
-         additional > self.capacity().wrapping_sub(len)
-     }
- 
--    fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) {
-+    /// # Safety:
-+    ///
-+    /// `cap` must not exceed `isize::MAX`.
-+    unsafe fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) {
-         // Allocators currently return a `NonNull<[u8]>` whose length matches
-         // the size requested. If that ever changes, the capacity here should
-         // change to `ptr.len() / mem::size_of::<T>()`.
-         self.ptr = unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) };
--        self.cap = cap;
-+        self.cap = unsafe { Cap(cap) };
-     }
- 
-     // This method is usually instantiated many times. So we want it to be as
-@@ -434,14 +453,15 @@ fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryRes
- 
-         // This guarantees exponential growth. The doubling cannot overflow
-         // because `cap <= isize::MAX` and the type of `cap` is `usize`.
--        let cap = cmp::max(self.cap * 2, required_cap);
-+        let cap = cmp::max(self.cap.0 * 2, required_cap);
-         let cap = cmp::max(Self::MIN_NON_ZERO_CAP, cap);
- 
-         let new_layout = Layout::array::<T>(cap);
- 
-         // `finish_grow` is non-generic over `T`.
-         let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
--        self.set_ptr_and_cap(ptr, cap);
-+        // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than isize::MAX items
-+        unsafe { self.set_ptr_and_cap(ptr, cap) };
-         Ok(())
-     }
- 
-@@ -460,7 +480,10 @@ fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserve
- 
-         // `finish_grow` is non-generic over `T`.
-         let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
--        self.set_ptr_and_cap(ptr, cap);
-+        // SAFETY: finish_grow would have resulted in a capacity overflow if we tried to allocate more than isize::MAX items
-+        unsafe {
-+            self.set_ptr_and_cap(ptr, cap);
-+        }
-         Ok(())
-     }
- 
-diff --git a/rust/alloc/vec/into_iter.rs b/rust/alloc/vec/into_iter.rs
-index aac0ec16aef1..136bfe94af6c 100644
---- a/rust/alloc/vec/into_iter.rs
-+++ b/rust/alloc/vec/into_iter.rs
-@@ -9,7 +9,8 @@
- use core::array;
- use core::fmt;
- use core::iter::{
--    FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce,
-+    FusedIterator, InPlaceIterable, SourceIter, TrustedFused, TrustedLen,
-+    TrustedRandomAccessNoCoerce,
- };
- use core::marker::PhantomData;
- use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
-@@ -287,9 +288,7 @@ unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
-         // Also note the implementation of `Self: TrustedRandomAccess` requires
-         // that `T: Copy` so reading elements from the buffer doesn't invalidate
-         // them for `Drop`.
--        unsafe {
--            if T::IS_ZST { mem::zeroed() } else { ptr::read(self.ptr.add(i)) }
--        }
-+        unsafe { if T::IS_ZST { mem::zeroed() } else { ptr::read(self.ptr.add(i)) } }
-     }
- }
- 
-@@ -341,6 +340,10 @@ fn is_empty(&self) -> bool {
- #[stable(feature = "fused", since = "1.26.0")]
- impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {}
- 
-+#[doc(hidden)]
-+#[unstable(issue = "none", feature = "trusted_fused")]
-+unsafe impl<T, A: Allocator> TrustedFused for IntoIter<T, A> {}
-+
- #[unstable(feature = "trusted_len", issue = "37572")]
- unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {}
- 
-@@ -425,7 +428,10 @@ fn drop(&mut self) {
- // also refer to the vec::in_place_collect module documentation to get an overview
- #[unstable(issue = "none", feature = "inplace_iteration")]
- #[doc(hidden)]
--unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {}
-+unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {
-+    const EXPAND_BY: Option<NonZeroUsize> = NonZeroUsize::new(1);
-+    const MERGE_BY: Option<NonZeroUsize> = NonZeroUsize::new(1);
-+}
- 
- #[unstable(issue = "none", feature = "inplace_iteration")]
- #[doc(hidden)]
-diff --git a/rust/alloc/vec/mod.rs b/rust/alloc/vec/mod.rs
-index 05c70de0227e..2534ec65500e 100644
---- a/rust/alloc/vec/mod.rs
-+++ b/rust/alloc/vec/mod.rs
-@@ -105,6 +105,7 @@
- #[cfg(not(no_global_oom_handling))]
- use self::is_zero::IsZero;
- 
-+#[cfg(not(no_global_oom_handling))]
- mod is_zero;
- 
- #[cfg(not(no_global_oom_handling))]
-@@ -123,7 +124,7 @@
- mod set_len_on_drop;
- 
- #[cfg(not(no_global_oom_handling))]
--use self::in_place_drop::{InPlaceDrop, InPlaceDstBufDrop};
-+use self::in_place_drop::{InPlaceDrop, InPlaceDstDataSrcBufDrop};
- 
- #[cfg(not(no_global_oom_handling))]
- mod in_place_drop;
-@@ -1837,7 +1838,32 @@ pub fn dedup_by<F>(&mut self, mut same_bucket: F)
-             return;
-         }
- 
--        /* INVARIANT: vec.len() > read >= write > write-1 >= 0 */
-+        // Check if we ever want to remove anything.
-+        // This allows to use copy_non_overlapping in next cycle.
-+        // And avoids any memory writes if we don't need to remove anything.
-+        let mut first_duplicate_idx: usize = 1;
-+        let start = self.as_mut_ptr();
-+        while first_duplicate_idx != len {
-+            let found_duplicate = unsafe {
-+                // SAFETY: first_duplicate always in range [1..len)
-+                // Note that we start iteration from 1 so we never overflow.
-+                let prev = start.add(first_duplicate_idx.wrapping_sub(1));
-+                let current = start.add(first_duplicate_idx);
-+                // We explicitly say in docs that references are reversed.
-+                same_bucket(&mut *current, &mut *prev)
-+            };
-+            if found_duplicate {
-+                break;
-+            }
-+            first_duplicate_idx += 1;
-+        }
-+        // Don't need to remove anything.
-+        // We cannot get bigger than len.
-+        if first_duplicate_idx == len {
-+            return;
-+        }
-+
-+        /* INVARIANT: vec.len() > read > write > write-1 >= 0 */
-         struct FillGapOnDrop<'a, T, A: core::alloc::Allocator> {
-             /* Offset of the element we want to check if it is duplicate */
-             read: usize,
-@@ -1883,31 +1909,39 @@ fn drop(&mut self) {
-             }
-         }
- 
--        let mut gap = FillGapOnDrop { read: 1, write: 1, vec: self };
--        let ptr = gap.vec.as_mut_ptr();
--
-         /* Drop items while going through Vec, it should be more efficient than
-          * doing slice partition_dedup + truncate */
- 
-+        // Construct gap first and then drop item to avoid memory corruption if `T::drop` panics.
-+        let mut gap =
-+            FillGapOnDrop { read: first_duplicate_idx + 1, write: first_duplicate_idx, vec: self };
-+        unsafe {
-+            // SAFETY: we checked that first_duplicate_idx in bounds before.
-+            // If drop panics, `gap` would remove this item without drop.
-+            ptr::drop_in_place(start.add(first_duplicate_idx));
-+        }
-+
-         /* SAFETY: Because of the invariant, read_ptr, prev_ptr and write_ptr
-          * are always in-bounds and read_ptr never aliases prev_ptr */
-         unsafe {
-             while gap.read < len {
--                let read_ptr = ptr.add(gap.read);
--                let prev_ptr = ptr.add(gap.write.wrapping_sub(1));
-+                let read_ptr = start.add(gap.read);
-+                let prev_ptr = start.add(gap.write.wrapping_sub(1));
- 
--                if same_bucket(&mut *read_ptr, &mut *prev_ptr) {
-+                // We explicitly say in docs that references are reversed.
-+                let found_duplicate = same_bucket(&mut *read_ptr, &mut *prev_ptr);
-+                if found_duplicate {
-                     // Increase `gap.read` now since the drop may panic.
-                     gap.read += 1;
-                     /* We have found duplicate, drop it in-place */
-                     ptr::drop_in_place(read_ptr);
-                 } else {
--                    let write_ptr = ptr.add(gap.write);
-+                    let write_ptr = start.add(gap.write);
- 
--                    /* Because `read_ptr` can be equal to `write_ptr`, we either
--                     * have to use `copy` or conditional `copy_nonoverlapping`.
--                     * Looks like the first option is faster. */
--                    ptr::copy(read_ptr, write_ptr, 1);
-+                    /* read_ptr cannot be equal to write_ptr because at this point
-+                     * we guaranteed to skip at least one element (before loop starts).
-+                     */
-+                    ptr::copy_nonoverlapping(read_ptr, write_ptr, 1);
- 
-                     /* We have filled that place, so go further */
-                     gap.write += 1;
-@@ -2802,6 +2836,7 @@ pub fn from_elem_in<T: Clone, A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<
-     <T as SpecFromElem>::from_elem(elem, n, alloc)
- }
- 
-+#[cfg(not(no_global_oom_handling))]
- trait ExtendFromWithinSpec {
-     /// # Safety
-     ///
-@@ -2810,6 +2845,7 @@ trait ExtendFromWithinSpec {
-     unsafe fn spec_extend_from_within(&mut self, src: Range<usize>);
- }
- 
-+#[cfg(not(no_global_oom_handling))]
- impl<T: Clone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
-     default unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) {
-         // SAFETY:
-@@ -2829,6 +2865,7 @@ impl<T: Clone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
-     }
- }
- 
-+#[cfg(not(no_global_oom_handling))]
- impl<T: Copy, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
-     unsafe fn spec_extend_from_within(&mut self, src: Range<usize>) {
-         let count = src.len();
-@@ -2909,7 +2946,7 @@ fn clone_from(&mut self, other: &Self) {
- /// ```
- /// use std::hash::BuildHasher;
- ///
--/// let b = std::collections::hash_map::RandomState::new();
-+/// let b = std::hash::RandomState::new();
- /// let v: Vec<u8> = vec![0xa8, 0x3c, 0x09];
- /// let s: &[u8] = &[0xa8, 0x3c, 0x09];
- /// assert_eq!(b.hash_one(v), b.hash_one(s));
diff --git a/modules/nixos-apple-silicon/apple-silicon-support/packages/m1n1/default.nix b/modules/nixos-apple-silicon/apple-silicon-support/packages/m1n1/default.nix
index 86a8bcdf8bc8..d758f218565a 100644
--- a/modules/nixos-apple-silicon/apple-silicon-support/packages/m1n1/default.nix
+++ b/modules/nixos-apple-silicon/apple-silicon-support/packages/m1n1/default.nix
@@ -25,14 +25,14 @@ let
   });
 in stdenv.mkDerivation rec {
   pname = "m1n1";
-  version = "1.4.11";
+  version = "1.4.12";
 
   src = fetchFromGitHub {
     # tracking: https://src.fedoraproject.org/rpms/m1n1
     owner = "AsahiLinux";
     repo = "m1n1";
     rev = "v${version}";
-    hash = "sha256-1lWI9tcOxgrcfaPfdSF+xRE9qofhNR3SQiA4h86VVeE=";
+    hash = "sha256-ZIrNL2+5gWrT3Woz4Nab6M9xvGjIE2Md8/cfPo5rfFQ=";
     fetchSubmodules = true;
   };
 
diff --git a/modules/nixos-apple-silicon/apple-silicon-support/packages/uboot-asahi/default.nix b/modules/nixos-apple-silicon/apple-silicon-support/packages/uboot-asahi/default.nix
index 02075891677d..a73984356d97 100644
--- a/modules/nixos-apple-silicon/apple-silicon-support/packages/uboot-asahi/default.nix
+++ b/modules/nixos-apple-silicon/apple-silicon-support/packages/uboot-asahi/default.nix
@@ -9,10 +9,10 @@
     # tracking: https://pagure.io/fedora-asahi/uboot-tools/commits/main
     owner = "AsahiLinux";
     repo = "u-boot";
-    rev = "asahi-v2023.07.02-4";
-    hash = "sha256-M4qkEyNgwV2AKSr5VzPGfhHo1kGy8Tw8TfyP36cgYjc=";
+    rev = "c134629a8bc448e979967bf0632fdd5bb42ee1d7";
+    hash = "sha256-EPdpyvblkvQrMCiPjX3Bnqp8s/3Yd/gYM1PQu4PDMhs=";
   };
-  version = "2023.07.02.asahi4-1";
+  version = "2024.04-4-asahi";
 
   defconfig = "apple_m1_defconfig";
   extraMeta.platforms = [ "aarch64-linux" ];
diff --git a/modules/nixos-apple-silicon/docs/release-notes.md b/modules/nixos-apple-silicon/docs/release-notes.md
index 0dd0d4e90aba..be317daf57ea 100644
--- a/modules/nixos-apple-silicon/docs/release-notes.md
+++ b/modules/nixos-apple-silicon/docs/release-notes.md
@@ -2,6 +2,57 @@
 
 This file contains important information for each release.
 
+## 2024-05-17
+
+This release updates nixpkgs and the kernel.
+
+**This release fixes a data corruption bug for dm-crypt users.**
+* The bug apparently only affects dm-crypt block devices and was introduced in
+  the 6.8 kernel update in release 2024-04-27. Users who don't use dm-crypt, or
+  who haven't upgraded to 2024-04-27 or 2024-05-14, are not at risk.
+* The Nix store can be checked for corruption using the command
+  `nix-store --verify --check-contents`; this will take a while and should
+  complete without any error messages.
+* If corruption is detected, whether in the store or elsewhere, a complete
+  backup, reformat, and reinstall of the affected filesystem is recommended.
+* Thanks to flokli for the initial report, mixi for identifying the issue, and
+  others for their help!
+* More info available [here](https://github.com/AsahiLinux/linux/commit/b58cc025c2014597fcb4649e3a9c77a31cf72591).
+
+**Users of M2 Mac Mini/Studio systems** are also recommended to upgrade m1n1
+using the instructions available
+[here](https://discussion.fedoraproject.org/t/important-psa-update-your-m1n1-before-updating-to-macos-sonoma-14-5/117192)
+to avoid loss of display after an update to macOS Sonoma 14.5. Other users
+should not upgrade at this time.
+
+## 2024-05-14
+
+This release updates nixpkgs, the kernel, m1n1, and the Asahi sound packages.
+Thanks to LeSuisse for the kernel update and fx-chun for the sound update.
+
+The new sound packages are necessary for the latest nixpkgs, but are not
+compatible with nixpkgs stable's WirePlumber, nor older versions of nixpkgs
+unstable. Affected users are encouraged to remain on a previous release.
+
+## 2024-04-27
+
+This release updates nixpkgs, the kernel, and U-Boot. Thanks to oliverbestmann
+for the kernel update.
+
+The new kernel is not compatible with nixpkgs stable's Rust compiler. Therefore,
+graphics support will be unavailable. Stable users are encouraged to remain on
+the previous release, or contribute patches.
+
+The new U-Boot uses a new command to boot from a USB drive. Run the `bootmenu`
+command then select the `usb 0` option.
+
+## 2024-04-20
+
+This release updates nixpkgs.
+
+This release includes patches to correct building of the kernel with Rust
+1.77.0.
+
 ## 2024-04-04
 
 This release updates nixpkgs.
diff --git a/modules/nixos-apple-silicon/docs/uefi-standalone.md b/modules/nixos-apple-silicon/docs/uefi-standalone.md
index 3133535c740b..89a743d62e91 100644
--- a/modules/nixos-apple-silicon/docs/uefi-standalone.md
+++ b/modules/nixos-apple-silicon/docs/uefi-standalone.md
@@ -1,11 +1,11 @@
-# UEFI Boot Standalone NixOS (2024-04-04)
+# UEFI Boot Standalone NixOS (2024-05-17)
 
 This guide will build and was tested with the following software:
-* Asahi Linux kernel version 6.6.0-asahi16
+* Asahi Linux kernel version asahi-6.8.9-6
 * Asahi Linux's Mesa version 24.1.0_asahi-20240228-1
-* m1n1 version v1.4.11
-* Asahi Linux's U-Boot version 2023.07.02.asahi4-1
-* Nixpkgs, as of 2024-04-03
+* m1n1 version v1.4.12
+* Asahi Linux's U-Boot version 2024.04-4-asahi
+* Nixpkgs, as of 2024-05-15
 * macOS stub 12.3
 
 NOTE: The latest version of this guide will always be [at its home](https://github.com/tpwrules/nixos-apple-silicon/blob/main/docs/uefi-standalone.md). For more general information about Linux on Apple Silicon Macs, refer to the [Asahi Linux project](https://asahilinux.org/) and [alpha installer release](https://asahilinux.org/2022/03/asahi-linux-alpha-release/).
@@ -133,7 +133,7 @@ If everything went well, you will restart into U-Boot with the Asahi Linux and U
 
 Shut down the machine fully. Connect the flash drive with the installer ISO to a USB port. If not using Wi-Fi, connect the Ethernet cable to the network port or adapter as well.
 
-Start the Mac, and U-Boot should start booting from the USB drive automatically. If you've already installed something to the internal NVMe drive, U-Boot will try to boot it first. To instead boot from USB, hit a key to stop autoboot when prompted, then run the command `env set boot_efi_bootmgr ; run bootcmd_usb0`. GRUB will start, then the NixOS installer after a short delay (the default GRUB option is fine).
+Start the Mac, and U-Boot should start booting from the USB drive automatically. If you've already installed something to the internal NVMe drive, U-Boot will try to boot it first. To instead boot from USB, hit a key to stop autoboot when prompted, then run the command `bootmenu` and select the `usb 0` entry. If this command is not available, instead use `env set boot_efi_bootmgr ; run bootcmd_usb0`. GRUB will start, then the NixOS installer after a short delay (the default GRUB option is fine).
 
 <details>
   <summary>If "mounting `/dev/root` on `/mnt-root/iso` failed: No such file or directory" during boot…</summary>
@@ -332,7 +332,7 @@ Downloading the kernel over USB using m1n1 is not supported.
 
 If something goes wrong and NixOS doesn't boot or is otherwise unusable, you can first try rolling back to a previous generation. Instead of selecting the default bootloader option, choose another configuration that worked previously.
 
-If something is seriously wrong and the bootloader does not work (or you don't have any other generations), you will want to get back into the installer. To start the installer with a system installed on the internal disk, shut down the computer, re-insert the USB drive with the installer, start it up again, hit a key in U-Boot when prompted to stop autoboot, then run the command `env set boot_efi_bootmgr ; run bootcmd_usb0`.
+If something is seriously wrong and the bootloader does not work (or you don't have any other generations), you will want to get back into the installer. To start the installer with a system installed on the internal disk, shut down the computer, re-insert the USB drive with the installer, start it up again, hit a key in U-Boot when prompted to stop autoboot, then run the command `bootmenu` and select the `usb 0` entry. If this command is not available, instead use `env set boot_efi_bootmgr ; run bootcmd_usb0`.
 
 Once in the installer, you can re-mount your root partition and EFI system partition without reformatting them. Depending on what exactly went wrong, you might need to edit your configuration, copy over the latest Apple Silicon support module, or update U-Boot using the latest installer.
 
diff --git a/modules/nixos-apple-silicon/flake.lock b/modules/nixos-apple-silicon/flake.lock
index 1f7f83fd0b51..5eb262ee2fed 100644
--- a/modules/nixos-apple-silicon/flake.lock
+++ b/modules/nixos-apple-silicon/flake.lock
@@ -17,17 +17,17 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1712163089,
-        "narHash": "sha256-Um+8kTIrC19vD4/lUCN9/cU9kcOsD1O1m+axJqQPyMM=",
+        "lastModified": 1715787315,
+        "narHash": "sha256-cYApT0NXJfqBkKcci7D9Kr4CBYZKOQKDYA23q8XNuWg=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "fd281bd6b7d3e32ddfa399853946f782553163b5",
+        "rev": "33d1e753c82ffc557b4a585c77de43d4c922ebb5",
         "type": "github"
       },
       "original": {
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "fd281bd6b7d3e32ddfa399853946f782553163b5",
+        "rev": "33d1e753c82ffc557b4a585c77de43d4c922ebb5",
         "type": "github"
       }
     },
diff --git a/modules/nixos-apple-silicon/flake.nix b/modules/nixos-apple-silicon/flake.nix
index e7515b264971..232aa1edb8ec 100644
--- a/modules/nixos-apple-silicon/flake.nix
+++ b/modules/nixos-apple-silicon/flake.nix
@@ -5,7 +5,7 @@
     nixpkgs = {
       # https://hydra.nixos.org/jobset/mobile-nixos/unstable/evals
       # these evals have a cross-compiled stdenv available
-      url = "github:nixos/nixpkgs/fd281bd6b7d3e32ddfa399853946f782553163b5";
+      url = "github:nixos/nixpkgs/33d1e753c82ffc557b4a585c77de43d4c922ebb5";
     };
 
     rust-overlay = {
diff --git a/modules/nixos-apple-silicon/iso-configuration/installer-configuration.nix b/modules/nixos-apple-silicon/iso-configuration/installer-configuration.nix
index 321ccf70c4c9..7cd6c59a8d57 100644
--- a/modules/nixos-apple-silicon/iso-configuration/installer-configuration.nix
+++ b/modules/nixos-apple-silicon/iso-configuration/installer-configuration.nix
@@ -107,18 +107,6 @@
       util-linux = prev.util-linux.override {
         translateManpages = false;
       };
-
-      # fix for gnupg cross-compilation:
-      # https://github.com/NixOS/nixpkgs/pull/298001
-      gnupg = prev.gnupg.overrideAttrs (old: {
-        configureFlags = (old.configureFlags or []) ++ [
-          "GPGRT_CONFIG=${final.lib.getDev final.libgpg-error}/bin/gpgrt-config"
-        ];
-      });
-
-      # fix for refind cross-compilation:
-      # https://github.com/NixOS/nixpkgs/pull/301598
-      refind = prev.refind.override { sbsigntool = null; };
     })
   ];
 
diff --git a/sys/mbp.nix b/sys/mbp.nix
index 94d80e5404aa..2421ef767609 100644
--- a/sys/mbp.nix
+++ b/sys/mbp.nix
@@ -29,16 +29,6 @@
 
   hardware.asahi.withRust = true;
 
-  boot.kernelPatches = [
-    {
-      name = "drm-fix.patch";
-      patch = pkgs.fetchpatch {
-        url = "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/patch/?id=e0f04e41e8eedd4e5a1275f2318df7e1841855f2";
-        hash = "sha256-rQXDlsUQxQr9na0jW0CfQRK+4rVsmInCkxHfLx5Qn7g=";
-      };
-    }
-  ];
-
   # appledrm with software rendering is much laggier than simpledrm with software.
   boot.blacklistedKernelModules = [ "appledrm" ];