Merge branch 'drm' into 'master'

Implement DRM ioctls for Redox

See merge request redox-os/relibc!801
This commit is contained in:
Jeremy Soller
2025-12-16 12:56:22 -07:00
9 changed files with 580 additions and 7 deletions
+7 -5
View File
@@ -27,12 +27,14 @@ impl winsize {
}
}
pub use self::sys::*;
#[cfg(target_os = "linux")]
pub use self::linux::*;
#[cfg(target_os = "linux")]
#[path = "linux.rs"]
pub mod sys;
pub mod linux;
#[cfg(target_os = "redox")]
#[path = "redox.rs"]
pub mod sys;
pub use self::redox::*;
#[cfg(target_os = "redox")]
pub mod redox;
+120
View File
@@ -0,0 +1,120 @@
use core::slice;
use redox_ioctl::{IoctlData, drm::*};
use crate::{
error::{Errno, Result},
header::errno::EINVAL,
platform::types::*,
};
use super::IoctlBuffer;
const DRM_FORMAT_ARGB8888: u32 = 0x34325241; // 'AR24' fourcc code, for ARGB8888
fn id_index(id: u32) -> u32 {
id & 0xFF
}
fn conn_id(i: u32) -> u32 {
id_index(i) | (1 << 8)
}
fn crtc_id(i: u32) -> u32 {
id_index(i) | (1 << 9)
}
fn enc_id(i: u32) -> u32 {
id_index(i) | (1 << 10)
}
fn fb_id(i: u32) -> u32 {
id_index(i) | (1 << 11)
}
fn fb_handle_id(i: u32) -> u32 {
id_index(i) | (1 << 12)
}
fn plane_id(i: u32) -> u32 {
id_index(i) | (1 << 13)
}
unsafe fn copy_array<T: Copy>(src: &[T], dst_ptr: *mut T, dst_len: usize) -> usize {
let dst = slice::from_raw_parts_mut(dst_ptr, dst_len);
dst.copy_from_slice(&src[..src.len().min(dst_len)]);
src.len()
}
struct Dev {
fd: c_int,
}
impl Dev {
fn new(fd: c_int) -> Result<Self> {
//TODO: check display scheme using fpath?
Ok(Self { fd })
}
unsafe fn call<T>(&self, payload: &mut T, func: u64) -> syscall::Result<usize> {
let bytes = slice::from_raw_parts_mut(payload as *mut T as *mut u8, size_of::<T>());
redox_rt::sys::sys_call(
self.fd as usize,
bytes,
syscall::CallFlags::empty(),
&[func],
)
}
unsafe fn read_write_ioctl<T: IoctlData>(
&self,
mut buf: IoctlBuffer,
func: u64,
) -> Result<c_int> {
let mut data = buf.read::<T>()?;
let mut wire = data.write();
let res = redox_rt::sys::sys_call(
self.fd as usize,
&mut wire,
syscall::CallFlags::empty(),
&[func],
)?;
data.read_from(&wire);
buf.write(data)?;
Ok(res as c_int)
}
unsafe fn write_ioctl<T: IoctlData>(&self, mut buf: IoctlBuffer, func: u64) -> Result<c_int> {
let mut data = buf.read::<T>()?;
let mut wire = data.write();
let res = redox_rt::sys::sys_call(
self.fd as usize,
&mut wire,
syscall::CallFlags::empty(),
&[func],
)?;
Ok(res as c_int)
}
}
pub(super) unsafe fn ioctl(fd: c_int, func: u8, buf: IoctlBuffer) -> Result<c_int> {
let dev = Dev::new(fd)?;
match func {
0x00 => dev.read_write_ioctl::<drm_version>(buf, VERSION),
0x0C => dev.read_write_ioctl::<drm_get_cap>(buf, GET_CAP),
0x0D => dev.write_ioctl::<drm_set_client_cap>(buf, SET_CLIENT_CAP),
0xA0 => dev.read_write_ioctl::<drm_mode_card_res>(buf, MODE_CARD_RES),
0xA1 => dev.read_write_ioctl::<drm_mode_crtc>(buf, MODE_GET_CRTC),
0xA6 => dev.read_write_ioctl::<drm_mode_get_encoder>(buf, MODE_GET_ENCODER),
0xA7 => dev.read_write_ioctl::<drm_mode_get_connector>(buf, MODE_GET_CONNECTOR),
0xAD => dev.read_write_ioctl::<drm_mode_fb_cmd>(buf, MODE_GET_FB),
0xB5 => dev.read_write_ioctl::<drm_mode_get_plane_res>(buf, MODE_GET_PLANE_RES),
0xB6 => dev.read_write_ioctl::<drm_mode_get_plane>(buf, MODE_GET_PLANE),
0xB9 => dev.read_write_ioctl::<drm_mode_obj_get_properties>(buf, MODE_OBJ_GET_PROPERTIES),
0xCE => dev.read_write_ioctl::<drm_mode_fb_cmd2>(buf, MODE_GET_FB2),
_ => {
eprintln!("unimplemented DRM ioctl({}, 0x{:02x}, {:?})", fd, func, buf);
Err(Errno(EINVAL))
}
}
}
@@ -1,4 +1,4 @@
use core::{mem, slice};
use core::{mem, ptr, slice};
use redox_rt::proc::FdGuard;
use syscall;
@@ -13,6 +13,8 @@ use crate::{
use super::winsize;
mod drm;
pub const TCGETS: c_ulong = 0x5401;
pub const TCSETS: c_ulong = 0x5402;
pub const TCSETSW: c_ulong = 0x5403;
@@ -61,6 +63,47 @@ fn dup_write<T>(fd: c_int, name: &str, t: &T) -> Result<usize> {
Ok(bytes / size)
}
#[derive(Debug)]
enum IoctlBuffer {
None,
Read(*mut c_void, usize), // read (write to userspace)
Write(*const c_void, usize), // write (read from userspace)
ReadWrite(*mut c_void, usize),
}
impl IoctlBuffer {
unsafe fn read<T>(&self) -> Result<T> {
let (ptr, size) = match *self {
Self::Write(ptr, size) => (ptr, size),
Self::ReadWrite(ptr, size) => (ptr as *const c_void, size),
_ => {
return Err(Errno(EINVAL));
}
};
if size == mem::size_of::<T>() {
let value = unsafe { ptr::read(ptr as *const T) };
Ok(value)
} else {
Err(Errno(EINVAL))
}
}
unsafe fn write<T>(&mut self, value: T) -> Result<()> {
let (ptr, size) = match *self {
Self::Read(ptr, size) | Self::ReadWrite(ptr, size) => (ptr, size),
_ => {
return Err(Errno(EINVAL));
}
};
if size == mem::size_of::<T>() {
unsafe { ptr::write(ptr as *mut T, value) };
Ok(())
} else {
Err(Errno(EINVAL))
}
}
}
unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Result<c_int> {
match request {
FIONBIO => {
@@ -120,7 +163,25 @@ unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Result<c
eprintln!("TODO: ioctl SIOCATMARK");
}
_ => {
return Err(Errno(EINVAL));
// See https://docs.kernel.org/userspace-api/ioctl/ioctl-decoding.html for details
let dir = (request >> 30) & 0b11;
let size = ((request >> 16) & 0x3FFF) as usize;
let name = (((request >> 8) & 0xFF) as u8) as char;
let func = (request & 0xFF) as u8;
match name {
'd' => {
let buf = match dir {
0b10 => IoctlBuffer::Read(out, size),
0b01 => IoctlBuffer::Write(out, size),
0b11 => IoctlBuffer::ReadWrite(out, size),
_ => IoctlBuffer::None,
};
return drm::ioctl(fd, func, buf);
}
_ => {
return Err(Errno(EINVAL));
}
}
}
}
Ok(0)