sentry_uapi/
systypes.rs

1// SPDX-FileCopyrightText: 2023 Ledger SAS
2// SPDX-FileCopyrightText: 2025 ANSSI & H2Lab OSS Team
3// SPDX-License-Identifier: Apache-2.0
4
5/// This library defines types (structs, enums, ...) related to syscalls,
6/// that need to be shared between the kernel and the uapi.
7///
8/// Most important enum is `Syscall`, which defines the list of available
9/// syscalls and sets their identifier/number.
10///
11/// This macro takes an enum and implements fallible conversion from a u8
12/// exhaustively, as required by the SVC Handler.
13///
14/// ```
15/// pub enum Syscall {
16///     Exit,
17/// }
18///
19/// impl TryFrom<u8> for Syscall {
20///     type Error = ();
21///     fn try_from(v: u8) -> Result<Self, Self::Error> {
22///         match v {
23///             x if x == Syscall::Exit as u8 => Ok(Syscall::Exit),
24///             _ => Err(())
25///         }
26///     }
27/// }
28/// ```
29/// (inspired by https://stackoverflow.com/a/58715864)
30///
31/// It also ensures that there cannot be a mismatch between the u8 value
32/// used to define the enum, and the value used for converting to it.
33macro_rules! syscall_list {
34    ($vis:vis enum $name:ident {
35        $($vname:ident,)*
36    }) => {
37        #[repr(C)]
38        #[cfg_attr(debug_assertions, derive(Debug))]
39        $vis enum $name {
40            $($vname,)*
41        }
42
43        impl TryFrom<u8> for $name {
44            type Error = Status;
45
46            fn try_from(v: u8) -> Result<Self, Self::Error> {
47                match v {
48                    $(x if x == $name::$vname as u8 => Ok($name::$vname),)*
49                    _ => Err(Status::Invalid),
50                }
51            }
52        }
53    }
54}
55
56// FIXME: #[cfg()] does not seems to be supported with macro rules....
57// We need to find a way to make the last two autotest_ syscalls conditionally declared
58syscall_list! {
59pub enum Syscall {
60    Exit,
61    GetProcessHandle,
62    GetDeviceHandle,
63    Yield,
64    Sleep,
65    Start,
66    MapDev,
67    MapShm,
68    UnmapDev,
69    UnmapShm,
70    SHMSetCredential,
71    SendIPC,
72    SendSignal,
73    WaitForEvent,
74    PmManage,
75    PmSetClock,
76    Log,
77    Alarm,
78    GetRandom,
79    GetCycle,
80    GpioGet,
81    GpioSet,
82    GpioReset,
83    GpioToggle,
84    GpioConfigure,
85    IrqAcknowledge,
86    IrqEnable,
87    IrqDisable,
88    GetShmHandle,
89    GetDmaStreamHandle,
90    DmaStartStream,
91    DmaSuspendStream,
92    DmaGetStreamStatus,
93    ShmGetInfos,
94    DmaAssignStream,
95    DmaUnassignStream,
96    DmaGetStreamInfo,
97    DmaResumeStream,
98    AutotestSetCapa,
99    AutotestClearCapa,
100}
101}
102
103macro_rules! mirror_enum {
104    ($to:ty, $vis:vis enum $name:ident {
105        $($vname:ident,)*
106    }) => {
107        #[repr(C)]
108        $vis enum $name {
109            $($vname,)*
110        }
111
112        impl TryFrom<$to> for $name {
113            type Error = Status;
114
115            fn try_from(v: $to) -> Result<Self, Self::Error> {
116                match v {
117                    $(x if x == $name::$vname as $to => Ok($name::$vname),)*
118                    _ => Err(Status::Invalid),
119                }
120            }
121        }
122    }
123}
124
125/// Sentry syscall return values
126///
127/// Note: the kernel also hold, at kernel level, another value denoted
128/// 'NonSense'. This value must never be returned to userspace. This
129/// is why this value do not exist here.
130///
131/// Such a return should raise a security exception. All syscalls that can't set
132/// they return code synchronously (e.g. IPC), MUST use this value as
133/// default one
134#[repr(C)]
135#[cfg_attr(debug_assertions, derive(Debug))]
136#[derive(Copy, Clone, PartialEq)]
137pub enum Status {
138    /// Successful result, the kernel has terminated its task with no error
139    Ok,
140    /// At least one parameter is not valid (not allowed or not found)
141    Invalid,
142    /// The requested action is not allowed for caller, or the resource is not owned
143    Denied,
144    /// The requested resource do not exist
145    NoEntity,
146    /// The requested resource is in a state that do now allow the current call
147    Busy,
148    /// The requested resource is already mapped
149    AlreadyMapped,
150    /// Critical (mostly security-related) unexpected event
151    Critical,
152    /// The requested resource did not respond or the call has reached its maximum wait time
153    Timeout,
154    /// The requested resource is not here yet, come back later
155    Again,
156    /// The call has been interrupted sooner than expected. Used for blocking calls
157    Intr,
158    /// The requested resource can't be manipulated without generating a dead lock
159    Deadlk,
160}
161
162/// u32 to Status converter, required to support register encoded value
163impl From<u32> for Status {
164    fn from(status_int: u32) -> Status {
165        match status_int {
166            0 => Status::Ok,
167            1 => Status::Invalid,
168            2 => Status::Denied,
169            3 => Status::NoEntity,
170            4 => Status::Busy,
171            5 => Status::AlreadyMapped,
172            6 => Status::Critical,
173            7 => Status::Timeout,
174            8 => Status::Again,
175            9 => Status::Intr,
176            10 => Status::Deadlk,
177            _ => panic!(),
178        }
179    }
180}
181
182/// A process label is a development-time fixed identifier that can be used hardcoded
183///  in the source code. This can be used in order to get back remote process effective
184/// identifier from label at any time in order to communicate
185pub type TaskLabel = u32;
186
187/// A shm label is a development-time fixed identifier that can be used hardcoded
188/// in the source code. This label is set in the device-tree in the shm declaration,
189/// and can be used in order to get back the effective shm handler from it in order
190/// to manipulate it
191pub type ShmLabel = u32;
192
193/// A stream label is a development-time fixed identifier that can be used hardcoded
194/// in the source code in order to identify declared DMA streams.
195/// This label is set in the device-tree in the stream declaration,
196/// and can be used in order to get back the effective DMA stream handler from it in order
197/// to manipulate it
198pub type StreamLabel = u32;
199
200/// A device label is a development-time fixed identifier that can be used hardcoded
201/// in the source code in order to identify declared device.
202/// This label is, by now, the result of the device tree analysis but will be replaced by
203/// a clean sentry,label field at dts level, in the same way other label are set, to
204/// highly simplify userspace level usage.
205/// This label is used to get back the associated handle at run time.
206pub type DeviceLabel = u32;
207
208/// A device handle is a unique identifier required to manipulate a devive
209///
210/// That handle is forged by the kernel at bootup time and vary from one boot to another.
211/// The device handle can be retrieved by using the [`crate::syscall::get_device_handle`]
212/// syscall.
213///
214pub type DeviceHandle = u32;
215
216/// A task handle is a unique identifier required to communicate with another task.
217///
218/// A task handle is associated to a job, meaning that if a task job terminates and
219/// is restarted, the associated handle is reforged and diverge from the previous one.
220///
221/// All jobs have a task handle. This handle is the only way to uniquely identify a
222/// given job with which we need to communicate..
223/// The task handle can be retrieved by using the [`crate::syscall::get_process_handle`]
224/// syscall.
225///
226pub type TaskHandle = u32;
227
228/// A SHM handle is a unique identifier required to manipulate a shared memory.
229///
230/// That handle is forged by the kernel at bootup time and vary from one boot to another.
231/// The SHM handle can be retrieved by using the [`crate::syscall::get_shm_handle`]
232/// syscall.
233///
234pub type ShmHandle = u32;
235
236/// A DMA stream handle is a unique identifier required to manipulate a DMA stream.
237///
238/// That handle is forged by the kernel at bootup time and vary from one boot to another.
239/// The DMA stream handle can be retrieved by using the [`crate::syscall::get_dma_stream_handle`]
240/// syscall.
241///
242pub type StreamHandle = u32;
243
244/// Definition of Sentry events
245///
246/// Multiple events can targets a given task. These events are strictly
247/// identified so that the task can easily differentiate them.
248///
249/// As multiple events can be set at once, event field is using a
250/// bitfield model to keep C+Rust usage easy
251#[repr(C)]
252#[derive(Clone, PartialEq, Copy, Debug)]
253pub enum EventType {
254    /// No event
255    None = 0,
256    /// Inter-task slow path IPC event
257    Ipc = 1,
258    /// Inter-task signal event
259    Signal = 2,
260    /// Hardware interrupt event
261    Irq = 4,
262    /// DMA stream event
263    Dma = 8,
264    /// Any of the above events
265    All = 15,
266}
267
268/// list of potential Event types, encoded as u8 to exchange with kernel
269///
270/// This value corresponds to a set of one or multiple EventType value, so
271/// that the job can wait for multiple events at a time.
272/// Events priority when returning from the kernel is described in the events
273/// chapter of the Sentry documentation.
274///
275pub type EventList = u8;
276
277impl From<EventType> for u8 {
278    fn from(event: EventType) -> u8 {
279        match event {
280            EventType::None => 0,
281            EventType::Ipc => 1,
282            EventType::Signal => 2,
283            EventType::Irq => 4,
284            EventType::Dma => 8,
285            EventType::All => 15,
286        }
287    }
288}
289
290impl From<u8> for EventType {
291    fn from(event: u8) -> EventType {
292        match event {
293            0 => EventType::None,
294            1 => EventType::Ipc,
295            2 => EventType::Signal,
296            4 => EventType::Irq,
297            8 => EventType::Dma,
298            15 => EventType::All,
299            _ => EventType::None,
300        }
301    }
302}
303/// Erase type that can be used to clear the SVC_Exchange.
304///
305/// TODO: to be moved to svc_exchange module as used exclusively by
306/// this module primitives.
307///
308/// There are two types of erase model:
309/// - Zeroify, that write 0x0 pattern in the SVC exchange zone
310/// - Random, that write a random pattern
311///
312/// By now, only Zeroify is supported.
313#[repr(C)]
314pub enum EraseType {
315    Zeroify = 0x5a,
316    Random = 0xa5,
317}
318
319impl From<EraseType> for u32 {
320    fn from(etype: EraseType) -> u32 {
321        match etype {
322            EraseType::Zeroify => 0x5a,
323            EraseType::Random => 0xa5,
324        }
325    }
326}
327
328/// Erase mode that can be used to clear the SVC_Exchange.
329///
330/// There are two types of erase mode:
331/// - UserErase, leaving the write action to the UAPI crate, withtout kernel call
332/// - KernelErase, requiring the kernel to execute the erasing.
333///   This last mode ensure that the erasing is atomic while it is started.
334///
335/// By now, only UserErase ils supported.
336#[repr(C)]
337pub enum EraseMode {
338    UserErase = 0x72,
339    KernelErase = 0x27,
340}
341
342impl From<EraseMode> for u32 {
343    fn from(emode: EraseMode) -> u32 {
344        match emode {
345            EraseMode::UserErase => 0x72,
346            EraseMode::KernelErase => 0x27,
347        }
348    }
349}
350
351/// Alarm type for alarm-related API
352#[repr(C)]
353pub enum AlarmFlag {
354    /// Start an alarm
355    AlarmStart,
356    /// Start a periodic alarm
357    AlarmStartPeriodic,
358    /// Stop an alarm, being periodic or not
359    AlarmStop,
360}
361
362impl From<AlarmFlag> for u32 {
363    fn from(mode: AlarmFlag) -> u32 {
364        match mode {
365            AlarmFlag::AlarmStart => 0,
366            AlarmFlag::AlarmStartPeriodic => 1,
367            AlarmFlag::AlarmStop => 2,
368        }
369    }
370}
371
372/// Permission model definition for shared memories
373#[repr(C)]
374pub enum SHMPermission {
375    /// allows target process to map the SHM. No read nor write though
376    Map = 0x1,
377
378    /// allows target process to read the mapped SHM. Requires MAP
379    Read = 0x2,
380
381    /// allows target process to write shared memory. Requires MAP
382    Write = 0x4,
383
384    /// allows target process to transfer SHM to another, pre-allowed, process
385    Transfer = 0x8,
386}
387
388/// Converter for SHM permission to register encoding (u32)
389impl From<SHMPermission> for u32 {
390    fn from(shm_perm: SHMPermission) -> u32 {
391        match shm_perm {
392            SHMPermission::Map => 0x1,
393            SHMPermission::Read => 0x2,
394            SHMPermission::Write => 0x4,
395            SHMPermission::Transfer => 0x8,
396        }
397    }
398}
399
400/// Sentry signals definition. Most of them are aligned on standard POSIX signals
401#[repr(C)]
402#[derive(Clone, PartialEq, Copy, Debug)]
403pub enum Signal {
404    /// Abort signal
405    Abort = 1,
406
407    /// Timer (from alarm)
408    Alarm,
409
410    /// Bus error (bad memory access, memory required)
411    Bus,
412
413    /// Continue if previously stopped
414    Cont,
415
416    /// Illegal instruction. Can be also used for upper provtocols
417    Ill,
418
419    /// I/O now ready
420    Io,
421
422    /// Broken pipe
423    Pipe,
424
425    /// Event pollable
426    Poll,
427
428    /// Termination signal
429    Term,
430
431    /// Trace/bp signal (debug usage only)
432    Trap,
433
434    /// 1st user-defined signal
435    Usr1,
436
437    /// 2nd user-defined signal
438    Usr2,
439
440    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
441    /// Autotest-specific: User hardfault detected
442    PanicUserHardFault,
443    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
444    /// Autotest-specific: A panic() has been reached in kernel handler
445    PanicKernelHardFault,
446    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
447    /// Autotest-specific: User bus fault detected
448    PanicUserBusFault,
449    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
450    /// Autotest-specific: Kernel bus fault detected
451    PanicKernelBusFault,
452    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
453    /// Autotest-specific: User user usage fault detected
454    PanicUserUsageFault,
455    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
456    /// Autotest-specific: Kernel usage fault detected
457    PanicKernelUsageFault,
458    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
459    /// Autotest-specific: User memory fault detected
460    PanicUserMemAccess,
461    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
462    /// Autotest-specific: Kernel memoryfault detected
463    PanicKernelMemAccess,
464    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
465    /// Autotest-specific: Invalid userspace input received
466    PanicKernelInvalidUserspaceInput,
467    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
468    /// Autotest-specific: Memory limit reached in a kernel buffer
469    PanicKernelShorterKBuffersConfig,
470    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
471    /// Autotest-specific: A given manager returns invalid state error
472    PanicKernelInvalidManagerState,
473    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
474    /// Autotest-specific: A given manager return an invalid response
475    PanicKernelInvalidManagerResponse,
476    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
477    /// Autotest-specific: Kernel handler as reach timeout limit
478    PanicKernelTimeout,
479    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
480    /// Autotest-specific: Kernel CFI violation
481    PanicKernelBadCFICalculation,
482    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
483    /// Autotest-specific: Kernel-related hardware IP (MPU, etc.) is in invalid state
484    PanicHardwareInvalidState,
485    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
486    /// Autotest-specific: An unexpected modification of a kernel context has been detected
487    PanicHardwareUnexpectedModification,
488    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
489    /// Autotest-specific: Requested kernel autotest has finished successfully
490    AutotestDone,
491    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
492    /// Autotest-specific: Requested kernel autotest has finished with a failure
493    AutotestFailed,
494    #[cfg(CONFIG_BUILD_TARGET_AUTOTEST)]
495    /// Autotest-specific: Requested kernel autotest has timed-out
496    AutotestTimedOut,
497}
498
499/// Sleep durations input values for the sleep API
500#[repr(C)]
501pub enum SleepDuration {
502    /// Sleep for 1ms
503    D1ms,
504    /// Sleep for 2ms
505    D2ms,
506    /// Sleep for 5ms
507    D5ms,
508    /// Sleep for 10ms
509    D10ms,
510    /// Sleep for 20ms
511    D20ms,
512    /// Sleep for 50ms
513    D50ms,
514    /// Sleep for a user-specificed number of ms (>0)
515    ArbitraryMs(u32),
516}
517
518/// Converter for SleepDuration type to register-encoded value
519impl From<SleepDuration> for u32 {
520    fn from(duration: SleepDuration) -> u32 {
521        match duration {
522            SleepDuration::D1ms => 1,
523            SleepDuration::D2ms => 2,
524            SleepDuration::D5ms => 5,
525            SleepDuration::D10ms => 10,
526            SleepDuration::D20ms => 20,
527            SleepDuration::D50ms => 50,
528            SleepDuration::ArbitraryMs(v) => v,
529        }
530    }
531}
532
533/// Sleep mode requested
534#[repr(C)]
535pub enum SleepMode {
536    /// Sleep in shallow mode. External events awake the job
537    Shallow,
538    /// Sleep in deep mode. No sleep interruption
539    Deep,
540}
541
542/// Converter for SleepMode type to register-encoded value
543impl From<SleepMode> for u32 {
544    fn from(mode: SleepMode) -> u32 {
545        match mode {
546            SleepMode::Shallow => 0,
547            SleepMode::Deep => 1,
548        }
549    }
550}
551
552/// Converter from register-encoded or C FFI defined value to SleepMode
553impl TryFrom<u32> for SleepMode {
554    type Error = Status;
555    fn try_from(mode: u32) -> Result<SleepMode, Self::Error> {
556        match mode {
557            0 => Ok(SleepMode::Shallow),
558            1 => Ok(SleepMode::Deep),
559            _ => Err(Status::Invalid),
560        }
561    }
562}
563
564/// Low power configuration support, defining the CPU sleep state exit event
565///
566/// There are multiple HW events that may terminate a low-power hardware cycle.
567/// These are separated in two main families:
568///
569/// - Interrupt event (external interrupt)
570/// - external event (not interrupt related)
571///
572/// Moreover, there is some time when the CPU must NOT enter sleep mode for a
573/// given amount of time. This can be set with this CPUSleep configuration state.
574///
575/// > **FIXME**: the sleep trigger and the sleep constraints shoud be defined in separated
576/// > types and calls.
577#[repr(C)]
578pub enum CPUSleep {
579    /// Enter sleep mode and wait for external interrupt
580    WaitForInterrupt,
581    /// Enter sleep mode and wait for external event
582    WaitForEvent,
583    /// Disable any enter to the low power mode
584    ForbidSleep,
585    /// Re-enable low power
586    AllowSleep,
587}
588
589impl From<CPUSleep> for u32 {
590    fn from(mode: CPUSleep) -> u32 {
591        match mode {
592            CPUSleep::WaitForInterrupt => 0,
593            CPUSleep::WaitForEvent => 1,
594            CPUSleep::ForbidSleep => 2,
595            CPUSleep::AllowSleep => 3,
596        }
597    }
598}
599
600impl TryFrom<u32> for CPUSleep {
601    type Error = Status;
602    fn try_from(mode: u32) -> Result<CPUSleep, Self::Error> {
603        match mode {
604            0 => Ok(CPUSleep::WaitForInterrupt),
605            1 => Ok(CPUSleep::WaitForEvent),
606            2 => Ok(CPUSleep::ForbidSleep),
607            3 => Ok(CPUSleep::AllowSleep),
608            _ => Err(Status::Invalid),
609        }
610    }
611}
612
613mirror_enum! {
614    u32,
615    pub enum Precision {
616        Cycle,
617        Nanoseconds,
618        Microseconds,
619        Milliseconds,
620    }
621}
622
623/// Header received from the kernel when waiting for at one event type
624///
625/// Received when returning from [`crate::syscall::wait_for_event`] syscall with
626/// a [`Status::Ok`] value.
627/// The kernel return data for a single event type at a time, store in event field,
628/// while wait_for_event() allows waiting for multiple event at a time.
629#[repr(C)]
630#[derive(Debug, Copy, Clone, PartialEq)]
631pub struct ExchangeHeader {
632    pub event: u8,
633    pub length: u8,
634    pub magic: u16,
635    pub peer: u32,
636}
637
638#[test]
639fn test_layout_exchange_header() {
640    const UNINIT: ::std::mem::MaybeUninit<ExchangeHeader> = ::std::mem::MaybeUninit::uninit();
641    let ptr = UNINIT.as_ptr();
642    assert_eq!(
643        ::std::mem::size_of::<ExchangeHeader>(),
644        8usize,
645        concat!("Size of: ", stringify!(ExchangeHeader))
646    );
647    assert_eq!(
648        ::std::mem::align_of::<ExchangeHeader>(),
649        4usize,
650        concat!("Alignment of ", stringify!(ExchangeHeader))
651    );
652    assert_eq!(
653        unsafe { ::std::ptr::addr_of!((*ptr).event) as usize - ptr as usize },
654        0usize,
655        concat!(
656            "Offset of field: ",
657            stringify!(ExchangeHeader),
658            "::",
659            stringify!(event)
660        )
661    );
662    assert_eq!(
663        unsafe { ::std::ptr::addr_of!((*ptr).length) as usize - ptr as usize },
664        1usize,
665        concat!(
666            "Offset of field: ",
667            stringify!(ExchangeHeader),
668            "::",
669            stringify!(length)
670        )
671    );
672    assert_eq!(
673        unsafe { ::std::ptr::addr_of!((*ptr).magic) as usize - ptr as usize },
674        2usize,
675        concat!(
676            "Offset of field: ",
677            stringify!(ExchangeHeader),
678            "::",
679            stringify!(magic)
680        )
681    );
682    assert_eq!(
683        unsafe { ::std::ptr::addr_of!((*ptr).peer) as usize - ptr as usize },
684        4usize,
685        concat!(
686            "Offset of field: ",
687            stringify!(ExchangeHeader),
688            "::",
689            stringify!(peer)
690        )
691    );
692}
693
694impl ExchangeHeader {
695    pub fn is_valid(self) -> bool {
696        // TODO: hard-coded by now
697        self.magic == 0x4242
698    }
699}
700
701/// Typical Event received by the kernel using the copy_from_kernel(my_event)
702///
703/// Event is SentryExchangeable, see [`crate::exchange::SentryExchangeable`] and
704/// the corresponding implementation for this struct for more information.
705///
706#[derive(Debug)]
707pub struct Event<'a> {
708    pub header: ExchangeHeader,
709    pub data: &'a mut [u8],
710}
711
712/// Device related types definitions
713pub mod dev {
714
715    #[repr(C)]
716    #[derive(Debug, Copy, Clone)]
717    pub struct InterruptInfo {
718        /// interrupt number
719        pub it_num: u16,
720        /// interrupt controler identifier
721        pub it_controler: u8,
722    }
723
724    #[test]
725    fn test_layout_it_info() {
726        const UNINIT: ::std::mem::MaybeUninit<InterruptInfo> = ::std::mem::MaybeUninit::uninit();
727        let ptr = UNINIT.as_ptr();
728        assert_eq!(
729            ::std::mem::size_of::<InterruptInfo>(),
730            4usize,
731            concat!("Size of: ", stringify!(InterruptInfo))
732        );
733        assert_eq!(
734            ::std::mem::align_of::<InterruptInfo>(),
735            2usize,
736            concat!("Alignment of ", stringify!(InterruptInfo))
737        );
738        assert_eq!(
739            unsafe { ::std::ptr::addr_of!((*ptr).it_num) as usize - ptr as usize },
740            0usize,
741            concat!(
742                "Offset of field: ",
743                stringify!(InterruptInfo),
744                "::",
745                stringify!(num)
746            )
747        );
748        assert_eq!(
749            unsafe { ::std::ptr::addr_of!((*ptr).it_controler) as usize - ptr as usize },
750            2usize,
751            concat!(
752                "Offset of field: ",
753                stringify!(InterruptInfo),
754                "::",
755                stringify!(controller)
756            )
757        );
758    }
759
760    #[repr(C)]
761    #[derive(Copy, Clone, Debug)]
762    pub struct IoInfo {
763        pub port: u8,
764        pub pin: u8,
765        pub mode: u8,
766        pub af: u8,
767        pub ppull: u8,
768        pub speed: u8,
769        pub pupdr: u8,
770    }
771
772    /// userspace oriented device definition
773    ///
774    #[repr(C)]
775    #[derive(Debug, Copy, Clone)]
776    pub struct DevInfo {
777        pub id: u8,
778        /// mappable device. Direct-IO (LED...) are not
779        /// Not parsed from the DTS, useless ?
780        pub mappable: bool,
781        /// for mappable devices, base address
782        pub baseaddr: usize,
783        /// for mappable devices, mapped size */\n/**<\n  number of device's interrupt.
784        /// Can be EXTI (button) or NVIC interrupts (SoC device)
785        pub size: usize,
786        /// number of device interrupts
787        pub num_interrupt: u8,
788        /// device interrupt list
789        pub its: [InterruptInfo; 8usize],
790        /// number of device I/O (pinmux)
791        pub num_ios: u8,
792        /// device I/O list
793        pub ios: [IoInfo; 8usize],
794    }
795}
796
797/// SHM related types definitions
798pub mod shm {
799
800    #[repr(C)]
801    #[derive(PartialEq, Debug, Copy, Clone)]
802    pub struct ShmInfo {
803        pub handle: crate::systypes::ShmHandle,
804        pub label: u32,
805        pub base: usize,
806        pub len: usize,
807        pub perms: u32,
808    }
809
810    #[test]
811    fn test_layout_shm_infos() {
812        const UNINIT: ::std::mem::MaybeUninit<ShmInfo> = ::std::mem::MaybeUninit::uninit();
813        let ptr = UNINIT.as_ptr();
814        assert_eq!(
815            ::std::mem::size_of::<ShmInfo>(),
816            32usize,
817            concat!("Size of: ", stringify!(ShmInfo))
818        );
819        assert_eq!(
820            ::std::mem::align_of::<ShmInfo>(),
821            8usize,
822            concat!("Alignment of ", stringify!(ShmInfo))
823        );
824        assert_eq!(
825            unsafe { ::std::ptr::addr_of!((*ptr).handle) as usize - ptr as usize },
826            0usize,
827            concat!(
828                "Offset of field: ",
829                stringify!(ShmInfo),
830                "::",
831                stringify!(handle)
832            )
833        );
834        assert_eq!(
835            unsafe { ::std::ptr::addr_of!((*ptr).label) as usize - ptr as usize },
836            4usize,
837            concat!(
838                "Offset of field: ",
839                stringify!(shm_infos),
840                "::",
841                stringify!(label)
842            )
843        );
844        assert_eq!(
845            unsafe { ::std::ptr::addr_of!((*ptr).base) as usize - ptr as usize },
846            8usize,
847            concat!(
848                "Offset of field: ",
849                stringify!(shm_infos),
850                "::",
851                stringify!(base)
852            )
853        );
854        assert_eq!(
855            unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize },
856            16usize,
857            concat!(
858                "Offset of field: ",
859                stringify!(shm_infos),
860                "::",
861                stringify!(len)
862            )
863        );
864        assert_eq!(
865            unsafe { ::std::ptr::addr_of!((*ptr).perms) as usize - ptr as usize },
866            24usize,
867            concat!(
868                "Offset of field: ",
869                stringify!(shm_infos),
870                "::",
871                stringify!(perms)
872            )
873        );
874    }
875}
876
877/// DMA related types definitions
878///
879/// In order to help with proper hierarchy of types for Sentry UAPI, syscall families
880/// that requires a lot of shared types. This is the case of the DMA subsystem for
881/// which all related types and types helpers are stored in the dma submodule.
882pub mod dma {
883    // FIXME: this enum is used for bitfield-based manipulation, as the
884    // interrupts field is a local OR of this enumerate values
885    pub enum GpdmaChanInt {
886        /// DMA channel trigger on transfer complete
887        TransferComplete = 1,
888        /// DMA channel trigger on half transfer and transfer complete
889        HalfTransfer = 2,
890        /// triggers on DMA transfer or config error, get status for complete information
891        DmaError = 4,
892    }
893
894    // FIXME: the interrupts field is a bitfield of one to 3 possible interrupts
895    // we mai consider intlevels (TC+Error, TC+HT+Error, etc.) meaning that the field
896    // is no more a bitfield
897    impl TryFrom<u8> for GpdmaChanInt {
898        type Error = crate::systypes::Status;
899        fn try_from(mode: u8) -> Result<GpdmaChanInt, Self::Error> {
900            match mode {
901                1 => Ok(GpdmaChanInt::TransferComplete),
902                2 => Ok(GpdmaChanInt::HalfTransfer),
903                4 => Ok(GpdmaChanInt::DmaError),
904                _ => Err(crate::systypes::Status::Invalid),
905            }
906        }
907    }
908
909    pub enum GpdmaTransferType {
910        MemoryToDevice = 0,
911        DeviceToMemory = 1,
912        MemoryToMemory = 2,
913        DeviceToDevice = 3,
914    }
915
916    impl TryFrom<u16> for GpdmaTransferType {
917        type Error = crate::systypes::Status;
918        fn try_from(mode: u16) -> Result<GpdmaTransferType, Self::Error> {
919            match mode {
920                0 => Ok(GpdmaTransferType::MemoryToDevice),
921                1 => Ok(GpdmaTransferType::DeviceToMemory),
922                2 => Ok(GpdmaTransferType::MemoryToMemory),
923                3 => Ok(GpdmaTransferType::DeviceToDevice),
924                _ => Err(crate::systypes::Status::Invalid),
925            }
926        }
927    }
928
929    // FIXME: this is a bitmask. We may consider moving to enum value instead
930    // for e.g. by using IncrementBoth = 3
931    pub enum GpdmaTransferMode {
932        IncrementNone = 0,
933        IncrementSrc = 1,
934        IncrementDest = 2,
935    }
936
937    pub enum GpdmaBeatLen {
938        /// Data len to manipulate is in bytes
939        Byte = 0,
940        /// Data len to manipulate is in half word
941        Halfword = 1,
942        /// Data len to manipulate is in word
943        Word = 2,
944    }
945
946    impl TryFrom<u8> for GpdmaBeatLen {
947        type Error = crate::systypes::Status;
948        fn try_from(mode: u8) -> Result<GpdmaBeatLen, Self::Error> {
949            match mode {
950                0 => Ok(GpdmaBeatLen::Byte),
951                1 => Ok(GpdmaBeatLen::Halfword),
952                2 => Ok(GpdmaBeatLen::Word),
953                _ => Err(crate::systypes::Status::Invalid),
954            }
955        }
956    }
957
958    pub enum GpdmaPriority {
959        Low = 0,
960        Medium = 1,
961        High = 2,
962        VeryHigh = 3,
963    }
964
965    impl TryFrom<u8> for GpdmaPriority {
966        type Error = crate::systypes::Status;
967        fn try_from(mode: u8) -> Result<GpdmaPriority, Self::Error> {
968            match mode {
969                0 => Ok(GpdmaPriority::Low),
970                1 => Ok(GpdmaPriority::Medium),
971                2 => Ok(GpdmaPriority::High),
972                3 => Ok(GpdmaPriority::VeryHigh),
973                _ => Err(crate::systypes::Status::Invalid),
974            }
975        }
976    }
977
978    /// DMA static configuration information
979    ///
980    /// # Usage
981    ///
982    /// This structure is delivered by the kernel into svc_exchange when
983    /// calling successfully [`crate::syscall::dma_get_stream_info()`].
984    ///
985    /// The structure content correspond to the static build-time information
986    /// as defined in the device-tree and do not require any DTS manipulation
987    /// in user-space.
988    ///
989    /// # Example
990    ///
991    /// ```ignore
992    /// let dmacfg: dma_stream_cfg;
993    /// match get_dma_stream_info(dmah) {
994    ///    Status::Ok => (svc_exchange::copy_from(&dma_stream_cfg, mem::sizeof(dma_stream_cfg)))
995    /// }
996    /// ```
997    ///
998    #[repr(C)]
999    #[derive(Debug, Copy, Clone)]
1000    pub struct GpdmaStreamConfig {
1001        pub channel: u16,
1002        pub stream: u16,
1003        pub controller: u16,
1004        pub transfer_type: u16,
1005        pub source: usize,
1006        pub dest: usize,
1007        pub transfer_len: usize,
1008        pub circular_source: bool,
1009        pub circular_dest: bool,
1010        pub interrupts: u8,
1011        pub is_triggered: bool,
1012        pub trigger: u8,
1013        pub priority: u8,
1014        pub transfer_mode: u8,
1015        pub src_beat_len: u8,
1016        pub dest_beat_len: u8,
1017    }
1018
1019    // test that the Rust structure fields offset do match the corresponding C one,
1020    // as the kernel delivers in its ABI the C-defined structure
1021    #[test]
1022    fn test_layout_gpdma_stream_cfg() {
1023        const UNINIT: ::std::mem::MaybeUninit<GpdmaStreamConfig> =
1024            ::std::mem::MaybeUninit::uninit();
1025        let ptr = UNINIT.as_ptr();
1026        assert_eq!(
1027            ::std::mem::size_of::<GpdmaStreamConfig>(),
1028            48usize,
1029            concat!("Size of: ", stringify!(GpdmaStreamConfig))
1030        );
1031        assert_eq!(
1032            ::std::mem::align_of::<GpdmaStreamConfig>(),
1033            8usize,
1034            concat!("Alignment of ", stringify!(GpdmaStreamConfig))
1035        );
1036        assert_eq!(
1037            unsafe { ::std::ptr::addr_of!((*ptr).channel) as usize - ptr as usize },
1038            0usize,
1039            concat!(
1040                "Offset of field: ",
1041                stringify!(GpdmaStreamConfig),
1042                "::",
1043                stringify!(channel)
1044            )
1045        );
1046        assert_eq!(
1047            unsafe { ::std::ptr::addr_of!((*ptr).stream) as usize - ptr as usize },
1048            2usize,
1049            concat!(
1050                "Offset of field: ",
1051                stringify!(gpdma_stream_cfg),
1052                "::",
1053                stringify!(stream)
1054            )
1055        );
1056        assert_eq!(
1057            unsafe { ::std::ptr::addr_of!((*ptr).controller) as usize - ptr as usize },
1058            4usize,
1059            concat!(
1060                "Offset of field: ",
1061                stringify!(gpdma_stream_cfg),
1062                "::",
1063                stringify!(controller)
1064            )
1065        );
1066        assert_eq!(
1067            unsafe { ::std::ptr::addr_of!((*ptr).transfer_type) as usize - ptr as usize },
1068            6usize,
1069            concat!(
1070                "Offset of field: ",
1071                stringify!(gpdma_stream_cfg),
1072                "::",
1073                stringify!(transfer_type)
1074            )
1075        );
1076        assert_eq!(
1077            unsafe { ::std::ptr::addr_of!((*ptr).source) as usize - ptr as usize },
1078            8usize,
1079            concat!(
1080                "Offset of field: ",
1081                stringify!(gpdma_stream_cfg),
1082                "::",
1083                stringify!(source)
1084            )
1085        );
1086        assert_eq!(
1087            unsafe { ::std::ptr::addr_of!((*ptr).dest) as usize - ptr as usize },
1088            16usize,
1089            concat!(
1090                "Offset of field: ",
1091                stringify!(gpdma_stream_cfg),
1092                "::",
1093                stringify!(dest)
1094            )
1095        );
1096        assert_eq!(
1097            unsafe { ::std::ptr::addr_of!((*ptr).transfer_len) as usize - ptr as usize },
1098            24usize,
1099            concat!(
1100                "Offset of field: ",
1101                stringify!(gpdma_stream_cfg),
1102                "::",
1103                stringify!(transfer_len)
1104            )
1105        );
1106        assert_eq!(
1107            unsafe { ::std::ptr::addr_of!((*ptr).circular_source) as usize - ptr as usize },
1108            32usize,
1109            concat!(
1110                "Offset of field: ",
1111                stringify!(gpdma_stream_cfg),
1112                "::",
1113                stringify!(circular_source)
1114            )
1115        );
1116        assert_eq!(
1117            unsafe { ::std::ptr::addr_of!((*ptr).circular_dest) as usize - ptr as usize },
1118            33usize,
1119            concat!(
1120                "Offset of field: ",
1121                stringify!(gpdma_stream_cfg),
1122                "::",
1123                stringify!(circular_dest)
1124            )
1125        );
1126        assert_eq!(
1127            unsafe { ::std::ptr::addr_of!((*ptr).interrupts) as usize - ptr as usize },
1128            34usize,
1129            concat!(
1130                "Offset of field: ",
1131                stringify!(gpdma_stream_cfg),
1132                "::",
1133                stringify!(interrupts)
1134            )
1135        );
1136        assert_eq!(
1137            unsafe { ::std::ptr::addr_of!((*ptr).is_triggered) as usize - ptr as usize },
1138            35usize,
1139            concat!(
1140                "Offset of field: ",
1141                stringify!(gpdma_stream_cfg),
1142                "::",
1143                stringify!(is_triggered)
1144            )
1145        );
1146        assert_eq!(
1147            unsafe { ::std::ptr::addr_of!((*ptr).trigger) as usize - ptr as usize },
1148            36usize,
1149            concat!(
1150                "Offset of field: ",
1151                stringify!(gpdma_stream_cfg),
1152                "::",
1153                stringify!(trigger)
1154            )
1155        );
1156        assert_eq!(
1157            unsafe { ::std::ptr::addr_of!((*ptr).priority) as usize - ptr as usize },
1158            37usize,
1159            concat!(
1160                "Offset of field: ",
1161                stringify!(gpdma_stream_cfg),
1162                "::",
1163                stringify!(priority)
1164            )
1165        );
1166        assert_eq!(
1167            unsafe { ::std::ptr::addr_of!((*ptr).transfer_mode) as usize - ptr as usize },
1168            38usize,
1169            concat!(
1170                "Offset of field: ",
1171                stringify!(gpdma_stream_cfg),
1172                "::",
1173                stringify!(transfer_mode)
1174            )
1175        );
1176        assert_eq!(
1177            unsafe { ::std::ptr::addr_of!((*ptr).src_beat_len) as usize - ptr as usize },
1178            39usize,
1179            concat!(
1180                "Offset of field: ",
1181                stringify!(gpdma_stream_cfg),
1182                "::",
1183                stringify!(src_beat_len)
1184            )
1185        );
1186        assert_eq!(
1187            unsafe { ::std::ptr::addr_of!((*ptr).dest_beat_len) as usize - ptr as usize },
1188            40usize,
1189            concat!(
1190                "Offset of field: ",
1191                stringify!(gpdma_stream_cfg),
1192                "::",
1193                stringify!(dest_beat_len)
1194            )
1195        );
1196    }
1197
1198    pub enum GpdmaChanState {
1199        Idle = 1,
1200        Running = 2,
1201        Aborted = 3,
1202        Suspended = 4,
1203        TransmissionFailure = 5,
1204        ConfigurationFailure = 6,
1205        Overrun = 7,
1206        TransferComplete = 8,
1207        HalfTransfer = 9,
1208    }
1209}