From 105b24a21f5eb294410b345b912354f05f8ba258 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 14 Dec 2025 08:39:00 -0700 Subject: [PATCH 1/8] Implement DRM ioctls for Redox --- src/header/sys_ioctl/mod.rs | 12 +- src/header/sys_ioctl/redox/drm.rs | 425 ++++++++++++++++++ src/header/sys_ioctl/redox/graphics_ipc.rs | 55 +++ .../sys_ioctl/{redox.rs => redox/mod.rs} | 67 ++- 4 files changed, 552 insertions(+), 7 deletions(-) create mode 100644 src/header/sys_ioctl/redox/drm.rs create mode 100644 src/header/sys_ioctl/redox/graphics_ipc.rs rename src/header/sys_ioctl/{redox.rs => redox/mod.rs} (65%) diff --git a/src/header/sys_ioctl/mod.rs b/src/header/sys_ioctl/mod.rs index c1716d0861..a5892f9a17 100644 --- a/src/header/sys_ioctl/mod.rs +++ b/src/header/sys_ioctl/mod.rs @@ -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; diff --git a/src/header/sys_ioctl/redox/drm.rs b/src/header/sys_ioctl/redox/drm.rs new file mode 100644 index 0000000000..6c60ec586f --- /dev/null +++ b/src/header/sys_ioctl/redox/drm.rs @@ -0,0 +1,425 @@ +use alloc::vec::Vec; +use core::{mem, slice}; + +use crate::{ + error::{Errno, Result}, + header::errno::EINVAL, + platform::types::*, +}; + +use super::{IoctlBuffer, graphics_ipc as ipc}; + +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(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 { + //TODO: check display scheme using fpath? + Ok(Self { fd }) + } + + unsafe fn call( + &self, + payload: &mut T, + func: u64, + ) -> syscall::Result { + let bytes = slice::from_raw_parts_mut( + payload as *mut T as *mut u8, + mem::size_of::(), + ); + redox_rt::sys::sys_call( + self.fd as usize, + bytes, + syscall::CallFlags::empty(), + &[func] + ) + } + + fn display_count(&self) -> Result { + let mut cmd = ipc::DisplayCount { count: 0 }; + unsafe { + self.call(&mut cmd, ipc::DISPLAY_COUNT)?; + } + Ok(cmd.count) + } + + fn display_size(&self, display_id: usize) -> Result<(u32, u32)> { + let mut cmd = ipc::DisplaySize { display_id, width: 0, height: 0 }; + unsafe { + self.call(&mut cmd, ipc::DISPLAY_SIZE)?; + } + Ok((cmd.width, cmd.height)) + } +} + +// Structs adapted from drm-sys bindings: https://docs.rs/drm-sys/0.8.0/src/drm_sys/bindings.rs.html +//TODO: can we auto generate these from libdrm without causing dependency issues? +#[repr(C)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +struct drm_version { + pub version_major: c_int, + pub version_minor: c_int, + pub version_patchlevel: c_int, + pub name_len: size_t, + pub name: *mut c_char, + pub date_len: size_t, + pub date: *mut c_char, + pub desc_len: size_t, + pub desc: *mut c_char, +} + +unsafe fn version(dev: Dev, mut buf: IoctlBuffer) -> Result { + let mut vers = buf.read::()?; + vers.version_major = 1; + vers.version_minor = 0; + vers.version_patchlevel = 0; + vers.name_len = copy_array("redox".as_bytes(), vers.name as *mut u8, vers.name_len); + vers.date_len = copy_array("0".as_bytes(), vers.date as *mut u8, vers.date_len); + vers.desc_len = copy_array("Redox OS".as_bytes(), vers.desc as *mut u8, vers.desc_len); + buf.write(vers)?; + Ok(0) +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] +pub struct drm_get_cap { + pub capability: u64, + pub value: u64, +} + +unsafe fn get_cap(dev: Dev, buf: IoctlBuffer) -> Result { + //TODO: get capabilities + Err(Errno(EINVAL)) +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] +pub struct drm_set_client_cap { + pub capability: u64, + pub value: u64, +} + +unsafe fn set_client_cap(dev: Dev, buf: IoctlBuffer) -> Result { + //TODO: set capabilities + Err(Errno(EINVAL)) +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] +pub struct drm_mode_card_res { + pub fb_id_ptr: u64, + pub crtc_id_ptr: u64, + pub connector_id_ptr: u64, + pub encoder_id_ptr: u64, + pub count_fbs: u32, + pub count_crtcs: u32, + pub count_connectors: u32, + pub count_encoders: u32, + pub min_width: u32, + pub max_width: u32, + pub min_height: u32, + pub max_height: u32, +} + +unsafe fn mode_card_res(dev: Dev, mut buf: IoctlBuffer) -> Result { + let mut res = buf.read::()?; + let count = dev.display_count()?; + let mut conn_ids = Vec::with_capacity(count); + let mut crtc_ids = Vec::with_capacity(count); + let mut enc_ids = Vec::with_capacity(count); + let mut fb_ids = Vec::with_capacity(count); + for i in 0..(count as u32) { + conn_ids.push(conn_id(i)); + crtc_ids.push(crtc_id(i)); + enc_ids.push(enc_id(i)); + fb_ids.push(fb_id(i)); + } + res.count_fbs = copy_array(&fb_ids, res.fb_id_ptr as *mut u32, res.count_fbs as usize) as u32; + res.count_crtcs = copy_array(&crtc_ids, res.crtc_id_ptr as *mut u32, res.count_crtcs as usize) as u32; + res.count_connectors = copy_array(&conn_ids, res.connector_id_ptr as *mut u32, res.count_connectors as usize) as u32; + res.count_encoders = copy_array(&enc_ids, res.encoder_id_ptr as *mut u32, res.count_encoders as usize) as u32; + res.min_width = 0; + res.max_width = 16384; + res.min_height = 0; + res.max_height = 16384; + buf.write(res)?; + Ok(0) +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] +pub struct drm_mode_modeinfo { + pub clock: u32, + pub hdisplay: u16, + pub hsync_start: u16, + pub hsync_end: u16, + pub htotal: u16, + pub hskew: u16, + pub vdisplay: u16, + pub vsync_start: u16, + pub vsync_end: u16, + pub vtotal: u16, + pub vscan: u16, + pub vrefresh: u32, + pub flags: u32, + pub type_: u32, + pub name: [c_char; 32], +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] +pub struct drm_mode_crtc { + pub set_connectors_ptr: u64, + pub count_connectors: u32, + pub crtc_id: u32, + pub fb_id: u32, + pub x: u32, + pub y: u32, + pub gamma_size: u32, + pub mode_valid: u32, + pub mode: drm_mode_modeinfo, +} + +unsafe fn mode_get_crtc(dev: Dev, mut buf: IoctlBuffer) -> Result { + let mut crtc = buf.read::()?; + let i = id_index(crtc.crtc_id); + let (width, height) = dev.display_size(i as usize)?; + //TOOD: connectors + crtc.fb_id = fb_id(i); + crtc.x = 0; + crtc.y = 0; + crtc.gamma_size = 0; + crtc.mode_valid = 0; + //TODO: mode + crtc.mode = Default::default(); + buf.write(crtc)?; + Ok(0) +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] +pub struct drm_mode_get_encoder { + pub encoder_id: u32, + pub encoder_type: u32, + pub crtc_id: u32, + pub possible_crtcs: u32, + pub possible_clones: u32, +} + +unsafe fn mode_get_encoder(dev: Dev, mut buf: IoctlBuffer) -> Result { + let mut enc = buf.read::()?; + let i = id_index(enc.encoder_id); + let (width, height) = dev.display_size(i as usize)?; + enc.crtc_id = crtc_id(i); + enc.possible_crtcs = (1 << i); + enc.possible_clones = (1 << i); + buf.write(enc)?; + Ok(0) +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] +pub struct drm_mode_get_connector { + pub encoders_ptr: u64, + pub modes_ptr: u64, + pub props_ptr: u64, + pub prop_values_ptr: u64, + pub count_modes: u32, + pub count_props: u32, + pub count_encoders: u32, + pub encoder_id: u32, + pub connector_id: u32, + pub connector_type: u32, + pub connector_type_id: u32, + pub connection: u32, + pub mm_width: u32, + pub mm_height: u32, + pub subpixel: u32, + pub pad: u32, +} + +unsafe fn mode_get_connector(dev: Dev, mut buf: IoctlBuffer) -> Result { + let mut conn = buf.read::()?; + let i = id_index(conn.connector_id); + let (width, height) = dev.display_size(i as usize)?; + conn.count_modes = 0; + conn.count_props = 0; + conn.count_encoders = copy_array(&[enc_id(i)], conn.encoders_ptr as *mut u32, conn.count_encoders as usize) as u32; + buf.write(conn)?; + Ok(0) +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] +pub struct drm_mode_fb_cmd { + pub fb_id: u32, + pub width: u32, + pub height: u32, + pub pitch: u32, + pub bpp: u32, + pub depth: u32, + pub handle: u32, +} + +unsafe fn mode_get_fb(dev: Dev, mut buf: IoctlBuffer) -> Result { + let mut fb = buf.read::()?; + let i = id_index(fb.fb_id); + let (width, height) = dev.display_size(i as usize)?; + fb.width = width; + fb.height = height; + fb.pitch = width * 4; //TODO: stride + fb.bpp = 32; + fb.depth = 24; + fb.handle = fb_handle_id(i); + buf.write(fb)?; + Ok(0) +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] +pub struct drm_mode_get_plane_res { + pub plane_id_ptr: u64, + pub count_planes: u32, +} + +unsafe fn mode_get_plane_res(dev: Dev, mut buf: IoctlBuffer) -> Result { + let mut res = buf.read::()?; + let count = dev.display_count()?; + let mut ids = Vec::with_capacity(count); + for i in 0..(count as u32) { + ids.push(plane_id(i)); + } + res.count_planes = copy_array(&ids, res.plane_id_ptr as *mut u32, res.count_planes as usize) as u32; + buf.write(res)?; + Ok(0) +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] +pub struct drm_mode_get_plane { + pub plane_id: u32, + pub crtc_id: u32, + pub fb_id: u32, + pub possible_crtcs: u32, + pub gamma_size: u32, + pub count_format_types: u32, + pub format_type_ptr: u64, +} + +unsafe fn mode_get_plane(dev: Dev, mut buf: IoctlBuffer) -> Result { + let mut plane = buf.read::()?; + let i = id_index(plane.plane_id); + let (width, height) = dev.display_size(i as usize)?; + plane.crtc_id = crtc_id(i); + plane.fb_id = fb_id(i); + plane.possible_crtcs = (1 << i); + plane.count_format_types = copy_array(&[DRM_FORMAT_ARGB8888], plane.format_type_ptr as *mut u32, plane.count_format_types as usize) as u32; + buf.write(plane)?; + Ok(0) +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] +pub struct drm_mode_obj_get_properties { + pub props_ptr: u64, + pub prop_values_ptr: u64, + pub count_props: u32, + pub obj_id: u32, + pub obj_type: u32, +} + +unsafe fn mode_obj_get_properties(dev: Dev, mut buf: IoctlBuffer) -> Result { + let mut props = buf.read::()?; + //TODO + props.count_props = 0; + buf.write(props)?; + Ok(0) +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] +pub struct drm_mode_fb_cmd2 { + pub fb_id: u32, + pub width: u32, + pub height: u32, + pub pixel_format: u32, + pub flags: u32, + pub handles: [u32; 4], + pub pitches: [u32; 4], + pub offsets: [u32; 4], + pub modifier: [u64; 4], +} + +unsafe fn mode_get_fb2(dev: Dev, mut buf: IoctlBuffer) -> Result { + let mut fb = buf.read::()?; + let i = id_index(fb.fb_id); + let (width, height) = dev.display_size(i as usize)?; + fb.width = width; + fb.height = height; + fb.pixel_format = DRM_FORMAT_ARGB8888; + fb.handles[0] = fb_handle_id(i); + fb.pitches[0] = width * 4; + fb.offsets[0] = 0; + fb.modifier[0] = 0; + buf.write(fb)?; + Ok(0) +} + +pub(super) unsafe fn ioctl(fd: c_int, func: u8, buf: IoctlBuffer) -> Result { + let dev = Dev::new(fd)?; + match func { + 0x00 => version(dev, buf), + 0x0C => get_cap(dev, buf), + 0x0D => set_client_cap(dev, buf), + 0xA0 => mode_card_res(dev, buf), + 0xA1 => mode_get_crtc(dev, buf), + 0xA6 => mode_get_encoder(dev, buf), + 0xA7 => mode_get_connector(dev, buf), + 0xAD => mode_get_fb(dev, buf), + 0xB5 => mode_get_plane_res(dev, buf), + 0xB6 => mode_get_plane(dev, buf), + 0xB9 => mode_obj_get_properties(dev, buf), + 0xCE => mode_get_fb2(dev, buf), + _ => { + eprintln!("unimplemented DRM ioctl({}, 0x{:02x}, {:?})", fd, func, buf); + Err(Errno(EINVAL)) + }, + } +} \ No newline at end of file diff --git a/src/header/sys_ioctl/redox/graphics_ipc.rs b/src/header/sys_ioctl/redox/graphics_ipc.rs new file mode 100644 index 0000000000..f9b2a8548f --- /dev/null +++ b/src/header/sys_ioctl/redox/graphics_ipc.rs @@ -0,0 +1,55 @@ +// Adapted from graphics-ipc v2 ipc module, cannot use as it needs libstd +#[derive(Debug, Copy, Clone)] +#[repr(C, packed)] +pub struct Damage { + pub x: u32, + pub y: u32, + pub width: u32, + pub height: u32, +} + +pub const DISPLAY_COUNT: u64 = 1; +#[repr(C, packed)] +pub struct DisplayCount { + pub count: usize, +} + +pub const DISPLAY_SIZE: u64 = 2; +#[repr(C, packed)] +pub struct DisplaySize { + pub display_id: usize, + + pub width: u32, + pub height: u32, +} + +pub const CREATE_DUMB_FRAMEBUFFER: u64 = 3; +#[repr(C, packed)] +pub struct CreateDumbFramebuffer { + pub width: u32, + pub height: u32, + + pub fb_id: usize, +} + +pub const DUMB_FRAMEBUFFER_MAP_OFFSET: u64 = 4; +#[repr(C, packed)] +pub struct DumbFramebufferMapOffset { + pub fb_id: usize, + + pub offset: usize, +} + +pub const DESTROY_DUMB_FRAMEBUFFER: u64 = 5; +#[repr(C, packed)] +pub struct DestroyDumbFramebuffer { + pub fb_id: usize, +} + +pub const UPDATE_PLANE: u64 = 6; +#[repr(C, packed)] +pub struct UpdatePlane { + pub display_id: usize, + pub fb_id: usize, + pub damage: Damage, +} \ No newline at end of file diff --git a/src/header/sys_ioctl/redox.rs b/src/header/sys_ioctl/redox/mod.rs similarity index 65% rename from src/header/sys_ioctl/redox.rs rename to src/header/sys_ioctl/redox/mod.rs index 5cf69b4c5b..bc2f08fa69 100644 --- a/src/header/sys_ioctl/redox.rs +++ b/src/header/sys_ioctl/redox/mod.rs @@ -1,4 +1,4 @@ -use core::{mem, slice}; +use core::{mem, ptr, slice}; use redox_rt::proc::FdGuard; use syscall; @@ -13,6 +13,9 @@ use crate::{ use super::winsize; +mod drm; +mod graphics_ipc; + pub const TCGETS: c_ulong = 0x5401; pub const TCSETS: c_ulong = 0x5402; pub const TCSETSW: c_ulong = 0x5403; @@ -61,6 +64,48 @@ fn dup_write(fd: c_int, name: &str, t: &T) -> Result { Ok(bytes / size) } +#[derive(Debug)] +enum IoctlBuffer { + None, + Read(*const c_void, usize), + Write(*mut c_void, usize), + ReadWrite(*mut c_void, usize), +} + +impl IoctlBuffer { + unsafe fn read(&self) -> Result { + let (ptr, size) = match *self { + Self::Read(ptr, size) => (ptr, size), + Self::ReadWrite(ptr, size) => (ptr as *const c_void, size), + _ => { + return Err(Errno(EINVAL)); + } + }; + if size == mem::size_of::() { + let value = unsafe { ptr::read(ptr as *const T) }; + Ok(value) + } else { + Err(Errno(EINVAL)) + } + } + + unsafe fn write(&mut self, value: T) -> Result<()> { + let (ptr, size) = match *self { + Self::Write(ptr, size) | Self::ReadWrite(ptr, size) => (ptr, size), + _ => { + return Err(Errno(EINVAL)); + } + }; + if size == mem::size_of::() { + 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 { match request { FIONBIO => { @@ -120,7 +165,25 @@ unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Result { - 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) From 6bce162b92ed7185e1f1cd8b6d9ee240858fea10 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 14 Dec 2025 20:45:26 +0100 Subject: [PATCH 2/8] Fix read-only and write-only ioctls Read-only ioctls write data to userspace, while write-only ioctls read data from userspace. This matches the read and write syscalls. --- src/header/sys_ioctl/redox/mod.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/header/sys_ioctl/redox/mod.rs b/src/header/sys_ioctl/redox/mod.rs index bc2f08fa69..2914769366 100644 --- a/src/header/sys_ioctl/redox/mod.rs +++ b/src/header/sys_ioctl/redox/mod.rs @@ -67,15 +67,15 @@ fn dup_write(fd: c_int, name: &str, t: &T) -> Result { #[derive(Debug)] enum IoctlBuffer { None, - Read(*const c_void, usize), - Write(*mut c_void, usize), + 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(&self) -> Result { let (ptr, size) = match *self { - Self::Read(ptr, size) => (ptr, size), + Self::Write(ptr, size) => (ptr, size), Self::ReadWrite(ptr, size) => (ptr as *const c_void, size), _ => { return Err(Errno(EINVAL)); @@ -91,7 +91,7 @@ impl IoctlBuffer { unsafe fn write(&mut self, value: T) -> Result<()> { let (ptr, size) = match *self { - Self::Write(ptr, size) | Self::ReadWrite(ptr, size) => (ptr, size), + Self::Read(ptr, size) | Self::ReadWrite(ptr, size) => (ptr, size), _ => { return Err(Errno(EINVAL)); } @@ -105,7 +105,6 @@ impl IoctlBuffer { } } - unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Result { match request { FIONBIO => { @@ -179,7 +178,7 @@ unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Result IoctlBuffer::None, }; return drm::ioctl(fd, func, buf); - }, + } _ => { return Err(Errno(EINVAL)); } From 395c686f8d8bff1dfb11b33fabbf2d67c27bea54 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 14 Dec 2025 20:46:36 +0100 Subject: [PATCH 3/8] Rustfmt --- src/header/sys_ioctl/redox/drm.rs | 61 +++++++++++++++------- src/header/sys_ioctl/redox/graphics_ipc.rs | 2 +- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/header/sys_ioctl/redox/drm.rs b/src/header/sys_ioctl/redox/drm.rs index 6c60ec586f..78933b4f21 100644 --- a/src/header/sys_ioctl/redox/drm.rs +++ b/src/header/sys_ioctl/redox/drm.rs @@ -55,20 +55,13 @@ impl Dev { Ok(Self { fd }) } - unsafe fn call( - &self, - payload: &mut T, - func: u64, - ) -> syscall::Result { - let bytes = slice::from_raw_parts_mut( - payload as *mut T as *mut u8, - mem::size_of::(), - ); - redox_rt::sys::sys_call( + unsafe fn call(&self, payload: &mut T, func: u64) -> syscall::Result { + let bytes = slice::from_raw_parts_mut(payload as *mut T as *mut u8, mem::size_of::()); + redox_rt::sys::sys_call( self.fd as usize, bytes, syscall::CallFlags::empty(), - &[func] + &[func], ) } @@ -81,7 +74,11 @@ impl Dev { } fn display_size(&self, display_id: usize) -> Result<(u32, u32)> { - let mut cmd = ipc::DisplaySize { display_id, width: 0, height: 0 }; + let mut cmd = ipc::DisplaySize { + display_id, + width: 0, + height: 0, + }; unsafe { self.call(&mut cmd, ipc::DISPLAY_SIZE)?; } @@ -172,9 +169,21 @@ unsafe fn mode_card_res(dev: Dev, mut buf: IoctlBuffer) -> Result { fb_ids.push(fb_id(i)); } res.count_fbs = copy_array(&fb_ids, res.fb_id_ptr as *mut u32, res.count_fbs as usize) as u32; - res.count_crtcs = copy_array(&crtc_ids, res.crtc_id_ptr as *mut u32, res.count_crtcs as usize) as u32; - res.count_connectors = copy_array(&conn_ids, res.connector_id_ptr as *mut u32, res.count_connectors as usize) as u32; - res.count_encoders = copy_array(&enc_ids, res.encoder_id_ptr as *mut u32, res.count_encoders as usize) as u32; + res.count_crtcs = copy_array( + &crtc_ids, + res.crtc_id_ptr as *mut u32, + res.count_crtcs as usize, + ) as u32; + res.count_connectors = copy_array( + &conn_ids, + res.connector_id_ptr as *mut u32, + res.count_connectors as usize, + ) as u32; + res.count_encoders = copy_array( + &enc_ids, + res.encoder_id_ptr as *mut u32, + res.count_encoders as usize, + ) as u32; res.min_width = 0; res.max_width = 16384; res.min_height = 0; @@ -281,7 +290,11 @@ unsafe fn mode_get_connector(dev: Dev, mut buf: IoctlBuffer) -> Result { let (width, height) = dev.display_size(i as usize)?; conn.count_modes = 0; conn.count_props = 0; - conn.count_encoders = copy_array(&[enc_id(i)], conn.encoders_ptr as *mut u32, conn.count_encoders as usize) as u32; + conn.count_encoders = copy_array( + &[enc_id(i)], + conn.encoders_ptr as *mut u32, + conn.count_encoders as usize, + ) as u32; buf.write(conn)?; Ok(0) } @@ -326,7 +339,11 @@ unsafe fn mode_get_plane_res(dev: Dev, mut buf: IoctlBuffer) -> Result { for i in 0..(count as u32) { ids.push(plane_id(i)); } - res.count_planes = copy_array(&ids, res.plane_id_ptr as *mut u32, res.count_planes as usize) as u32; + res.count_planes = copy_array( + &ids, + res.plane_id_ptr as *mut u32, + res.count_planes as usize, + ) as u32; buf.write(res)?; Ok(0) } @@ -350,7 +367,11 @@ unsafe fn mode_get_plane(dev: Dev, mut buf: IoctlBuffer) -> Result { plane.crtc_id = crtc_id(i); plane.fb_id = fb_id(i); plane.possible_crtcs = (1 << i); - plane.count_format_types = copy_array(&[DRM_FORMAT_ARGB8888], plane.format_type_ptr as *mut u32, plane.count_format_types as usize) as u32; + plane.count_format_types = copy_array( + &[DRM_FORMAT_ARGB8888], + plane.format_type_ptr as *mut u32, + plane.count_format_types as usize, + ) as u32; buf.write(plane)?; Ok(0) } @@ -420,6 +441,6 @@ pub(super) unsafe fn ioctl(fd: c_int, func: u8, buf: IoctlBuffer) -> Result { eprintln!("unimplemented DRM ioctl({}, 0x{:02x}, {:?})", fd, func, buf); Err(Errno(EINVAL)) - }, + } } -} \ No newline at end of file +} diff --git a/src/header/sys_ioctl/redox/graphics_ipc.rs b/src/header/sys_ioctl/redox/graphics_ipc.rs index f9b2a8548f..51d886481f 100644 --- a/src/header/sys_ioctl/redox/graphics_ipc.rs +++ b/src/header/sys_ioctl/redox/graphics_ipc.rs @@ -52,4 +52,4 @@ pub struct UpdatePlane { pub display_id: usize, pub fb_id: usize, pub damage: Damage, -} \ No newline at end of file +} From d70e2dc61068bdc12e404fc4980220214421801b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 14 Dec 2025 20:47:41 +0100 Subject: [PATCH 4/8] drm: Use new VERSION, GET_CAP and SET_CLIENT_CAP driver commands --- src/header/sys_ioctl/redox/drm.rs | 69 ++++++++++++++++++---- src/header/sys_ioctl/redox/graphics_ipc.rs | 30 ++++++++++ 2 files changed, 88 insertions(+), 11 deletions(-) diff --git a/src/header/sys_ioctl/redox/drm.rs b/src/header/sys_ioctl/redox/drm.rs index 78933b4f21..5c1b5c707a 100644 --- a/src/header/sys_ioctl/redox/drm.rs +++ b/src/header/sys_ioctl/redox/drm.rs @@ -65,6 +65,41 @@ impl Dev { ) } + fn version(&self) -> Result { + let mut cmd = ipc::Version { + version_major: 0, + version_minor: 0, + version_patchlevel: 0, + name_len: 0, + name: [0; 16], + desc_len: 0, + desc: [0; 16], + }; + unsafe { + self.call(&mut cmd, ipc::VERSION)?; + } + Ok(cmd) + } + + fn get_cap(&self, capability: u64) -> Result { + let mut cmd = ipc::GetCap { + capability, + value: 0, + }; + unsafe { + self.call(&mut cmd, ipc::GET_CAP)?; + } + Ok(cmd.value) + } + + fn set_client_cap(&self, capability: u64, value: u64) -> Result<()> { + let mut cmd = ipc::SetClientCap { capability, value }; + unsafe { + self.call(&mut cmd, ipc::SET_CLIENT_CAP)?; + } + Ok(()) + } + fn display_count(&self) -> Result { let mut cmd = ipc::DisplayCount { count: 0 }; unsafe { @@ -104,12 +139,21 @@ struct drm_version { unsafe fn version(dev: Dev, mut buf: IoctlBuffer) -> Result { let mut vers = buf.read::()?; - vers.version_major = 1; - vers.version_minor = 0; - vers.version_patchlevel = 0; - vers.name_len = copy_array("redox".as_bytes(), vers.name as *mut u8, vers.name_len); + let version = dev.version()?; + vers.version_major = version.version_major as i32; + vers.version_minor = version.version_minor as i32; + vers.version_patchlevel = version.version_patchlevel as i32; + vers.name_len = copy_array( + &version.name[..version.name_len], + vers.name as *mut u8, + vers.name_len, + ); vers.date_len = copy_array("0".as_bytes(), vers.date as *mut u8, vers.date_len); - vers.desc_len = copy_array("Redox OS".as_bytes(), vers.desc as *mut u8, vers.desc_len); + vers.desc_len = copy_array( + &version.desc[..version.desc_len], + vers.desc as *mut u8, + vers.desc_len, + ); buf.write(vers)?; Ok(0) } @@ -121,9 +165,11 @@ pub struct drm_get_cap { pub value: u64, } -unsafe fn get_cap(dev: Dev, buf: IoctlBuffer) -> Result { - //TODO: get capabilities - Err(Errno(EINVAL)) +unsafe fn get_cap(dev: Dev, mut buf: IoctlBuffer) -> Result { + let mut cap = buf.read::()?; + cap.value = dev.get_cap(cap.capability)?; + buf.write(cap)?; + Ok(0) } #[repr(C)] @@ -133,9 +179,10 @@ pub struct drm_set_client_cap { pub value: u64, } -unsafe fn set_client_cap(dev: Dev, buf: IoctlBuffer) -> Result { - //TODO: set capabilities - Err(Errno(EINVAL)) +unsafe fn set_client_cap(dev: Dev, mut buf: IoctlBuffer) -> Result { + let mut cap = buf.read::()?; + dev.set_client_cap(cap.capability, cap.value)?; + Ok(0) } #[repr(C)] diff --git a/src/header/sys_ioctl/redox/graphics_ipc.rs b/src/header/sys_ioctl/redox/graphics_ipc.rs index 51d886481f..517fe6e8b6 100644 --- a/src/header/sys_ioctl/redox/graphics_ipc.rs +++ b/src/header/sys_ioctl/redox/graphics_ipc.rs @@ -8,6 +8,36 @@ pub struct Damage { pub height: u32, } +pub const VERSION: u64 = 0; +#[repr(C, packed)] +pub struct Version { + pub version_major: u32, + pub version_minor: u32, + pub version_patchlevel: u32, + // FIXME allow variable sized fields + pub name_len: usize, + pub name: [u8; 16], + pub desc_len: usize, + pub desc: [u8; 16], +} + +pub const GET_CAP: u64 = 0x0C; +pub const CAP_DUMB_BUFFER: u64 = 0x1; +#[repr(C, packed)] +pub struct GetCap { + pub capability: u64, + pub value: u64, +} + +pub const SET_CLIENT_CAP: u64 = 0x0D; +pub const CLIENT_CAP_CURSOR_PLANE_HOTSPOT: u64 = 6; +#[repr(C, packed)] +pub struct SetClientCap { + pub capability: u64, + pub value: u64, +} + +// FIXME replace these with proper drm interfaces pub const DISPLAY_COUNT: u64 = 1; #[repr(C, packed)] pub struct DisplayCount { From 93f9401cf0aefcc0b7ea0001ae9abbdfe52b8a8a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 14 Dec 2025 22:32:43 +0100 Subject: [PATCH 5/8] Use drm-sys for DRM types and consts --- Cargo.lock | 17 ++ Cargo.toml | 1 + src/header/sys_ioctl/redox/drm.rs | 176 +-------------------- src/header/sys_ioctl/redox/graphics_ipc.rs | 14 +- 4 files changed, 27 insertions(+), 181 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c194a25be8..29af2ad0a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -179,6 +179,16 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "drm-sys" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafb66c8dbc944d69e15cfcc661df7e703beffbaec8bd63151368b06c5f9858c" +dependencies = [ + "libc", + "linux-raw-sys", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -248,6 +258,12 @@ dependencies = [ "libc", ] +[[package]] +name = "linux-raw-sys" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7" + [[package]] name = "lock_api" version = "0.4.14" @@ -449,6 +465,7 @@ dependencies = [ "chrono", "chrono-tz", "dlmalloc", + "drm-sys", "generic-rt", "libc", "libm", diff --git a/Cargo.toml b/Cargo.toml index be96f42c01..29550d0ddf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,7 @@ features = ["c_api"] sc = "0.2.7" [target.'cfg(target_os = "redox")'.dependencies] +drm-sys = "0.8.0" redox_syscall = "0.5.13" redox-rt = { path = "redox-rt" } redox-path = "0.3" diff --git a/src/header/sys_ioctl/redox/drm.rs b/src/header/sys_ioctl/redox/drm.rs index 5c1b5c707a..d3dc635b54 100644 --- a/src/header/sys_ioctl/redox/drm.rs +++ b/src/header/sys_ioctl/redox/drm.rs @@ -1,5 +1,10 @@ use alloc::vec::Vec; use core::{mem, slice}; +use drm_sys::{ + drm_get_cap, drm_mode_card_res, drm_mode_crtc, drm_mode_fb_cmd, drm_mode_fb_cmd2, + drm_mode_get_connector, drm_mode_get_encoder, drm_mode_get_plane, drm_mode_get_plane_res, + drm_mode_obj_get_properties, drm_set_client_cap, drm_version, +}; use crate::{ error::{Errno, Result}, @@ -82,7 +87,7 @@ impl Dev { } fn get_cap(&self, capability: u64) -> Result { - let mut cmd = ipc::GetCap { + let mut cmd = drm_get_cap { capability, value: 0, }; @@ -93,7 +98,7 @@ impl Dev { } fn set_client_cap(&self, capability: u64, value: u64) -> Result<()> { - let mut cmd = ipc::SetClientCap { capability, value }; + let mut cmd = drm_set_client_cap { capability, value }; unsafe { self.call(&mut cmd, ipc::SET_CLIENT_CAP)?; } @@ -121,22 +126,6 @@ impl Dev { } } -// Structs adapted from drm-sys bindings: https://docs.rs/drm-sys/0.8.0/src/drm_sys/bindings.rs.html -//TODO: can we auto generate these from libdrm without causing dependency issues? -#[repr(C)] -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -struct drm_version { - pub version_major: c_int, - pub version_minor: c_int, - pub version_patchlevel: c_int, - pub name_len: size_t, - pub name: *mut c_char, - pub date_len: size_t, - pub date: *mut c_char, - pub desc_len: size_t, - pub desc: *mut c_char, -} - unsafe fn version(dev: Dev, mut buf: IoctlBuffer) -> Result { let mut vers = buf.read::()?; let version = dev.version()?; @@ -158,13 +147,6 @@ unsafe fn version(dev: Dev, mut buf: IoctlBuffer) -> Result { Ok(0) } -#[repr(C)] -#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] -pub struct drm_get_cap { - pub capability: u64, - pub value: u64, -} - unsafe fn get_cap(dev: Dev, mut buf: IoctlBuffer) -> Result { let mut cap = buf.read::()?; cap.value = dev.get_cap(cap.capability)?; @@ -172,36 +154,12 @@ unsafe fn get_cap(dev: Dev, mut buf: IoctlBuffer) -> Result { Ok(0) } -#[repr(C)] -#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] -pub struct drm_set_client_cap { - pub capability: u64, - pub value: u64, -} - unsafe fn set_client_cap(dev: Dev, mut buf: IoctlBuffer) -> Result { let mut cap = buf.read::()?; dev.set_client_cap(cap.capability, cap.value)?; Ok(0) } -#[repr(C)] -#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] -pub struct drm_mode_card_res { - pub fb_id_ptr: u64, - pub crtc_id_ptr: u64, - pub connector_id_ptr: u64, - pub encoder_id_ptr: u64, - pub count_fbs: u32, - pub count_crtcs: u32, - pub count_connectors: u32, - pub count_encoders: u32, - pub min_width: u32, - pub max_width: u32, - pub min_height: u32, - pub max_height: u32, -} - unsafe fn mode_card_res(dev: Dev, mut buf: IoctlBuffer) -> Result { let mut res = buf.read::()?; let count = dev.display_count()?; @@ -239,40 +197,6 @@ unsafe fn mode_card_res(dev: Dev, mut buf: IoctlBuffer) -> Result { Ok(0) } -#[repr(C)] -#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] -pub struct drm_mode_modeinfo { - pub clock: u32, - pub hdisplay: u16, - pub hsync_start: u16, - pub hsync_end: u16, - pub htotal: u16, - pub hskew: u16, - pub vdisplay: u16, - pub vsync_start: u16, - pub vsync_end: u16, - pub vtotal: u16, - pub vscan: u16, - pub vrefresh: u32, - pub flags: u32, - pub type_: u32, - pub name: [c_char; 32], -} - -#[repr(C)] -#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] -pub struct drm_mode_crtc { - pub set_connectors_ptr: u64, - pub count_connectors: u32, - pub crtc_id: u32, - pub fb_id: u32, - pub x: u32, - pub y: u32, - pub gamma_size: u32, - pub mode_valid: u32, - pub mode: drm_mode_modeinfo, -} - unsafe fn mode_get_crtc(dev: Dev, mut buf: IoctlBuffer) -> Result { let mut crtc = buf.read::()?; let i = id_index(crtc.crtc_id); @@ -289,16 +213,6 @@ unsafe fn mode_get_crtc(dev: Dev, mut buf: IoctlBuffer) -> Result { Ok(0) } -#[repr(C)] -#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] -pub struct drm_mode_get_encoder { - pub encoder_id: u32, - pub encoder_type: u32, - pub crtc_id: u32, - pub possible_crtcs: u32, - pub possible_clones: u32, -} - unsafe fn mode_get_encoder(dev: Dev, mut buf: IoctlBuffer) -> Result { let mut enc = buf.read::()?; let i = id_index(enc.encoder_id); @@ -310,27 +224,6 @@ unsafe fn mode_get_encoder(dev: Dev, mut buf: IoctlBuffer) -> Result { Ok(0) } -#[repr(C)] -#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] -pub struct drm_mode_get_connector { - pub encoders_ptr: u64, - pub modes_ptr: u64, - pub props_ptr: u64, - pub prop_values_ptr: u64, - pub count_modes: u32, - pub count_props: u32, - pub count_encoders: u32, - pub encoder_id: u32, - pub connector_id: u32, - pub connector_type: u32, - pub connector_type_id: u32, - pub connection: u32, - pub mm_width: u32, - pub mm_height: u32, - pub subpixel: u32, - pub pad: u32, -} - unsafe fn mode_get_connector(dev: Dev, mut buf: IoctlBuffer) -> Result { let mut conn = buf.read::()?; let i = id_index(conn.connector_id); @@ -346,18 +239,6 @@ unsafe fn mode_get_connector(dev: Dev, mut buf: IoctlBuffer) -> Result { Ok(0) } -#[repr(C)] -#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] -pub struct drm_mode_fb_cmd { - pub fb_id: u32, - pub width: u32, - pub height: u32, - pub pitch: u32, - pub bpp: u32, - pub depth: u32, - pub handle: u32, -} - unsafe fn mode_get_fb(dev: Dev, mut buf: IoctlBuffer) -> Result { let mut fb = buf.read::()?; let i = id_index(fb.fb_id); @@ -372,13 +253,6 @@ unsafe fn mode_get_fb(dev: Dev, mut buf: IoctlBuffer) -> Result { Ok(0) } -#[repr(C)] -#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] -pub struct drm_mode_get_plane_res { - pub plane_id_ptr: u64, - pub count_planes: u32, -} - unsafe fn mode_get_plane_res(dev: Dev, mut buf: IoctlBuffer) -> Result { let mut res = buf.read::()?; let count = dev.display_count()?; @@ -395,18 +269,6 @@ unsafe fn mode_get_plane_res(dev: Dev, mut buf: IoctlBuffer) -> Result { Ok(0) } -#[repr(C)] -#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] -pub struct drm_mode_get_plane { - pub plane_id: u32, - pub crtc_id: u32, - pub fb_id: u32, - pub possible_crtcs: u32, - pub gamma_size: u32, - pub count_format_types: u32, - pub format_type_ptr: u64, -} - unsafe fn mode_get_plane(dev: Dev, mut buf: IoctlBuffer) -> Result { let mut plane = buf.read::()?; let i = id_index(plane.plane_id); @@ -423,16 +285,6 @@ unsafe fn mode_get_plane(dev: Dev, mut buf: IoctlBuffer) -> Result { Ok(0) } -#[repr(C)] -#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] -pub struct drm_mode_obj_get_properties { - pub props_ptr: u64, - pub prop_values_ptr: u64, - pub count_props: u32, - pub obj_id: u32, - pub obj_type: u32, -} - unsafe fn mode_obj_get_properties(dev: Dev, mut buf: IoctlBuffer) -> Result { let mut props = buf.read::()?; //TODO @@ -441,20 +293,6 @@ unsafe fn mode_obj_get_properties(dev: Dev, mut buf: IoctlBuffer) -> Result Result { let mut fb = buf.read::()?; let i = id_index(fb.fb_id); diff --git a/src/header/sys_ioctl/redox/graphics_ipc.rs b/src/header/sys_ioctl/redox/graphics_ipc.rs index 517fe6e8b6..374bd97ca0 100644 --- a/src/header/sys_ioctl/redox/graphics_ipc.rs +++ b/src/header/sys_ioctl/redox/graphics_ipc.rs @@ -22,20 +22,10 @@ pub struct Version { } pub const GET_CAP: u64 = 0x0C; -pub const CAP_DUMB_BUFFER: u64 = 0x1; -#[repr(C, packed)] -pub struct GetCap { - pub capability: u64, - pub value: u64, -} +pub use drm_sys::DRM_CAP_DUMB_BUFFER; pub const SET_CLIENT_CAP: u64 = 0x0D; -pub const CLIENT_CAP_CURSOR_PLANE_HOTSPOT: u64 = 6; -#[repr(C, packed)] -pub struct SetClientCap { - pub capability: u64, - pub value: u64, -} +pub use drm_sys::DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT; // FIXME replace these with proper drm interfaces pub const DISPLAY_COUNT: u64 = 1; From cf90f89b42e4a4ca76dd84cc542c72537bcb253c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 15 Dec 2025 22:26:52 +0100 Subject: [PATCH 6/8] Introduce infrastructure for serializing ioctls And use it for a couple of drm interfaces --- src/header/sys_ioctl/redox/drm.rs | 103 +++------ src/header/sys_ioctl/redox/graphics_ipc.rs | 229 ++++++++++++++++++++- src/lib.rs | 1 + 3 files changed, 254 insertions(+), 79 deletions(-) diff --git a/src/header/sys_ioctl/redox/drm.rs b/src/header/sys_ioctl/redox/drm.rs index d3dc635b54..07218e19cd 100644 --- a/src/header/sys_ioctl/redox/drm.rs +++ b/src/header/sys_ioctl/redox/drm.rs @@ -12,7 +12,7 @@ use crate::{ platform::types::*, }; -use super::{IoctlBuffer, graphics_ipc as ipc}; +use super::{IoctlBuffer, graphics_ipc as ipc, graphics_ipc::IoctlData}; const DRM_FORMAT_ARGB8888: u32 = 0x34325241; // 'AR24' fourcc code, for ARGB8888 @@ -70,39 +70,38 @@ impl Dev { ) } - fn version(&self) -> Result { - let mut cmd = ipc::Version { - version_major: 0, - version_minor: 0, - version_patchlevel: 0, - name_len: 0, - name: [0; 16], - desc_len: 0, - desc: [0; 16], - }; - unsafe { - self.call(&mut cmd, ipc::VERSION)?; - } - Ok(cmd) + unsafe fn read_write_ioctl( + &self, + mut buf: IoctlBuffer, + func: u64, + ) -> Result { + let mut data = buf.read::()?; + 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) } - fn get_cap(&self, capability: u64) -> Result { - let mut cmd = drm_get_cap { - capability, - value: 0, - }; - unsafe { - self.call(&mut cmd, ipc::GET_CAP)?; - } - Ok(cmd.value) - } - - fn set_client_cap(&self, capability: u64, value: u64) -> Result<()> { - let mut cmd = drm_set_client_cap { capability, value }; - unsafe { - self.call(&mut cmd, ipc::SET_CLIENT_CAP)?; - } - Ok(()) + unsafe fn write_ioctl( + &self, + mut buf: IoctlBuffer, + func: u64, + ) -> Result { + let mut data = buf.read::()?; + 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) } fn display_count(&self) -> Result { @@ -126,40 +125,6 @@ impl Dev { } } -unsafe fn version(dev: Dev, mut buf: IoctlBuffer) -> Result { - let mut vers = buf.read::()?; - let version = dev.version()?; - vers.version_major = version.version_major as i32; - vers.version_minor = version.version_minor as i32; - vers.version_patchlevel = version.version_patchlevel as i32; - vers.name_len = copy_array( - &version.name[..version.name_len], - vers.name as *mut u8, - vers.name_len, - ); - vers.date_len = copy_array("0".as_bytes(), vers.date as *mut u8, vers.date_len); - vers.desc_len = copy_array( - &version.desc[..version.desc_len], - vers.desc as *mut u8, - vers.desc_len, - ); - buf.write(vers)?; - Ok(0) -} - -unsafe fn get_cap(dev: Dev, mut buf: IoctlBuffer) -> Result { - let mut cap = buf.read::()?; - cap.value = dev.get_cap(cap.capability)?; - buf.write(cap)?; - Ok(0) -} - -unsafe fn set_client_cap(dev: Dev, mut buf: IoctlBuffer) -> Result { - let mut cap = buf.read::()?; - dev.set_client_cap(cap.capability, cap.value)?; - Ok(0) -} - unsafe fn mode_card_res(dev: Dev, mut buf: IoctlBuffer) -> Result { let mut res = buf.read::()?; let count = dev.display_count()?; @@ -311,9 +276,9 @@ unsafe fn mode_get_fb2(dev: Dev, mut buf: IoctlBuffer) -> Result { pub(super) unsafe fn ioctl(fd: c_int, func: u8, buf: IoctlBuffer) -> Result { let dev = Dev::new(fd)?; match func { - 0x00 => version(dev, buf), - 0x0C => get_cap(dev, buf), - 0x0D => set_client_cap(dev, buf), + 0x00 => dev.read_write_ioctl::(buf, ipc::VERSION), + 0x0C => dev.read_write_ioctl::(buf, ipc::GET_CAP), + 0x0D => dev.write_ioctl::(buf, ipc::SET_CLIENT_CAP), 0xA0 => mode_card_res(dev, buf), 0xA1 => mode_get_crtc(dev, buf), 0xA6 => mode_get_encoder(dev, buf), diff --git a/src/header/sys_ioctl/redox/graphics_ipc.rs b/src/header/sys_ioctl/redox/graphics_ipc.rs index 374bd97ca0..c37017845d 100644 --- a/src/header/sys_ioctl/redox/graphics_ipc.rs +++ b/src/header/sys_ioctl/redox/graphics_ipc.rs @@ -8,24 +8,233 @@ pub struct Damage { pub height: u32, } +use alloc::vec::Vec; +use core::{ + cmp, + ffi::{c_char, c_int}, + iter, mem, slice, +}; + +pub trait IoctlData { + unsafe fn write(&self) -> Vec; + unsafe fn read_from(&mut self, buf: &[u8]); +} + +macro_rules! define_ioctl_data { + (struct $ioctl_ty:ident, $mem_ty:ident { + $($rest:tt)* + }) => { + define_ioctl_data!( + struct $ioctl_ty, $mem_ty { $($rest)* } => (), (), () + ); + }; + (struct $ioctl_ty:ident, $mem_ty:ident { + $field:ident: $ty:ty, + $($rest:tt)* + } => + ($($ioctl_fields:tt)*), + ($($counted_fields:tt)*), + ($($noncounted_fields:tt)*) + ) => { + define_ioctl_data!( + struct $ioctl_ty, $mem_ty { $($rest)* } => + ($($ioctl_fields)* $field: $ty,), + ($($counted_fields)*), + ($($noncounted_fields)* $field: $ty,) + ); + }; + (struct $ioctl_ty:ident, $mem_ty:ident { + $field:ident: $ty:ty [array<$el:ident, $counted_by:ident>], + $($rest:tt)* + } => + ($($ioctl_fields:tt)*), + ($($counted_fields:tt)*), + ($($noncounted_fields:tt)*) + ) => { + define_ioctl_data!( + struct $ioctl_ty, $mem_ty { $($rest)* } => + ($($ioctl_fields)* $field: $ty,), + ($($counted_fields)* $field: $ty [array<$el, $counted_by>],), + ($($noncounted_fields)*) + ); + }; + (struct $ioctl_ty:ident, $mem_ty:ident {} => + ($($ioctl_field:ident: $ioctl_field_ty:ty,)*), + ($($counted_field:ident: $counted_ty:ty [array<$el:ident, $counted_by:ident>],)*), + ($($noncounted_field:ident: $noncounted_ty:ty,)*) + ) => { + pub use drm_sys::$ioctl_ty; + + // FIXME check ioctl_ty doesn't have padding + const _: $ioctl_ty = $ioctl_ty { + $($ioctl_field: unsafe { mem::zeroed::<$ioctl_field_ty>() },)* + }; + + #[repr(C)] + pub struct ${concat(__, $mem_ty, Noncounted)} { + $($noncounted_field: $noncounted_ty,)* + } + + pub struct $mem_ty<'a> { + noncounted_fields: &'a mut ${concat(__, $mem_ty, Noncounted)}, + $($counted_field: &'a mut [$el],)* + } + + impl IoctlData for $ioctl_ty { + unsafe fn write(&self) -> Vec { + let noncounted_fields = ${concat(__, $mem_ty, Noncounted)} { + $($noncounted_field: self.$noncounted_field,)* + }; + // FIXME use Vec::with_capacity + let mut data = Vec::::new(); + data.extend_from_slice(&unsafe { + mem::transmute::< + ${concat(__, $mem_ty, Noncounted)}, + [u8; size_of::<${concat(__, $mem_ty, Noncounted)}>()], + >(noncounted_fields) + }); + $( + let size = self.$counted_by as usize * size_of::<$el>(); + if self.$counted_field as usize != 0 { + let $counted_field = unsafe { + slice::from_raw_parts(self.$counted_field as *const u8, size) + }; + data.extend_from_slice(&$counted_field); + } else { + data.extend(iter::repeat(0u8).take(size)); + }; + + )* + data + } + + unsafe fn read_from(&mut self, mut buf: &[u8]) { + // FIXME be robust against malicious scheme implementations by returning an error + // when the buf is the wrong size + let noncounted_fields = buf.split_off(..size_of::<${concat(__, $mem_ty, Noncounted)}>()).unwrap(); + + $( + let size = self.$counted_by as usize * size_of::<$el>(); + let $counted_field = buf.split_off(..size).unwrap(); + if self.$counted_field as usize != 0 { + unsafe { + slice::from_raw_parts_mut(self.$counted_field as *mut u8, size).copy_from_slice($counted_field); + } + } + )* + + assert!(buf.is_empty()); + + let noncounted_fields = unsafe { &*(noncounted_fields as *const _ as *const ${concat(__, $mem_ty, Noncounted)}) }; + $(self.$noncounted_field = noncounted_fields.$noncounted_field;)* + } + } + + impl<'a> $mem_ty<'a> { + pub fn with( + mut buf: &'a mut [u8], + f: impl FnOnce($mem_ty<'a>) -> syscall::Result, + ) -> syscall::Result { + let noncounted_fields = buf.split_off_mut(..size_of::<${concat(__, $mem_ty, Noncounted)}>()) + .ok_or(syscall::Error::new(syscall::EINVAL))?; + let noncounted_fields = unsafe { &mut *(noncounted_fields as *mut _ as *mut ${concat(__, $mem_ty, Noncounted)}) }; + + $( + let $counted_field = buf.split_off_mut(..noncounted_fields.$counted_by as usize * size_of::<$el>()) + .ok_or(syscall::Error::new(syscall::EINVAL))?; + let $counted_field = unsafe { + slice::from_raw_parts_mut($counted_field as *mut _ as *mut $el, noncounted_fields.$counted_by as usize) + }; + )* + + if !buf.is_empty() { + return Err(syscall::Error::new(syscall::EINVAL)); + } + + + + Ok( f($mem_ty { + noncounted_fields, + $($counted_field,)* + })?) + } + + $( + pub fn $noncounted_field(&self) -> $noncounted_ty { + self.noncounted_fields.$noncounted_field + } + + /// Should not be called for fields used as array length + pub fn ${concat(set_, $noncounted_field)}(&mut self, data: $noncounted_ty) { + self.noncounted_fields.$noncounted_field = data; + } + )* + + $( + pub fn $counted_field(&self) -> &[$el] { + self.$counted_field + } + + pub fn ${concat(set_, $counted_field)}(&mut self, data: &[$el]) { + let copied_count = cmp::min(data.len(), self.$counted_field.len()); + self.$counted_field[..copied_count].copy_from_slice(&data[..copied_count]); + self.noncounted_fields.$counted_by = data.len() as _; + } + )* + } + }; + } + pub const VERSION: u64 = 0; -#[repr(C, packed)] -pub struct Version { - pub version_major: u32, - pub version_minor: u32, - pub version_patchlevel: u32, - // FIXME allow variable sized fields - pub name_len: usize, - pub name: [u8; 16], - pub desc_len: usize, - pub desc: [u8; 16], +define_ioctl_data! { + struct drm_version, DrmVersion { + version_major: c_int, + version_minor: c_int, + version_patchlevel: c_int, + name_len: drm_sys::__kernel_size_t, + name: *mut c_char [array], + date_len: drm_sys::__kernel_size_t, + date: *mut c_char [array], + desc_len: drm_sys::__kernel_size_t, + desc: *mut c_char [array], + } } pub const GET_CAP: u64 = 0x0C; pub use drm_sys::DRM_CAP_DUMB_BUFFER; +define_ioctl_data! { + struct drm_get_cap, DrmGetCap { + capability: u64, + value: u64, + } +} pub const SET_CLIENT_CAP: u64 = 0x0D; pub use drm_sys::DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT; +define_ioctl_data! { + struct drm_set_client_cap, DrmSetClientCap { + capability: u64, + value: u64, + } +} + +pub const MODE_CARD_RES: u64 = 0xA0; +define_ioctl_data! { + struct drm_mode_card_res, DrmModeCardRes { + fb_id_ptr: u64 [array], + crtc_id_ptr: u64 [array], + connector_id_ptr: u64 [array], + encoder_id_ptr: u64 [array], + count_fbs: u32, + count_crtcs: u32, + count_connectors: u32, + count_encoders: u32, + min_width: u32, + max_width: u32, + min_height: u32, + max_height: u32, + } +} // FIXME replace these with proper drm interfaces pub const DISPLAY_COUNT: u64 = 1; diff --git a/src/lib.rs b/src/lib.rs index 3ea46c6a6b..e74975e661 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ #![feature(c_variadic)] #![feature(core_intrinsics)] #![feature(macro_derive)] +#![feature(macro_metavar_expr_concat)] #![feature(maybe_uninit_slice)] #![feature(lang_items)] #![feature(linkage)] From c4ffcedbd09257c0897e4b63f5b03091e9501e97 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 15 Dec 2025 23:34:44 +0100 Subject: [PATCH 7/8] Port remaining drm ioctls to the new infrastructure --- src/header/sys_ioctl/redox/drm.rs | 168 ++------------------- src/header/sys_ioctl/redox/graphics_ipc.rs | 112 +++++++++++++- 2 files changed, 121 insertions(+), 159 deletions(-) diff --git a/src/header/sys_ioctl/redox/drm.rs b/src/header/sys_ioctl/redox/drm.rs index 07218e19cd..01b0d5afbf 100644 --- a/src/header/sys_ioctl/redox/drm.rs +++ b/src/header/sys_ioctl/redox/drm.rs @@ -125,169 +125,23 @@ impl Dev { } } -unsafe fn mode_card_res(dev: Dev, mut buf: IoctlBuffer) -> Result { - let mut res = buf.read::()?; - let count = dev.display_count()?; - let mut conn_ids = Vec::with_capacity(count); - let mut crtc_ids = Vec::with_capacity(count); - let mut enc_ids = Vec::with_capacity(count); - let mut fb_ids = Vec::with_capacity(count); - for i in 0..(count as u32) { - conn_ids.push(conn_id(i)); - crtc_ids.push(crtc_id(i)); - enc_ids.push(enc_id(i)); - fb_ids.push(fb_id(i)); - } - res.count_fbs = copy_array(&fb_ids, res.fb_id_ptr as *mut u32, res.count_fbs as usize) as u32; - res.count_crtcs = copy_array( - &crtc_ids, - res.crtc_id_ptr as *mut u32, - res.count_crtcs as usize, - ) as u32; - res.count_connectors = copy_array( - &conn_ids, - res.connector_id_ptr as *mut u32, - res.count_connectors as usize, - ) as u32; - res.count_encoders = copy_array( - &enc_ids, - res.encoder_id_ptr as *mut u32, - res.count_encoders as usize, - ) as u32; - res.min_width = 0; - res.max_width = 16384; - res.min_height = 0; - res.max_height = 16384; - buf.write(res)?; - Ok(0) -} - -unsafe fn mode_get_crtc(dev: Dev, mut buf: IoctlBuffer) -> Result { - let mut crtc = buf.read::()?; - let i = id_index(crtc.crtc_id); - let (width, height) = dev.display_size(i as usize)?; - //TOOD: connectors - crtc.fb_id = fb_id(i); - crtc.x = 0; - crtc.y = 0; - crtc.gamma_size = 0; - crtc.mode_valid = 0; - //TODO: mode - crtc.mode = Default::default(); - buf.write(crtc)?; - Ok(0) -} - -unsafe fn mode_get_encoder(dev: Dev, mut buf: IoctlBuffer) -> Result { - let mut enc = buf.read::()?; - let i = id_index(enc.encoder_id); - let (width, height) = dev.display_size(i as usize)?; - enc.crtc_id = crtc_id(i); - enc.possible_crtcs = (1 << i); - enc.possible_clones = (1 << i); - buf.write(enc)?; - Ok(0) -} - -unsafe fn mode_get_connector(dev: Dev, mut buf: IoctlBuffer) -> Result { - let mut conn = buf.read::()?; - let i = id_index(conn.connector_id); - let (width, height) = dev.display_size(i as usize)?; - conn.count_modes = 0; - conn.count_props = 0; - conn.count_encoders = copy_array( - &[enc_id(i)], - conn.encoders_ptr as *mut u32, - conn.count_encoders as usize, - ) as u32; - buf.write(conn)?; - Ok(0) -} - -unsafe fn mode_get_fb(dev: Dev, mut buf: IoctlBuffer) -> Result { - let mut fb = buf.read::()?; - let i = id_index(fb.fb_id); - let (width, height) = dev.display_size(i as usize)?; - fb.width = width; - fb.height = height; - fb.pitch = width * 4; //TODO: stride - fb.bpp = 32; - fb.depth = 24; - fb.handle = fb_handle_id(i); - buf.write(fb)?; - Ok(0) -} - -unsafe fn mode_get_plane_res(dev: Dev, mut buf: IoctlBuffer) -> Result { - let mut res = buf.read::()?; - let count = dev.display_count()?; - let mut ids = Vec::with_capacity(count); - for i in 0..(count as u32) { - ids.push(plane_id(i)); - } - res.count_planes = copy_array( - &ids, - res.plane_id_ptr as *mut u32, - res.count_planes as usize, - ) as u32; - buf.write(res)?; - Ok(0) -} - -unsafe fn mode_get_plane(dev: Dev, mut buf: IoctlBuffer) -> Result { - let mut plane = buf.read::()?; - let i = id_index(plane.plane_id); - let (width, height) = dev.display_size(i as usize)?; - plane.crtc_id = crtc_id(i); - plane.fb_id = fb_id(i); - plane.possible_crtcs = (1 << i); - plane.count_format_types = copy_array( - &[DRM_FORMAT_ARGB8888], - plane.format_type_ptr as *mut u32, - plane.count_format_types as usize, - ) as u32; - buf.write(plane)?; - Ok(0) -} - -unsafe fn mode_obj_get_properties(dev: Dev, mut buf: IoctlBuffer) -> Result { - let mut props = buf.read::()?; - //TODO - props.count_props = 0; - buf.write(props)?; - Ok(0) -} - -unsafe fn mode_get_fb2(dev: Dev, mut buf: IoctlBuffer) -> Result { - let mut fb = buf.read::()?; - let i = id_index(fb.fb_id); - let (width, height) = dev.display_size(i as usize)?; - fb.width = width; - fb.height = height; - fb.pixel_format = DRM_FORMAT_ARGB8888; - fb.handles[0] = fb_handle_id(i); - fb.pitches[0] = width * 4; - fb.offsets[0] = 0; - fb.modifier[0] = 0; - buf.write(fb)?; - Ok(0) -} - pub(super) unsafe fn ioctl(fd: c_int, func: u8, buf: IoctlBuffer) -> Result { let dev = Dev::new(fd)?; match func { 0x00 => dev.read_write_ioctl::(buf, ipc::VERSION), 0x0C => dev.read_write_ioctl::(buf, ipc::GET_CAP), 0x0D => dev.write_ioctl::(buf, ipc::SET_CLIENT_CAP), - 0xA0 => mode_card_res(dev, buf), - 0xA1 => mode_get_crtc(dev, buf), - 0xA6 => mode_get_encoder(dev, buf), - 0xA7 => mode_get_connector(dev, buf), - 0xAD => mode_get_fb(dev, buf), - 0xB5 => mode_get_plane_res(dev, buf), - 0xB6 => mode_get_plane(dev, buf), - 0xB9 => mode_obj_get_properties(dev, buf), - 0xCE => mode_get_fb2(dev, buf), + 0xA0 => dev.read_write_ioctl::(buf, ipc::MODE_CARD_RES), + 0xA1 => dev.read_write_ioctl::(buf, ipc::MODE_GET_CRTC), + 0xA6 => dev.read_write_ioctl::(buf, ipc::MODE_GET_ENCODER), + 0xA7 => dev.read_write_ioctl::(buf, ipc::MODE_GET_CONNECTOR), + 0xAD => dev.read_write_ioctl::(buf, ipc::MODE_GET_FB), + 0xB5 => dev.read_write_ioctl::(buf, ipc::MODE_GET_PLANE_RES), + 0xB6 => dev.read_write_ioctl::(buf, ipc::MODE_GET_PLANE), + 0xB9 => { + dev.read_write_ioctl::(buf, ipc::MODE_OBJ_GET_PROPERTIES) + } + 0xCE => dev.read_write_ioctl::(buf, ipc::MODE_GET_FB2), _ => { eprintln!("unimplemented DRM ioctl({}, 0x{:02x}, {:?})", fd, func, buf); Err(Errno(EINVAL)) diff --git a/src/header/sys_ioctl/redox/graphics_ipc.rs b/src/header/sys_ioctl/redox/graphics_ipc.rs index c37017845d..86938a053d 100644 --- a/src/header/sys_ioctl/redox/graphics_ipc.rs +++ b/src/header/sys_ioctl/redox/graphics_ipc.rs @@ -44,7 +44,7 @@ macro_rules! define_ioctl_data { ); }; (struct $ioctl_ty:ident, $mem_ty:ident { - $field:ident: $ty:ty [array<$el:ident, $counted_by:ident>], + $field:ident: $ty:ty [array<$el:ty, $counted_by:ident>], $($rest:tt)* } => ($($ioctl_fields:tt)*), @@ -60,7 +60,7 @@ macro_rules! define_ioctl_data { }; (struct $ioctl_ty:ident, $mem_ty:ident {} => ($($ioctl_field:ident: $ioctl_field_ty:ty,)*), - ($($counted_field:ident: $counted_ty:ty [array<$el:ident, $counted_by:ident>],)*), + ($($counted_field:ident: $counted_ty:ty [array<$el:ty, $counted_by:ident>],)*), ($($noncounted_field:ident: $noncounted_ty:ty,)*) ) => { pub use drm_sys::$ioctl_ty; @@ -236,6 +236,114 @@ define_ioctl_data! { } } +pub const MODE_GET_CRTC: u64 = 0xA1; +define_ioctl_data! { + struct drm_mode_crtc, DrmModeCrtc { + set_connectors_ptr: u64, + count_connectors: u32, + crtc_id: u32, + fb_id: u32, + x: u32, + y: u32, + gamma_size: u32, + mode_valid: u32, + mode: drm_sys::drm_mode_modeinfo, + } +} + +pub const MODE_GET_ENCODER: u64 = 0xA6; +define_ioctl_data! { + struct drm_mode_get_encoder, DrmModeGetEncoder { + encoder_id: u32, + encoder_type: u32, + crtc_id: u32, + possible_crtcs: u32, + possible_clones: u32, + } +} + +pub const MODE_GET_CONNECTOR: u64 = 0xA7; +define_ioctl_data! { + struct drm_mode_get_connector, DrmModeGetConnector { + encoders_ptr: u64 [array], + modes_ptr: u64 [array], + props_ptr: u64 [array], + prop_values_ptr: u64 [array], + count_modes: u32, + count_props: u32, + count_encoders: u32, + encoder_id: u32, + connector_id: u32, + connector_type: u32, + connector_type_id: u32, + connection: u32, + mm_width: u32, + mm_height: u32, + subpixel: u32, + pad: u32, + } +} + +pub const MODE_GET_FB: u64 = 0xAD; +define_ioctl_data! { + struct drm_mode_fb_cmd, DrmModeFbCmd { + fb_id: u32, + width: u32, + height: u32, + pitch: u32, + bpp: u32, + depth: u32, + handle: u32, + } +} + +pub const MODE_GET_PLANE_RES: u64 = 0xB5; +define_ioctl_data! { + struct drm_mode_get_plane_res, DrmModeGetPlaneRes { + plane_id_ptr: u64 [array], + count_planes: u32, + } +} + +pub const MODE_GET_PLANE: u64 = 0xB6; +define_ioctl_data! { + struct drm_mode_get_plane, DrmModeGetPlane { + plane_id: u32, + crtc_id: u32, + fb_id: u32, + possible_crtcs: u32, + gamma_size: u32, + count_format_types: u32, + format_type_ptr: u64 [array], + } +} + +pub const MODE_OBJ_GET_PROPERTIES: u64 = 0xB9; +define_ioctl_data! { + struct drm_mode_obj_get_properties, DrmModeObjGetProperties { + props_ptr: u64 [array], + prop_values_ptr: u64 [array], + count_props: u32, + obj_id: u32, + obj_type: u32, + } +} + +pub const MODE_GET_FB2: u64 = 0xCE; +define_ioctl_data! { + struct drm_mode_fb_cmd2, DrmModeFbCmd2 { + fb_id: u32, + width: u32, + height: u32, + pixel_format: u32, + flags: u32, + handles: [u32; 4], + pitches: [u32; 4], + offsets: [u32; 4], + modifier: [u64; 4], + } +} + // FIXME replace these with proper drm interfaces pub const DISPLAY_COUNT: u64 = 1; #[repr(C, packed)] From 61dc5271560ef4536f1397acbf56ec1af8cb5d9b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 16 Dec 2025 20:37:33 +0100 Subject: [PATCH 8/8] Move drm ioctl (de)serialization into a new redox-ioctl crate This will make it easier to share this code with gpu drivers in the base repo. --- Cargo.lock | 10 +- Cargo.toml | 2 +- redox-ioctl/Cargo.toml | 13 + redox-ioctl/src/drm.rs | 172 +++++++++ redox-ioctl/src/ioctl_data.rs | 169 +++++++++ redox-ioctl/src/lib.rs | 10 + src/header/sys_ioctl/redox/drm.rs | 68 +--- src/header/sys_ioctl/redox/graphics_ipc.rs | 392 --------------------- src/header/sys_ioctl/redox/mod.rs | 1 - src/lib.rs | 1 - 10 files changed, 393 insertions(+), 445 deletions(-) create mode 100644 redox-ioctl/Cargo.toml create mode 100644 redox-ioctl/src/drm.rs create mode 100644 redox-ioctl/src/ioctl_data.rs create mode 100644 redox-ioctl/src/lib.rs delete mode 100644 src/header/sys_ioctl/redox/graphics_ipc.rs diff --git a/Cargo.lock b/Cargo.lock index 29af2ad0a1..42bed02ac7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -417,6 +417,14 @@ dependencies = [ "rand_core", ] +[[package]] +name = "redox-ioctl" +version = "0.1.0" +dependencies = [ + "drm-sys", + "redox_syscall", +] + [[package]] name = "redox-path" version = "0.3.1" @@ -465,7 +473,6 @@ dependencies = [ "chrono", "chrono-tz", "dlmalloc", - "drm-sys", "generic-rt", "libc", "libm", @@ -478,6 +485,7 @@ dependencies = [ "rand", "rand_jitter", "rand_xorshift", + "redox-ioctl", "redox-path", "redox-rt", "redox_event", diff --git a/Cargo.toml b/Cargo.toml index 29550d0ddf..c5191f508e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,13 +62,13 @@ features = ["c_api"] sc = "0.2.7" [target.'cfg(target_os = "redox")'.dependencies] -drm-sys = "0.8.0" redox_syscall = "0.5.13" redox-rt = { path = "redox-rt" } redox-path = "0.3" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git", default-features = false, features = [ "redox_syscall", ] } +redox-ioctl = { path = "redox-ioctl" } [features] default = ["check_against_libc_crate"] diff --git a/redox-ioctl/Cargo.toml b/redox-ioctl/Cargo.toml new file mode 100644 index 0000000000..1096248d3a --- /dev/null +++ b/redox-ioctl/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "redox-ioctl" +authors = ["bjorn3 "] +version = "0.1.0" +edition = "2024" +license = "MIT" +description = "Ioctl definitions and (de)serialization for Redox" + +[dependencies] +drm-sys = "0.8.0" +redox_syscall = "0.5.8" + +[features] diff --git a/redox-ioctl/src/drm.rs b/redox-ioctl/src/drm.rs new file mode 100644 index 0000000000..edab1d5424 --- /dev/null +++ b/redox-ioctl/src/drm.rs @@ -0,0 +1,172 @@ +use alloc::vec::Vec; +use core::{ + cmp, + ffi::{c_char, c_int}, + iter, mem, slice, +}; + +pub use drm_sys::{ + __kernel_size_t, drm_get_cap, drm_mode_card_res, drm_mode_crtc, drm_mode_fb_cmd, + drm_mode_fb_cmd2, drm_mode_get_connector, drm_mode_get_encoder, drm_mode_get_plane, + drm_mode_get_plane_res, drm_mode_modeinfo, drm_mode_obj_get_properties, drm_set_client_cap, + drm_version, +}; + +pub const VERSION: u64 = 0; +define_ioctl_data! { + struct drm_version, DrmVersion { + version_major: c_int, + version_minor: c_int, + version_patchlevel: c_int, + name_len: __kernel_size_t, + name: *mut c_char [array], + date_len: __kernel_size_t, + date: *mut c_char [array], + desc_len: __kernel_size_t, + desc: *mut c_char [array], + } +} + +pub const GET_CAP: u64 = 0x0C; +pub use drm_sys::DRM_CAP_DUMB_BUFFER; +define_ioctl_data! { + struct drm_get_cap, DrmGetCap { + capability: u64, + value: u64, + } +} + +pub const SET_CLIENT_CAP: u64 = 0x0D; +pub use drm_sys::DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT; +define_ioctl_data! { + struct drm_set_client_cap, DrmSetClientCap { + capability: u64, + value: u64, + } +} + +pub const MODE_CARD_RES: u64 = 0xA0; +define_ioctl_data! { + struct drm_mode_card_res, DrmModeCardRes { + fb_id_ptr: u64 [array], + crtc_id_ptr: u64 [array], + connector_id_ptr: u64 [array], + encoder_id_ptr: u64 [array], + count_fbs: u32, + count_crtcs: u32, + count_connectors: u32, + count_encoders: u32, + min_width: u32, + max_width: u32, + min_height: u32, + max_height: u32, + } +} + +pub const MODE_GET_CRTC: u64 = 0xA1; +define_ioctl_data! { + struct drm_mode_crtc, DrmModeCrtc { + set_connectors_ptr: u64, + count_connectors: u32, + crtc_id: u32, + fb_id: u32, + x: u32, + y: u32, + gamma_size: u32, + mode_valid: u32, + mode: drm_mode_modeinfo, + } +} + +pub const MODE_GET_ENCODER: u64 = 0xA6; +define_ioctl_data! { + struct drm_mode_get_encoder, DrmModeGetEncoder { + encoder_id: u32, + encoder_type: u32, + crtc_id: u32, + possible_crtcs: u32, + possible_clones: u32, + } +} + +pub const MODE_GET_CONNECTOR: u64 = 0xA7; +define_ioctl_data! { + struct drm_mode_get_connector, DrmModeGetConnector { + encoders_ptr: u64 [array], + modes_ptr: u64 [array], + props_ptr: u64 [array], + prop_values_ptr: u64 [array], + count_modes: u32, + count_props: u32, + count_encoders: u32, + encoder_id: u32, + connector_id: u32, + connector_type: u32, + connector_type_id: u32, + connection: u32, + mm_width: u32, + mm_height: u32, + subpixel: u32, + pad: u32, + } +} + +pub const MODE_GET_FB: u64 = 0xAD; +define_ioctl_data! { + struct drm_mode_fb_cmd, DrmModeFbCmd { + fb_id: u32, + width: u32, + height: u32, + pitch: u32, + bpp: u32, + depth: u32, + handle: u32, + } +} + +pub const MODE_GET_PLANE_RES: u64 = 0xB5; +define_ioctl_data! { + struct drm_mode_get_plane_res, DrmModeGetPlaneRes { + plane_id_ptr: u64 [array], + count_planes: u32, + } +} + +pub const MODE_GET_PLANE: u64 = 0xB6; +define_ioctl_data! { + struct drm_mode_get_plane, DrmModeGetPlane { + plane_id: u32, + crtc_id: u32, + fb_id: u32, + possible_crtcs: u32, + gamma_size: u32, + count_format_types: u32, + format_type_ptr: u64 [array], + } +} + +pub const MODE_OBJ_GET_PROPERTIES: u64 = 0xB9; +define_ioctl_data! { + struct drm_mode_obj_get_properties, DrmModeObjGetProperties { + props_ptr: u64 [array], + prop_values_ptr: u64 [array], + count_props: u32, + obj_id: u32, + obj_type: u32, + } +} + +pub const MODE_GET_FB2: u64 = 0xCE; +define_ioctl_data! { + struct drm_mode_fb_cmd2, DrmModeFbCmd2 { + fb_id: u32, + width: u32, + height: u32, + pixel_format: u32, + flags: u32, + handles: [u32; 4], + pitches: [u32; 4], + offsets: [u32; 4], + modifier: [u64; 4], + } +} diff --git a/redox-ioctl/src/ioctl_data.rs b/redox-ioctl/src/ioctl_data.rs new file mode 100644 index 0000000000..f9673f6d7d --- /dev/null +++ b/redox-ioctl/src/ioctl_data.rs @@ -0,0 +1,169 @@ +use alloc::vec::Vec; + +pub trait IoctlData { + unsafe fn write(&self) -> Vec; + unsafe fn read_from(&mut self, buf: &[u8]); +} + +macro_rules! define_ioctl_data { + (struct $ioctl_ty:ident, $mem_ty:ident { + $($rest:tt)* + }) => { + define_ioctl_data!( + struct $ioctl_ty, $mem_ty { $($rest)* } => (), (), () + ); + }; + (struct $ioctl_ty:ident, $mem_ty:ident { + $field:ident: $ty:ty, + $($rest:tt)* + } => + ($($ioctl_fields:tt)*), + ($($counted_fields:tt)*), + ($($noncounted_fields:tt)*) + ) => { + define_ioctl_data!( + struct $ioctl_ty, $mem_ty { $($rest)* } => + ($($ioctl_fields)* $field: $ty,), + ($($counted_fields)*), + ($($noncounted_fields)* $field: $ty,) + ); + }; + (struct $ioctl_ty:ident, $mem_ty:ident { + $field:ident: $ty:ty [array<$el:ty, $counted_by:ident>], + $($rest:tt)* + } => + ($($ioctl_fields:tt)*), + ($($counted_fields:tt)*), + ($($noncounted_fields:tt)*) + ) => { + define_ioctl_data!( + struct $ioctl_ty, $mem_ty { $($rest)* } => + ($($ioctl_fields)* $field: $ty,), + ($($counted_fields)* $field: $ty [array<$el, $counted_by>],), + ($($noncounted_fields)*) + ); + }; + (struct $ioctl_ty:ident, $mem_ty:ident {} => + ($($ioctl_field:ident: $ioctl_field_ty:ty,)*), + ($($counted_field:ident: $counted_ty:ty [array<$el:ty, $counted_by:ident>],)*), + ($($noncounted_field:ident: $noncounted_ty:ty,)*) + ) => { + // FIXME check ioctl_ty doesn't have padding + const _: $ioctl_ty = $ioctl_ty { + $($ioctl_field: unsafe { mem::zeroed::<$ioctl_field_ty>() },)* + }; + + #[repr(C)] + pub struct ${concat(__, $mem_ty, Noncounted)} { + $($noncounted_field: $noncounted_ty,)* + } + + pub struct $mem_ty<'a> { + noncounted_fields: &'a mut ${concat(__, $mem_ty, Noncounted)}, + $($counted_field: &'a mut [$el],)* + } + + impl $crate::ioctl_data::IoctlData for $ioctl_ty { + unsafe fn write(&self) -> Vec { + let noncounted_fields = ${concat(__, $mem_ty, Noncounted)} { + $($noncounted_field: self.$noncounted_field,)* + }; + // FIXME use Vec::with_capacity + let mut data = Vec::::new(); + data.extend_from_slice(&unsafe { + mem::transmute::< + ${concat(__, $mem_ty, Noncounted)}, + [u8; size_of::<${concat(__, $mem_ty, Noncounted)}>()], + >(noncounted_fields) + }); + $( + let size = self.$counted_by as usize * size_of::<$el>(); + if self.$counted_field as usize != 0 { + let $counted_field = unsafe { + slice::from_raw_parts(self.$counted_field as *const u8, size) + }; + data.extend_from_slice(&$counted_field); + } else { + data.extend(iter::repeat(0u8).take(size)); + }; + + )* + data + } + + unsafe fn read_from(&mut self, mut buf: &[u8]) { + // FIXME be robust against malicious scheme implementations by returning an error + // when the buf is the wrong size + let noncounted_fields = buf.split_off(..size_of::<${concat(__, $mem_ty, Noncounted)}>()).unwrap(); + + $( + let size = self.$counted_by as usize * size_of::<$el>(); + let $counted_field = buf.split_off(..size).unwrap(); + if self.$counted_field as usize != 0 { + unsafe { + slice::from_raw_parts_mut(self.$counted_field as *mut u8, size).copy_from_slice($counted_field); + } + } + )* + + assert!(buf.is_empty()); + + let noncounted_fields = unsafe { &*(noncounted_fields as *const _ as *const ${concat(__, $mem_ty, Noncounted)}) }; + $(self.$noncounted_field = noncounted_fields.$noncounted_field;)* + } + } + + impl<'a> $mem_ty<'a> { + pub fn with( + mut buf: &'a mut [u8], + f: impl FnOnce($mem_ty<'a>) -> syscall::Result, + ) -> syscall::Result { + let noncounted_fields = buf.split_off_mut(..size_of::<${concat(__, $mem_ty, Noncounted)}>()) + .ok_or(syscall::Error::new(syscall::EINVAL))?; + let noncounted_fields = unsafe { &mut *(noncounted_fields as *mut _ as *mut ${concat(__, $mem_ty, Noncounted)}) }; + + $( + let $counted_field = buf.split_off_mut(..noncounted_fields.$counted_by as usize * size_of::<$el>()) + .ok_or(syscall::Error::new(syscall::EINVAL))?; + let $counted_field = unsafe { + slice::from_raw_parts_mut($counted_field as *mut _ as *mut $el, noncounted_fields.$counted_by as usize) + }; + )* + + if !buf.is_empty() { + return Err(syscall::Error::new(syscall::EINVAL)); + } + + + + Ok( f($mem_ty { + noncounted_fields, + $($counted_field,)* + })?) + } + + $( + pub fn $noncounted_field(&self) -> $noncounted_ty { + self.noncounted_fields.$noncounted_field + } + + /// Should not be called for fields used as array length + pub fn ${concat(set_, $noncounted_field)}(&mut self, data: $noncounted_ty) { + self.noncounted_fields.$noncounted_field = data; + } + )* + + $( + pub fn $counted_field(&self) -> &[$el] { + self.$counted_field + } + + pub fn ${concat(set_, $counted_field)}(&mut self, data: &[$el]) { + let copied_count = cmp::min(data.len(), self.$counted_field.len()); + self.$counted_field[..copied_count].copy_from_slice(&data[..copied_count]); + self.noncounted_fields.$counted_by = data.len() as _; + } + )* + } + }; +} diff --git a/redox-ioctl/src/lib.rs b/redox-ioctl/src/lib.rs new file mode 100644 index 0000000000..2405f5eeb2 --- /dev/null +++ b/redox-ioctl/src/lib.rs @@ -0,0 +1,10 @@ +#![feature(macro_metavar_expr_concat)] +#![no_std] + +extern crate alloc; + +#[macro_use] +mod ioctl_data; +pub use ioctl_data::IoctlData; + +pub mod drm; diff --git a/src/header/sys_ioctl/redox/drm.rs b/src/header/sys_ioctl/redox/drm.rs index 01b0d5afbf..a0692bdd95 100644 --- a/src/header/sys_ioctl/redox/drm.rs +++ b/src/header/sys_ioctl/redox/drm.rs @@ -1,10 +1,6 @@ -use alloc::vec::Vec; -use core::{mem, slice}; -use drm_sys::{ - drm_get_cap, drm_mode_card_res, drm_mode_crtc, drm_mode_fb_cmd, drm_mode_fb_cmd2, - drm_mode_get_connector, drm_mode_get_encoder, drm_mode_get_plane, drm_mode_get_plane_res, - drm_mode_obj_get_properties, drm_set_client_cap, drm_version, -}; +use core::slice; + +use redox_ioctl::{IoctlData, drm::*}; use crate::{ error::{Errno, Result}, @@ -12,7 +8,7 @@ use crate::{ platform::types::*, }; -use super::{IoctlBuffer, graphics_ipc as ipc, graphics_ipc::IoctlData}; +use super::IoctlBuffer; const DRM_FORMAT_ARGB8888: u32 = 0x34325241; // 'AR24' fourcc code, for ARGB8888 @@ -61,7 +57,7 @@ impl Dev { } unsafe fn call(&self, payload: &mut T, func: u64) -> syscall::Result { - let bytes = slice::from_raw_parts_mut(payload as *mut T as *mut u8, mem::size_of::()); + let bytes = slice::from_raw_parts_mut(payload as *mut T as *mut u8, size_of::()); redox_rt::sys::sys_call( self.fd as usize, bytes, @@ -70,7 +66,7 @@ impl Dev { ) } - unsafe fn read_write_ioctl( + unsafe fn read_write_ioctl( &self, mut buf: IoctlBuffer, func: u64, @@ -88,11 +84,7 @@ impl Dev { Ok(res as c_int) } - unsafe fn write_ioctl( - &self, - mut buf: IoctlBuffer, - func: u64, - ) -> Result { + unsafe fn write_ioctl(&self, mut buf: IoctlBuffer, func: u64) -> Result { let mut data = buf.read::()?; let mut wire = data.write(); let res = redox_rt::sys::sys_call( @@ -103,45 +95,23 @@ impl Dev { )?; Ok(res as c_int) } - - fn display_count(&self) -> Result { - let mut cmd = ipc::DisplayCount { count: 0 }; - unsafe { - self.call(&mut cmd, ipc::DISPLAY_COUNT)?; - } - Ok(cmd.count) - } - - fn display_size(&self, display_id: usize) -> Result<(u32, u32)> { - let mut cmd = ipc::DisplaySize { - display_id, - width: 0, - height: 0, - }; - unsafe { - self.call(&mut cmd, ipc::DISPLAY_SIZE)?; - } - Ok((cmd.width, cmd.height)) - } } pub(super) unsafe fn ioctl(fd: c_int, func: u8, buf: IoctlBuffer) -> Result { let dev = Dev::new(fd)?; match func { - 0x00 => dev.read_write_ioctl::(buf, ipc::VERSION), - 0x0C => dev.read_write_ioctl::(buf, ipc::GET_CAP), - 0x0D => dev.write_ioctl::(buf, ipc::SET_CLIENT_CAP), - 0xA0 => dev.read_write_ioctl::(buf, ipc::MODE_CARD_RES), - 0xA1 => dev.read_write_ioctl::(buf, ipc::MODE_GET_CRTC), - 0xA6 => dev.read_write_ioctl::(buf, ipc::MODE_GET_ENCODER), - 0xA7 => dev.read_write_ioctl::(buf, ipc::MODE_GET_CONNECTOR), - 0xAD => dev.read_write_ioctl::(buf, ipc::MODE_GET_FB), - 0xB5 => dev.read_write_ioctl::(buf, ipc::MODE_GET_PLANE_RES), - 0xB6 => dev.read_write_ioctl::(buf, ipc::MODE_GET_PLANE), - 0xB9 => { - dev.read_write_ioctl::(buf, ipc::MODE_OBJ_GET_PROPERTIES) - } - 0xCE => dev.read_write_ioctl::(buf, ipc::MODE_GET_FB2), + 0x00 => dev.read_write_ioctl::(buf, VERSION), + 0x0C => dev.read_write_ioctl::(buf, GET_CAP), + 0x0D => dev.write_ioctl::(buf, SET_CLIENT_CAP), + 0xA0 => dev.read_write_ioctl::(buf, MODE_CARD_RES), + 0xA1 => dev.read_write_ioctl::(buf, MODE_GET_CRTC), + 0xA6 => dev.read_write_ioctl::(buf, MODE_GET_ENCODER), + 0xA7 => dev.read_write_ioctl::(buf, MODE_GET_CONNECTOR), + 0xAD => dev.read_write_ioctl::(buf, MODE_GET_FB), + 0xB5 => dev.read_write_ioctl::(buf, MODE_GET_PLANE_RES), + 0xB6 => dev.read_write_ioctl::(buf, MODE_GET_PLANE), + 0xB9 => dev.read_write_ioctl::(buf, MODE_OBJ_GET_PROPERTIES), + 0xCE => dev.read_write_ioctl::(buf, MODE_GET_FB2), _ => { eprintln!("unimplemented DRM ioctl({}, 0x{:02x}, {:?})", fd, func, buf); Err(Errno(EINVAL)) diff --git a/src/header/sys_ioctl/redox/graphics_ipc.rs b/src/header/sys_ioctl/redox/graphics_ipc.rs deleted file mode 100644 index 86938a053d..0000000000 --- a/src/header/sys_ioctl/redox/graphics_ipc.rs +++ /dev/null @@ -1,392 +0,0 @@ -// Adapted from graphics-ipc v2 ipc module, cannot use as it needs libstd -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -pub struct Damage { - pub x: u32, - pub y: u32, - pub width: u32, - pub height: u32, -} - -use alloc::vec::Vec; -use core::{ - cmp, - ffi::{c_char, c_int}, - iter, mem, slice, -}; - -pub trait IoctlData { - unsafe fn write(&self) -> Vec; - unsafe fn read_from(&mut self, buf: &[u8]); -} - -macro_rules! define_ioctl_data { - (struct $ioctl_ty:ident, $mem_ty:ident { - $($rest:tt)* - }) => { - define_ioctl_data!( - struct $ioctl_ty, $mem_ty { $($rest)* } => (), (), () - ); - }; - (struct $ioctl_ty:ident, $mem_ty:ident { - $field:ident: $ty:ty, - $($rest:tt)* - } => - ($($ioctl_fields:tt)*), - ($($counted_fields:tt)*), - ($($noncounted_fields:tt)*) - ) => { - define_ioctl_data!( - struct $ioctl_ty, $mem_ty { $($rest)* } => - ($($ioctl_fields)* $field: $ty,), - ($($counted_fields)*), - ($($noncounted_fields)* $field: $ty,) - ); - }; - (struct $ioctl_ty:ident, $mem_ty:ident { - $field:ident: $ty:ty [array<$el:ty, $counted_by:ident>], - $($rest:tt)* - } => - ($($ioctl_fields:tt)*), - ($($counted_fields:tt)*), - ($($noncounted_fields:tt)*) - ) => { - define_ioctl_data!( - struct $ioctl_ty, $mem_ty { $($rest)* } => - ($($ioctl_fields)* $field: $ty,), - ($($counted_fields)* $field: $ty [array<$el, $counted_by>],), - ($($noncounted_fields)*) - ); - }; - (struct $ioctl_ty:ident, $mem_ty:ident {} => - ($($ioctl_field:ident: $ioctl_field_ty:ty,)*), - ($($counted_field:ident: $counted_ty:ty [array<$el:ty, $counted_by:ident>],)*), - ($($noncounted_field:ident: $noncounted_ty:ty,)*) - ) => { - pub use drm_sys::$ioctl_ty; - - // FIXME check ioctl_ty doesn't have padding - const _: $ioctl_ty = $ioctl_ty { - $($ioctl_field: unsafe { mem::zeroed::<$ioctl_field_ty>() },)* - }; - - #[repr(C)] - pub struct ${concat(__, $mem_ty, Noncounted)} { - $($noncounted_field: $noncounted_ty,)* - } - - pub struct $mem_ty<'a> { - noncounted_fields: &'a mut ${concat(__, $mem_ty, Noncounted)}, - $($counted_field: &'a mut [$el],)* - } - - impl IoctlData for $ioctl_ty { - unsafe fn write(&self) -> Vec { - let noncounted_fields = ${concat(__, $mem_ty, Noncounted)} { - $($noncounted_field: self.$noncounted_field,)* - }; - // FIXME use Vec::with_capacity - let mut data = Vec::::new(); - data.extend_from_slice(&unsafe { - mem::transmute::< - ${concat(__, $mem_ty, Noncounted)}, - [u8; size_of::<${concat(__, $mem_ty, Noncounted)}>()], - >(noncounted_fields) - }); - $( - let size = self.$counted_by as usize * size_of::<$el>(); - if self.$counted_field as usize != 0 { - let $counted_field = unsafe { - slice::from_raw_parts(self.$counted_field as *const u8, size) - }; - data.extend_from_slice(&$counted_field); - } else { - data.extend(iter::repeat(0u8).take(size)); - }; - - )* - data - } - - unsafe fn read_from(&mut self, mut buf: &[u8]) { - // FIXME be robust against malicious scheme implementations by returning an error - // when the buf is the wrong size - let noncounted_fields = buf.split_off(..size_of::<${concat(__, $mem_ty, Noncounted)}>()).unwrap(); - - $( - let size = self.$counted_by as usize * size_of::<$el>(); - let $counted_field = buf.split_off(..size).unwrap(); - if self.$counted_field as usize != 0 { - unsafe { - slice::from_raw_parts_mut(self.$counted_field as *mut u8, size).copy_from_slice($counted_field); - } - } - )* - - assert!(buf.is_empty()); - - let noncounted_fields = unsafe { &*(noncounted_fields as *const _ as *const ${concat(__, $mem_ty, Noncounted)}) }; - $(self.$noncounted_field = noncounted_fields.$noncounted_field;)* - } - } - - impl<'a> $mem_ty<'a> { - pub fn with( - mut buf: &'a mut [u8], - f: impl FnOnce($mem_ty<'a>) -> syscall::Result, - ) -> syscall::Result { - let noncounted_fields = buf.split_off_mut(..size_of::<${concat(__, $mem_ty, Noncounted)}>()) - .ok_or(syscall::Error::new(syscall::EINVAL))?; - let noncounted_fields = unsafe { &mut *(noncounted_fields as *mut _ as *mut ${concat(__, $mem_ty, Noncounted)}) }; - - $( - let $counted_field = buf.split_off_mut(..noncounted_fields.$counted_by as usize * size_of::<$el>()) - .ok_or(syscall::Error::new(syscall::EINVAL))?; - let $counted_field = unsafe { - slice::from_raw_parts_mut($counted_field as *mut _ as *mut $el, noncounted_fields.$counted_by as usize) - }; - )* - - if !buf.is_empty() { - return Err(syscall::Error::new(syscall::EINVAL)); - } - - - - Ok( f($mem_ty { - noncounted_fields, - $($counted_field,)* - })?) - } - - $( - pub fn $noncounted_field(&self) -> $noncounted_ty { - self.noncounted_fields.$noncounted_field - } - - /// Should not be called for fields used as array length - pub fn ${concat(set_, $noncounted_field)}(&mut self, data: $noncounted_ty) { - self.noncounted_fields.$noncounted_field = data; - } - )* - - $( - pub fn $counted_field(&self) -> &[$el] { - self.$counted_field - } - - pub fn ${concat(set_, $counted_field)}(&mut self, data: &[$el]) { - let copied_count = cmp::min(data.len(), self.$counted_field.len()); - self.$counted_field[..copied_count].copy_from_slice(&data[..copied_count]); - self.noncounted_fields.$counted_by = data.len() as _; - } - )* - } - }; - } - -pub const VERSION: u64 = 0; -define_ioctl_data! { - struct drm_version, DrmVersion { - version_major: c_int, - version_minor: c_int, - version_patchlevel: c_int, - name_len: drm_sys::__kernel_size_t, - name: *mut c_char [array], - date_len: drm_sys::__kernel_size_t, - date: *mut c_char [array], - desc_len: drm_sys::__kernel_size_t, - desc: *mut c_char [array], - } -} - -pub const GET_CAP: u64 = 0x0C; -pub use drm_sys::DRM_CAP_DUMB_BUFFER; -define_ioctl_data! { - struct drm_get_cap, DrmGetCap { - capability: u64, - value: u64, - } -} - -pub const SET_CLIENT_CAP: u64 = 0x0D; -pub use drm_sys::DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT; -define_ioctl_data! { - struct drm_set_client_cap, DrmSetClientCap { - capability: u64, - value: u64, - } -} - -pub const MODE_CARD_RES: u64 = 0xA0; -define_ioctl_data! { - struct drm_mode_card_res, DrmModeCardRes { - fb_id_ptr: u64 [array], - crtc_id_ptr: u64 [array], - connector_id_ptr: u64 [array], - encoder_id_ptr: u64 [array], - count_fbs: u32, - count_crtcs: u32, - count_connectors: u32, - count_encoders: u32, - min_width: u32, - max_width: u32, - min_height: u32, - max_height: u32, - } -} - -pub const MODE_GET_CRTC: u64 = 0xA1; -define_ioctl_data! { - struct drm_mode_crtc, DrmModeCrtc { - set_connectors_ptr: u64, - count_connectors: u32, - crtc_id: u32, - fb_id: u32, - x: u32, - y: u32, - gamma_size: u32, - mode_valid: u32, - mode: drm_sys::drm_mode_modeinfo, - } -} - -pub const MODE_GET_ENCODER: u64 = 0xA6; -define_ioctl_data! { - struct drm_mode_get_encoder, DrmModeGetEncoder { - encoder_id: u32, - encoder_type: u32, - crtc_id: u32, - possible_crtcs: u32, - possible_clones: u32, - } -} - -pub const MODE_GET_CONNECTOR: u64 = 0xA7; -define_ioctl_data! { - struct drm_mode_get_connector, DrmModeGetConnector { - encoders_ptr: u64 [array], - modes_ptr: u64 [array], - props_ptr: u64 [array], - prop_values_ptr: u64 [array], - count_modes: u32, - count_props: u32, - count_encoders: u32, - encoder_id: u32, - connector_id: u32, - connector_type: u32, - connector_type_id: u32, - connection: u32, - mm_width: u32, - mm_height: u32, - subpixel: u32, - pad: u32, - } -} - -pub const MODE_GET_FB: u64 = 0xAD; -define_ioctl_data! { - struct drm_mode_fb_cmd, DrmModeFbCmd { - fb_id: u32, - width: u32, - height: u32, - pitch: u32, - bpp: u32, - depth: u32, - handle: u32, - } -} - -pub const MODE_GET_PLANE_RES: u64 = 0xB5; -define_ioctl_data! { - struct drm_mode_get_plane_res, DrmModeGetPlaneRes { - plane_id_ptr: u64 [array], - count_planes: u32, - } -} - -pub const MODE_GET_PLANE: u64 = 0xB6; -define_ioctl_data! { - struct drm_mode_get_plane, DrmModeGetPlane { - plane_id: u32, - crtc_id: u32, - fb_id: u32, - possible_crtcs: u32, - gamma_size: u32, - count_format_types: u32, - format_type_ptr: u64 [array], - } -} - -pub const MODE_OBJ_GET_PROPERTIES: u64 = 0xB9; -define_ioctl_data! { - struct drm_mode_obj_get_properties, DrmModeObjGetProperties { - props_ptr: u64 [array], - prop_values_ptr: u64 [array], - count_props: u32, - obj_id: u32, - obj_type: u32, - } -} - -pub const MODE_GET_FB2: u64 = 0xCE; -define_ioctl_data! { - struct drm_mode_fb_cmd2, DrmModeFbCmd2 { - fb_id: u32, - width: u32, - height: u32, - pixel_format: u32, - flags: u32, - handles: [u32; 4], - pitches: [u32; 4], - offsets: [u32; 4], - modifier: [u64; 4], - } -} - -// FIXME replace these with proper drm interfaces -pub const DISPLAY_COUNT: u64 = 1; -#[repr(C, packed)] -pub struct DisplayCount { - pub count: usize, -} - -pub const DISPLAY_SIZE: u64 = 2; -#[repr(C, packed)] -pub struct DisplaySize { - pub display_id: usize, - - pub width: u32, - pub height: u32, -} - -pub const CREATE_DUMB_FRAMEBUFFER: u64 = 3; -#[repr(C, packed)] -pub struct CreateDumbFramebuffer { - pub width: u32, - pub height: u32, - - pub fb_id: usize, -} - -pub const DUMB_FRAMEBUFFER_MAP_OFFSET: u64 = 4; -#[repr(C, packed)] -pub struct DumbFramebufferMapOffset { - pub fb_id: usize, - - pub offset: usize, -} - -pub const DESTROY_DUMB_FRAMEBUFFER: u64 = 5; -#[repr(C, packed)] -pub struct DestroyDumbFramebuffer { - pub fb_id: usize, -} - -pub const UPDATE_PLANE: u64 = 6; -#[repr(C, packed)] -pub struct UpdatePlane { - pub display_id: usize, - pub fb_id: usize, - pub damage: Damage, -} diff --git a/src/header/sys_ioctl/redox/mod.rs b/src/header/sys_ioctl/redox/mod.rs index 2914769366..c859e6193c 100644 --- a/src/header/sys_ioctl/redox/mod.rs +++ b/src/header/sys_ioctl/redox/mod.rs @@ -14,7 +14,6 @@ use crate::{ use super::winsize; mod drm; -mod graphics_ipc; pub const TCGETS: c_ulong = 0x5401; pub const TCSETS: c_ulong = 0x5402; diff --git a/src/lib.rs b/src/lib.rs index e74975e661..3ea46c6a6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,6 @@ #![feature(c_variadic)] #![feature(core_intrinsics)] #![feature(macro_derive)] -#![feature(macro_metavar_expr_concat)] #![feature(maybe_uninit_slice)] #![feature(lang_items)] #![feature(linkage)]