sentry_uapi/
systypes.rs

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