926: nrf: PPI fixes r=Dirbaio a=Dirbaio

- Feature-gate DPPI-only stuff that should be feature-gated
- Fix unsoundness due to Task/Event ptr being public: this meant you could construct a Task/Event with an arbitrary pointer and then safely call `Ppi::new_*` which would blindly write to it. Now you have to go through `Task/Event::new_unchecked` which is unsafe, with the right safety contract.

Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
This commit is contained in:
bors[bot] 2022-08-24 00:05:38 +00:00 committed by GitHub
commit 529535194d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -35,21 +35,32 @@ pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize
tasks: [Task; TASK_COUNT],
}
#[cfg(feature = "_dppi")]
const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::<u32>();
/// Represents a task that a peripheral can do.
/// When a task is subscribed to a PPI channel it will run when the channel is triggered by
/// a published event.
///
/// The pointer is to a task register
/// When a task is subscribed to a PPI channel, it will run when the channel is triggered by
/// a published event.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Task(pub NonNull<u32>);
pub struct Task(NonNull<u32>);
impl Task {
/// Create a new `Task` from a task register pointer
///
/// # Safety
///
/// `ptr` must be a pointer to a valid `TASKS_*` register from an nRF peripheral.
pub unsafe fn new_unchecked(ptr: NonNull<u32>) -> Self {
Self(ptr)
}
pub(crate) fn from_reg<T>(reg: &T) -> Self {
Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
}
/// Address off subscription register for this task.
/// Address of subscription register for this task.
#[cfg(feature = "_dppi")]
pub fn subscribe_reg(&self) -> *mut u32 {
unsafe { self.0.as_ptr().add(REGISTER_DPPI_CONFIG_OFFSET) }
}
@ -61,17 +72,27 @@ impl Task {
unsafe impl Send for Task {}
/// Represents an event that a peripheral can publish.
/// An event can be set to publish on a PPI channel when the event happens.
///
/// The pointer is to an event register
/// An event can be set to publish on a PPI channel when the event happens.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Event(pub NonNull<u32>);
pub struct Event(NonNull<u32>);
impl Event {
/// Create a new `Event` from an event register pointer
///
/// # Safety
///
/// `ptr` must be a pointer to a valid `EVENTS_*` register from an nRF peripheral.
pub unsafe fn new_unchecked(ptr: NonNull<u32>) -> Self {
Self(ptr)
}
pub(crate) fn from_reg<T>(reg: &T) -> Self {
Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
}
/// Address of publish register for this event.
#[cfg(feature = "_dppi")]
pub fn publish_reg(&self) -> *mut u32 {
unsafe { self.0.as_ptr().add(REGISTER_DPPI_CONFIG_OFFSET) }
}