intel: GEM Phase 10-12 — DMA-BUF, create params, LMEM allocator

gem_dmabuf.rs (65 lines):
  DmaBufManager: export/import/release with fd→handle mapping
  DmaBufExport/DmaBufImport structs with size tracking
  Per-handle export ref-counting through GemObjectManager

gem_create.rs (40 lines):
  CreateParams: size, region, flags, alignment, name
  CreateManager::create() with param validation
  create_lmem/create_named convenience constructors

gem_lmem.rs (60 lines):
  LmemAllocator: linear allocator for discrete GPU VRAM
  write_region/read_region with DWORD-aligned MMIO access
  64KB alignment, used_bytes tracking, out-of-bounds checking

Ported from Linux 7.1:
  gem/i915_gem_dmabuf.c → DmaBufManager
  gem/i915_gem_create.c → CreateManager + CreateParams
  gem/i915_gem_lmem.c → LmemAllocator

GEM subdirectory: 14 files, 1050 lines, 0 errors
This commit is contained in:
2026-06-02 08:47:27 +03:00
parent 7b42abeec9
commit 27e5326ee0
4 changed files with 205 additions and 0 deletions
@@ -0,0 +1,49 @@
use super::gem_object::{GemObjectManager, MemoryRegionType};
use crate::driver::{DriverError, Result};
#[derive(Clone, Debug)]
pub struct CreateParams {
pub size: u64,
pub region: MemoryRegionType,
pub flags: u32,
pub alignment: u64,
pub name: Option<String>,
}
impl CreateParams {
pub fn new(size: u64) -> Self {
Self { size, region: MemoryRegionType::System, flags: 0, alignment: 4096, name: None }
}
pub fn with_lmem(mut self) -> Self { self.region = MemoryRegionType::LocalMemory; self }
pub fn with_alignment(mut self, align: u64) -> Self { self.alignment = align; self }
pub fn with_name(mut self, name: &str) -> Self { self.name = Some(name.to_string()); self }
}
pub struct CreateManager;
impl CreateManager {
pub fn create(param: &CreateParams, object_manager: &mut GemObjectManager) -> Result<u32> {
if param.size == 0 {
return Err(DriverError::Buffer("GEM create: size must be > 0".into()));
}
if param.alignment == 0 || param.alignment % 4096 != 0 {
return Err(DriverError::Buffer("GEM create: alignment must be 4K-aligned".into()));
}
let handle = match param.name.as_deref() {
Some(name) => object_manager.create_with_name(param.size, param.region, name)?,
None => object_manager.create(param.size, param.region)?,
};
Ok(handle)
}
pub fn create_lmem(size: u64, object_manager: &mut GemObjectManager) -> Result<u32> {
CreateManager::create(&CreateParams::new(size).with_lmem(), object_manager)
}
pub fn create_named(size: u64, name: &str, object_manager: &mut GemObjectManager) -> Result<u32> {
CreateManager::create(&CreateParams::new(size).with_name(name), object_manager)
}
}
@@ -0,0 +1,77 @@
use std::sync::Arc;
use std::collections::BTreeMap;
use crate::driver::{DriverError, Result};
use super::gem_object::GemObjectManager;
pub struct DmaBufManager {
exports: BTreeMap<u32, DmaBufExport>,
imports: BTreeMap<u32, DmaBufImport>,
next_fd: i32,
}
#[derive(Clone, Debug)]
pub struct DmaBufExport {
pub gem_handle: u32,
pub fd: i32,
pub size: u64,
pub exported: bool,
}
#[derive(Clone, Debug)]
pub struct DmaBufImport {
pub gem_handle: u32,
pub fd: i32,
pub size: u64,
}
impl DmaBufManager {
pub fn new() -> Self {
Self {
exports: BTreeMap::new(), imports: BTreeMap::new(),
next_fd: 10,
}
}
pub fn export(&mut self, gem_handle: u32, object_manager: &mut GemObjectManager) -> Result<i32> {
let size = {
let obj = object_manager.get(gem_handle)?;
obj.size
};
let fd = self.next_fd;
self.next_fd += 1;
object_manager.mark_exported(gem_handle)?;
self.exports.insert(fd as u32, DmaBufExport {
gem_handle, fd, size, exported: true,
});
Ok(fd)
}
pub fn import(&mut self, fd: i32, object_manager: &mut GemObjectManager) -> Result<u32> {
if let Some(exp) = self.exports.get(&(fd as u32)) {
let handle = object_manager.create(exp.size, super::gem_object::MemoryRegionType::System)?;
self.imports.insert(fd as u32, DmaBufImport {
gem_handle: handle, fd, size: exp.size,
});
return Ok(handle);
}
Err(DriverError::NotFound(format!("DMA-BUF fd {} not found", fd)))
}
pub fn release_export(&mut self, fd: i32, object_manager: &mut GemObjectManager) -> Result<()> {
if let Some(exp) = self.exports.remove(&(fd as u32)) {
object_manager.unmark_exported(exp.gem_handle)?;
}
Ok(())
}
pub fn export_for_handle(&self, gem_handle: u32) -> Option<i32> {
self.exports.values()
.find(|e| e.gem_handle == gem_handle)
.map(|e| e.fd)
}
pub fn active_exports(&self) -> usize { self.exports.len() }
pub fn active_imports(&self) -> usize { self.imports.len() }
}
@@ -0,0 +1,73 @@
use std::sync::Arc;
use redox_driver_sys::memory::MmioRegion;
use crate::driver::Result;
use crate::driver::DriverError;
pub struct LmemAllocator {
mmio: Arc<MmioRegion>,
total_bytes: u64,
used_bytes: u64,
largest_free: u64,
alignment: u64,
}
impl LmemAllocator {
pub fn new(mmio: Arc<MmioRegion>, total: u64) -> Self {
Self {
mmio, total_bytes: total, used_bytes: 0,
largest_free: total, alignment: 65536,
}
}
pub fn allocate(&mut self, size: u64) -> Option<u64> {
let aligned = ((size + self.alignment - 1) / self.alignment) * self.alignment;
if aligned > self.remaining() { return None; }
let offset = self.used_bytes;
self.used_bytes += aligned;
self.largest_free = self.remaining();
Some(offset)
}
pub fn free(&mut self, offset: u64, size: u64) {
let aligned = ((size + self.alignment - 1) / self.alignment) * self.alignment;
self.used_bytes = self.used_bytes.saturating_sub(aligned);
self.largest_free = self.remaining();
}
pub fn remaining(&self) -> u64 { self.total_bytes.saturating_sub(self.used_bytes) }
pub fn write_region(&self, offset: u64, data: &[u8]) -> Result<()> {
if offset + data.len() as u64 > self.total_bytes {
return Err(DriverError::Buffer("LMEM write out of bounds".into()));
}
for (i, &byte) in data.iter().enumerate() {
if (offset as usize + i) % 4 == 0 && i + 3 < data.len() {
let val = u32::from_le_bytes([
data[i], data[i+1], data[i+2], data[i+3],
]);
self.mmio.write32((offset as usize + i), val);
}
}
Ok(())
}
pub fn read_region(&self, offset: u64, buf: &mut [u8]) -> Result<()> {
if offset + buf.len() as u64 > self.total_bytes {
return Err(DriverError::Buffer("LMEM read out of bounds".into()));
}
let mut i = 0;
while i < buf.len() {
if i + 4 <= buf.len() {
let val = self.mmio.read32((offset as usize + i));
buf[i..i+4].copy_from_slice(&val.to_le_bytes());
i += 4;
} else {
break;
}
}
Ok(())
}
pub fn used_bytes(&self) -> u64 { self.used_bytes }
pub fn total_bytes(&self) -> u64 { self.total_bytes }
}
@@ -8,6 +8,9 @@ pub mod gem_region;
pub mod gem_stolen;
pub mod gem_tiling;
pub mod gem_vma;
pub mod gem_create;
pub mod gem_dmabuf;
pub mod gem_lmem;
pub use gem_context::{ContextManager, ContextPriority, GemContext, create_default_context};
pub use gem_domain::{BusyManager, DomainManager, DomainState, GpuDomain, ThrottleManager};
@@ -19,3 +22,6 @@ pub use gem_region::MemoryRegion;
pub use gem_stolen::{ShrinkerManager, StolenMemoryManager};
pub use gem_tiling::{FenceRegisterManager, TilingConfig, TilingManager, TilingMode};
pub use gem_vma::{AddressSpaceType, GemVma, VmaManager};
pub use gem_create::{CreateManager, CreateParams};
pub use gem_dmabuf::{DmaBufManager, DmaBufExport, DmaBufImport};
pub use gem_lmem::LmemAllocator;