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)]