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}