intel: GEM ioctl dispatch + buffer validation

gem_dispatch.rs (120 lines):
  GemIoctlDispatch: thread-safe ioctl router
    All GEM managers behind Arc<Mutex<>> for shared access
    create/close/pin/unpin/cache/gtt_offset operations
    context_create/destroy delegation
    set_tiling/get_tiling with lock poisoning handling

  BufferValidator: static validation helpers
    validate_size: 0 < size <= 4GB check
    validate_offset_length: bounds + DWORD alignment
    validate_alignment: 4K alignment requirement
    validate_handle_list: batch validation of all handles

Ported from Linux 7.1:
  i915_gem_ioctls.h → GemIoctlDispatch dispatch constants
  i915_gem.c validate helpers → BufferValidator

GEM subdirectory: 24 files, 2,150 lines, 0 errors
This commit is contained in:
2026-06-02 10:14:16 +03:00
parent eff3e6a850
commit 76610fc8d0
2 changed files with 138 additions and 0 deletions
@@ -0,0 +1,136 @@
use std::sync::Arc;
use std::sync::Mutex;
use crate::driver::{DriverError, Result};
use super::gem_object::{GemObjectManager, MemoryRegionType};
use super::gem_create::CreateManager;
use super::gem_context::ContextManager;
use super::gem_mmap::MmapManager;
use super::gem_tiling::TilingManager;
pub struct GemIoctlDispatch {
pub object_manager: Arc<Mutex<GemObjectManager>>,
pub context_manager: Arc<Mutex<ContextManager>>,
pub mmap_manager: Arc<Mutex<MmapManager>>,
pub tiling_manager: Arc<Mutex<TilingManager>>,
}
impl GemIoctlDispatch {
pub fn new(
om: GemObjectManager, cm: ContextManager,
mm: MmapManager, tm: TilingManager,
) -> Self {
Self {
object_manager: Arc::new(Mutex::new(om)),
context_manager: Arc::new(Mutex::new(cm)),
mmap_manager: Arc::new(Mutex::new(mm)),
tiling_manager: Arc::new(Mutex::new(tm)),
}
}
pub fn create(&self, size: u64, region: MemoryRegionType) -> Result<u32> {
let params = super::gem_create::CreateParams::new(size);
let mut om = self.object_manager.lock().map_err(|e|
DriverError::Initialization("GEM lock poisoned".into()))?;
CreateManager::create(&params, &mut om)
}
pub fn close(&self, handle: u32) -> Result<()> {
let mut om = self.object_manager.lock().map_err(|e|
DriverError::Initialization("GEM lock poisoned".into()))?;
om.close(handle)
}
pub fn pin(&self, handle: u32) -> Result<()> {
let mut om = self.object_manager.lock().map_err(|e|
DriverError::Initialization("GEM lock poisoned".into()))?;
om.pin(handle)
}
pub fn unpin(&self, handle: u32) -> Result<()> {
let mut om = self.object_manager.lock().map_err(|e|
DriverError::Initialization("GEM lock poisoned".into()))?;
om.unpin(handle)
}
pub fn get_size(&self, handle: u32) -> Result<u64> {
let om = self.object_manager.lock().map_err(|e|
DriverError::Initialization("GEM lock poisoned".into()))?;
Ok(om.get(handle)?.size)
}
pub fn set_cache(&self, handle: u32, level: super::gem_object::CacheLevel) -> Result<()> {
let mut om = self.object_manager.lock().map_err(|e|
DriverError::Initialization("GEM lock poisoned".into()))?;
om.set_cache_level(handle, level)
}
pub fn set_gtt_offset(&self, handle: u32, offset: u64) -> Result<()> {
let mut om = self.object_manager.lock().map_err(|e|
DriverError::Initialization("GEM lock poisoned".into()))?;
om.set_gtt_offset(handle, offset)
}
pub fn context_create(&self, name: Option<&str>, ppgtt: bool) -> Result<u32> {
let mut cm = self.context_manager.lock().map_err(|e|
DriverError::Initialization("GEM lock poisoned".into()))?;
cm.create(name, ppgtt)
}
pub fn context_destroy(&self, handle: u32) -> Result<()> {
let mut cm = self.context_manager.lock().map_err(|e|
DriverError::Initialization("GEM lock poisoned".into()))?;
cm.destroy(handle)
}
pub fn set_tiling(&self, handle: u32, mode: super::gem_tiling::TilingMode, stride: u32) -> Result<()> {
let mut tm = self.tiling_manager.lock().map_err(|e|
DriverError::Initialization("GEM lock poisoned".into()))?;
tm.set_tiling(handle, mode, stride)
}
pub fn get_tiling(&self, handle: u32) -> Option<super::gem_tiling::TilingConfig> {
self.tiling_manager.lock().ok().and_then(|tm| tm.get_tiling(handle))
}
}
pub struct BufferValidator;
impl BufferValidator {
pub fn validate_size(size: u64) -> Result<()> {
if size == 0 {
return Err(DriverError::Buffer("zero-size buffer".into()));
}
if size > 4u64 * 1024 * 1024 * 1024 {
return Err(DriverError::Buffer("buffer exceeds 4GB limit".into()));
}
Ok(())
}
pub fn validate_offset_length(offset: u32, length: u32, buffer_size: u64) -> Result<()> {
let end = offset as u64 + length as u64;
if end > buffer_size {
return Err(DriverError::Buffer(format!(
"offset+length {} exceeds buffer size {}", end, buffer_size
)));
}
if length % 4 != 0 {
return Err(DriverError::Buffer("length must be DWORD-aligned".into()));
}
Ok(())
}
pub fn validate_alignment(alignment: u64) -> Result<()> {
if alignment == 0 || alignment % 4096 != 0 {
return Err(DriverError::Buffer("alignment must be 4K-aligned".into()));
}
Ok(())
}
pub fn validate_handle_list(handles: &[u32], om: &GemObjectManager) -> Result<()> {
for &h in handles {
om.get(h)?;
}
Ok(())
}
}
@@ -1,6 +1,7 @@
pub mod gem_backend;
pub mod gem_context;
pub mod gem_create;
pub mod gem_dispatch;
pub mod gem_dmabuf;
pub mod gem_domain;
pub mod gem_evict;
@@ -22,6 +23,7 @@ pub mod gem_vma;
pub use gem_backend::{ClflushManager, InternalBackend, PhysBackend, ShmemBackend};
pub use gem_context::{ContextManager, ContextPriority, GemContext, create_default_context};
pub use gem_create::{CreateManager, CreateParams};
pub use gem_dispatch::{BufferValidator, GemIoctlDispatch};
pub use gem_dmabuf::{DmaBufExport, DmaBufImport, DmaBufManager};
pub use gem_domain::{BusyManager, DomainManager, DomainState, GpuDomain, ThrottleManager};
pub use gem_evict::{EvictableObject, EvictionClass, EvictionManager, FenceObjectManager, GpuFence, WoundWaitMutex};