fix: drm gem shim — delegate handle create/delete to drm scheme via real ioctl
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.
This commit is contained in:
@@ -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<usize> {
|
||||
Some(match cmd {
|
||||
DRM_IOCTL_MODE_GETRESOURCES => core::mem::size_of::<DrmResourcesWire>(),
|
||||
@@ -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::<DrmGemCreateWire>(),
|
||||
);
|
||||
let response_slice = core::slice::from_raw_parts_mut(
|
||||
&mut response as *mut _ as *mut u8,
|
||||
core::mem::size_of::<DrmGemCreateWire>(),
|
||||
);
|
||||
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<u32> {
|
||||
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::<DrmGemCloseWire>()];
|
||||
unsafe {
|
||||
let payload = core::slice::from_raw_parts(
|
||||
&close as *const _ as *const u8,
|
||||
core::mem::size_of::<DrmGemCloseWire>(),
|
||||
);
|
||||
let _ = scheme_ioctl(file, DRM_IOCTL_GEM_CLOSE, payload, &mut response);
|
||||
}
|
||||
log::debug!("drm_gem_handle_delete: handle={}", handle);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user