Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • lyudess/linux
1 result
Show changes
Commits on Source (36)
......@@ -22,7 +22,6 @@ use kernel::{
ModeConfigInfo,
UnregisteredKmsDevice,
atomic::*,
fbdev::*,
},
},
platform,
......@@ -73,8 +72,6 @@ impl drv::Driver for RvkmsDriver {
#[vtable]
impl KmsDriver for RvkmsDriver {
type Fbdev = FbdevShmem<Self>;
fn mode_config_info(
_dev: &device::Device,
_drm_data: <Self::Data as kernel::types::ForeignOwnable>::Borrowed<'_>,
......
use bindings;
use core::{ops::*, slice, ptr};
/// Return a fourcc format code
const fn fourcc_code(a: u8, b: u8, c: u8, d: u8) -> u32 {
(a as u32) | (b as u32) << 8 | (c as u32) << 16 | (d as u32) << 24
}
// TODO: We manually import this because we don't have a reasonable way of getting constants from
// function-like macros in bindgen yet.
pub(crate) const FORMAT_MOD_INVALID: u64 = 0xffffffffffffff;
// TODO: Figure out a more automated way of importing this
pub const XRGB888: u32 = fourcc_code(b'X', b'R', b'2', b'4');
#[derive(Copy, Clone)]
#[repr(C)]
pub struct FormatList<const COUNT: usize> {
list: [u32; COUNT],
_sentinel: u32,
}
impl<const COUNT: usize> FormatList<COUNT> {
/// Create a new [`FormatList`]
pub const fn new(list: [u32; COUNT]) -> Self {
Self {
list,
_sentinel: 0
}
}
/// Returns the number of entries in the list, including the sentinel.
///
/// This is generally only useful for passing [`FormatList`] to C bindings.
pub const fn raw_len(&self) -> usize {
COUNT + 1
}
}
impl<const COUNT: usize> Deref for FormatList<COUNT> {
type Target = [u32; COUNT];
fn deref(&self) -> &Self::Target {
&self.list
}
}
impl<const COUNT: usize> DerefMut for FormatList<COUNT> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.list
}
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct ModifierList<const COUNT: usize> {
list: [u64; COUNT],
_sentinel: u64
}
impl<const COUNT: usize> ModifierList<COUNT> {
/// Create a new [`ModifierList`]
pub const fn new(list: [u64; COUNT]) -> Self {
Self {
list,
_sentinel: 0
}
}
}
impl<const COUNT: usize> Deref for ModifierList<COUNT> {
type Target = [u64; COUNT];
fn deref(&self) -> &Self::Target {
&self.list
}
}
impl<const COUNT: usize> DerefMut for ModifierList<COUNT> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.list
}
}
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct FormatInfo {
......
......@@ -69,6 +69,57 @@ pub(crate) mod private {
}
}
/// Implement the repetitive from_opaque/try_from_opaque methods for a mode object
macro_rules! impl_from_opaque_mode_obj {
($full:ident, $drv_trait:ident, $inner:ident, $opaque:ident) => {
#[doc = concat!("Convert a [`", stringify!($opaque), "`] into a fully qualfied ",
"[`", stringify!($full), "`].")]
#[doc = ""]
#[doc = concat!("This checks if the given [`", stringify!($opaque), "`] uses the same ",
"[`", stringify!($drv_trait), "`] implementation, and returns the ",
"[`", stringify!($opaque), "`] as a [`", stringify!($full), "`] if ",
"so.")]
pub fn try_from_opaque<'a, D>(opaque: &'a $opaque<D>) -> Option<&'a $full<T>>
where
D: KmsDriver,
T: $drv_trait<Driver = D>
{
// SAFETY: The vtables for a modesetting object are initialized throughout the
// lifetime of the object.
let funcs = unsafe { (*opaque.$inner.get()).funcs };
// SAFETY: We only perform this transmutation if the opaque object shares our vtable
// pointers, so the underlying full object must share our data layout.
core::ptr::eq(funcs, &T::OPS.funcs).then(|| unsafe { core::mem::transmute(opaque) })
}
#[doc = concat!("Convert a [`", stringify!($opaque), "`] into its fully qualified [`",
stringify!($full), "`].")]
#[doc = ""]
#[doc = concat!("This is an infallible version of [`", stringify!($full),
"::try_from_opaque`]. This function is mainly useful for drivers ",
"where only a single [`", stringify!($drv_trait), "`] implementation ",
"exists.")]
#[doc = ""]
#[doc = "# Panics"]
#[doc = ""]
#[doc = concat!("This function will panic if the underlying [`", stringify!($full),
"`] in the provided [`", stringify!($opaque), "`] does not belong to ",
"the same [`", stringify!($drv_trait), "`] implementation.")]
pub fn from_opaque<'a, D>(opaque: &'a $opaque<D>) -> &'a $full<T>
where
D: KmsDriver,
T: $drv_trait<Driver = D>
{
Self::try_from_opaque(opaque)
.expect(concat!("Passed ", stringify!($opaque), " does not share this ",
stringify!($drv_trait), " implementation."))
}
};
}
pub(crate) use impl_from_opaque_mode_obj;
/// A [`Device`] with KMS initialized that has not been registered with userspace.
///
/// This type is identical to [`Device`], except that it is able to create new static KMS resources.
......
......@@ -173,7 +173,7 @@ impl<T: KmsDriver> AtomicStateMutator<T> {
self.state.as_raw()
}
/// Return the [`Device`] for this [`AtomicStateMutator`]
/// Return the [`Device`] for this [`AtomicStateMutator`].
pub fn drm_dev(&self) -> &Device<T> {
self.state.drm_dev()
}
......@@ -214,8 +214,8 @@ impl<T: KmsDriver> AtomicStateMutator<T> {
/// Return a composer for `plane`s new atomic state if it was previously added to the atomic
/// state being composed.
///
/// Returns `None` otherwise, or if a composer still exists for this state.
pub fn get_new_crtc_state<C>(&self, crtc: &C) -> Option<BorrowedCrtcState<'_, C::State>>
/// Returns `None` otherwise, or if another mutator still exists for this state.
pub fn get_new_crtc_state<C>(&self, crtc: &C) -> Option<CrtcStateMutator<'_, C::State>>
where
C: AsRawCrtc<Driver = T>
{
......@@ -224,14 +224,14 @@ impl<T: KmsDriver> AtomicStateMutator<T> {
bindings::drm_atomic_get_new_crtc_state(self.as_raw(), crtc.as_raw())
};
BorrowedCrtcState::<C::State>::new(self, NonNull::new(state)?)
CrtcStateMutator::<C::State>::new(self, NonNull::new(state)?)
}
/// Return a composer for `plane`s new atomic state if it was previously added to the atomic
/// state being composed.
///
/// Returns `None` otherwise, or if a composer still exists for this state.
pub fn get_new_plane_state<P>(&self, plane: &P) -> Option<BorrowedPlaneState<'_, P::State>>
/// Returns `None` otherwise, or if another mutator still exists for this state.
pub fn get_new_plane_state<P>(&self, plane: &P) -> Option<PlaneStateMutator<'_, P::State>>
where
P: AsRawPlane<Driver = T>,
{
......@@ -240,17 +240,17 @@ impl<T: KmsDriver> AtomicStateMutator<T> {
bindings::drm_atomic_get_new_plane_state(self.as_raw(), plane.as_raw())
};
BorrowedPlaneState::<P::State>::new(self, NonNull::new(state)?)
PlaneStateMutator::<P::State>::new(self, NonNull::new(state)?)
}
/// Return a composer for `crtc`s new atomic state if it was previously added to the atomic
/// state being composed.
///
/// Returns `None` otherwise, or if a composer still exists for this state.
/// Returns `None` otherwise, or if another mutator still exists for this state.
pub fn get_new_connector_state<C>(
&self,
connector: &C
) -> Option<BorrowedConnectorState<'_, C::State>>
) -> Option<ConnectorStateMutator<'_, C::State>>
where
C: AsRawConnector<Driver = T>,
{
......@@ -259,7 +259,7 @@ impl<T: KmsDriver> AtomicStateMutator<T> {
bindings::drm_atomic_get_new_connector_state(self.as_raw(), connector.as_raw())
};
BorrowedConnectorState::<C::State>::new(self, NonNull::new(state)?)
ConnectorStateMutator::<C::State>::new(self, NonNull::new(state)?)
}
/// Iterate through each of the planes (regardless of type) currently in this atomic state.
......@@ -304,7 +304,7 @@ impl<T: KmsDriver> AtomicStateComposer<T> {
///
/// If a composer already exists for this `crtc`, this function returns `Error(EBUSY)`. If
/// attempting to add the state fails, another error code will be returned.
pub fn add_crtc_state<C>(&self, crtc: &C) -> Result<BorrowedCrtcState<'_, C::State>>
pub fn add_crtc_state<C>(&self, crtc: &C) -> Result<CrtcStateMutator<'_, C::State>>
where
C: AsRawCrtc<Driver = T>
{
......@@ -315,7 +315,7 @@ impl<T: KmsDriver> AtomicStateComposer<T> {
).map(|c| NonNull::new_unchecked(c))
}?;
BorrowedCrtcState::<C::State>::new(self, state).ok_or(EBUSY)
CrtcStateMutator::<C::State>::new(self, state).ok_or(EBUSY)
}
/// Attempt to add the state for `plane` to the atomic state for this composer if it hasn't
......@@ -323,7 +323,7 @@ impl<T: KmsDriver> AtomicStateComposer<T> {
///
/// If a composer already exists for this `plane`, this function returns `Error(EBUSY)`. If
/// attempting to add the state fails, another error code will be returned.
pub fn add_plane_state<P>(&self, plane: &P) -> Result<BorrowedPlaneState<'_, P::State>>
pub fn add_plane_state<P>(&self, plane: &P) -> Result<PlaneStateMutator<'_, P::State>>
where
P: AsRawPlane<Driver = T>,
{
......@@ -334,7 +334,7 @@ impl<T: KmsDriver> AtomicStateComposer<T> {
).map(|p| NonNull::new_unchecked(p))
}?;
BorrowedPlaneState::<P::State>::new(self, state).ok_or(EBUSY)
PlaneStateMutator::<P::State>::new(self, state).ok_or(EBUSY)
}
/// Attempt to add the state for `connector` to the atomic state for this composer if it hasn't
......@@ -345,7 +345,7 @@ impl<T: KmsDriver> AtomicStateComposer<T> {
pub fn add_connector_state<C>(
&self,
connector: &C
) -> Result<BorrowedConnectorState<'_, C::State>>
) -> Result<ConnectorStateMutator<'_, C::State>>
where
C: AsRawConnector<Driver = T>,
{
......@@ -356,7 +356,7 @@ impl<T: KmsDriver> AtomicStateComposer<T> {
).map(|c| NonNull::new_unchecked(c))
}?;
BorrowedConnectorState::<C::State>::new(self, state).ok_or(EBUSY)
ConnectorStateMutator::<C::State>::new(self, state).ok_or(EBUSY)
}
/// Attempt to add any planes affected by changes on `crtc` to this [`AtomicStateComposer`].
......
// SPDX-License-Identifier: GPL-2.0 OR MIT
//! Rust bindings for DRM connectors
//! Bindings for [`struct drm_connector`] and friends.
//!
//! [`struct drm_connector`]: srctree/include/drm/drm_connector.h
use crate::{
bindings,
sync::ArcBorrow,
drm::{
drv::{Driver, FEAT_MODESET},
kms::UnregisteredKmsDevice,
device::Device,
},
types::{AlwaysRefCounted, Opaque, ARef},
......@@ -197,12 +200,9 @@ impl<T: DriverConnector> Connector<T> {
///
/// A driver may use this to create new [`Connector`] objects.
///
/// TODO: Add a way to handle creating connectors after device registration. Also, that's why we
/// don't ask for a UnregisteredKms device here.
///
/// [`KmsDriver::create_objects`]: kernel::drm::kms::KmsDriver::create_objects
pub fn new(
dev: &Device<T::Driver>,
dev: &UnregisteredKmsDevice<T::Driver>,
type_: u32,
args: T::Args,
) -> Result<ARef<Self>> {
......@@ -218,7 +218,9 @@ impl<T: DriverConnector> Connector<T> {
GFP_KERNEL
)?;
// SAFETY: FFI call with no special safety requirements
// SAFETY:
// - We just allocated `new` above
// - `new` starts with `drm_connector` via its type invariants.
to_result(unsafe {
bindings::drm_connector_init(
dev.as_raw(),
......@@ -238,6 +240,8 @@ impl<T: DriverConnector> Connector<T> {
})
}
super::impl_from_opaque_mode_obj!(Connector, DriverConnector, connector, OpaqueConnector);
/// Acquire a [`ConnectorGuard`] for this connector from a [`ModeConfigGuard`].
///
/// This verifies using the provided reference that the given guard is actually for the same
......@@ -277,11 +281,6 @@ impl<T: DriverConnector> Connector<T> {
/// [`as_raw()`]: AsRawConnector::as_raw()
/// [`struct drm_connector`]: srctree/include/drm/drm_connector.h
pub unsafe trait AsRawConnector: RcModeObject {
/// The parent [`Driver`] for this [`Connector`] interface
///
/// TODO: get rid of this
type Driver: KmsDriver;
/// The type this connector interface returns for its atomic state
type State: FromRawConnectorState;
......@@ -331,7 +330,6 @@ unsafe impl<T: DriverConnector> RcModeObject for Connector<T> {}
// * Since we don't expose `Connector` to users before it has been initialized, this and our data
// layout ensure that `as_raw()` always returns a valid pointer to a `drm_connector`.
unsafe impl<T: DriverConnector> AsRawConnector for Connector<T> {
type Driver = T::Driver;
type State = ConnectorState<T::State>;
fn as_raw(&self) -> *mut bindings::drm_connector {
......@@ -420,7 +418,6 @@ impl<T: KmsDriver> Sealed for OpaqueConnector<T> {}
// * Since we don't expose `OpaqueConnector` to users before it has been initialized, this and our
// data layout ensure that `as_raw()` always returns a valid pointer to a `drm_connector`.
unsafe impl<T: KmsDriver> AsRawConnector for OpaqueConnector<T> {
type Driver = T;
type State = OpaqueConnectorState<T>;
fn as_raw(&self) -> *mut bindings::drm_connector {
......@@ -542,22 +539,24 @@ pub(super) use private::AsRawConnectorState as AsRawConnectorStatePrivate;
/// [`struct drm_connector_state`]: srctree/include/drm/drm_connector.h
pub trait FromRawConnectorState: AsRawConnectorState {
/// Get an immutable reference to this type from the given raw [`struct drm_connector_state`]
/// pointer
/// pointer.
///
/// # Safety
///
/// The caller guarantees `ptr` is contained within a valid instance of `Self`
/// - The caller guarantees `ptr` is contained within a valid instance of `Self`.
/// - The caller guarantees that `ptr` cannot not be modified for the lifetime of `'a`.
///
/// [`struct drm_connector_state`]: srctree/include/drm/drm_connector.h
unsafe fn from_raw<'a>(ptr: *const bindings::drm_connector_state) -> &'a Self;
/// Get a mutable reference to this type from the given raw [`struct drm_connector_state`]
/// pointer
/// pointer.
///
/// # Safety
///
/// The caller guarantees `ptr` is contained within a valid instance of `Self`, and that no
/// other references (mutable or immutable) to `ptr` exist.
/// - The caller guarantees that `ptr` is contained within a valid instance of `Self`.
/// - The caller guarantees that `ptr` cannot have any other references taken out for the
/// lifetime of `'a`.
///
/// [`struct drm_connector_state`]: srctree/include/drm/drm_connector.h
unsafe fn from_raw_mut<'a>(ptr: *mut bindings::drm_connector_state) -> &'a mut Self;
......@@ -638,13 +637,25 @@ impl<T: DriverConnectorState> private::AsRawConnectorState for ConnectorState<T>
impl<T: DriverConnectorState> FromRawConnectorState for ConnectorState<T> {
unsafe fn from_raw<'a>(ptr: *const bindings::drm_connector_state) -> &'a Self {
// SAFETY: Our data layout starts with `bindings::drm_connector_state`
unsafe { &*ptr.cast() }
// Our data layout starts with `bindings::drm_connector_state`.
let ptr: *const Self = ptr.cast();
// SAFETY:
// - Our safety contract requires that `ptr` be contained within `Self`.
// - Our safety contract requires the caller ensure that it is safe for us to take an
// immutable reference.
unsafe { &*ptr }
}
unsafe fn from_raw_mut<'a>(ptr: *mut bindings::drm_connector_state) -> &'a mut Self {
// SAFETY: Our data layout starts with `bindings::drm_connector_state`
unsafe { &mut *ptr.cast() }
// Our data layout starts with `bindings::drm_connector_state`.
let ptr: *mut Self = ptr.cast();
// SAFETY:
// - Our safety contract requires that `ptr` be contained within `Self`.
// - Our safety contract requires the caller ensure it is safe for us to take a mutable
// reference.
unsafe { &mut *ptr }
}
}
......@@ -702,20 +713,21 @@ impl<T: KmsDriver> FromRawConnectorState for OpaqueConnectorState<T> {
///
/// This type is typically returned by an [`AtomicStateMutator`] within contexts where it is
/// possible to safely mutate a connector's state. In order to uphold rust's data-aliasing rules,
/// only [`BorrowedConnectorState`] may exist at a time.
pub struct BorrowedConnectorState<'a, T: FromRawConnectorState> {
/// only [`ConnectorStateMutator`] may exist at a time.
pub struct ConnectorStateMutator<'a, T: FromRawConnectorState> {
state: &'a mut T,
mask: &'a Cell<u32>
}
impl<'a, T: FromRawConnectorState> BorrowedConnectorState<'a, T> {
impl<'a, T: FromRawConnectorState> ConnectorStateMutator<'a, T> {
pub(super) fn new<D: KmsDriver>(
mutator: &'a AtomicStateMutator<D>,
state: NonNull<bindings::drm_connector_state>
) -> Option<Self> {
// SAFETY: `connector` is invariant throughout the lifetime of the atomic state, is
// initialized by this point, and we're guaranteed it is of type `OpaqueConnector<T>` by
// type invariance
// SAFETY:
// - `connector` is invariant throughout the lifetime of the atomic state.
// - `state` is initialized by the time it is passed to this function.
// - We're guaranteed that `state` is compatible with `drm_connector` by type invariants.
let connector = unsafe { T::Connector::from_raw((*state.as_ptr()).connector) };
let conn_mask = connector.mask();
let borrowed_mask = mutator.borrowed_connectors.get();
......@@ -724,19 +736,18 @@ impl<'a, T: FromRawConnectorState> BorrowedConnectorState<'a, T> {
mutator.borrowed_connectors.set(borrowed_mask | conn_mask);
Some(Self {
mask: &mutator.borrowed_connectors,
// SAFETY: We're guaranteed `state` is of `ConnectorState<T>` by type invariance,
// and we just confirmed by checking `borrowed_connectors` that no other mutable
// borrows have been taken out for `state`
// SAFETY: We're guaranteed `state` is of `T` by type invariance, and we just
// confirmed by checking `borrowed_connectors` that no other mutable borrows have
// been taken out for `state`
state: unsafe { T::from_raw_mut(state.as_ptr()) },
})
} else {
// TODO: Print a kernel warning here, this is a user error
None
}
}
}
impl<'a, T: DriverConnectorState> Deref for BorrowedConnectorState<'a, ConnectorState<T>> {
impl<'a, T: DriverConnectorState> Deref for ConnectorStateMutator<'a, ConnectorState<T>> {
type Target = T;
fn deref(&self) -> &Self::Target {
......@@ -744,24 +755,24 @@ impl<'a, T: DriverConnectorState> Deref for BorrowedConnectorState<'a, Connector
}
}
impl<'a, T: DriverConnectorState> DerefMut for BorrowedConnectorState<'a, ConnectorState<T>> {
impl<'a, T: DriverConnectorState> DerefMut for ConnectorStateMutator<'a, ConnectorState<T>> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.state.inner
}
}
impl<'a, T: FromRawConnectorState> Drop for BorrowedConnectorState<'a, T> {
impl<'a, T: FromRawConnectorState> Drop for ConnectorStateMutator<'a, T> {
fn drop(&mut self) {
let mask = self.state.connector().mask();
self.mask.set(self.mask.get() & !mask);
}
}
impl<'a, T: FromRawConnectorState> AsRawConnectorState for BorrowedConnectorState<'a, T> {
impl<'a, T: FromRawConnectorState> AsRawConnectorState for ConnectorStateMutator<'a, T> {
type Connector = T::Connector;
}
impl<'a, T: FromRawConnectorState> private::AsRawConnectorState for BorrowedConnectorState<'a, T> {
impl<'a, T: FromRawConnectorState> private::AsRawConnectorState for ConnectorStateMutator<'a, T> {
fn as_raw(&self) -> &bindings::drm_connector_state {
self.state.as_raw()
}
......@@ -796,7 +807,10 @@ unsafe extern "C" fn atomic_duplicate_state_callback<T: DriverConnectorState>(
);
if let Ok(mut new) = new {
// SAFETY: Just a lil' FFI call, nothing special here
// SAFETY:
// - `new` provides a valid pointer to a newly allocated `drm_plane_state` via type
// invariants
// - This initializes `new` via memcpy()
unsafe {
bindings::__drm_atomic_helper_connector_duplicate_state(connector, new.as_raw_mut())
};
......
// SPDX-License-Identifier: GPL-2.0 OR MIT
//! KMS driver abstractions for rust.
//! Bindings for [`struct drm_crtc`] and friends.
//!
//! [`struct drm_crtc`]: srctree/include/drm/drm_crtc.h
use super::{
atomic::*,
......@@ -280,16 +282,16 @@ impl<T: DriverCrtc> Crtc<T> {
/// construct new [`Crtc`] objects.
///
/// [`KmsDriver::create_objects`]: kernel::drm::kms::KmsDriver::create_objects
pub fn new<'a, 'b: 'a, P, C>(
pub fn new<'a, 'b: 'a, PrimaryData, CursorData>(
dev: &'a UnregisteredKmsDevice<'a, T::Driver>,
primary: &'a Plane<P>,
cursor: Option<&'a Plane<C>>,
primary: &'a Plane<PrimaryData>,
cursor: Option<&'a Plane<CursorData>>,
name: Option<&CStr>,
args: T::Args,
) -> Result<&'b Self>
where
P: DriverPlane<Driver = T::Driver>,
C: DriverPlane<Driver = T::Driver>
PrimaryData: DriverPlane<Driver = T::Driver>,
CursorData: DriverPlane<Driver = T::Driver>
{
if Self::has_vblank() {
dev.has_vblanks.set(true)
......@@ -307,6 +309,10 @@ impl<T: DriverCrtc> Crtc<T> {
GFP_KERNEL
)?;
// SAFETY:
// - We just allocated `this`, and we won't move it since it's pinned
// - `primary` and `cursor` share the lifetime 'a with `dev`
// - This function will memcpy the contents of `name` into its own storage.
to_result(unsafe {
bindings::drm_crtc_init_with_planes(
dev.as_raw(),
......@@ -318,45 +324,16 @@ impl<T: DriverCrtc> Crtc<T> {
)
})?;
// Convert the box into a raw pointer, we'll re-assemble it in crtc_destroy_callback()
// SAFETY: We don't move anything
Ok(unsafe { &*KBox::into_raw(Pin::into_inner_unchecked(this)) })
}
/// Attempt to convert an [`OpaqueCrtc`] into a fully qualified [`Crtc`].
///
/// This checks if the given [`OpaqueCrtc`] uses the same [`DriverCrtc`] implementation, and
/// returns the [`OpaqueCrtc`] as a [`Crtc`] object if so.
pub fn try_from_opaque<'a, D>(opaque: &'a OpaqueCrtc<D>) -> Option<&'a Self>
where
D: KmsDriver,
T: DriverCrtc<Driver = D>
{
// SAFETY: The vtables for a `Crtc` are initialized throughout the lifetime of the object
let funcs = unsafe { (*opaque.crtc.get()).funcs };
let this = unsafe { Pin::into_inner_unchecked(this) };
// SAFETY: We only perform this transmutation if the opaque CRTC shares our vtable pointers,
// so the underlying `Crtc` must share our data layout.
ptr::eq(funcs, &T::OPS.funcs).then(|| unsafe { mem::transmute(opaque) })
// Convert the box into a raw pointer, then convert that raw pointer into a reference to
// return to the caller.
// SAFETY: `this` shares the lifetime of the device, so ti is valid for the entirity of 'b
Ok(unsafe { &*KBox::into_raw(this) })
}
/// Convert a [`OpaqueCrtc`] into its fully qualified [`Crtc`].
///
/// This is an infallible version of [`Self::try_from_opaque`]. This function is mainly useful
/// for drivers where only a single [`DriverCrtc`] implementation exists.
///
/// # Panics
///
/// This function will panic if the underlying CRTC in the provided [`OpaqueCrtc`] does not
/// belong to the same [`DriverCrtc`] implementation.
pub fn from_opaque<'a, D>(opaque: &'a OpaqueCrtc<D>) -> &'a Self
where
D: KmsDriver,
T: DriverCrtc<Driver = D>
{
Self::try_from_opaque(opaque)
.expect("Passed OpaqueCrtc does not share this DriverCrtc implementation")
}
super::impl_from_opaque_mode_obj!(Crtc, DriverCrtc, crtc, OpaqueCrtc);
pub(crate) fn get_vblank_ptr(&self) -> *mut bindings::drm_vblank_crtc {
// SAFETY: FFI Call with no special requirements
......@@ -385,9 +362,13 @@ pub unsafe trait AsRawCrtc: StaticModeObject {
/// Return a raw pointer to the `bindings::drm_crtc` for this object
fn as_raw(&self) -> *mut bindings::drm_crtc;
/// Convert a raw `bindings::drm_crtc` pointer into an object of this type.
/// Convert a raw [`struct drm_crtc`] pointer into an object of this type.
///
/// # Safety
///
/// Callers promise that `ptr` points to a valid instance of this type
///
/// SAFETY: Callers promise that `ptr` points to a valid instance of this type
/// [`struct drm_crtc`]: srctree/include/drm/drm_plane.h
unsafe fn from_raw<'a>(ptr: *mut bindings::drm_crtc) -> &'a Self;
}
......@@ -403,8 +384,11 @@ unsafe impl<T: DriverCrtc> AsRawCrtc for Crtc<T> {
}
unsafe fn from_raw<'a>(ptr: *mut bindings::drm_crtc) -> &'a Self {
// SAFETY: Our data layout starts with `bindings::drm_crtc`
unsafe { &*ptr.cast() }
// Our data layout start with `bindings::drm_crtc`.
let ptr: *mut Self = ptr.cast();
// SAFETY: Our safety contract requires that `ptr` point to a valid intance of `Self`.
unsafe { &*ptr }
}
}
......@@ -531,7 +515,15 @@ pub trait DriverCrtcState: Clone + Default + Unpin {
/// [`struct drm_crtc_state`]: srctree/include/drm/drm_crtc.h
#[repr(C)]
pub struct CrtcState<T: DriverCrtcState> {
// It should be noted that CrtcState is a bit of an oddball - it's the only atomic state
// structure that can be modified after it has been swapped in, which is why we need to have
// `state` within an `Opaque<>`…
state: Opaque<bindings::drm_crtc_state>,
// …it is also one of the few atomic states that some drivers will embed work structures into,
// which means there's a good chance in the future we may have pinned data here - making it
// impossible for us to hold a mutable or immutable reference to the CrtcState. In preparation
// for that possibility, we keep `T` in an UnsafeCell.
inner: UnsafeCell<T>,
}
......@@ -677,17 +669,17 @@ impl<T: KmsDriver> FromRawCrtcState for OpaqueCrtcState<T> {
///
/// This type is typically returned by an [`AtomicStateMutator`] within contexts where it is
/// possible to safely mutate a plane's state. In order to uphold rust's data-aliasing rules, only
/// [`BorrowedCrtcState`] may exist at a time.
/// [`CrtcStateMutator`] may exist at a time.
///
/// # Invariants
///
/// `self.state` always points to a valid instance of a [`FromRawCrtcState`] object.
pub struct BorrowedCrtcState<'a, T: FromRawCrtcState> {
pub struct CrtcStateMutator<'a, T: FromRawCrtcState> {
state: NonNull<T>,
mask: &'a Cell<u32>,
}
impl<'a, T: FromRawCrtcState> BorrowedCrtcState<'a, T> {
impl<'a, T: FromRawCrtcState> CrtcStateMutator<'a, T> {
pub(super) fn new<D: KmsDriver>(
mutator: &'a AtomicStateMutator<D>,
state: NonNull<bindings::drm_crtc_state>
......@@ -710,7 +702,7 @@ impl<'a, T: FromRawCrtcState> BorrowedCrtcState<'a, T> {
}
}
impl<'a, T: FromRawCrtcState> Drop for BorrowedCrtcState<'a, T> {
impl<'a, T: FromRawCrtcState> Drop for CrtcStateMutator<'a, T> {
fn drop(&mut self) {
// SAFETY: Our interface is proof that we are the only ones with a reference to this data
let mask = unsafe { self.state.as_ref() }.crtc().mask();
......@@ -718,7 +710,7 @@ impl<'a, T: FromRawCrtcState> Drop for BorrowedCrtcState<'a, T> {
}
}
impl<'a, T: DriverCrtcState> Deref for BorrowedCrtcState<'a, CrtcState<T>> {
impl<'a, T: DriverCrtcState> Deref for CrtcStateMutator<'a, CrtcState<T>> {
type Target = T;
fn deref(&self) -> &Self::Target {
......@@ -728,7 +720,7 @@ impl<'a, T: DriverCrtcState> Deref for BorrowedCrtcState<'a, CrtcState<T>> {
}
}
impl<'a, T: DriverCrtcState> DerefMut for BorrowedCrtcState<'a, CrtcState<T>> {
impl<'a, T: DriverCrtcState> DerefMut for CrtcStateMutator<'a, CrtcState<T>> {
fn deref_mut(&mut self) -> &mut Self::Target {
// SAFETY: Our interface ensures that `self.state.inner` follows rust's data-aliasing rules,
// so this is safe
......@@ -736,11 +728,11 @@ impl<'a, T: DriverCrtcState> DerefMut for BorrowedCrtcState<'a, CrtcState<T>> {
}
}
impl<'a, T: FromRawCrtcState> AsRawCrtcState for BorrowedCrtcState<'a, T> {
impl<'a, T: FromRawCrtcState> AsRawCrtcState for CrtcStateMutator<'a, T> {
type Crtc = T::Crtc;
}
impl<'a, T: FromRawCrtcState> private::AsRawCrtcState for BorrowedCrtcState<'a, T> {
impl<'a, T: FromRawCrtcState> private::AsRawCrtcState for CrtcStateMutator<'a, T> {
fn as_raw(&self) -> *mut bindings::drm_crtc_state {
self.state.as_ptr().cast()
}
......@@ -785,8 +777,10 @@ unsafe extern "C" fn atomic_duplicate_state_callback<T: DriverCrtcState>(
if let Ok(mut new) = new {
let new = KBox::into_raw(new).cast();
// SAFETY: DRM simply copies the data from the previous base DRM state here and does not
// move the contents of `ptr`
// SAFETY:
// - `new` provides a valid pointer to a newly allocated `drm_crtc_state` via type
// invariants
// - This initializes `new` via memcpy()
unsafe { bindings::__drm_atomic_helper_crtc_duplicate_state(crtc.as_raw(), new) }
new
......
......@@ -245,6 +245,8 @@ impl<T: DriverEncoder> Encoder<T> {
// SAFETY: We don't move anything
Ok(unsafe { &*KBox::into_raw(Pin::into_inner_unchecked(this)) })
}
super::impl_from_opaque_mode_obj!(Encoder, DriverEncoder, encoder, OpaqueEncoder);
}
/// A [`struct drm_encoder`] without a known [`DriverEncoder`] implementation.
......@@ -253,8 +255,6 @@ impl<T: DriverEncoder> Encoder<T> {
/// for a [`struct drm_encoder`] automatically. It is identical to [`Encoder`], except that it does not
/// provide access to the driver's private data.
///
/// TODO: Add functions for upcasting.
///
/// # Invariants
///
/// Same as [`Encoder`].
......
......@@ -22,6 +22,7 @@ use core::{
ptr::{self, null, null_mut, NonNull},
marker::*,
ops::*,
iter,
};
use macros::pin_data;
use super::{
......@@ -114,7 +115,7 @@ pub trait DriverPlane: Send + Sync + Sized {
/// [`drm_plane_helper_funcs.atomic_update`]: srctree/include/drm/drm_modeset_helper_vtables.h
fn atomic_update(
plane: &Plane<Self>,
new_state: BorrowedPlaneState<'_, PlaneState<Self::State>>,
new_state: PlaneStateMutator<'_, PlaneState<Self::State>>,
old_state: &PlaneState<Self::State>,
state: &AtomicStateMutator<Self::Driver>
) {
......@@ -129,7 +130,7 @@ pub trait DriverPlane: Send + Sync + Sized {
/// [`drm_plane_helper_funcs.atomic_check`]: srctree/include/drm/drm_modeset_helper_vtables.h
fn atomic_check(
plane: &Plane<Self>,
new_state: BorrowedPlaneState<'_, PlaneState<Self::State>>,
new_state: PlaneStateMutator<'_, PlaneState<Self::State>>,
old_state: &PlaneState<Self::State>,
state: &AtomicStateComposer<Self::Driver>
) -> Result {
......@@ -150,20 +151,24 @@ pub struct DriverPlaneOps {
/// An enumerator describing a type of [`Plane`].
///
/// This is mainly just relevant for DRM legacy drivers.
///
/// # Invariants
///
/// This type is identical to `drm_plane_type`.
pub enum PlaneType {
/// Overlay planes represent all non-primary, non-cursor planes. Some drivers refer to these
/// types of planes as "sprites" internally.
OVERLAY = bindings::drm_plane_type_DRM_PLANE_TYPE_OVERLAY,
Overlay = bindings::drm_plane_type_DRM_PLANE_TYPE_OVERLAY,
/// A primary plane attached to a CRTC that is the most likely to be able to light up the CRTC
/// when no scaling/cropping is used, and the plane covers the whole CRTC.
PRIMARY = bindings::drm_plane_type_DRM_PLANE_TYPE_PRIMARY,
Primary = bindings::drm_plane_type_DRM_PLANE_TYPE_PRIMARY,
/// A cursor plane attached to a CRTC that is more likely to be enabled when no scaling/cropping
/// is used, and the framebuffer has the size indicated by [`ModeConfigInfo::max_cursor`].
///
/// [`ModeConfigInfo::max_cursor`]: crate::drm::kms::ModeConfigInfo
CURSOR = bindings::drm_plane_type_DRM_PLANE_TYPE_CURSOR,
Cursor = bindings::drm_plane_type_DRM_PLANE_TYPE_CURSOR,
}
/// The main interface for a [`struct drm_plane`].
......@@ -206,15 +211,15 @@ impl<T: DriverPlane> Deref for Plane<T> {
impl<T: DriverPlane> Plane<T> {
/// Construct a new [`Plane`].
///
/// A driver may use this from their [`KmsDriver::create_objects`] callback in order to construct new
/// [`Plane`] objects.
/// A driver may use this from their [`KmsDriver::create_objects`] callback in order to
/// construct new [`Plane`] objects.
///
/// [`KmsDriver::create_objects`]: kernel::drm::kms::KmsDriver::create_objects
pub fn new<'a, 'b: 'a, const FMT_COUNT: usize, const MOD_COUNT: usize>(
pub fn new<'a, 'b: 'a>(
dev: &'a UnregisteredKmsDevice<'a, T::Driver>,
possible_crtcs: u32,
formats: &'static FormatList<FMT_COUNT>,
format_modifiers: Option<&'static ModifierList<MOD_COUNT>>,
formats: &[u32],
format_modifiers: Option<&[u64]>,
type_: PlaneType,
name: Option<&CStr>,
args: T::Args,
......@@ -231,7 +236,31 @@ impl<T: DriverPlane> Plane<T> {
GFP_KERNEL
)?;
// SAFETY: FFI call with no special requirements
// TODO: Move this over to using collect() someday
// Create a modifiers array with the sentinel for passing to DRM
let format_modifiers_raw;
if let Some(modifiers) = format_modifiers {
let mut raw = KVec::with_capacity(modifiers.len() + 1, GFP_KERNEL)?;
for modifier in modifiers {
raw.push(*modifier, GFP_KERNEL)?;
}
raw.push(FORMAT_MOD_INVALID, GFP_KERNEL)?;
format_modifiers_raw = Some(raw);
} else {
format_modifiers_raw = None;
}
// SAFETY:
// - We just allocated `this`, and we won't move it since it's pinned
// - We just allocated the `format_modifiers_raw` vec and added the sentinel DRM expects
// above
// - `drm_universal_plane_init` will memcpy() the following parameters into its own storage,
// so it's safe for them to become inaccessible after this call returns:
// - `formats`
// - `format_modifiers_raw`
// - `name`
// - `type_` is equivalent to `drm_plane_type` via its type invariants.
to_result(unsafe {
bindings::drm_universal_plane_init(
dev.as_raw(),
......@@ -239,8 +268,8 @@ impl<T: DriverPlane> Plane<T> {
possible_crtcs,
&T::OPS.funcs,
formats.as_ptr(),
formats.raw_len() as _,
format_modifiers.map_or(null(), |f| f.as_ptr()),
formats.len() as _,
format_modifiers_raw.map_or(null(), |f| f.as_ptr()),
type_ as _,
name.map_or(null(), |n| n.as_char_ptr())
)
......@@ -251,42 +280,7 @@ impl<T: DriverPlane> Plane<T> {
Ok(unsafe { &*KBox::into_raw(Pin::into_inner_unchecked(this)) })
}
/// Attempt to convert an [`OpaquePlane`] into a fully qualified [`Plane`].
///
/// This checks if the given [`OpaquePlane`] uses the same [`DriverPlane`] implementation, and
/// returns the [`OpaquePlane`] as a [`Plane`] object if so.
pub fn try_from_opaque<'a, D>(opaque: &'a OpaquePlane<D>) -> Option<&'a Self>
where
D: KmsDriver,
T: DriverPlane<Driver = D>
{
// SAFETY: The vtables for a `Plane` are initialized by the time that we expose `Plane`
// objects to users, and their values are invariant throughout the lifetime of the device.
let funcs = unsafe { (*opaque.plane.get()).funcs };
// SAFETY: We just guaranteed that the opaque plane shares our vtable pointers, which means
// it must belong to our `DriverPlane` implementation. As well, all `Plane<DriverPlane>`
// objects start with an identical data layout to `OpaquePlane`
ptr::eq(funcs, &T::OPS.funcs).then(|| unsafe { mem::transmute(opaque) })
}
/// Convert a [`OpaquePlane`] into its fully qualified [`Plane`].
///
/// This is an infallible version of [`Self::try_from_opaque`]. This function is mainly useful
/// for drivers where only a single [`DriverPlane`] implementation exists.
///
/// # Panics
///
/// This function will panic if the underlying [`Plane`] which contains the provided
/// [`OpaquePlane`] does not belong to the same [`DriverPlane`] implementation.
pub fn from_opaque<'a, D>(opaque: &'a OpaquePlane<D>) -> &'a Self
where
D: KmsDriver,
T: DriverPlane<Driver = D>
{
Self::try_from_opaque(opaque)
.expect("Passed OpaquePlane does not share this DriverPlane implementation")
}
super::impl_from_opaque_mode_obj!(Plane, DriverPlane, plane, OpaquePlane);
}
/// A trait implemented by any type that acts as a [`struct drm_plane`] interface.
......@@ -326,8 +320,11 @@ unsafe impl<T: DriverPlane> AsRawPlane for Plane<T> {
}
unsafe fn from_raw<'a>(ptr: *mut bindings::drm_plane) -> &'a Self {
// SAFETY: Our data layout starts with `bindings::drm_plane`
unsafe { &*ptr.cast() }
// Our data layout start with `bindings::drm_plane`.
let ptr: *mut Self = ptr.cast();
// SAFETY: Our safety contract requires that `ptr` point to a valid intance of `Self`.
unsafe { &*ptr }
}
}
......@@ -364,9 +361,11 @@ pub trait RawPlane: AsRawPlane {
/// Return the index of this DRM plane
#[inline]
fn index(&self) -> u32 {
// SAFETY: The index is initialized by the time we expose `Plane` objects to users, and is
// invariant throughout the lifetime of the `Plane`
unsafe { (*self.as_raw()).index }
// SAFETY:
// - The index is initialized by the time we expose planes to users, and does not change
// throughout its lifetime
// - `.as_raw()` always returns a valid poiinter.
unsafe { *self.as_raw() }.index
}
/// Return the index of this DRM plane in the form of a bitmask
......@@ -481,20 +480,26 @@ pub(crate) use private::AsRawPlaneState as AsRawPlaneStatePrivate;
///
/// [`struct drm_plane_state`]: srctree/include/drm/drm_plane.h
pub trait FromRawPlaneState: AsRawPlaneState {
/// Get an immutable reference to this type from the given raw `bindings::drm_plane_state`
/// pointer
/// Get an immutable reference to this type from the given raw [`struct drm_plane_state`]
/// pointer.
///
/// # Safety
///
/// The caller guarantees `ptr` is contained within a valid instance of `Self`
/// - The caller guarantees `ptr` is contained within a valid instance of `Self`
/// - The caller guarantees that `ptr` cannot not be modified for the lifetime of `'a`.
///
/// [`struct drm_plane_state`]: srctree/include/drm/drm_plane.h
unsafe fn from_raw<'a>(ptr: *const bindings::drm_plane_state) -> &'a Self;
/// Get a mutable reference to this type from the given raw `bindings::drm_plane_state` pointer
/// Get a mutable reference to this type from the given raw [`struct drm_plane_state`] pointer.
///
/// # Safety
///
/// The caller guarantees `ptr` is contained within a valid instance of `Self`, and that no
/// other references (mutable or immutable) to `ptr` exist.
/// - The caller guarantees that `ptr` is contained within a valid instance of `Self`
/// - The caller guarantees that `ptr` cannot have any other references taken out for the
/// lifetime of `'a`.
///
/// [`struct drm_plane_state`]: srctree/include/drm/drm_plane.h
unsafe fn from_raw_mut<'a>(ptr: *mut bindings::drm_plane_state) -> &'a mut Self;
}
......@@ -516,10 +521,10 @@ pub trait RawPlaneState: AsRawPlaneState {
NonNull::new(self.as_raw().crtc).map(|c| unsafe { OpaqueCrtc::from_raw(c.as_ptr()) })
}
/// Run the atomic check helper for this plane and the given CRTC state
/// Run the atomic check helper for this plane and the given CRTC state.
fn atomic_helper_check<S>(
&mut self,
crtc_state: &BorrowedCrtcState<'_, S>,
crtc_state: &CrtcStateMutator<'_, S>,
can_position: bool,
can_update_disabled: bool
) -> Result
......@@ -611,13 +616,25 @@ impl<T: DriverPlaneState> private::AsRawPlaneState for PlaneState<T> {
impl<T: DriverPlaneState> FromRawPlaneState for PlaneState<T> {
unsafe fn from_raw<'a>(ptr: *const bindings::drm_plane_state) -> &'a Self {
// SAFETY: Our data layout starts with `bindings::drm_plane_state`
unsafe { &*ptr.cast() }
// Our data layout starts with `bindings::drm_plane_state`.
let ptr: *const Self = ptr.cast();
// SAFETY:
// - Our safety contract requires that `ptr` be contained within `Self`.
// - Our safety contract requires the caller ensure that it is safe for us to take an
// immutable reference.
unsafe { &*ptr }
}
unsafe fn from_raw_mut<'a>(ptr: *mut bindings::drm_plane_state) -> &'a mut Self {
// SAFETY: Our data layout starts with `bindings::drm_plane_state`
unsafe { &mut *ptr.cast() }
// Our data layout starts with `bindings::drm_plane_state`.
let ptr: *mut Self = ptr.cast();
// SAFETY:
// - Our safety contract requires that `ptr` be contained within `Self`.
// - Our safety contract requires the caller ensure it is safe for us to take a mutable
// reference.
unsafe { &mut *ptr }
}
}
......@@ -691,13 +708,13 @@ impl<T: KmsDriver> FromRawPlaneState for OpaquePlaneState<T> {
///
/// This type is typically returned by an [`AtomicStateMutator`] within contexts where it is
/// possible to safely mutate a plane's state. In order to uphold rust's data-aliasing rules, only
/// [`BorrowedPlaneState`] may exist at a time.
pub struct BorrowedPlaneState<'a, T: FromRawPlaneState> {
/// [`PlaneStateMutator`] may exist at a time.
pub struct PlaneStateMutator<'a, T: FromRawPlaneState> {
state: &'a mut T,
mask: &'a Cell<u32>
}
impl<'a, T: FromRawPlaneState> BorrowedPlaneState<'a, T> {
impl<'a, T: FromRawPlaneState> PlaneStateMutator<'a, T> {
pub(super) fn new<D: KmsDriver>(
mutator: &'a AtomicStateMutator<D>,
state: NonNull<bindings::drm_plane_state>
......@@ -724,18 +741,18 @@ impl<'a, T: FromRawPlaneState> BorrowedPlaneState<'a, T> {
}
}
impl<'a, T: FromRawPlaneState> Drop for BorrowedPlaneState<'a, T> {
impl<'a, T: FromRawPlaneState> Drop for PlaneStateMutator<'a, T> {
fn drop(&mut self) {
let mask = self.state.plane().mask();
self.mask.set(self.mask.get() & !mask);
}
}
impl<'a, T: FromRawPlaneState> AsRawPlaneState for BorrowedPlaneState<'a, T> {
impl<'a, T: FromRawPlaneState> AsRawPlaneState for PlaneStateMutator<'a, T> {
type Plane = T::Plane;
}
impl<'a, T: FromRawPlaneState> private::AsRawPlaneState for BorrowedPlaneState<'a, T> {
impl<'a, T: FromRawPlaneState> private::AsRawPlaneState for PlaneStateMutator<'a, T> {
fn as_raw(&self) -> &bindings::drm_plane_state {
self.state.as_raw()
}
......@@ -746,9 +763,9 @@ impl<'a, T: FromRawPlaneState> private::AsRawPlaneState for BorrowedPlaneState<'
}
}
impl<'a, T: FromRawPlaneState> Sealed for BorrowedPlaneState<'a, T> {}
impl<'a, T: FromRawPlaneState> Sealed for PlaneStateMutator<'a, T> {}
impl<'a, T: DriverPlaneState> Deref for BorrowedPlaneState<'a, PlaneState<T>> {
impl<'a, T: DriverPlaneState> Deref for PlaneStateMutator<'a, PlaneState<T>> {
type Target = T;
fn deref(&self) -> &Self::Target {
......@@ -756,7 +773,7 @@ impl<'a, T: DriverPlaneState> Deref for BorrowedPlaneState<'a, PlaneState<T>> {
}
}
impl<'a, T: DriverPlaneState> DerefMut for BorrowedPlaneState<'a, PlaneState<T>> {
impl<'a, T: DriverPlaneState> DerefMut for PlaneStateMutator<'a, PlaneState<T>> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.state.inner
}
......@@ -795,7 +812,10 @@ unsafe extern "C" fn atomic_duplicate_state_callback<T: DriverPlaneState>(
);
if let Ok(mut new) = new {
// SAFETY: Just a lil' FFI call, nothing special here
// SAFETY:
// - `new` provides a valid pointer to a newly allocated `drm_plane_state` via type
// invariants
// - This initializes `new` via memcpy()
unsafe {
bindings::__drm_atomic_helper_plane_duplicate_state(plane, new.as_raw_mut())
};
......