mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
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.
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQS2q/xV6QjXAdC7k+1FlHeO1qrKLgUCadPUOQAKCRBFlHeO1qrK
LgOfAP0ccOjRYuACBcwJHsWio19SmVsuzdCjcSX3S6lPsPaaYAD/QuOLCvbKLPUz
3/8yI+jdw8FL9BfI+MI4gUVQAuehJg4=
=oEBZ
-----END PGP SIGNATURE-----
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
This commit is contained in:
commit
650c54b6a5
|
|
@ -314,12 +314,11 @@ fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
|
|||
/// Returns a value for the bitfield where all fields are set to their default value.
|
||||
impl ::core::default::Default for $name {
|
||||
fn default() -> Self {
|
||||
#[allow(unused_mut)]
|
||||
let mut value = Self(Default::default());
|
||||
let value = Self(Default::default());
|
||||
|
||||
::kernel::macros::paste!(
|
||||
$(
|
||||
value.[<set_ $field>](Default::default());
|
||||
let value = value.[<set_ $field>](Default::default());
|
||||
)*
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
},
|
||||
dma::{
|
||||
Coherent,
|
||||
CoherentBox,
|
||||
DmaAddress,
|
||||
DmaMask, //
|
||||
},
|
||||
|
|
@ -613,8 +614,24 @@ fn dma_load<F: FalconFirmware<Target = E> + FalconDmaLoadable>(
|
|||
bar: &Bar0,
|
||||
fw: &F,
|
||||
) -> Result {
|
||||
// Create DMA object with firmware content as the source of the DMA engine.
|
||||
let dma_obj = Coherent::from_slice(dev, fw.as_slice(), GFP_KERNEL)?;
|
||||
// DMA object with firmware content as the source of the DMA engine.
|
||||
let dma_obj = {
|
||||
let fw_slice = fw.as_slice();
|
||||
|
||||
// DMA copies are done in chunks of `MEM_BLOCK_ALIGNMENT`, so pad the length
|
||||
// accordingly and fill with `0`.
|
||||
let mut dma_obj = CoherentBox::zeroed_slice(
|
||||
dev,
|
||||
fw_slice.len().next_multiple_of(MEM_BLOCK_ALIGNMENT),
|
||||
GFP_KERNEL,
|
||||
)?;
|
||||
|
||||
// PANIC: `dma_obj` has been created with a length equal to or larger than
|
||||
// `fw_slice.len()`, so the range `..fw_slice.len()` is valid.
|
||||
dma_obj[..fw_slice.len()].copy_from_slice(fw_slice);
|
||||
|
||||
dma_obj.into()
|
||||
};
|
||||
|
||||
self.dma_reset(bar);
|
||||
bar.update(regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>().at(0), |v| {
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ pub(crate) fn boot(
|
|||
Some(wpr_handle as u32),
|
||||
Some((wpr_handle >> 32) as u32),
|
||||
)?;
|
||||
dev_dbg!(pdev, "SEC2 MBOX0: {:#x}, MBOX1{:#x}\n", mbox0, mbox1);
|
||||
dev_dbg!(pdev, "SEC2 MBOX0: {:#x}, MBOX1: {:#x}\n", mbox0, mbox1);
|
||||
|
||||
if mbox0 != 0 {
|
||||
dev_err!(pdev, "Booter-load failed with error {:#x}\n", mbox0);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
},
|
||||
new_mutex,
|
||||
prelude::*,
|
||||
ptr,
|
||||
sync::{
|
||||
aref::ARef,
|
||||
Mutex, //
|
||||
|
|
@ -255,37 +256,46 @@ fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
|
|||
/// As the message queue is a circular buffer, the region may be discontiguous in memory. In
|
||||
/// that case the second slice will have a non-zero length.
|
||||
fn driver_write_area(&mut self) -> (&mut [[u8; GSP_PAGE_SIZE]], &mut [[u8; GSP_PAGE_SIZE]]) {
|
||||
let tx = self.cpu_write_ptr() as usize;
|
||||
let rx = self.gsp_read_ptr() as usize;
|
||||
let tx = self.cpu_write_ptr();
|
||||
let rx = self.gsp_read_ptr();
|
||||
|
||||
// Pointer to the first entry of the CPU message queue.
|
||||
let data = ptr::project!(mut self.0.as_mut_ptr(), .cpuq.msgq.data[0]);
|
||||
|
||||
let (tail_end, wrap_end) = if rx == 0 {
|
||||
// The write area is non-wrapping, and stops at the second-to-last entry of the command
|
||||
// queue (to leave the last one empty).
|
||||
(MSGQ_NUM_PAGES - 1, 0)
|
||||
} else if rx <= tx {
|
||||
// The write area wraps and continues until `rx - 1`.
|
||||
(MSGQ_NUM_PAGES, rx - 1)
|
||||
} else {
|
||||
// The write area doesn't wrap and stops at `rx - 1`.
|
||||
(rx - 1, 0)
|
||||
};
|
||||
|
||||
// SAFETY:
|
||||
// - We will only access the driver-owned part of the shared memory.
|
||||
// - Per the safety statement of the function, no concurrent access will be performed.
|
||||
let gsp_mem = unsafe { &mut *self.0.as_mut() };
|
||||
// PANIC: per the invariant of `cpu_write_ptr`, `tx` is `< MSGQ_NUM_PAGES`.
|
||||
let (before_tx, after_tx) = gsp_mem.cpuq.msgq.data.split_at_mut(tx);
|
||||
|
||||
// The area starting at `tx` and ending at `rx - 2` modulo MSGQ_NUM_PAGES, inclusive,
|
||||
// belongs to the driver for writing.
|
||||
|
||||
if rx == 0 {
|
||||
// Since `rx` is zero, leave an empty slot at end of the buffer.
|
||||
let last = after_tx.len() - 1;
|
||||
(&mut after_tx[..last], &mut [])
|
||||
} else if rx <= tx {
|
||||
// The area is discontiguous and we leave an empty slot before `rx`.
|
||||
// PANIC:
|
||||
// - The index `rx - 1` is non-negative because `rx != 0` in this branch.
|
||||
// - The index does not exceed `before_tx.len()` (which equals `tx`) because
|
||||
// `rx <= tx` in this branch.
|
||||
(after_tx, &mut before_tx[..(rx - 1)])
|
||||
} else {
|
||||
// The area is contiguous and we leave an empty slot before `rx`.
|
||||
// PANIC:
|
||||
// - The index `rx - tx - 1` is non-negative because `rx > tx` in this branch.
|
||||
// - The index does not exceed `after_tx.len()` (which is `MSGQ_NUM_PAGES - tx`)
|
||||
// because `rx < MSGQ_NUM_PAGES` by the `gsp_read_ptr` invariant.
|
||||
(&mut after_tx[..(rx - tx - 1)], &mut [])
|
||||
// - `data` was created from a valid pointer, and `rx` and `tx` are in the
|
||||
// `0..MSGQ_NUM_PAGES` range per the invariants of `cpu_write_ptr` and `gsp_read_ptr`,
|
||||
// thus the created slices are valid.
|
||||
// - The area starting at `tx` and ending at `rx - 2` modulo `MSGQ_NUM_PAGES`,
|
||||
// inclusive, belongs to the driver for writing and is not accessed concurrently by
|
||||
// the GSP.
|
||||
// - The caller holds a reference to `self` for as long as the returned slices are live,
|
||||
// meaning the CPU write pointer cannot be advanced and thus that the returned area
|
||||
// remains exclusive to the CPU for the duration of the slices.
|
||||
// - The created slices point to non-overlapping sub-ranges of `data` in all
|
||||
// branches (in the `rx <= tx` case, the second slice ends at `rx - 1` which is strictly
|
||||
// less than `tx` where the first slice starts; in the other cases the second slice is
|
||||
// empty), so creating two `&mut` references from them does not violate aliasing rules.
|
||||
unsafe {
|
||||
(
|
||||
core::slice::from_raw_parts_mut(
|
||||
data.add(num::u32_as_usize(tx)),
|
||||
num::u32_as_usize(tail_end - tx),
|
||||
),
|
||||
core::slice::from_raw_parts_mut(data, num::u32_as_usize(wrap_end)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -308,26 +318,38 @@ fn driver_write_area_size(&self) -> usize {
|
|||
/// As the message queue is a circular buffer, the region may be discontiguous in memory. In
|
||||
/// that case the second slice will have a non-zero length.
|
||||
fn driver_read_area(&self) -> (&[[u8; GSP_PAGE_SIZE]], &[[u8; GSP_PAGE_SIZE]]) {
|
||||
let tx = self.gsp_write_ptr() as usize;
|
||||
let rx = self.cpu_read_ptr() as usize;
|
||||
let tx = self.gsp_write_ptr();
|
||||
let rx = self.cpu_read_ptr();
|
||||
|
||||
// Pointer to the first entry of the GSP message queue.
|
||||
let data = ptr::project!(self.0.as_ptr(), .gspq.msgq.data[0]);
|
||||
|
||||
let (tail_end, wrap_end) = if rx <= tx {
|
||||
// Read area is non-wrapping and stops right before `tx`.
|
||||
(tx, 0)
|
||||
} else {
|
||||
// Read area is wrapping and stops right before `tx`.
|
||||
(MSGQ_NUM_PAGES, tx)
|
||||
};
|
||||
|
||||
// SAFETY:
|
||||
// - We will only access the driver-owned part of the shared memory.
|
||||
// - Per the safety statement of the function, no concurrent access will be performed.
|
||||
let gsp_mem = unsafe { &*self.0.as_ptr() };
|
||||
let data = &gsp_mem.gspq.msgq.data;
|
||||
|
||||
// The area starting at `rx` and ending at `tx - 1` modulo MSGQ_NUM_PAGES, inclusive,
|
||||
// belongs to the driver for reading.
|
||||
// PANIC:
|
||||
// - per the invariant of `cpu_read_ptr`, `rx < MSGQ_NUM_PAGES`
|
||||
// - per the invariant of `gsp_write_ptr`, `tx < MSGQ_NUM_PAGES`
|
||||
if rx <= tx {
|
||||
// The area is contiguous.
|
||||
(&data[rx..tx], &[])
|
||||
} else {
|
||||
// The area is discontiguous.
|
||||
(&data[rx..], &data[..tx])
|
||||
// - `data` was created from a valid pointer, and `rx` and `tx` are in the
|
||||
// `0..MSGQ_NUM_PAGES` range per the invariants of `gsp_write_ptr` and `cpu_read_ptr`,
|
||||
// thus the created slices are valid.
|
||||
// - The area starting at `rx` and ending at `tx - 1` modulo `MSGQ_NUM_PAGES`,
|
||||
// inclusive, belongs to the driver for reading and is not accessed concurrently by
|
||||
// the GSP.
|
||||
// - The caller holds a reference to `self` for as long as the returned slices are live,
|
||||
// meaning the CPU read pointer cannot be advanced and thus that the returned area
|
||||
// remains exclusive to the CPU for the duration of the slices.
|
||||
unsafe {
|
||||
(
|
||||
core::slice::from_raw_parts(
|
||||
data.add(num::u32_as_usize(rx)),
|
||||
num::u32_as_usize(tail_end - rx),
|
||||
),
|
||||
core::slice::from_raw_parts(data, num::u32_as_usize(wrap_end)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -507,12 +507,7 @@ fn new(dev: &device::Device, data: &[u8]) -> Result<Self> {
|
|||
|
||||
if data.len() >= 30 {
|
||||
// Read size_of_block at offset 0x1A.
|
||||
size_of_block = Some(
|
||||
u32::from(data[29]) << 24
|
||||
| u32::from(data[28]) << 16
|
||||
| u32::from(data[27]) << 8
|
||||
| u32::from(data[26]),
|
||||
);
|
||||
size_of_block = Some(u32::from_le_bytes([data[26], data[27], data[28], data[29]]));
|
||||
}
|
||||
|
||||
// For NBSI images, try to read the nbsiDataOffset at offset 0x16.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user