[PATCH 3/3] gpu: nova-core: gsp: map the WPR meta for streaming DMA
Maurice Hieronymus <[email protected]> Wed, 05 Aug 2026 23:54:43 +0200
| Newsgroups | org.kernel.vger.rust-for-linux,dev.linux.lists.driver-core,dev.linux.lists.nova-gpu,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
`GspFwWprMeta` is filled in once during boot, read out of system memory by the booter, and dropped when `Gsp::boot()` returns. That is a streaming transfer, so a coherent allocation buys nothing. Map a `KBox<GspFwWprMeta>` instead. The mapping is submitted right after initialization, which makes the contents unreachable for the duration of the chipset-specific boot sequence and lets `dma_handle()` be read through a shared reference. `complete()` is called as soon as `hal.boot()` succeeds, the earliest point the device is provably done with the metadata: on Tu102 the Booter-load falcon has halted, on GH100 GSP-FMC has released the lockdown. If `hal.boot()` fails instead, no such proof exists -- `Gsp::unload()` deliberately carries on past failed steps, so the falcon may still be reading the buffer -- and `wpr_meta` drops in flight, trading a one-off leak for a device-side use-after-free. Signed-off-by: Maurice Hieronymus <[email protected]> --- drivers/gpu/nova-core/firmware/booter.rs | 11 +++++++---- drivers/gpu/nova-core/gsp/boot.rs | 20 ++++++++++++++++++-- drivers/gpu/nova-core/gsp/hal.rs | 4 ++-- drivers/gpu/nova-core/gsp/hal/gh100.rs | 4 ++-- drivers/gpu/nova-core/gsp/hal/tu102.rs | 4 ++-- 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs index d9313ac361af..780c7702a777 100644 --- a/drivers/gpu/nova-core/firmware/booter.rs +++ b/drivers/gpu/nova-core/firmware/booter.rs @@ -9,9 +9,12 @@ use kernel::{ device, - dma::Coherent, + dma::StreamingInFlight, prelude::*, - transmute::FromBytes, // + transmute::{ + AsBytes, + FromBytes, // + }, }; use crate::{ @@ -402,12 +405,12 @@ pub(crate) fn new( /// /// Resets SEC2, loads this firmware image, then boots with the WPR metadata /// address passed via the SEC2 mailboxes. - pub(crate) fn run<T>( + pub(crate) fn run<T: FromBytes + AsBytes>( &self, dev: &device::Device<device::Bound>, bar: Bar0<'_>, sec2_falcon: &Falcon<Sec2>, - wpr_meta: &Coherent<T>, + wpr_meta: &StreamingInFlight<'_, KBox<T>>, ) -> Result { sec2_falcon.reset(bar)?; sec2_falcon.load(dev, bar, self)?; diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs index 8afb62d689cb..300ebf4e843d 100644 --- a/drivers/gpu/nova-core/gsp/boot.rs +++ b/drivers/gpu/nova-core/gsp/boot.rs @@ -4,7 +4,10 @@ use kernel::{ bits, device, - dma::Coherent, + dma::{ + DataDirection, + Streaming, // + }, io::poll::read_poll_timeout, pci, prelude::*, @@ -117,7 +120,12 @@ pub(crate) fn boot( let fb_layout = FbLayout::new(chipset, bar, &gsp_fw)?; dev_dbg!(dev, "{:#x?}\n", fb_layout); - let wpr_meta = Coherent::init(dev, GFP_KERNEL, GspFwWprMeta::new(&gsp_fw, &fb_layout))?; + let wpr_meta = Streaming::new( + dev, + KBox::init(GspFwWprMeta::new(&gsp_fw, &fb_layout), GFP_KERNEL)?, + DataDirection::ToDevice, + )? + .submit(); // Perform the chipset-specific boot sequence, and retrieve the unload bundle. let unload_guard = hal.boot( @@ -131,6 +139,14 @@ pub(crate) fn boot( sec2_falcon, )?; + // The chipset-specific boot sequence only succeeds once the device is done reading the + // WPR metadata: on Tu102 the Booter-load falcon has halted, on GH100 GSP-FMC has released + // the lockdown. If it fails instead, `wpr_meta` drops in flight and leaks, as the falcon + // may still be reading the buffer. + // + // SAFETY: Per the above, the device has finished accessing the buffer. + let _ = unsafe { wpr_meta.complete() }; + gsp_falcon.write_os_version(bar, gsp_fw.bootloader.app_version); // Poll for RISC-V to become active before continuing. diff --git a/drivers/gpu/nova-core/gsp/hal.rs b/drivers/gpu/nova-core/gsp/hal.rs index 04f004856c60..09a523e3a180 100644 --- a/drivers/gpu/nova-core/gsp/hal.rs +++ b/drivers/gpu/nova-core/gsp/hal.rs @@ -8,7 +8,7 @@ use kernel::{ device, - dma::Coherent, // + dma::StreamingInFlight, // }; use crate::{ @@ -61,7 +61,7 @@ fn boot<'a>( bar: Bar0<'a>, chipset: Chipset, fb_layout: &FbLayout, - wpr_meta: &Coherent<GspFwWprMeta>, + wpr_meta: &StreamingInFlight<'_, KBox<GspFwWprMeta>>, gsp_falcon: &'a Falcon<GspEngine>, sec2_falcon: &'a Falcon<Sec2>, ) -> Result<BootUnloadGuard<'a>>; diff --git a/drivers/gpu/nova-core/gsp/hal/gh100.rs b/drivers/gpu/nova-core/gsp/hal/gh100.rs index 98f5ce197d13..67a79c54a739 100644 --- a/drivers/gpu/nova-core/gsp/hal/gh100.rs +++ b/drivers/gpu/nova-core/gsp/hal/gh100.rs @@ -5,7 +5,7 @@ use kernel::{ device, - dma::Coherent, + dma::StreamingInFlight, io::poll::read_poll_timeout, time::Delta, // }; @@ -156,7 +156,7 @@ fn boot<'a>( bar: Bar0<'a>, chipset: Chipset, fb_layout: &FbLayout, - wpr_meta: &Coherent<GspFwWprMeta>, + wpr_meta: &StreamingInFlight<'_, KBox<GspFwWprMeta>>, gsp_falcon: &'a Falcon<GspEngine>, sec2_falcon: &'a Falcon<Sec2>, ) -> Result<BootUnloadGuard<'a>> { diff --git a/drivers/gpu/nova-core/gsp/hal/tu102.rs b/drivers/gpu/nova-core/gsp/hal/tu102.rs index 2f6301af7113..7d906de6d8bf 100644 --- a/drivers/gpu/nova-core/gsp/hal/tu102.rs +++ b/drivers/gpu/nova-core/gsp/hal/tu102.rs @@ -5,7 +5,7 @@ use kernel::{ device, - dma::Coherent, + dma::StreamingInFlight, io::Io, // }; @@ -262,7 +262,7 @@ fn boot<'a>( bar: Bar0<'a>, chipset: Chipset, fb_layout: &FbLayout, - wpr_meta: &Coherent<GspFwWprMeta>, + wpr_meta: &StreamingInFlight<'_, KBox<GspFwWprMeta>>, gsp_falcon: &'a Falcon<GspEngine>, sec2_falcon: &'a Falcon<Sec2>, ) -> Result<BootUnloadGuard<'a>> { -- 2.54.0