Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <airlied@redhat.com>

From: "Danilo Krummrich" <dakr@kernel.org>
Link: https://patch.msgid.link/DHN5GMSIBKO2.2AYOLXDU4X19S@kernel.org

+92 -59
+2 -3
drivers/gpu/nova-core/bitfield.rs
··· 314 314 /// Returns a value for the bitfield where all fields are set to their default value. 315 315 impl ::core::default::Default for $name { 316 316 fn default() -> Self { 317 - #[allow(unused_mut)] 318 - let mut value = Self(Default::default()); 317 + let value = Self(Default::default()); 319 318 320 319 ::kernel::macros::paste!( 321 320 $( 322 - value.[<set_ $field>](Default::default()); 321 + let value = value.[<set_ $field>](Default::default()); 323 322 )* 324 323 ); 325 324
+19 -2
drivers/gpu/nova-core/falcon.rs
··· 11 11 }, 12 12 dma::{ 13 13 Coherent, 14 + CoherentBox, 14 15 DmaAddress, 15 16 DmaMask, // 16 17 }, ··· 614 613 bar: &Bar0, 615 614 fw: &F, 616 615 ) -> Result { 617 - // Create DMA object with firmware content as the source of the DMA engine. 618 - let dma_obj = Coherent::from_slice(dev, fw.as_slice(), GFP_KERNEL)?; 616 + // DMA object with firmware content as the source of the DMA engine. 617 + let dma_obj = { 618 + let fw_slice = fw.as_slice(); 619 + 620 + // DMA copies are done in chunks of `MEM_BLOCK_ALIGNMENT`, so pad the length 621 + // accordingly and fill with `0`. 622 + let mut dma_obj = CoherentBox::zeroed_slice( 623 + dev, 624 + fw_slice.len().next_multiple_of(MEM_BLOCK_ALIGNMENT), 625 + GFP_KERNEL, 626 + )?; 627 + 628 + // PANIC: `dma_obj` has been created with a length equal to or larger than 629 + // `fw_slice.len()`, so the range `..fw_slice.len()` is valid. 630 + dma_obj[..fw_slice.len()].copy_from_slice(fw_slice); 631 + 632 + dma_obj.into() 633 + }; 619 634 620 635 self.dma_reset(bar); 621 636 bar.update(regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>().at(0), |v| {
+1 -1
drivers/gpu/nova-core/gsp/boot.rs
··· 195 195 Some(wpr_handle as u32), 196 196 Some((wpr_handle >> 32) as u32), 197 197 )?; 198 - dev_dbg!(pdev, "SEC2 MBOX0: {:#x}, MBOX1{:#x}\n", mbox0, mbox1); 198 + dev_dbg!(pdev, "SEC2 MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1); 199 199 200 200 if mbox0 != 0 { 201 201 dev_err!(pdev, "Booter-load failed with error {:#x}\n", mbox0);
+69 -47
drivers/gpu/nova-core/gsp/cmdq.rs
··· 17 17 }, 18 18 new_mutex, 19 19 prelude::*, 20 + ptr, 20 21 sync::{ 21 22 aref::ARef, 22 23 Mutex, // ··· 256 255 /// As the message queue is a circular buffer, the region may be discontiguous in memory. In 257 256 /// that case the second slice will have a non-zero length. 258 257 fn driver_write_area(&mut self) -> (&mut [[u8; GSP_PAGE_SIZE]], &mut [[u8; GSP_PAGE_SIZE]]) { 259 - let tx = self.cpu_write_ptr() as usize; 260 - let rx = self.gsp_read_ptr() as usize; 258 + let tx = self.cpu_write_ptr(); 259 + let rx = self.gsp_read_ptr(); 260 + 261 + // Pointer to the first entry of the CPU message queue. 262 + let data = ptr::project!(mut self.0.as_mut_ptr(), .cpuq.msgq.data[0]); 263 + 264 + let (tail_end, wrap_end) = if rx == 0 { 265 + // The write area is non-wrapping, and stops at the second-to-last entry of the command 266 + // queue (to leave the last one empty). 267 + (MSGQ_NUM_PAGES - 1, 0) 268 + } else if rx <= tx { 269 + // The write area wraps and continues until `rx - 1`. 270 + (MSGQ_NUM_PAGES, rx - 1) 271 + } else { 272 + // The write area doesn't wrap and stops at `rx - 1`. 273 + (rx - 1, 0) 274 + }; 261 275 262 276 // SAFETY: 263 - // - We will only access the driver-owned part of the shared memory. 264 - // - Per the safety statement of the function, no concurrent access will be performed. 265 - let gsp_mem = unsafe { &mut *self.0.as_mut() }; 266 - // PANIC: per the invariant of `cpu_write_ptr`, `tx` is `< MSGQ_NUM_PAGES`. 267 - let (before_tx, after_tx) = gsp_mem.cpuq.msgq.data.split_at_mut(tx); 268 - 269 - // The area starting at `tx` and ending at `rx - 2` modulo MSGQ_NUM_PAGES, inclusive, 270 - // belongs to the driver for writing. 271 - 272 - if rx == 0 { 273 - // Since `rx` is zero, leave an empty slot at end of the buffer. 274 - let last = after_tx.len() - 1; 275 - (&mut after_tx[..last], &mut []) 276 - } else if rx <= tx { 277 - // The area is discontiguous and we leave an empty slot before `rx`. 278 - // PANIC: 279 - // - The index `rx - 1` is non-negative because `rx != 0` in this branch. 280 - // - The index does not exceed `before_tx.len()` (which equals `tx`) because 281 - // `rx <= tx` in this branch. 282 - (after_tx, &mut before_tx[..(rx - 1)]) 283 - } else { 284 - // The area is contiguous and we leave an empty slot before `rx`. 285 - // PANIC: 286 - // - The index `rx - tx - 1` is non-negative because `rx > tx` in this branch. 287 - // - The index does not exceed `after_tx.len()` (which is `MSGQ_NUM_PAGES - tx`) 288 - // because `rx < MSGQ_NUM_PAGES` by the `gsp_read_ptr` invariant. 289 - (&mut after_tx[..(rx - tx - 1)], &mut []) 277 + // - `data` was created from a valid pointer, and `rx` and `tx` are in the 278 + // `0..MSGQ_NUM_PAGES` range per the invariants of `cpu_write_ptr` and `gsp_read_ptr`, 279 + // thus the created slices are valid. 280 + // - The area starting at `tx` and ending at `rx - 2` modulo `MSGQ_NUM_PAGES`, 281 + // inclusive, belongs to the driver for writing and is not accessed concurrently by 282 + // the GSP. 283 + // - The caller holds a reference to `self` for as long as the returned slices are live, 284 + // meaning the CPU write pointer cannot be advanced and thus that the returned area 285 + // remains exclusive to the CPU for the duration of the slices. 286 + // - The created slices point to non-overlapping sub-ranges of `data` in all 287 + // branches (in the `rx <= tx` case, the second slice ends at `rx - 1` which is strictly 288 + // less than `tx` where the first slice starts; in the other cases the second slice is 289 + // empty), so creating two `&mut` references from them does not violate aliasing rules. 290 + unsafe { 291 + ( 292 + core::slice::from_raw_parts_mut( 293 + data.add(num::u32_as_usize(tx)), 294 + num::u32_as_usize(tail_end - tx), 295 + ), 296 + core::slice::from_raw_parts_mut(data, num::u32_as_usize(wrap_end)), 297 + ) 290 298 } 291 299 } 292 300 ··· 318 308 /// As the message queue is a circular buffer, the region may be discontiguous in memory. In 319 309 /// that case the second slice will have a non-zero length. 320 310 fn driver_read_area(&self) -> (&[[u8; GSP_PAGE_SIZE]], &[[u8; GSP_PAGE_SIZE]]) { 321 - let tx = self.gsp_write_ptr() as usize; 322 - let rx = self.cpu_read_ptr() as usize; 311 + let tx = self.gsp_write_ptr(); 312 + let rx = self.cpu_read_ptr(); 313 + 314 + // Pointer to the first entry of the GSP message queue. 315 + let data = ptr::project!(self.0.as_ptr(), .gspq.msgq.data[0]); 316 + 317 + let (tail_end, wrap_end) = if rx <= tx { 318 + // Read area is non-wrapping and stops right before `tx`. 319 + (tx, 0) 320 + } else { 321 + // Read area is wrapping and stops right before `tx`. 322 + (MSGQ_NUM_PAGES, tx) 323 + }; 323 324 324 325 // SAFETY: 325 - // - We will only access the driver-owned part of the shared memory. 326 - // - Per the safety statement of the function, no concurrent access will be performed. 327 - let gsp_mem = unsafe { &*self.0.as_ptr() }; 328 - let data = &gsp_mem.gspq.msgq.data; 329 - 330 - // The area starting at `rx` and ending at `tx - 1` modulo MSGQ_NUM_PAGES, inclusive, 331 - // belongs to the driver for reading. 332 - // PANIC: 333 - // - per the invariant of `cpu_read_ptr`, `rx < MSGQ_NUM_PAGES` 334 - // - per the invariant of `gsp_write_ptr`, `tx < MSGQ_NUM_PAGES` 335 - if rx <= tx { 336 - // The area is contiguous. 337 - (&data[rx..tx], &[]) 338 - } else { 339 - // The area is discontiguous. 340 - (&data[rx..], &data[..tx]) 326 + // - `data` was created from a valid pointer, and `rx` and `tx` are in the 327 + // `0..MSGQ_NUM_PAGES` range per the invariants of `gsp_write_ptr` and `cpu_read_ptr`, 328 + // thus the created slices are valid. 329 + // - The area starting at `rx` and ending at `tx - 1` modulo `MSGQ_NUM_PAGES`, 330 + // inclusive, belongs to the driver for reading and is not accessed concurrently by 331 + // the GSP. 332 + // - The caller holds a reference to `self` for as long as the returned slices are live, 333 + // meaning the CPU read pointer cannot be advanced and thus that the returned area 334 + // remains exclusive to the CPU for the duration of the slices. 335 + unsafe { 336 + ( 337 + core::slice::from_raw_parts( 338 + data.add(num::u32_as_usize(rx)), 339 + num::u32_as_usize(tail_end - rx), 340 + ), 341 + core::slice::from_raw_parts(data, num::u32_as_usize(wrap_end)), 342 + ) 341 343 } 342 344 } 343 345
+1 -6
drivers/gpu/nova-core/vbios.rs
··· 507 507 508 508 if data.len() >= 30 { 509 509 // 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]])); 516 511 } 517 512 518 513 // For NBSI images, try to read the nbsiDataOffset at offset 0x16.