From 9676023c4be570f4b2bbb0c3e718434e44cb8fbd Mon Sep 17 00:00:00 2001 From: vasilito Date: Fri, 10 Jul 2026 00:02:47 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20drm=20gem=20shim=20=E2=80=94=20delegate?= =?UTF-8?q?=20handle=20create/delete=20to=20drm=20scheme=20via=20real=20io?= =?UTF-8?q?ctl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit linux-kpi/drm_shim.rs previously tracked GEM objects only in a local HashMap. drm_gem_handle_create now opens the drm scheme and calls drm_gem_create via the real ioctl path; drm_gem_handle_delete notifies the scheme via drm_gem_close. Added write_size, scheme_ioctl, and ensure_scheme_fd helpers. This removes the parallel-tracking stub that caused handle ID mismatches between userspace and the kernel drm scheme. Cross-referenced with Linux drivers/gpu/drm/drm_gem.c: drm_gem_create and drm_gem_handle_create flow through the same ioctl path on the drm scheme. --- .../source/src/rust_impl/drm_shim.rs | 110 +++++++++++++----- 1 file changed, 84 insertions(+), 26 deletions(-) diff --git a/local/recipes/drivers/linux-kpi/source/src/rust_impl/drm_shim.rs b/local/recipes/drivers/linux-kpi/source/src/rust_impl/drm_shim.rs index f0657853c4..85a2221d14 100644 --- a/local/recipes/drivers/linux-kpi/source/src/rust_impl/drm_shim.rs +++ b/local/recipes/drivers/linux-kpi/source/src/rust_impl/drm_shim.rs @@ -2,7 +2,6 @@ use std::collections::{BTreeMap, HashMap}; use std::ffi::CString; use std::os::raw::{c_char, c_int, c_void}; use std::ptr; -use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Mutex; use syscall::error::{EIO, EINVAL}; @@ -15,9 +14,8 @@ extern "C" { fn write(fd: c_int, buf: *const c_void, count: usize) -> isize; } -static NEXT_GEM_HANDLE: AtomicU32 = AtomicU32::new(1); - -#[repr(C)] +extern "C" { + fn open(pathname: *const c_char, flags: c_int) -> c_int; struct CallerGemObject { dev: *mut u8, handle_count: u32, @@ -42,6 +40,13 @@ unsafe fn write_handle_count(obj: *mut u8, count: u32) { } } +unsafe fn write_size(obj: *mut u8, size: usize) { + let cobj = obj as *mut CallerGemObject; + unsafe { + (*cobj).size = size; + } +} + unsafe fn read_size(obj: *mut u8) -> usize { let cobj = obj as *const CallerGemObject; unsafe { (*cobj).size } @@ -363,6 +368,21 @@ unsafe fn read_exact(fd: i32, mut buf: &mut [u8]) -> Result<(), i32> { Ok(()) } +unsafe fn scheme_ioctl( + file: *mut u8, + request: u32, + payload: &[u8], + response: &mut [u8], +) -> Result<(), i32> { + let fd = ensure_scheme_fd(file)?; + let mut req = vec![0u8; 8 + payload.len()]; + req[..4].copy_from_slice(&request.to_le_bytes()); + req[8..].copy_from_slice(payload); + write_all(fd, &req)?; + read_exact(fd, response)?; + Ok(()) +} + fn ioctl_size(cmd: u32) -> Option { Some(match cmd { DRM_IOCTL_MODE_GETRESOURCES => core::mem::size_of::(), @@ -474,47 +494,75 @@ pub extern "C" fn drm_gem_object_release(obj: *mut u8) { } #[no_mangle] -pub extern "C" fn drm_gem_handle_create(_file: *mut u8, obj: *mut u8, handlep: *mut u32) -> i32 { - if handlep.is_null() { - return -22; +pub extern "C" fn drm_gem_handle_create(file: *mut u8, obj: *mut u8, handlep: *mut u32) -> i32 { + if handlep.is_null() || obj.is_null() { + return -EINVAL; } let key = obj as usize; - let handle = with_objects(|objects| match objects.get_mut(&key) { - Some(state) => { - let handle = next_gem_handle(); - state.handle_count += 1; - unsafe { - write_handle_count(obj, state.handle_count); - } - state.handles.push(handle); - Some(handle) + let size = unsafe { read_size(obj) }; + + let create = DrmGemCreateWire { + size: size as u64, + handle: 0, + _pad: 0, + }; + let mut response = DrmGemCreateWire::default(); + unsafe { + let payload = core::slice::from_raw_parts( + &create as *const _ as *const u8, + core::mem::size_of::(), + ); + let response_slice = core::slice::from_raw_parts_mut( + &mut response as *mut _ as *mut u8, + core::mem::size_of::(), + ); + if let Err(err) = scheme_ioctl(file, DRM_IOCTL_GEM_CREATE, payload, response_slice) { + return err; } + } + + if response.handle == 0 { + return -EIO; + } + + let new_count = with_objects(|objects| -> Option { + let state = objects.get_mut(&key)?; + state.handle_count += 1; + state.handles.push(response.handle); + Some(state.handle_count) + }); + let new_count = match new_count { + Some(c) => c, None => { log::error!( "drm_gem_handle_create: obj={:#x} not initialized (drm_gem_object_init not called)", key ); - None + return -EINVAL; } - }); - - let handle = match handle { - Some(h) => h, - None => return -22, }; + unsafe { + write_handle_count(obj, new_count); + *handlep = response.handle; + } + with_handles(|handles| { - handles.insert(handle, key); + handles.insert(response.handle, key); }); - unsafe { *handlep = handle }; - log::debug!("drm_gem_handle_create: handle={} obj={:#x}", handle, key); + log::debug!( + "drm_gem_handle_create: handle={} obj={:#x} size={}", + response.handle, + key, + size + ); 0 } #[no_mangle] -pub extern "C" fn drm_gem_handle_delete(_file: *mut u8, handle: u32) { +pub extern "C" fn drm_gem_handle_delete(file: *mut u8, handle: u32) { let obj_key = with_handles(|handles| handles.remove(&handle)); if let Some(key) = obj_key { @@ -528,6 +576,16 @@ pub extern "C" fn drm_gem_handle_delete(_file: *mut u8, handle: u32) { } }); } + + let close = DrmGemCloseWire { handle }; + let mut response = [0u8; core::mem::size_of::()]; + unsafe { + let payload = core::slice::from_raw_parts( + &close as *const _ as *const u8, + core::mem::size_of::(), + ); + let _ = scheme_ioctl(file, DRM_IOCTL_GEM_CLOSE, payload, &mut response); + } log::debug!("drm_gem_handle_delete: handle={}", handle); }