Skip to content

Commit 650c54b

Browse files
committed
Merge tag 'drm-rust-next-2026-04-06' of https://gitlab.freedesktop.org/drm/rust/kernel into drm-next
DRM Rust changes for v7.1-rc1 (2nd) Nova (Core): - Don't create intermediate (mutable) references to the whole command queue buffer, which is potential undefined behavior. - Add missing padding to the falcon firmware DMA buffer to prevent DMA transfers going out of range of the DMA buffer. - Actually set the default values in the bitfield Default implementation. - Use u32::from_le_bytes() instead of manual bit shifts to parse the PCI ROM header. - Fix a missing colon in the SEC2 boot debug message. Signed-off-by: Dave Airlie <[email protected]> From: "Danilo Krummrich" <[email protected]> Link: https://patch.msgid.link/[email protected]
2 parents 4516432 + a7a080b commit 650c54b

5 files changed

Lines changed: 91 additions & 58 deletions

File tree

drivers/gpu/nova-core/bitfield.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -314,12 +314,11 @@ macro_rules! bitfield {
314314
/// Returns a value for the bitfield where all fields are set to their default value.
315315
impl ::core::default::Default for $name {
316316
fn default() -> Self {
317-
#[allow(unused_mut)]
318-
let mut value = Self(Default::default());
317+
let value = Self(Default::default());
319318

320319
::kernel::macros::paste!(
321320
$(
322-
value.[<set_ $field>](Default::default());
321+
let value = value.[<set_ $field>](Default::default());
323322
)*
324323
);
325324

drivers/gpu/nova-core/falcon.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use kernel::{
1111
},
1212
dma::{
1313
Coherent,
14+
CoherentBox,
1415
DmaAddress,
1516
DmaMask, //
1617
},
@@ -613,8 +614,24 @@ impl<E: FalconEngine + 'static> Falcon<E> {
613614
bar: &Bar0,
614615
fw: &F,
615616
) -> Result {
616-
// Create DMA object with firmware content as the source of the DMA engine.
617-
let dma_obj = Coherent::from_slice(dev, fw.as_slice(), GFP_KERNEL)?;
617+
// DMA object with firmware content as the source of the DMA engine.
618+
let dma_obj = {
619+
let fw_slice = fw.as_slice();
620+
621+
// DMA copies are done in chunks of `MEM_BLOCK_ALIGNMENT`, so pad the length
622+
// accordingly and fill with `0`.
623+
let mut dma_obj = CoherentBox::zeroed_slice(
624+
dev,
625+
fw_slice.len().next_multiple_of(MEM_BLOCK_ALIGNMENT),
626+
GFP_KERNEL,
627+
)?;
628+
629+
// PANIC: `dma_obj` has been created with a length equal to or larger than
630+
// `fw_slice.len()`, so the range `..fw_slice.len()` is valid.
631+
dma_obj[..fw_slice.len()].copy_from_slice(fw_slice);
632+
633+
dma_obj.into()
634+
};
618635

619636
self.dma_reset(bar);
620637
bar.update(regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>().at(0), |v| {

drivers/gpu/nova-core/gsp/boot.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ impl super::Gsp {
195195
Some(wpr_handle as u32),
196196
Some((wpr_handle >> 32) as u32),
197197
)?;
198-
dev_dbg!(pdev, "SEC2 MBOX0: {:#x}, MBOX1{:#x}\n", mbox0, mbox1);
198+
dev_dbg!(pdev, "SEC2 MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1);
199199

200200
if mbox0 != 0 {
201201
dev_err!(pdev, "Booter-load failed with error {:#x}\n", mbox0);

drivers/gpu/nova-core/gsp/cmdq.rs

Lines changed: 68 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use kernel::{
1717
},
1818
new_mutex,
1919
prelude::*,
20+
ptr,
2021
sync::{
2122
aref::ARef,
2223
Mutex, //
@@ -255,37 +256,46 @@ impl DmaGspMem {
255256
/// As the message queue is a circular buffer, the region may be discontiguous in memory. In
256257
/// that case the second slice will have a non-zero length.
257258
fn driver_write_area(&mut self) -> (&mut [[u8; GSP_PAGE_SIZE]], &mut [[u8; GSP_PAGE_SIZE]]) {
258-
let tx = self.cpu_write_ptr() as usize;
259-
let rx = self.gsp_read_ptr() as usize;
259+
let tx = self.cpu_write_ptr();
260+
let rx = self.gsp_read_ptr();
260261

261-
// SAFETY:
262-
// - We will only access the driver-owned part of the shared memory.
263-
// - Per the safety statement of the function, no concurrent access will be performed.
264-
let gsp_mem = unsafe { &mut *self.0.as_mut() };
265-
// PANIC: per the invariant of `cpu_write_ptr`, `tx` is `< MSGQ_NUM_PAGES`.
266-
let (before_tx, after_tx) = gsp_mem.cpuq.msgq.data.split_at_mut(tx);
267-
268-
// The area starting at `tx` and ending at `rx - 2` modulo MSGQ_NUM_PAGES, inclusive,
269-
// belongs to the driver for writing.
270-
271-
if rx == 0 {
272-
// Since `rx` is zero, leave an empty slot at end of the buffer.
273-
let last = after_tx.len() - 1;
274-
(&mut after_tx[..last], &mut [])
262+
// Pointer to the first entry of the CPU message queue.
263+
let data = ptr::project!(mut self.0.as_mut_ptr(), .cpuq.msgq.data[0]);
264+
265+
let (tail_end, wrap_end) = if rx == 0 {
266+
// The write area is non-wrapping, and stops at the second-to-last entry of the command
267+
// queue (to leave the last one empty).
268+
(MSGQ_NUM_PAGES - 1, 0)
275269
} else if rx <= tx {
276-
// The area is discontiguous and we leave an empty slot before `rx`.
277-
// PANIC:
278-
// - The index `rx - 1` is non-negative because `rx != 0` in this branch.
279-
// - The index does not exceed `before_tx.len()` (which equals `tx`) because
280-
// `rx <= tx` in this branch.
281-
(after_tx, &mut before_tx[..(rx - 1)])
270+
// The write area wraps and continues until `rx - 1`.
271+
(MSGQ_NUM_PAGES, rx - 1)
282272
} else {
283-
// The area is contiguous and we leave an empty slot before `rx`.
284-
// PANIC:
285-
// - The index `rx - tx - 1` is non-negative because `rx > tx` in this branch.
286-
// - The index does not exceed `after_tx.len()` (which is `MSGQ_NUM_PAGES - tx`)
287-
// because `rx < MSGQ_NUM_PAGES` by the `gsp_read_ptr` invariant.
288-
(&mut after_tx[..(rx - tx - 1)], &mut [])
273+
// The write area doesn't wrap and stops at `rx - 1`.
274+
(rx - 1, 0)
275+
};
276+
277+
// SAFETY:
278+
// - `data` was created from a valid pointer, and `rx` and `tx` are in the
279+
// `0..MSGQ_NUM_PAGES` range per the invariants of `cpu_write_ptr` and `gsp_read_ptr`,
280+
// thus the created slices are valid.
281+
// - The area starting at `tx` and ending at `rx - 2` modulo `MSGQ_NUM_PAGES`,
282+
// inclusive, belongs to the driver for writing and is not accessed concurrently by
283+
// the GSP.
284+
// - The caller holds a reference to `self` for as long as the returned slices are live,
285+
// meaning the CPU write pointer cannot be advanced and thus that the returned area
286+
// remains exclusive to the CPU for the duration of the slices.
287+
// - The created slices point to non-overlapping sub-ranges of `data` in all
288+
// branches (in the `rx <= tx` case, the second slice ends at `rx - 1` which is strictly
289+
// less than `tx` where the first slice starts; in the other cases the second slice is
290+
// empty), so creating two `&mut` references from them does not violate aliasing rules.
291+
unsafe {
292+
(
293+
core::slice::from_raw_parts_mut(
294+
data.add(num::u32_as_usize(tx)),
295+
num::u32_as_usize(tail_end - tx),
296+
),
297+
core::slice::from_raw_parts_mut(data, num::u32_as_usize(wrap_end)),
298+
)
289299
}
290300
}
291301

@@ -308,26 +318,38 @@ impl DmaGspMem {
308318
/// As the message queue is a circular buffer, the region may be discontiguous in memory. In
309319
/// that case the second slice will have a non-zero length.
310320
fn driver_read_area(&self) -> (&[[u8; GSP_PAGE_SIZE]], &[[u8; GSP_PAGE_SIZE]]) {
311-
let tx = self.gsp_write_ptr() as usize;
312-
let rx = self.cpu_read_ptr() as usize;
321+
let tx = self.gsp_write_ptr();
322+
let rx = self.cpu_read_ptr();
313323

314-
// SAFETY:
315-
// - We will only access the driver-owned part of the shared memory.
316-
// - Per the safety statement of the function, no concurrent access will be performed.
317-
let gsp_mem = unsafe { &*self.0.as_ptr() };
318-
let data = &gsp_mem.gspq.msgq.data;
319-
320-
// The area starting at `rx` and ending at `tx - 1` modulo MSGQ_NUM_PAGES, inclusive,
321-
// belongs to the driver for reading.
322-
// PANIC:
323-
// - per the invariant of `cpu_read_ptr`, `rx < MSGQ_NUM_PAGES`
324-
// - per the invariant of `gsp_write_ptr`, `tx < MSGQ_NUM_PAGES`
325-
if rx <= tx {
326-
// The area is contiguous.
327-
(&data[rx..tx], &[])
324+
// Pointer to the first entry of the GSP message queue.
325+
let data = ptr::project!(self.0.as_ptr(), .gspq.msgq.data[0]);
326+
327+
let (tail_end, wrap_end) = if rx <= tx {
328+
// Read area is non-wrapping and stops right before `tx`.
329+
(tx, 0)
328330
} else {
329-
// The area is discontiguous.
330-
(&data[rx..], &data[..tx])
331+
// Read area is wrapping and stops right before `tx`.
332+
(MSGQ_NUM_PAGES, tx)
333+
};
334+
335+
// SAFETY:
336+
// - `data` was created from a valid pointer, and `rx` and `tx` are in the
337+
// `0..MSGQ_NUM_PAGES` range per the invariants of `gsp_write_ptr` and `cpu_read_ptr`,
338+
// thus the created slices are valid.
339+
// - The area starting at `rx` and ending at `tx - 1` modulo `MSGQ_NUM_PAGES`,
340+
// inclusive, belongs to the driver for reading and is not accessed concurrently by
341+
// the GSP.
342+
// - The caller holds a reference to `self` for as long as the returned slices are live,
343+
// meaning the CPU read pointer cannot be advanced and thus that the returned area
344+
// remains exclusive to the CPU for the duration of the slices.
345+
unsafe {
346+
(
347+
core::slice::from_raw_parts(
348+
data.add(num::u32_as_usize(rx)),
349+
num::u32_as_usize(tail_end - rx),
350+
),
351+
core::slice::from_raw_parts(data, num::u32_as_usize(wrap_end)),
352+
)
331353
}
332354
}
333355

drivers/gpu/nova-core/vbios.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -507,12 +507,7 @@ impl PciRomHeader {
507507

508508
if data.len() >= 30 {
509509
// Read size_of_block at offset 0x1A.
510-
size_of_block = Some(
511-
u32::from(data[29]) << 24
512-
| u32::from(data[28]) << 16
513-
| u32::from(data[27]) << 8
514-
| u32::from(data[26]),
515-
);
510+
size_of_block = Some(u32::from_le_bytes([data[26], data[27], data[28], data[29]]));
516511
}
517512

518513
// For NBSI images, try to read the nbsiDataOffset at offset 0x16.

0 commit comments

Comments
 (0)