* [PATCH RFC 0/4] rust: dma: bridge zerocopy-derived types into the transmute byte-safety bound
@ 2026-06-28 17:10 ` SeungJong Ha
0 siblings, 0 replies; 20+ messages in thread
From: SeungJong Ha @ 2026-06-28 17:10 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, David Airlie, Simona Vetter
Cc: rust-for-linux, linux-kernel, nova-gpu, dri-devel, SeungJong Ha
DMA-coherent allocations (CoherentAllocation/Coherent/dma::Pool) bound
their element type on kernel::transmute::{AsBytes, FromBytes}. This RFC
lets a type satisfy that bound by deriving zerocopy's byte-safety traits
instead of a hand-written unsafe impl.
The bound cannot be switched to zerocopy wholesale (some DMA structs are
unions that IntoBytes cannot derive), and a blanket bridge impl is
rejected by coherence. So the series bridges the two per type:
1. add the bridge macro impl_transmute_via_zerocopy!, which emits the
transmute impls only for a zerocopy-derived type.
2. re-export zerocopy::Immutable from the prelude.
3-4. worked example: convert nova-core's GspMem and msgq POD types.
This series was prepared with the Claude Code AI assistant (model
claude-opus-4-8): it drafted the macro, the nova-core conversion and the
changelogs, which the submitter reviewed and takes responsibility for. It
was verified by building nova-core on rust-next and a negative test
confirming IntoBytes rejects mis-sized padding. See
Documentation/process/coding-assistants.rst.
Assisted-by: Claude-Code:claude-opus-4-8
Signed-off-by: SeungJong Ha <engineer.jjhama@gmail.com>
---
SeungJong Ha (4):
rust: transmute: add `impl_transmute_via_zerocopy!` macro
rust: prelude: re-export `zerocopy::Immutable`
gpu: nova-core: gsp: derive zerocopy traits for the msgq POD types
gpu: nova-core: gsp: convert GspMem to zerocopy via the transmute bridge
drivers/gpu/nova-core/gsp.rs | 13 ++-------
drivers/gpu/nova-core/gsp/cmdq.rs | 15 +++++-----
drivers/gpu/nova-core/gsp/fw.rs | 8 +++---
drivers/gpu/nova-core/gsp/fw/r570_144.rs | 2 ++
drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs | 4 +--
rust/kernel/prelude.rs | 2 ++
rust/kernel/transmute.rs | 35 +++++++++++++++++++++++
7 files changed, 54 insertions(+), 25 deletions(-)
---
base-commit: 780d569e6c4b422290f5cba319eb904b355d64be
change-id: 20260628-dma-zerocopy-bridge-dc1c96b610cf
Best regards,
--
SeungJong Ha <engineer.jjhama@gmail.com>
^ permalink raw reply [flat|nested] 20+ messages in thread* [PATCH RFC 1/4] rust: transmute: add `impl_transmute_via_zerocopy!` macro
2026-06-28 17:10 ` SeungJong Ha
@ 2026-06-28 17:10 ` SeungJong Ha
-1 siblings, 0 replies; 20+ messages in thread
From: SeungJong Ha via B4 Relay @ 2026-06-28 17:10 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, David Airlie, Simona Vetter
Cc: rust-for-linux, linux-kernel, nova-gpu, dri-devel, SeungJong Ha
From: SeungJong Ha <engineer.jjhama@gmail.com>
The DMA-coherent allocation APIs (`CoherentAllocation`, `Coherent`,
`dma::Pool`) bound their element type on
`transmute::{AsBytes, FromBytes}`, which a `zerocopy`-deriving type cannot
satisfy. A blanket bridge impl is rejected by coherence, as it overlaps
every existing concrete `transmute` impl.
Add a per-type bridge macro that emits the `transmute` impls for a
`zerocopy`-derived type. A compile-time assertion fails the build unless
the type is `zerocopy::{FromBytes, IntoBytes, Immutable}`, which subsumes
the `transmute::{FromBytes, AsBytes}` contracts, so the emitted unsafe
impls are machine-checked. This lets DMA structures adopt `zerocopy`
incrementally without flipping the DMA bound.
Assisted-by: Claude-Code:claude-opus-4-8
Signed-off-by: SeungJong Ha <engineer.jjhama@gmail.com>
---
rust/kernel/transmute.rs | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/rust/kernel/transmute.rs b/rust/kernel/transmute.rs
index 654b5ede2fe2..d9881f84dc62 100644
--- a/rust/kernel/transmute.rs
+++ b/rust/kernel/transmute.rs
@@ -227,3 +227,38 @@ macro_rules! impl_asbytes {
{<T: AsBytes>} [T],
{<T: AsBytes, const N: usize>} [T; N],
}
+
+/// Implements the kernel's `FromBytes` and `AsBytes` byte-safety traits for a type
+/// that already derives the equivalent `zerocopy` traits.
+///
+/// This lets a `zerocopy`-derived type satisfy the bounds required by the
+/// DMA-coherent allocation APIs (`CoherentAllocation`, `Coherent`, `dma::Pool`)
+/// without a hand-audited `unsafe`: the macro fails to compile unless `$t`
+/// implements `zerocopy::FromBytes`, `zerocopy::IntoBytes` and `zerocopy::Immutable`,
+/// which together subsume the safety contracts of [`FromBytes`] and [`AsBytes`].
+#[macro_export]
+macro_rules! impl_transmute_via_zerocopy {
+ ($t:ty) => {
+ const _: () = {
+ // Compile-time proof: fails to build unless `$t` carries the `zerocopy`
+ // byte-safety proofs.
+ fn assert_zerocopy<
+ T: ::zerocopy::FromBytes + ::zerocopy::IntoBytes + ::zerocopy::Immutable,
+ >() {
+ }
+ fn check() {
+ assert_zerocopy::<$t>();
+ }
+ };
+
+ // SAFETY: `$t: zerocopy::FromBytes` guarantees that all bit patterns are valid
+ // and `zerocopy::Immutable` that it has no interior mutability, which is exactly
+ // the contract of `FromBytes`.
+ unsafe impl $crate::transmute::FromBytes for $t {}
+
+ // SAFETY: `$t: zerocopy::IntoBytes` guarantees that it has no uninitialized
+ // (padding) bytes and `zerocopy::Immutable` that it has no interior mutability,
+ // which is exactly the contract of `AsBytes`.
+ unsafe impl $crate::transmute::AsBytes for $t {}
+ };
+}
--
2.54.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH RFC 1/4] rust: transmute: add `impl_transmute_via_zerocopy!` macro
@ 2026-06-28 17:10 ` SeungJong Ha
0 siblings, 0 replies; 20+ messages in thread
From: SeungJong Ha @ 2026-06-28 17:10 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, David Airlie, Simona Vetter
Cc: rust-for-linux, linux-kernel, nova-gpu, dri-devel, SeungJong Ha
The DMA-coherent allocation APIs (`CoherentAllocation`, `Coherent`,
`dma::Pool`) bound their element type on
`transmute::{AsBytes, FromBytes}`, which a `zerocopy`-deriving type cannot
satisfy. A blanket bridge impl is rejected by coherence, as it overlaps
every existing concrete `transmute` impl.
Add a per-type bridge macro that emits the `transmute` impls for a
`zerocopy`-derived type. A compile-time assertion fails the build unless
the type is `zerocopy::{FromBytes, IntoBytes, Immutable}`, which subsumes
the `transmute::{FromBytes, AsBytes}` contracts, so the emitted unsafe
impls are machine-checked. This lets DMA structures adopt `zerocopy`
incrementally without flipping the DMA bound.
Assisted-by: Claude-Code:claude-opus-4-8
Signed-off-by: SeungJong Ha <engineer.jjhama@gmail.com>
---
rust/kernel/transmute.rs | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/rust/kernel/transmute.rs b/rust/kernel/transmute.rs
index 654b5ede2fe2..d9881f84dc62 100644
--- a/rust/kernel/transmute.rs
+++ b/rust/kernel/transmute.rs
@@ -227,3 +227,38 @@ macro_rules! impl_asbytes {
{<T: AsBytes>} [T],
{<T: AsBytes, const N: usize>} [T; N],
}
+
+/// Implements the kernel's `FromBytes` and `AsBytes` byte-safety traits for a type
+/// that already derives the equivalent `zerocopy` traits.
+///
+/// This lets a `zerocopy`-derived type satisfy the bounds required by the
+/// DMA-coherent allocation APIs (`CoherentAllocation`, `Coherent`, `dma::Pool`)
+/// without a hand-audited `unsafe`: the macro fails to compile unless `$t`
+/// implements `zerocopy::FromBytes`, `zerocopy::IntoBytes` and `zerocopy::Immutable`,
+/// which together subsume the safety contracts of [`FromBytes`] and [`AsBytes`].
+#[macro_export]
+macro_rules! impl_transmute_via_zerocopy {
+ ($t:ty) => {
+ const _: () = {
+ // Compile-time proof: fails to build unless `$t` carries the `zerocopy`
+ // byte-safety proofs.
+ fn assert_zerocopy<
+ T: ::zerocopy::FromBytes + ::zerocopy::IntoBytes + ::zerocopy::Immutable,
+ >() {
+ }
+ fn check() {
+ assert_zerocopy::<$t>();
+ }
+ };
+
+ // SAFETY: `$t: zerocopy::FromBytes` guarantees that all bit patterns are valid
+ // and `zerocopy::Immutable` that it has no interior mutability, which is exactly
+ // the contract of `FromBytes`.
+ unsafe impl $crate::transmute::FromBytes for $t {}
+
+ // SAFETY: `$t: zerocopy::IntoBytes` guarantees that it has no uninitialized
+ // (padding) bytes and `zerocopy::Immutable` that it has no interior mutability,
+ // which is exactly the contract of `AsBytes`.
+ unsafe impl $crate::transmute::AsBytes for $t {}
+ };
+}
--
2.54.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH RFC 2/4] rust: prelude: re-export `zerocopy::Immutable`
2026-06-28 17:10 ` SeungJong Ha
@ 2026-06-28 17:10 ` SeungJong Ha
-1 siblings, 0 replies; 20+ messages in thread
From: SeungJong Ha via B4 Relay @ 2026-06-28 17:10 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, David Airlie, Simona Vetter
Cc: rust-for-linux, linux-kernel, nova-gpu, dri-devel, SeungJong Ha
From: SeungJong Ha <engineer.jjhama@gmail.com>
`impl_transmute_via_zerocopy!` requires `Immutable` (no interior
mutability) alongside `FromBytes`/`IntoBytes`. Re-export it from the
prelude like the other two.
Assisted-by: Claude-Code:claude-opus-4-8
Signed-off-by: SeungJong Ha <engineer.jjhama@gmail.com>
---
rust/kernel/prelude.rs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index ca396f1f78a6..3db51c972bde 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -63,12 +63,14 @@
#[doc(no_inline)]
pub use zerocopy::{
FromBytes,
+ Immutable,
IntoBytes, //
};
#[doc(no_inline)]
pub use zerocopy_derive::{
FromBytes,
+ Immutable,
IntoBytes, //
};
--
2.54.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH RFC 2/4] rust: prelude: re-export `zerocopy::Immutable`
@ 2026-06-28 17:10 ` SeungJong Ha
0 siblings, 0 replies; 20+ messages in thread
From: SeungJong Ha @ 2026-06-28 17:10 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, David Airlie, Simona Vetter
Cc: rust-for-linux, linux-kernel, nova-gpu, dri-devel, SeungJong Ha
`impl_transmute_via_zerocopy!` requires `Immutable` (no interior
mutability) alongside `FromBytes`/`IntoBytes`. Re-export it from the
prelude like the other two.
Assisted-by: Claude-Code:claude-opus-4-8
Signed-off-by: SeungJong Ha <engineer.jjhama@gmail.com>
---
rust/kernel/prelude.rs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index ca396f1f78a6..3db51c972bde 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -63,12 +63,14 @@
#[doc(no_inline)]
pub use zerocopy::{
FromBytes,
+ Immutable,
IntoBytes, //
};
#[doc(no_inline)]
pub use zerocopy_derive::{
FromBytes,
+ Immutable,
IntoBytes, //
};
--
2.54.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH RFC 3/4] gpu: nova-core: gsp: derive zerocopy traits for the msgq POD types
2026-06-28 17:10 ` SeungJong Ha
@ 2026-06-28 17:10 ` SeungJong Ha
-1 siblings, 0 replies; 20+ messages in thread
From: SeungJong Ha via B4 Relay @ 2026-06-28 17:10 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, David Airlie, Simona Vetter
Cc: rust-for-linux, linux-kernel, nova-gpu, dri-devel, SeungJong Ha
From: SeungJong Ha <engineer.jjhama@gmail.com>
Replace the hand-audited `unsafe impl transmute::{AsBytes, FromBytes}` on
the msgq header newtypes (`MsgqTxHeader`/`MsgqRxHeader`), `PteArray` and
the generated bindings (`msgqTxHeader`/`msgqRxHeader`) with `zerocopy`
derives. These are padding-free PODs, so the derive applies directly.
The bindings derives are hand-added for the demo; canonically they come
from bindgen's `--with-derive-custom-struct`.
Assisted-by: Claude-Code:claude-opus-4-8
Signed-off-by: SeungJong Ha <engineer.jjhama@gmail.com>
---
drivers/gpu/nova-core/gsp.rs | 13 ++-----------
drivers/gpu/nova-core/gsp/fw.rs | 8 ++++----
drivers/gpu/nova-core/gsp/fw/r570_144.rs | 2 ++
drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs | 4 ++--
4 files changed, 10 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index 69175ca3315c..d7da16e9177a 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -12,11 +12,7 @@
DmaAddress, //
},
pci,
- prelude::*,
- transmute::{
- AsBytes,
- FromBytes, //
- }, //
+ prelude::*, //
};
pub(crate) mod cmdq;
@@ -48,14 +44,9 @@
/// Array of page table entries, as understood by the GSP bootloader.
#[repr(C)]
+#[derive(FromBytes, IntoBytes, Immutable)]
struct PteArray<const NUM_ENTRIES: usize>([u64; NUM_ENTRIES]);
-/// SAFETY: arrays of `u64` implement `FromBytes` and we are but a wrapper around one.
-unsafe impl<const NUM_ENTRIES: usize> FromBytes for PteArray<NUM_ENTRIES> {}
-
-/// SAFETY: arrays of `u64` implement `AsBytes` and we are but a wrapper around one.
-unsafe impl<const NUM_ENTRIES: usize> AsBytes for PteArray<NUM_ENTRIES> {}
-
impl<const NUM_PAGES: usize> PteArray<NUM_PAGES> {
/// Returns the page table entry for `index`, for a mapping starting at `start`.
// TODO: Replace with `IoView` projection once available.
diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index 4db0cfa4dc4d..623ab33847c5 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -696,6 +696,7 @@ fn id8(name: &str) -> u64 {
/// TX header for setting up a message queue with the GSP.
#[repr(transparent)]
+#[derive(FromBytes, IntoBytes, Immutable)]
pub(crate) struct MsgqTxHeader(bindings::msgqTxHeader);
impl MsgqTxHeader {
@@ -722,11 +723,11 @@ pub(crate) fn new(msgq_size: u32, rx_hdr_offset: u32, msg_count: u32) -> Self {
}
}
-// SAFETY: Padding is explicit and does not contain uninitialized data.
-unsafe impl AsBytes for MsgqTxHeader {}
+kernel::impl_transmute_via_zerocopy!(MsgqTxHeader);
/// RX header for setting up a message queue with the GSP.
#[repr(transparent)]
+#[derive(FromBytes, IntoBytes, Immutable)]
pub(crate) struct MsgqRxHeader(bindings::msgqRxHeader);
/// Header for the message RX queue.
@@ -737,8 +738,7 @@ pub(crate) fn new() -> Self {
}
}
-// SAFETY: Padding is explicit and does not contain uninitialized data.
-unsafe impl AsBytes for MsgqRxHeader {}
+kernel::impl_transmute_via_zerocopy!(MsgqRxHeader);
bitfield! {
struct MsgHeaderVersion(u32) {
diff --git a/drivers/gpu/nova-core/gsp/fw/r570_144.rs b/drivers/gpu/nova-core/gsp/fw/r570_144.rs
index 2e6f0d298756..4b6280fab674 100644
--- a/drivers/gpu/nova-core/gsp/fw/r570_144.rs
+++ b/drivers/gpu/nova-core/gsp/fw/r570_144.rs
@@ -23,6 +23,8 @@
)]
use kernel::ffi;
use pin_init::MaybeZeroable;
+// Hand-added for the demo; canonically emitted by bindgen --with-derive-custom-struct.
+use kernel::prelude::{FromBytes, Immutable, IntoBytes};
include!("r570_144/bindings.rs");
diff --git a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs
index ea350f9b2cc4..82b1e8b155f0 100644
--- a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs
+++ b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs
@@ -846,7 +846,7 @@ pub struct PACKED_REGISTRY_TABLE {
pub entries: __IncompleteArrayField<PACKED_REGISTRY_ENTRY>,
}
#[repr(C)]
-#[derive(Debug, Default, Copy, Clone, MaybeZeroable)]
+#[derive(Debug, Default, Copy, Clone, MaybeZeroable, FromBytes, IntoBytes, Immutable)]
pub struct msgqTxHeader {
pub version: u32_,
pub size: u32_,
@@ -858,7 +858,7 @@ pub struct msgqTxHeader {
pub entryOff: u32_,
}
#[repr(C)]
-#[derive(Debug, Default, Copy, Clone, MaybeZeroable)]
+#[derive(Debug, Default, Copy, Clone, MaybeZeroable, FromBytes, IntoBytes, Immutable)]
pub struct msgqRxHeader {
pub readPtr: u32_,
}
--
2.54.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH RFC 3/4] gpu: nova-core: gsp: derive zerocopy traits for the msgq POD types
@ 2026-06-28 17:10 ` SeungJong Ha
0 siblings, 0 replies; 20+ messages in thread
From: SeungJong Ha @ 2026-06-28 17:10 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, David Airlie, Simona Vetter
Cc: rust-for-linux, linux-kernel, nova-gpu, dri-devel, SeungJong Ha
Replace the hand-audited `unsafe impl transmute::{AsBytes, FromBytes}` on
the msgq header newtypes (`MsgqTxHeader`/`MsgqRxHeader`), `PteArray` and
the generated bindings (`msgqTxHeader`/`msgqRxHeader`) with `zerocopy`
derives. These are padding-free PODs, so the derive applies directly.
The bindings derives are hand-added for the demo; canonically they come
from bindgen's `--with-derive-custom-struct`.
Assisted-by: Claude-Code:claude-opus-4-8
Signed-off-by: SeungJong Ha <engineer.jjhama@gmail.com>
---
drivers/gpu/nova-core/gsp.rs | 13 ++-----------
drivers/gpu/nova-core/gsp/fw.rs | 8 ++++----
drivers/gpu/nova-core/gsp/fw/r570_144.rs | 2 ++
drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs | 4 ++--
4 files changed, 10 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index 69175ca3315c..d7da16e9177a 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -12,11 +12,7 @@
DmaAddress, //
},
pci,
- prelude::*,
- transmute::{
- AsBytes,
- FromBytes, //
- }, //
+ prelude::*, //
};
pub(crate) mod cmdq;
@@ -48,14 +44,9 @@
/// Array of page table entries, as understood by the GSP bootloader.
#[repr(C)]
+#[derive(FromBytes, IntoBytes, Immutable)]
struct PteArray<const NUM_ENTRIES: usize>([u64; NUM_ENTRIES]);
-/// SAFETY: arrays of `u64` implement `FromBytes` and we are but a wrapper around one.
-unsafe impl<const NUM_ENTRIES: usize> FromBytes for PteArray<NUM_ENTRIES> {}
-
-/// SAFETY: arrays of `u64` implement `AsBytes` and we are but a wrapper around one.
-unsafe impl<const NUM_ENTRIES: usize> AsBytes for PteArray<NUM_ENTRIES> {}
-
impl<const NUM_PAGES: usize> PteArray<NUM_PAGES> {
/// Returns the page table entry for `index`, for a mapping starting at `start`.
// TODO: Replace with `IoView` projection once available.
diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index 4db0cfa4dc4d..623ab33847c5 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -696,6 +696,7 @@ fn id8(name: &str) -> u64 {
/// TX header for setting up a message queue with the GSP.
#[repr(transparent)]
+#[derive(FromBytes, IntoBytes, Immutable)]
pub(crate) struct MsgqTxHeader(bindings::msgqTxHeader);
impl MsgqTxHeader {
@@ -722,11 +723,11 @@ pub(crate) fn new(msgq_size: u32, rx_hdr_offset: u32, msg_count: u32) -> Self {
}
}
-// SAFETY: Padding is explicit and does not contain uninitialized data.
-unsafe impl AsBytes for MsgqTxHeader {}
+kernel::impl_transmute_via_zerocopy!(MsgqTxHeader);
/// RX header for setting up a message queue with the GSP.
#[repr(transparent)]
+#[derive(FromBytes, IntoBytes, Immutable)]
pub(crate) struct MsgqRxHeader(bindings::msgqRxHeader);
/// Header for the message RX queue.
@@ -737,8 +738,7 @@ pub(crate) fn new() -> Self {
}
}
-// SAFETY: Padding is explicit and does not contain uninitialized data.
-unsafe impl AsBytes for MsgqRxHeader {}
+kernel::impl_transmute_via_zerocopy!(MsgqRxHeader);
bitfield! {
struct MsgHeaderVersion(u32) {
diff --git a/drivers/gpu/nova-core/gsp/fw/r570_144.rs b/drivers/gpu/nova-core/gsp/fw/r570_144.rs
index 2e6f0d298756..4b6280fab674 100644
--- a/drivers/gpu/nova-core/gsp/fw/r570_144.rs
+++ b/drivers/gpu/nova-core/gsp/fw/r570_144.rs
@@ -23,6 +23,8 @@
)]
use kernel::ffi;
use pin_init::MaybeZeroable;
+// Hand-added for the demo; canonically emitted by bindgen --with-derive-custom-struct.
+use kernel::prelude::{FromBytes, Immutable, IntoBytes};
include!("r570_144/bindings.rs");
diff --git a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs
index ea350f9b2cc4..82b1e8b155f0 100644
--- a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs
+++ b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs
@@ -846,7 +846,7 @@ pub struct PACKED_REGISTRY_TABLE {
pub entries: __IncompleteArrayField<PACKED_REGISTRY_ENTRY>,
}
#[repr(C)]
-#[derive(Debug, Default, Copy, Clone, MaybeZeroable)]
+#[derive(Debug, Default, Copy, Clone, MaybeZeroable, FromBytes, IntoBytes, Immutable)]
pub struct msgqTxHeader {
pub version: u32_,
pub size: u32_,
@@ -858,7 +858,7 @@ pub struct msgqTxHeader {
pub entryOff: u32_,
}
#[repr(C)]
-#[derive(Debug, Default, Copy, Clone, MaybeZeroable)]
+#[derive(Debug, Default, Copy, Clone, MaybeZeroable, FromBytes, IntoBytes, Immutable)]
pub struct msgqRxHeader {
pub readPtr: u32_,
}
--
2.54.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH RFC 4/4] gpu: nova-core: gsp: convert GspMem to zerocopy via the transmute bridge
2026-06-28 17:10 ` SeungJong Ha
@ 2026-06-28 17:10 ` SeungJong Ha
-1 siblings, 0 replies; 20+ messages in thread
From: SeungJong Ha via B4 Relay @ 2026-06-28 17:10 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, David Airlie, Simona Vetter
Cc: rust-for-linux, linux-kernel, nova-gpu, dri-devel, SeungJong Ha
From: SeungJong Ha <engineer.jjhama@gmail.com>
`GspMem` (shared with the GSP over a DMA `Coherent`) carried a
hand-audited `unsafe impl transmute::{AsBytes, FromBytes}` that did not
actually meet the no-padding requirement: `Msgq` embeds a page-aligned
`MsgqData` after two small headers.
Make that padding explicit (`_pad`), derive the `zerocopy` traits on the
`MsgqData`/`Msgq`/`GspMem` chain, and bridge to `transmute` via
`impl_transmute_via_zerocopy!`. The `unsafe` is now machine-checked.
Unions (e.g. `GspFwWprMeta`) are left on their hand-audited impls, since
`zerocopy::IntoBytes` cannot derive for unions.
Assisted-by: Claude-Code:claude-opus-4-8
Signed-off-by: SeungJong Ha <engineer.jjhama@gmail.com>
---
drivers/gpu/nova-core/gsp/cmdq.rs | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 070de0731e95..d9929d24d316 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -152,7 +152,7 @@ fn read(
/// This area of memory is to be shared between the driver and the GSP to exchange commands or
/// messages.
#[repr(C, align(0x1000))]
-#[derive(Debug)]
+#[derive(Debug, FromBytes, IntoBytes, Immutable)]
struct MsgqData {
data: [[u8; GSP_PAGE_SIZE]; num::u32_as_usize(MSGQ_NUM_PAGES)],
}
@@ -169,6 +169,7 @@ struct MsgqData {
/// read pointer of `rx` actually refers to the `Msgq` owned by the other side.
/// This design ensures that only the driver or GSP ever writes to a given instance of this struct.
#[repr(C)]
+#[derive(FromBytes, IntoBytes, Immutable)]
// There is no struct defined for this in the open-gpu-kernel-source headers.
// Instead it is defined by code in `GspMsgQueuesInit()`.
// TODO: Revert to private once `IoView` projections replace the `gsp_mem` module.
@@ -177,12 +178,16 @@ pub(super) struct Msgq {
pub(super) tx: MsgqTxHeader,
/// Header for receiving messages, including the read pointer.
pub(super) rx: MsgqRxHeader,
+ _pad: [u8; GSP_PAGE_SIZE - size_of::<MsgqTxHeader>() - size_of::<MsgqRxHeader>()],
/// The message queue proper.
msgq: MsgqData,
}
+static_assert!(size_of::<MsgqTxHeader>() + size_of::<MsgqRxHeader>() <= GSP_PAGE_SIZE);
+
/// Structure shared between the driver and the GSP and containing the command and message queues.
#[repr(C)]
+#[derive(FromBytes, IntoBytes, Immutable)]
// TODO: Revert to private once `IoView` projections replace the `gsp_mem` module.
pub(super) struct GspMem {
/// Self-mapping page table entries.
@@ -205,13 +210,7 @@ impl GspMem {
const PTE_ARRAY_SIZE: usize = GSP_PAGE_SIZE / size_of::<u64>();
}
-// SAFETY: These structs don't meet the no-padding requirements of AsBytes but
-// that is not a problem because they are not used outside the kernel.
-unsafe impl AsBytes for GspMem {}
-
-// SAFETY: These structs don't meet the no-padding requirements of FromBytes but
-// that is not a problem because they are not used outside the kernel.
-unsafe impl FromBytes for GspMem {}
+kernel::impl_transmute_via_zerocopy!(GspMem);
/// Wrapper around [`GspMem`] to share it with the GPU using a [`Coherent`].
///
--
2.54.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [PATCH RFC 4/4] gpu: nova-core: gsp: convert GspMem to zerocopy via the transmute bridge
@ 2026-06-28 17:10 ` SeungJong Ha
0 siblings, 0 replies; 20+ messages in thread
From: SeungJong Ha @ 2026-06-28 17:10 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, David Airlie, Simona Vetter
Cc: rust-for-linux, linux-kernel, nova-gpu, dri-devel, SeungJong Ha
`GspMem` (shared with the GSP over a DMA `Coherent`) carried a
hand-audited `unsafe impl transmute::{AsBytes, FromBytes}` that did not
actually meet the no-padding requirement: `Msgq` embeds a page-aligned
`MsgqData` after two small headers.
Make that padding explicit (`_pad`), derive the `zerocopy` traits on the
`MsgqData`/`Msgq`/`GspMem` chain, and bridge to `transmute` via
`impl_transmute_via_zerocopy!`. The `unsafe` is now machine-checked.
Unions (e.g. `GspFwWprMeta`) are left on their hand-audited impls, since
`zerocopy::IntoBytes` cannot derive for unions.
Assisted-by: Claude-Code:claude-opus-4-8
Signed-off-by: SeungJong Ha <engineer.jjhama@gmail.com>
---
drivers/gpu/nova-core/gsp/cmdq.rs | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 070de0731e95..d9929d24d316 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -152,7 +152,7 @@ fn read(
/// This area of memory is to be shared between the driver and the GSP to exchange commands or
/// messages.
#[repr(C, align(0x1000))]
-#[derive(Debug)]
+#[derive(Debug, FromBytes, IntoBytes, Immutable)]
struct MsgqData {
data: [[u8; GSP_PAGE_SIZE]; num::u32_as_usize(MSGQ_NUM_PAGES)],
}
@@ -169,6 +169,7 @@ struct MsgqData {
/// read pointer of `rx` actually refers to the `Msgq` owned by the other side.
/// This design ensures that only the driver or GSP ever writes to a given instance of this struct.
#[repr(C)]
+#[derive(FromBytes, IntoBytes, Immutable)]
// There is no struct defined for this in the open-gpu-kernel-source headers.
// Instead it is defined by code in `GspMsgQueuesInit()`.
// TODO: Revert to private once `IoView` projections replace the `gsp_mem` module.
@@ -177,12 +178,16 @@ pub(super) struct Msgq {
pub(super) tx: MsgqTxHeader,
/// Header for receiving messages, including the read pointer.
pub(super) rx: MsgqRxHeader,
+ _pad: [u8; GSP_PAGE_SIZE - size_of::<MsgqTxHeader>() - size_of::<MsgqRxHeader>()],
/// The message queue proper.
msgq: MsgqData,
}
+static_assert!(size_of::<MsgqTxHeader>() + size_of::<MsgqRxHeader>() <= GSP_PAGE_SIZE);
+
/// Structure shared between the driver and the GSP and containing the command and message queues.
#[repr(C)]
+#[derive(FromBytes, IntoBytes, Immutable)]
// TODO: Revert to private once `IoView` projections replace the `gsp_mem` module.
pub(super) struct GspMem {
/// Self-mapping page table entries.
@@ -205,13 +210,7 @@ impl GspMem {
const PTE_ARRAY_SIZE: usize = GSP_PAGE_SIZE / size_of::<u64>();
}
-// SAFETY: These structs don't meet the no-padding requirements of AsBytes but
-// that is not a problem because they are not used outside the kernel.
-unsafe impl AsBytes for GspMem {}
-
-// SAFETY: These structs don't meet the no-padding requirements of FromBytes but
-// that is not a problem because they are not used outside the kernel.
-unsafe impl FromBytes for GspMem {}
+kernel::impl_transmute_via_zerocopy!(GspMem);
/// Wrapper around [`GspMem`] to share it with the GPU using a [`Coherent`].
///
--
2.54.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [PATCH RFC 4/4] gpu: nova-core: gsp: convert GspMem to zerocopy via the transmute bridge
2026-06-28 17:10 ` SeungJong Ha
(?)
@ 2026-06-28 17:22 ` sashiko-bot
2026-06-28 18:21 ` SeungJong Ha
-1 siblings, 1 reply; 20+ messages in thread
From: sashiko-bot @ 2026-06-28 17:22 UTC (permalink / raw)
To: SeungJong Ha via B4 Relay
Cc: ojeda, dri-devel, Alexandre Courbot, Danilo Krummrich
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Time-of-Check to Time-of-Use (TOCTOU) vulnerability parsing message queue headers from coherent DMA memory.
--
commit e9f51c49f1590127c704379d2f179c17f740df94
Author: SeungJong Ha <engineer.jjhama@gmail.com>
gpu: nova-core: gsp: convert GspMem to zerocopy via the transmute bridge
This commit converts GspMem and related structures to use zerocopy for safe
transmutations by adding explicit padding and deriving FromBytes and IntoBytes.
It replaces the manual unsafe transmute implementations.
> diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
> index 070de0731e950..d9929d24d3165 100644
> --- a/drivers/gpu/nova-core/gsp/cmdq.rs
> +++ b/drivers/gpu/nova-core/gsp/cmdq.rs
[ ... ]
> @@ -169,6 +169,7 @@ struct MsgqData {
> /// read pointer of `rx` actually refers to the `Msgq` owned by the other side.
> /// This design ensures that only the driver or GSP ever writes to a given instance of this struct.
> #[repr(C)]
> +#[derive(FromBytes, IntoBytes, Immutable)]
> // There is no struct defined for this in the open-gpu-kernel-source headers.
> // Instead it is defined by code in `GspMsgQueuesInit()`.
> // TODO: Revert to private once `IoView` projections replace the `gsp_mem` module.
[Severity: High]
This isn't a bug introduced by this patch, but could this coherent shared memory
lead to a time-of-check to time-of-use vulnerability?
The driver validates lengths and checksums by reading fields like length from
GspMsgElement, which is mapped directly into shared memory. For instance,
in wait_for_msg():
wait_for_msg()
let (header, slice_1) = GspMsgElement::from_bytes_prefix(slice_1).ok_or(EIO)?;
However, receive_msg() seems to re-read the header fields directly from shared
memory to advance the ring buffer pointer:
receive_msg()
self.gsp_mem.advance_cpu_read_ptr(u32::try_from(
message.header.length().div_ceil(GSP_PAGE_SIZE),
)?);
Can a compromised hardware component modify the message length concurrently
after the initial validation but before pointer advancement, potentially
corrupting the host read pointer?
Similarly, send_single_command() initializes a message header in shared memory
and then reads its element_count to advance the write pointer:
send_single_command()
let elem_count = dst.header.element_count();
self.seq += 1;
self.gsp_mem.advance_cpu_write_ptr(elem_count);
Does this allow the device to race and corrupt the host write pointer by
modifying element_count before it is read back?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260628-dma-zerocopy-bridge-v1-0-9a2895ebe30d@gmail.com?part=4
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [PATCH RFC 4/4] gpu: nova-core: gsp: convert GspMem to zerocopy via the transmute bridge
2026-06-28 17:22 ` sashiko-bot
@ 2026-06-28 18:21 ` SeungJong Ha
2026-06-29 7:10 ` Alexandre Courbot
0 siblings, 1 reply; 20+ messages in thread
From: SeungJong Ha @ 2026-06-28 18:21 UTC (permalink / raw)
To: sashiko-reviews
Cc: ojeda, dri-devel, acourbot, dakr, rust-for-linux, nova-gpu,
SeungJong Ha
This is pre-existing and not changed by this patch: it only makes
explicit (via a checked `zerocopy` derive) what the previous `unsafe
impl transmute::{FromBytes, AsBytes}` already allowed implicitly -- the
layout is byte-identical and the message-handling path is untouched -- so
it neither introduces nor addresses this. I'm not familiar enough with
the GSP threat model to judge whether the TOCTOU is in scope here; if it
is worth noting, I can add a TODO comment near the affected reads.
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [PATCH RFC 4/4] gpu: nova-core: gsp: convert GspMem to zerocopy via the transmute bridge
2026-06-28 18:21 ` SeungJong Ha
@ 2026-06-29 7:10 ` Alexandre Courbot
2026-06-29 7:59 ` SeungJong Ha
0 siblings, 1 reply; 20+ messages in thread
From: Alexandre Courbot @ 2026-06-29 7:10 UTC (permalink / raw)
To: SeungJong Ha
Cc: sashiko-reviews, ojeda, dri-devel, dakr, rust-for-linux, nova-gpu
On Mon Jun 29, 2026 at 3:21 AM JST, SeungJong Ha wrote:
> This is pre-existing and not changed by this patch: it only makes
> explicit (via a checked `zerocopy` derive) what the previous `unsafe
> impl transmute::{FromBytes, AsBytes}` already allowed implicitly -- the
> layout is byte-identical and the message-handling path is untouched -- so
> it neither introduces nor addresses this. I'm not familiar enough with
> the GSP threat model to judge whether the TOCTOU is in scope here; if it
> is worth noting, I can add a TODO comment near the affected reads.
So I understand that this as a copy-pasted Claude/Sashiko block, but
would also appreciate if the human behind the keyboard could provide the
context required to easily understand which part of the code this is
about.
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [PATCH RFC 4/4] gpu: nova-core: gsp: convert GspMem to zerocopy via the transmute bridge
2026-06-29 7:10 ` Alexandre Courbot
@ 2026-06-29 7:59 ` SeungJong Ha
2026-06-29 9:49 ` Alexandre Courbot
0 siblings, 1 reply; 20+ messages in thread
From: SeungJong Ha @ 2026-06-29 7:59 UTC (permalink / raw)
To: Alexandre Courbot, SeungJong Ha
Cc: sashiko-reviews, ojeda, dri-devel, dakr, rust-for-linux, nova-gpu
On Mon Jun 29, 2026 at 4:10 PM JST, Alexandre Courbot wrote:
> On Mon Jun 29, 2026 at 3:21 AM JST, SeungJong Ha wrote:
>> On Sun Jun 28, 2026 at 5:22 PM UTC, Sashiko AI review wrote:
>>> This isn't a bug introduced by this patch, but could this coherent shared
>>> memory lead to a time-of-check to time-of-use vulnerability?
>>>
>>> The driver validates lengths and checksums by reading fields like length
>>> from GspMsgElement, which is mapped directly into shared memory. For
>>> instance, in wait_for_msg():
>>>
>>> wait_for_msg()
>>> let (header, slice_1) = GspMsgElement::from_bytes_prefix(slice_1).ok_or(EIO)?;
>>>
>>> However, receive_msg() seems to re-read the header fields directly from
>>> shared memory to advance the ring buffer pointer:
>>>
>>> receive_msg()
>>> self.gsp_mem.advance_cpu_read_ptr(u32::try_from(
>>> message.header.length().div_ceil(GSP_PAGE_SIZE),
>>> )?);
>>>
>>> Can a compromised hardware component modify the message length concurrently
>>> after the initial validation but before pointer advancement, potentially
>>> corrupting the host read pointer?
>>>
>>> Similarly, send_single_command() initializes a message header in shared
>>> memory and then reads its element_count to advance the write pointer:
>>>
>>> send_single_command()
>>> let elem_count = dst.header.element_count();
>>> self.seq += 1;
>>> self.gsp_mem.advance_cpu_write_ptr(elem_count);
>>>
>>> Does this allow the device to race and corrupt the host write pointer by
>>> modifying element_count before it is read back?
>>
>> This is pre-existing and not changed by this patch: it only makes
>> explicit (via a checked `zerocopy` derive) what the previous `unsafe
>> impl transmute::{FromBytes, AsBytes}` already allowed implicitly -- the
>> layout is byte-identical and the message-handling path is untouched -- so
>> it neither introduces nor addresses this. I'm not familiar enough with
>> the GSP threat model to judge whether the TOCTOU is in scope here; if it
>> is worth noting, I can add a TODO comment near the affected reads.
>
> So I understand that this as a copy-pasted Claude/Sashiko block, but
> would also appreciate if the human behind the keyboard could provide the
> context required to easily understand which part of the code this is
> about.
Sorry, that reply was an unedited block. Here is the concrete context.
It is the message-queue read path in gsp/cmdq.rs (wait_for_msg() /
receive_msg() / send_single_command()).
I haven't touched that logic; this patch only swaps the unsafe transmute
impls for a checked zerocopy derive. If it's worth noting, I'm happy to add
a comment near those reads.
Thanks,
SeungJong
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [PATCH RFC 4/4] gpu: nova-core: gsp: convert GspMem to zerocopy via the transmute bridge
2026-06-29 7:59 ` SeungJong Ha
@ 2026-06-29 9:49 ` Alexandre Courbot
0 siblings, 0 replies; 20+ messages in thread
From: Alexandre Courbot @ 2026-06-29 9:49 UTC (permalink / raw)
To: SeungJong Ha
Cc: sashiko-reviews, ojeda, dri-devel, dakr, rust-for-linux, nova-gpu
On Mon Jun 29, 2026 at 4:59 PM JST, SeungJong Ha wrote:
> On Mon Jun 29, 2026 at 4:10 PM JST, Alexandre Courbot wrote:
>> On Mon Jun 29, 2026 at 3:21 AM JST, SeungJong Ha wrote:
>>> On Sun Jun 28, 2026 at 5:22 PM UTC, Sashiko AI review wrote:
>>>> This isn't a bug introduced by this patch, but could this coherent shared
>>>> memory lead to a time-of-check to time-of-use vulnerability?
>>>>
>>>> The driver validates lengths and checksums by reading fields like length
>>>> from GspMsgElement, which is mapped directly into shared memory. For
>>>> instance, in wait_for_msg():
>>>>
>>>> wait_for_msg()
>>>> let (header, slice_1) = GspMsgElement::from_bytes_prefix(slice_1).ok_or(EIO)?;
>>>>
>>>> However, receive_msg() seems to re-read the header fields directly from
>>>> shared memory to advance the ring buffer pointer:
>>>>
>>>> receive_msg()
>>>> self.gsp_mem.advance_cpu_read_ptr(u32::try_from(
>>>> message.header.length().div_ceil(GSP_PAGE_SIZE),
>>>> )?);
>>>>
>>>> Can a compromised hardware component modify the message length concurrently
>>>> after the initial validation but before pointer advancement, potentially
>>>> corrupting the host read pointer?
>>>>
>>>> Similarly, send_single_command() initializes a message header in shared
>>>> memory and then reads its element_count to advance the write pointer:
>>>>
>>>> send_single_command()
>>>> let elem_count = dst.header.element_count();
>>>> self.seq += 1;
>>>> self.gsp_mem.advance_cpu_write_ptr(elem_count);
>>>>
>>>> Does this allow the device to race and corrupt the host write pointer by
>>>> modifying element_count before it is read back?
>>>
>>> This is pre-existing and not changed by this patch: it only makes
>>> explicit (via a checked `zerocopy` derive) what the previous `unsafe
>>> impl transmute::{FromBytes, AsBytes}` already allowed implicitly -- the
>>> layout is byte-identical and the message-handling path is untouched -- so
>>> it neither introduces nor addresses this. I'm not familiar enough with
>>> the GSP threat model to judge whether the TOCTOU is in scope here; if it
>>> is worth noting, I can add a TODO comment near the affected reads.
>>
>> So I understand that this as a copy-pasted Claude/Sashiko block, but
>> would also appreciate if the human behind the keyboard could provide the
>> context required to easily understand which part of the code this is
>> about.
>
> Sorry, that reply was an unedited block. Here is the concrete context.
>
> It is the message-queue read path in gsp/cmdq.rs (wait_for_msg() /
> receive_msg() / send_single_command()).
> I haven't touched that logic; this patch only swaps the unsafe transmute
> impls for a checked zerocopy derive. If it's worth noting, I'm happy to add
> a comment near those reads.
Actually I also realized my mail setup made it so I couldn't see the
Sashiko email you replied to - after fixing this, the context is much
clearer. :)
But yes, as a general rule it is a good idea to quote, especially on
Sashiko emails that do not necessarily reach everyone.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH RFC 0/4] rust: dma: bridge zerocopy-derived types into the transmute byte-safety bound
2026-06-28 17:10 ` SeungJong Ha
` (4 preceding siblings ...)
(?)
@ 2026-06-29 7:17 ` Alexandre Courbot
2026-06-29 8:20 ` Alistair Popple
2026-06-29 11:16 ` SeungJong Ha
-1 siblings, 2 replies; 20+ messages in thread
From: Alexandre Courbot @ 2026-06-29 7:17 UTC (permalink / raw)
To: SeungJong Ha via B4 Relay
Cc: engineer.jjhama, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan, David Airlie, Simona Vetter, rust-for-linux,
linux-kernel, nova-gpu, dri-devel
On Mon Jun 29, 2026 at 2:10 AM JST, SeungJong Ha via B4 Relay wrote:
> DMA-coherent allocations (CoherentAllocation/Coherent/dma::Pool) bound
> their element type on kernel::transmute::{AsBytes, FromBytes}. This RFC
> lets a type satisfy that bound by deriving zerocopy's byte-safety traits
> instead of a hand-written unsafe impl.
>
> The bound cannot be switched to zerocopy wholesale (some DMA structs are
> unions that IntoBytes cannot derive), and a blanket bridge impl is
> rejected by coherence. So the series bridges the two per type:
>
> 1. add the bridge macro impl_transmute_via_zerocopy!, which emits the
> transmute impls only for a zerocopy-derived type.
> 2. re-export zerocopy::Immutable from the prelude.
> 3-4. worked example: convert nova-core's GspMem and msgq POD types.
Can you give more details about what the macro is for? My understanding
is that it is a temporary fix for the generated bindings; if so, I'd
prefer to apply a definitive solution (like using
`#[derive(zerocopy_derive::most_traits)]`, or updating the bindings
generator tool) rather than something that will be removed later.
I also notice that the macro is in the Rust `transmute` module, but the
only user is Nova; so it should have been either be Nova-local, or used
by other Rust modules.
But intuitively I'd say that we can (and should) probably do without
this intermediate step. But please let me know if there is something I
missed.
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [PATCH RFC 0/4] rust: dma: bridge zerocopy-derived types into the transmute byte-safety bound
2026-06-29 7:17 ` [PATCH RFC 0/4] rust: dma: bridge zerocopy-derived types into the transmute byte-safety bound Alexandre Courbot
@ 2026-06-29 8:20 ` Alistair Popple
2026-06-29 8:57 ` Danilo Krummrich
2026-06-29 11:16 ` SeungJong Ha
1 sibling, 1 reply; 20+ messages in thread
From: Alistair Popple @ 2026-06-29 8:20 UTC (permalink / raw)
To: Alexandre Courbot
Cc: SeungJong Ha via B4 Relay, engineer.jjhama, Miguel Ojeda,
Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
Daniel Almeida, Tamir Duberstein, Onur Özkan, David Airlie,
Simona Vetter, rust-for-linux, linux-kernel, nova-gpu, dri-devel
On 2026-06-29 at 17:17 +1000, Alexandre Courbot <acourbot@nvidia.com> wrote...
> On Mon Jun 29, 2026 at 2:10 AM JST, SeungJong Ha via B4 Relay wrote:
> > DMA-coherent allocations (CoherentAllocation/Coherent/dma::Pool) bound
> > their element type on kernel::transmute::{AsBytes, FromBytes}. This RFC
> > lets a type satisfy that bound by deriving zerocopy's byte-safety traits
> > instead of a hand-written unsafe impl.
> >
> > The bound cannot be switched to zerocopy wholesale (some DMA structs are
> > unions that IntoBytes cannot derive), and a blanket bridge impl is
> > rejected by coherence. So the series bridges the two per type:
> >
> > 1. add the bridge macro impl_transmute_via_zerocopy!, which emits the
> > transmute impls only for a zerocopy-derived type.
> > 2. re-export zerocopy::Immutable from the prelude.
> > 3-4. worked example: convert nova-core's GspMem and msgq POD types.
>
> Can you give more details about what the macro is for? My understanding
> is that it is a temporary fix for the generated bindings; if so, I'd
> prefer to apply a definitive solution (like using
> `#[derive(zerocopy_derive::most_traits)]`, or updating the bindings
> generator tool) rather than something that will be removed later.
I think the context is in the description for patch 1. It's not directly related
to the bindings generator. Basically the problem is that these bindings are a
little bit unique in that we access them using the dma_write/read macros. In
other words we use these with Dma::Coherent which still requires the transmute
rather than zerocopy trait bounds to be implemented.
That said I think the correct long-term fix here would be to fix Dma::Coherent
to make it work with the zerocopy traits. Not sure if anyone is looking at that
or not.
- Alistair
> I also notice that the macro is in the Rust `transmute` module, but the
> only user is Nova; so it should have been either be Nova-local, or used
> by other Rust modules.
>
> But intuitively I'd say that we can (and should) probably do without
> this intermediate step. But please let me know if there is something I
> missed.
>
^ permalink raw reply [flat|nested] 20+ messages in thread* Re: [PATCH RFC 0/4] rust: dma: bridge zerocopy-derived types into the transmute byte-safety bound
2026-06-29 8:20 ` Alistair Popple
@ 2026-06-29 8:57 ` Danilo Krummrich
2026-06-29 11:38 ` SeungJong Ha
0 siblings, 1 reply; 20+ messages in thread
From: Danilo Krummrich @ 2026-06-29 8:57 UTC (permalink / raw)
To: Alistair Popple
Cc: Alexandre Courbot, SeungJong Ha via B4 Relay, engineer.jjhama,
Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Daniel Almeida, Tamir Duberstein, Onur Özkan, David Airlie,
Simona Vetter, rust-for-linux, linux-kernel, nova-gpu, dri-devel
On Mon Jun 29, 2026 at 10:20 AM CEST, Alistair Popple wrote:
> I think the context is in the description for patch 1. It's not directly related
> to the bindings generator. Basically the problem is that these bindings are a
> little bit unique in that we access them using the dma_write/read macros. In
> other words we use these with Dma::Coherent which still requires the transmute
> rather than zerocopy trait bounds to be implemented.
>
> That said I think the correct long-term fix here would be to fix Dma::Coherent
> to make it work with the zerocopy traits. Not sure if anyone is looking at that
> or not.
I think it can just be done short term, please also see [1]. We can just convert
the DMA code right away, no need for the proposed indirection.
[1] https://lore.kernel.org/all/DJLEHDNJCUD0.38PFZ5773D6BX@kernel.org/
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH RFC 0/4] rust: dma: bridge zerocopy-derived types into the transmute byte-safety bound
2026-06-29 8:57 ` Danilo Krummrich
@ 2026-06-29 11:38 ` SeungJong Ha
0 siblings, 0 replies; 20+ messages in thread
From: SeungJong Ha @ 2026-06-29 11:38 UTC (permalink / raw)
To: Danilo Krummrich, Alistair Popple
Cc: Alexandre Courbot, SeungJong Ha via B4 Relay, engineer.jjhama,
Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Daniel Almeida, Tamir Duberstein, Onur Özkan, David Airlie,
Simona Vetter, rust-for-linux, linux-kernel, nova-gpu, dri-devel
On Mon Jun 29, 2026 at 8:57 AM UTC, Danilo Krummrich wrote:
> On Mon Jun 29, 2026 at 10:20 AM CEST, Alistair Popple wrote:
>> I think the context is in the description for patch 1. It's not directly related
>> to the bindings generator. Basically the problem is that these bindings are a
>> little bit unique in that we access them using the dma_write/read macros. In
>> other words we use these with Dma::Coherent which still requires the transmute
>> rather than zerocopy trait bounds to be implemented.
>>
>> That said I think the correct long-term fix here would be to fix Dma::Coherent
>> to make it work with the zerocopy traits. Not sure if anyone is looking at that
>> or not.
>
> I think it can just be done short term, please also see [1]. We can just convert
> the DMA code right away, no need for the proposed indirection.
>
> [1] https://lore.kernel.org/all/DJLEHDNJCUD0.38PFZ5773D6BX@kernel.org/
Same here [2], It'll be better to make full transition from transmute after the new
version of zerocopy[3] and auto derive is merged.
Best Regards,
SeungJong
[2] https://lore.kernel.org/all/DJLHOQA5UAP4.340P2TKXGMME5@gmail.com/
[3] https://lore.kernel.org/all/20260625231919.692444-1-ojeda@kernel.org/
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH RFC 0/4] rust: dma: bridge zerocopy-derived types into the transmute byte-safety bound
2026-06-29 7:17 ` [PATCH RFC 0/4] rust: dma: bridge zerocopy-derived types into the transmute byte-safety bound Alexandre Courbot
2026-06-29 8:20 ` Alistair Popple
@ 2026-06-29 11:16 ` SeungJong Ha
1 sibling, 0 replies; 20+ messages in thread
From: SeungJong Ha @ 2026-06-29 11:16 UTC (permalink / raw)
To: Alexandre Courbot, SeungJong Ha via B4 Relay
Cc: engineer.jjhama, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
Onur Özkan, David Airlie, Simona Vetter, rust-for-linux,
linux-kernel, nova-gpu, dri-devel
On Mon Jun 29, 2026 at 7:17 AM UTC, Alexandre Courbot wrote:
> On Mon Jun 29, 2026 at 2:10 AM JST, SeungJong Ha via B4 Relay wrote:
>> DMA-coherent allocations (CoherentAllocation/Coherent/dma::Pool) bound
>> their element type on kernel::transmute::{AsBytes, FromBytes}. This RFC
>> lets a type satisfy that bound by deriving zerocopy's byte-safety traits
>> instead of a hand-written unsafe impl.
>>
>> The bound cannot be switched to zerocopy wholesale (some DMA structs are
>> unions that IntoBytes cannot derive), and a blanket bridge impl is
>> rejected by coherence. So the series bridges the two per type:
>>
>> 1. add the bridge macro impl_transmute_via_zerocopy!, which emits the
>> transmute impls only for a zerocopy-derived type.
>> 2. re-export zerocopy::Immutable from the prelude.
>> 3-4. worked example: convert nova-core's GspMem and msgq POD types.
>
> Can you give more details about what the macro is for? My understanding
> is that it is a temporary fix for the generated bindings; if so, I'd
> prefer to apply a definitive solution (like using
> `#[derive(zerocopy_derive::most_traits)]`, or updating the bindings
> generator tool) rather than something that will be removed later.
This macro is giving safe manual derive from zercopy traits to
transmute. However, it is not necessary if the transmute is going to
be fully replaced with zerocopy. I found it seems to be true [1].
> But intuitively I'd say that we can (and should) probably do without
> this intermediate step. But please let me know if there is something I
> missed.
I agree. The only useful parts remain in this RFC patch is explicit
padding in GspMem. AFAIK it is still necessary after the auto
derivaiton of `most_traits`.
Best Regards
SeungJong
[1] https://lore.kernel.org/all/DJLEHDNJCUD0.38PFZ5773D6BX@kernel.org/
^ permalink raw reply [flat|nested] 20+ messages in thread