From: Alistair Popple <apopple@nvidia.com>
To: Alexandre Courbot <acourbot@nvidia.com>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
"Danilo Krummrich" <dakr@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Nicolás Antinori" <nico.antinori.7@gmail.com>,
"David Airlie" <airlied@gmail.com>,
"Shuah Khan" <skhan@linuxfoundation.org>,
"Simona Vetter" <simona@ffwll.ch>, "Gary Guo" <gary@garyguo.net>,
"Onur Özkan" <work@onurozkan.dev>,
"Tamir Duberstein" <tamird@kernel.org>,
"Trevor Gross" <tmgross@umich.edu>,
"Pedro Yudi Honda" <niyudi.honda@usp.br>,
"SeungJong Ha" <engineer.jjhama@gmail.com>,
linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
rust-for-linux@vger.kernel.org, nova-gpu@lists.linux.de
Subject: Re: [PATCH 1/1] nova-core: Update firmware bindings to use zerocopy traits
Date: Mon, 29 Jun 2026 17:56:50 +1000 [thread overview]
Message-ID: <akIiunspnSSbGWoZ@nvdebian.thelocal> (raw)
In-Reply-To: <DJLD0BCHI6LK.20SNCG6M3E1D1@nvidia.com>
On 2026-06-29 at 17:36 +1000, Alexandre Courbot <acourbot@nvidia.com> wrote...
> On Mon Jun 29, 2026 at 11:52 AM JST, Alistair Popple wrote:
> > Currently most of nova-core uses unsafe implementations of AsBytes and
> > FromBytes in order to read and write GSP commands using the generated
> > bindings. Whilst this is generally safe in practice there is nothing
> > that actually guarantees or checks this.
> >
> > This is exactly what the zerocopy library was introduced to do - provide
> > compile-time checks ensuring From/AsBytes is safe. Make use of these
> > checks by converting all our generated bindings to derive the required
> > traits for the zerocopy checks, removing many unsafe implementations in
> > the process.
> >
> > Note this does require the use of an unstable feature - trivial_bounds
> > - as some bindings end up needing to derive zerocopy::Unaligned.
> > A work-around is also required in the bindings to make some of the
> > __IncompleteArrayField<T> ZSTs monomorphic as the check macro can not
> > prove a generic type is aligned and thus forces T to derive
> > zerocopy::Unaligned, which is not satisfied by all types.
> >
> > Signed-off-by: Alistair Popple <apopple@nvidia.com>
>
> I have counted and this removes 28 unsafe statements. :) (it also adds
> 2 tbf)
>
> > ---
> > drivers/gpu/nova-core/Makefile | 4 +
> > drivers/gpu/nova-core/gsp/cmdq.rs | 21 +-
> > .../gpu/nova-core/gsp/cmdq/continuation.rs | 16 +-
> > drivers/gpu/nova-core/gsp/commands.rs | 19 +-
> > drivers/gpu/nova-core/gsp/fw.rs | 54 +----
> > drivers/gpu/nova-core/gsp/fw/commands.rs | 50 ++---
> > drivers/gpu/nova-core/gsp/fw/r570_144.rs | 41 ++++
> > .../gpu/nova-core/gsp/fw/r570_144/bindings.rs | 185 ++++++++++++------
> > drivers/gpu/nova-core/gsp/sequencer.rs | 5 +-
> > scripts/Makefile.build | 4 +-
> > 10 files changed, 223 insertions(+), 176 deletions(-)
> >
> > diff --git a/drivers/gpu/nova-core/Makefile b/drivers/gpu/nova-core/Makefile
> > index 4ae544f808f4..27a5752c4cf9 100644
> > --- a/drivers/gpu/nova-core/Makefile
> > +++ b/drivers/gpu/nova-core/Makefile
> > @@ -1,4 +1,8 @@
> > # SPDX-License-Identifier: GPL-2.0
> >
> > +# The GSP firmware bindings derive zerocopy's `IntoBytes` on `#[repr(C)]`
> > +# unions, which is gated behind the `zerocopy_derive_union_into_bytes` cfg.
> > +rustflags-y += --cfg zerocopy_derive_union_into_bytes
> > +
> > obj-$(CONFIG_NOVA_CORE) += nova-core.o
> > nova-core-y := nova_core.o
> > diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
> > index 0671ee8a9960..6e79ec688983 100644
> > --- a/drivers/gpu/nova-core/gsp/cmdq.rs
> > +++ b/drivers/gpu/nova-core/gsp/cmdq.rs
> > @@ -29,6 +29,14 @@
> > },
> > };
> >
> > +// TODO: Remove `as` once FromBytes is removed completely
> > +use zerocopy::{
> > + FromBytes as ZCFromBytes,
>
> Since zerocopy's `FromBytes` is the one we will keep long-term, should
> we rather rename the one from `transmute`?
Good idea - it ended up this way because I was going to split the series up to
convert one type at a time but ended up squashing it into one big change given
the mechanical nature of the conversions.
> <...>
> > --- a/drivers/gpu/nova-core/gsp/fw/r570_144.rs
> > +++ b/drivers/gpu/nova-core/gsp/fw/r570_144.rs
> > @@ -23,9 +23,50 @@
> > )]
> > use kernel::ffi;
> > use pin_init::MaybeZeroable;
> > +use zerocopy_derive::{
> > + FromBytes,
> > + Immutable,
> > + IntoBytes,
> > + KnownLayout, //
> > +};
> >
> > include!("r570_144/bindings.rs");
> >
> > // SAFETY: This type has a size of zero, so its inclusion into another type should not affect their
> > // ability to implement `Zeroable`.
> > unsafe impl<T> kernel::prelude::Zeroable for __IncompleteArrayField<T> {}
> > +
> > +/// Monomorphic version of [`__IncompleteArrayField<PACKED_REGISTRY_ENTRY>`].
> > +///
> > +/// zerocopy's `IntoBytes` derive can only run its compile-time no-padding check
> > +/// on a concrete type; for the generic `__IncompleteArrayField<T>` it falls back
> > +/// to requiring every field be `Unaligned`, which `PACKED_REGISTRY_ENTRY`
> > +/// does not satisfy. Specializing to a concrete type lets the derive succeed.
> > +#[repr(C)]
> > +#[derive(Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout, MaybeZeroable)]
> > +pub struct __IncompletePackedRegistryEntry(
> > + ::core::marker::PhantomData<PACKED_REGISTRY_ENTRY>,
> > + [PACKED_REGISTRY_ENTRY; 0],
> > +);
> > +impl __IncompletePackedRegistryEntry {
> > + #[inline]
> > + pub const fn new() -> Self {
> > + __IncompletePackedRegistryEntry(::core::marker::PhantomData, [])
> > + }
> > + #[inline]
> > + pub fn as_ptr(&self) -> *const PACKED_REGISTRY_ENTRY {
> > + self as *const _ as *const PACKED_REGISTRY_ENTRY
> > + }
> > + #[inline]
> > + pub fn as_mut_ptr(&mut self) -> *mut PACKED_REGISTRY_ENTRY {
> > + self as *mut _ as *mut PACKED_REGISTRY_ENTRY
> > + }
> > + #[inline]
> > + pub unsafe fn as_slice(&self, len: usize) -> &[PACKED_REGISTRY_ENTRY] {
> > + ::core::slice::from_raw_parts(self.as_ptr(), len)
> > + }
> > + #[inline]
> > + pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [PACKED_REGISTRY_ENTRY] {
> > + ::core::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
> > + }
> > +}
>
> Yikes, this is a one-shot so I guess we can live with that if neeeded.
Yes, this is a total hack but I couldn't figure out a better alternative.
Given this is the only type that has this problem I figured it was a bearable
trade-off to make, but am open to better suggestions if there are any.
> > 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..9c85c93f6eee 100644
> > --- a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs
> > +++ b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs
> > @@ -1,7 +1,7 @@
> > // SPDX-License-Identifier: GPL-2.0
> >
> > #[repr(C)]
> > -#[derive(Default)]
> > +#[derive(Default, FromBytes, IntoBytes, Immutable, KnownLayout)]
>
> This is the part my other email [1] was about: are we going, long-term,
> to replace this with a `#[derive(zerocopy_derive::most_traits)]`? If the
> Nova's bindings generator program can take care of producing the correct
> traits for each generated type then maybe that's even better, but at the
> same time I am wondering whether the kernel's bindgen invocation isn't
> going to automatically derive `most_traits` on all generated types. In
> this case, we could end up with duplicate implementations.
If that's coming soon I think it makes sense to wait simply to avoid churn
on the generated bindings. I didn't do anything too smart for Nova's binding
generator - it basically just derives all these traits for all our bindings.
Being able to have it derive `most_traits` would be cleaner. So happy to rebase
once that is merged.
> I think this point needs to be clarified before we can decide when to
> merge this patch.
>
> [1] https://lore.kernel.org/all/DJLCF3LR0KMN.1TMKMZEZWKN8O@nvidia.com/
>
> <...>
> > #[repr(C)]
> > -#[derive(Debug, Default, MaybeZeroable)]
> > +#[derive(Debug, Default, MaybeZeroable, FromBytes, Immutable, KnownLayout, IntoBytes)]
> > pub struct PACKED_REGISTRY_TABLE {
> > pub size: u32_,
> > pub numEntries: u32_,
> > - pub entries: __IncompleteArrayField<PACKED_REGISTRY_ENTRY>,
> > + pub entries: __IncompletePackedRegistryEntry,
>
> This is part of the generated bindings, right? How does the generator
> program know it needs to use `__IncompletePackedRegistryEntry`?
Maigc[1] ... otherwise known as `sed` :-)
[1] - https://github.com/apopple-nvidia/nova-gsp-binding-generator/blob/zerocopy/Kbuild#L153
> <...>
> > --- a/scripts/Makefile.build
> > +++ b/scripts/Makefile.build
> > @@ -314,10 +314,12 @@ $(obj)/%.lst: $(obj)/%.c FORCE
> > # - Stable since Rust 1.89.0: `feature(generic_arg_infer)`.
> > # - Expected to become stable: `feature(arbitrary_self_types)`.
> > # - To be determined: `feature(used_with_arg)`.
> > +# - Required by nova-core's zerocopy firmware bindings, whose derives emit
> > +# trivial `where` bounds: `feature(trivial_bounds)`.
> > #
> > # Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on
> > # the unstable features in use.
> > -rust_allowed_features := arbitrary_self_types,asm_goto,generic_arg_infer,used_with_arg
> > +rust_allowed_features := arbitrary_self_types,asm_goto,generic_arg_infer,used_with_arg,trivial_bounds
>
> This also might be something that will land soon through the Rust tree;
> Miguel, do you know what the plan is by any chance?
next prev parent reply other threads:[~2026-06-29 7:57 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-29 2:52 [PATCH 0/1] nova-core: Convert bindings to use zerocopy Alistair Popple
2026-06-29 2:52 ` [PATCH 1/1] nova-core: Update firmware bindings to use zerocopy traits Alistair Popple
2026-06-29 7:36 ` Alexandre Courbot
2026-06-29 7:56 ` Alistair Popple [this message]
2026-06-29 9:21 ` Miguel Ojeda
2026-06-29 9:45 ` Alexandre Courbot
2026-06-29 5:55 ` [PATCH 0/1] nova-core: Convert bindings to use zerocopy SeungJong Ha
2026-06-29 7:09 ` Alexandre Courbot
2026-06-29 8:05 ` Alistair Popple
2026-06-29 8:46 ` Danilo Krummrich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=akIiunspnSSbGWoZ@nvdebian.thelocal \
--to=apopple@nvidia.com \
--cc=acourbot@nvidia.com \
--cc=airlied@gmail.com \
--cc=aliceryhl@google.com \
--cc=dakr@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=engineer.jjhama@gmail.com \
--cc=gary@garyguo.net \
--cc=linux-kernel@vger.kernel.org \
--cc=nico.antinori.7@gmail.com \
--cc=niyudi.honda@usp.br \
--cc=nova-gpu@lists.linux.de \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=skhan@linuxfoundation.org \
--cc=tamird@kernel.org \
--cc=tmgross@umich.edu \
--cc=work@onurozkan.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox