Allow userspace to provide a buffer that is smaller or larger than the object that the kernel expects to write into it.
Set a minimum buffer size to match those in PANTHOR_UOBJ_MIN_SIZE. If userspace provides at least the minimum buffer size, then simply write until the buffer is full. If userspace provides a larger buffer than necessary, then zero out the remaining buffer. This ensures UAPI compatibility with Panthor. Signed-off-by: Deborah Brouwer <[email protected]> --- drivers/gpu/drm/tyr/file.rs | 49 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/tyr/file.rs b/drivers/gpu/drm/tyr/file.rs index ceadde976502..bf66238ea4c6 100644 --- a/drivers/gpu/drm/tyr/file.rs +++ b/drivers/gpu/drm/tyr/file.rs @@ -1,14 +1,18 @@ // SPDX-License-Identifier: GPL-2.0 or MIT +use core::mem::offset_of; + use kernel::{ drm::{ self, Registered, // }, + num::casts::FromSafeCast, prelude::*, uaccess::UserSlice, uapi, // }; +use zerocopy::Immutable; use crate::driver::{ TyrDrmDevice, @@ -16,6 +20,37 @@ TyrDrmRegistrationData, // }; +trait UobjMinSize { + fn min_size(&self) -> usize; +} + +impl UobjMinSize for uapi::drm_panthor_gpu_info { + fn min_size(&self) -> usize { + offset_of!(Self, tiler_present) + size_of_val(&self.tiler_present) + } +} + +// If the user buffer is at least the minimum required size, then +// copy as much of the kernel object as will fit into the user buffer. +// Don't fail if the user buffer is smaller than the kernel object. +// If the user buffer is bigger than needed, zero out the remainder. +fn set_uobj<T: IntoBytes + Immutable>( + usr_dst: u64, + size: u32, + min_size: usize, + src_obj: &T, +) -> Result { + let size = usize::from_safe_cast(size); + if size < min_size { + return Err(EINVAL); + } + + let mut writer = UserSlice::new(UserPtr::from_u64(usr_dst), size).writer(); + writer.write_slice_partial(src_obj.as_bytes(), 0)?; + writer.clear()?; + Ok(()) +} + #[pin_data] pub(crate) struct TyrDrmFileData {} @@ -48,14 +83,12 @@ pub(crate) fn dev_query( } else { match devquery.type_ { uapi::drm_panthor_dev_query_type_DRM_PANTHOR_DEV_QUERY_GPU_INFO => { - let mut writer = UserSlice::new( - UserPtr::from_addr(devquery.pointer as usize), - devquery.size as usize, - ) - .writer(); - - writer.write_slice(reg_data.gpu_info.as_bytes())?; - + set_uobj( + devquery.pointer, + devquery.size, + reg_data.gpu_info.min_size(), + ®_data.gpu_info, + )?; Ok(0) } _ => Err(EINVAL), -- 2.56.0
