atsamd_hal/peripherals/
icm.rs

1//! # ICM - Integrity Check Module
2//!
3//! Used to calculate SHA digests of memory regions
4//!
5//! Multiple modes available
6//!
7//! * Manual monitor of Internal SRAM (both contiguous and non-contiguous
8//!   memory)
9//! * Active monitoring of Internal SRAM (both contiguous and non-contiguous
10//!   memory)
11//! * Manual monitor of Internal Flash (both contiguous memory)
12//! * Generates Hash using SHA engine, useful for verifying content
13//! * ICM module has additional register protection and tamper detection
14//!
15//! Reading the Interrupt Status Register (ISR) clears the register,
16//! to provide a workaround for cases where multiple bits needs parsing,
17//! the [`Icm::get_interrupt_status()`] and
18//! [`Region<I>::get_interrupt_status()`] are provided.
19//! These return a queryable structure containing the interrupt register
20//! contents. Allowing multiple different interrupts to be read.
21//!
22//! >**IMPORTANT** - Memory safety considerations
23//! >
24//! >The ICM engine accesses the assigned `DSCR` memory address, so it must be
25//! >available. Depending on the application, this might entail making
26//! >[`Regions`] **static**.
27//! >
28//! >The same goes for [`HashArea`], but here it is even more **important** to
29//! >ensure the memory is designated for `HashArea` usage, since the ICM
30//! >controller will, depending on ICM configuration, write data to that
31//! >address.
32//! >
33//! >Setting [`HashArea`] **static** might be the safest path.
34//! >
35//! > Another alternative is to utilise the singleton macro provided by
36//! > [`cortex_m::singleton`](https://docs.rs/cortex-m/latest/cortex_m/macro.singleton.html)
37//! > ```no_run
38//! > # use atsamd_hal::{pac::Peripherals, icm::*};
39//! > use cortex_m::singleton;
40//! >
41//! > let hasharea: &'static mut HashArea =
42//! > singleton!(: HashArea = HashArea::default()).unwrap();
43//! > ```
44
45//!
46//! ## Usage:
47//!
48//! ### General ICM setup
49//!
50//! Initialise the ICM engine [`Icm::new()`] and reset ICM via [`Icm::swrst()`]
51//!
52//! Change any of the global options such as [`Icm::set_eomdis()`], if required.
53//!
54//! Enable and create the interface for required memory regions
55//! [`Icm::enable_region0()`] and enable it via
56//! [`Region::enable_monitoring()`]
57//!
58//! Depending on the number of regions required, the helper
59//! [`Regions::default()`] alows setting up all 4 regions directly, if one
60//! region is sufficient, manually create  [`MainRegionDesc<Region0>::
61//! default()`].
62//!
63//!  Modify the [`MainRegionDesc`], see documentation and cargo doc for all
64//! methods.
65//!
66//!  Set the `DSCR` address to the beginning of the [`MainRegionDesc`] via
67//!  [`Icm::set_dscr_addr()`] (or via helper in
68//! [`MainRegionDesc<Region0>::set_dscr_addr()`])
69//!
70//!  Via [`Region`], setup the desired interrupts depending on usecase.
71//!
72//!  To view which interrupts has been enabled in the debugger, check the
73//! `ICM->IMR` register.
74//!
75//!  Any object in memory can be used as the "Hash" area, but for convenience
76//! the provided  [`HashArea`] allows indexing of the 4 regions and is
77//! correctly memory aligned.
78//!
79//!  Set the pointer to [`HashArea`] via [`Icm::set_hash_addr()`]
80//!
81//!  **See note about memory safety above**
82//!
83//! ### Hash calculation
84//!
85//! Assuming general setup is already done, modify the [`RegionConfiguration`]
86//! which is part of the [`MainRegionDesc`]:
87//!
88//! * [`RegionConfiguration::set_rhien()`] to `false` to allow interrupts when
89//!   calculation is done
90//! * [`RegionConfiguration::set_eom()`] to `true` only for the last region
91//!
92//! Change [`RegionAddress`] to point to the object to SHA-sum with
93//! [`MainRegionDesc<RegionNumT>::set_region_address()`]
94//!
95//! ### Memory monitoring
96//!
97//! [`HashArea`] needs to contain the expected SHA-sums of the data to
98//! monitor, [`Icm::set_ascd()`] is provided to help with creating this data.
99//! Alternatively do it manually and then change mode, or prepopulate the
100//! [`HashArea`] with SHA-sums.
101//!
102//! Assuming general setup is already done, modify the [`RegionConfiguration`]
103//! which is part of the [`MainRegionDesc`]:
104//!
105//! * [`RegionConfiguration::set_dmien()`] to `false` to allow interrupts if
106//!   mismatch occurs
107//! * [`RegionConfiguration::set_cdwbn()`] to `true` to change to monitor mode
108//! * [`RegionConfiguration::set_wrap()`] to `true` only for the last region if
109//!   continuous monitoring is desired
110//!
111//! ## Examples
112//!
113//! ### Calculate SHA1, SHA224 and SHA256 sums, then switch to memory monitor
114//!
115//! 4 memory regions, SHA1 in region0 and region1.
116//! Region2 uses SHA224 and region3 SHA256.
117//!
118//! This only covers the setup part, to achieve the functionality of first
119//! computing the SHA-sums and then do region monitoring handling of
120//! interrupts and changing mode is required.
121//!
122//! ```no_run
123//! # use atsamd_hal::{pac::Peripherals, icm::*};
124//!
125//! // SHA Test data
126//! static MESSAGE_REF0: [u32; 16] = [
127//!     0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888,
128//!     0x99999999, 0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd, 0xeeeeeeee, 0xffffffff, 0x00000000,
129//! ];
130//!
131//! static MESSAGE_REF1: [u32; 16] = [
132//!     0x80636261, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
133//!     0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x18000000,
134//! ];
135//!
136//! // Expected SHA1 sum result
137//! static MESSAGE_SHA1_RES: [u32; 8] = [
138//!     0x363e99a9, 0x6a810647, 0x71253eba, 0x6cc25078, 0x9dd8d09c, 0x00000000, 0x00000000, 0x00000000,
139//! ];
140//!
141//! static MESSAGE_SHA224_RES: [u32; 8] = [
142//!     0x227d0923, 0x22d80534, 0x77a44286, 0xb355a2bd, 0xe4bcad2a, 0xf7b3a0bd, 0xa79d6ce3, 0x00000000,
143//! ];
144//! static MESSAGE_SHA256_RES: [u32; 8] = [
145//!     0xbf1678ba, 0xeacf018f, 0xde404141, 0x2322ae5d, 0xa36103b0, 0x9c7a1796, 0x61ff10b4, 0xad1500f2,
146//! ];
147//! static mut HASH: HashArea = HashArea::default();
148//! static mut ICM_REGION_DESC: Regions = Regions::default();
149//!
150//! // Alternatively
151//! //use cortex_m::singleton;
152//! //let hasharea: &'static mut HashArea = singleton!(: HashArea = HashArea::default()).unwrap();
153//!
154//! // Enable ICM apb clock
155//! // Clock v1
156//! //mclk.apbcmask.modify(|_, w| w.icm_().set_bit());
157//! // Clock v2
158//! //tokens.apbs.icm.enable();
159//!
160//! let mut peripherals = Peripherals::take().unwrap();
161//!
162//! // Create new ICM
163//! let mut icm = Icm::new(peripherals.ICM);
164//!
165//! // Reset the ICM, clearing past error states
166//! icm.swrst();
167//!
168//! // End of Monitoring is permitted
169//! icm.set_eomdis(false);
170//! // Write Back is permitted
171//! icm.set_wbdis(false);
172//! // Secondary List branching is forbidden
173//! icm.set_slbdis(false);
174//! // Automatic Switch to Compare is disabled
175//! icm.set_ascd(false);
176//!
177//! // Region Descriptor
178//! let mut icm_region_desc = Regions::default();
179//!
180//! // Get the interface for Region0 and enable monitoring
181//! let icm_region0 = icm.enable_region0();
182//! icm_region0.enable_monitoring();
183//!
184//! // Setup desired interrupts
185//! //
186//! // Region Hash Completed
187//! icm_region0.set_rhc_int();
188//!
189//! // Region0 raddr
190//! icm_region_desc.region0.set_region_address(MESSAGE_REF0.as_ptr());
191//!
192//! // Configure the RCFG
193//!
194//! // Some are default values, just as an example
195//!
196//! // Activate Write back (should be true when comparing memory)
197//! icm_region_desc.region0.rcfg.set_cdwbn(false);
198//! // Should the ICM controller loop back to DSCR after this region?
199//! icm_region_desc.region0.rcfg.set_wrap(false);
200//! // Set this as the end of descriptor linked list
201//! icm_region_desc.region0.rcfg.set_eom(false);
202//! // The RHC flag is set when the field NEXT = 0
203//! // in a descriptor of the main or second list
204//! icm_region_desc.region0.rcfg.set_rhien(false);
205//! // Set Algorithm to SHA1
206//! icm_region_desc.region0.rcfg.set_algo(icm_algorithm::SHA1);
207//!
208//! // Get the interface for region1
209//! let icm_region1 = icm.enable_region1();
210//!
211//! // Enable region monitoring
212//! icm_region1.enable_monitoring();
213//!
214//! // Setup desired interrupts
215//! //
216//! // Region Hash Completed
217//! icm_region1.set_rhc_int();
218//!
219//! // Region1 raddr
220//! icm_region_desc.region1.set_region_address(MESSAGE_REF1.as_ptr());
221//!
222//! // Configure the RCFG
223//! // The RHC flag is set when the field NEXT = 0
224//! // in a descriptor of the main or second list
225//! icm_region_desc.region1.rcfg.set_rhien(false);
226//! // Set Algorithm to SHA1
227//! icm_region_desc.region1.rcfg.set_algo(icm_algorithm::SHA1);
228//!
229//! // Get the interface for region2
230//! let icm_region2 = icm.enable_region2();
231//!
232//! // Enable region monitoring
233//! icm_region2.enable_monitoring();
234//!
235//! // Setup desired interrupts
236//! //
237//! // Region Hash Completed
238//! icm_region2.set_rhc_int();
239//!
240//! // Region2 raddr
241//! icm_region_desc.region2.set_region_address(MESSAGE_REF1.as_ptr());
242//!
243//! // Configure the RCFG
244//! // The RHC flag is set when the field NEXT = 0
245//! // in a descriptor of the main or second list
246//! icm_region_desc.region2.rcfg.set_rhien(false);
247//! // Set Algorithm to SHA224
248//! icm_region_desc.region2.rcfg.set_algo(icm_algorithm::SHA224);
249//!
250//! // Get the interface for region3
251//! let icm_region3 = icm.enable_region3();
252//!
253//! // Enable region monitoring
254//! icm_region3.enable_monitoring();
255//!
256//! // Setup desired interrupts
257//! //
258//! // Region Hash Completed
259//! icm_region3.set_rhc_int();
260//!
261//! // Region3 raddr
262//! icm_region_desc.region3.set_region_address(MESSAGE_REF1.as_ptr());
263//!
264//! // Configure the RCFG
265//! //
266//! // Set this as the end of descriptor linked list
267//! icm_region_desc.region3.rcfg.set_eom(true);
268//! // The RHC flag is set when the field NEXT = 0
269//! // in a descriptor of the main or second list
270//! icm_region_desc.region3.rcfg.set_rhien(false);
271//! // Set Algorithm to SHA256
272//! icm_region_desc.region3.rcfg.set_algo(icm_algorithm::SHA256);
273//!
274//! unsafe {
275//!     // Hash Area
276//!     // Set HASH addr to the beginning of the Hash area
277//!     icm.set_hash_addr(&HASH);
278//! }
279//!
280//! unsafe {
281//!     // Move the icm_region_desc into static
282//!     ICM_REGION_DESC = icm_region_desc;
283//!     // Set DSCR to the beginning of the region descriptor
284//!     icm.set_dscr_addr(&ICM_REGION_DESC.region0);
285//!     // the same but via helper function
286//!     //ICM_REGION_DESC.region0.set_dscr_addr(&icm);
287//! }
288//!
289//! // Start the ICM calculation
290//! icm.enable();
291//!
292//! // Setup memory region monitoring
293//! // Monitor all 4 memory regions
294//!
295//! // Setup the compare regions
296//! let mut message_region0_sha1 = MESSAGE_REF0;
297//! let mut message_region1_sha1 = MESSAGE_REF1;
298//! let mut message_region2_sha224 = MESSAGE_REF1;
299//! let mut message_region3_sha256 = MESSAGE_REF1;
300//!
301//! // Reset the ICM, clearing past error states
302//! icm.swrst();
303//!
304//! // End of Monitoring is permitted
305//! icm.set_eomdis(false);
306//! // Write Back is permitted
307//! icm.set_wbdis(false);
308//! // Secondary List branching is forbidden
309//! icm.set_slbdis(false);
310//! // Automatic Switch to Compare is disabled
311//! icm.set_ascd(false);
312//!
313//! // Also possible to directly edit `ICM_REGION_DESC`
314//! // in an unsafe block
315//! let mut icm_region_desc = Regions::default();
316//!
317//! // Setup region 0 to monitor memory
318//! icm_region_desc
319//!     .region0
320//!     .set_region_address(&message_region0_sha1);
321//! icm_region_desc.region0.rcfg.reset_region_configuration_to_default();
322//! icm_region_desc.region0.rcfg.set_algo(icm_algorithm::SHA1);
323//! // Activate Compare Digest (should be true when comparing memory)
324//! icm_region_desc.region0.rcfg.set_cdwbn(true);
325//! // Digest Mismatch Interrupt Disable (enabled)
326//! icm_region_desc.region0.rcfg.set_dmien(false);
327//!
328//! // Set Region Mismatch Interrupt
329//! icm_region0.set_rdm_int();
330//!
331//! // Setup region 1 to monitor memory
332//! icm_region_desc
333//!     .region1
334//!     .set_region_address(&message_region1_sha1);
335//! icm_region_desc.region1.rcfg.reset_region_configuration_to_default();
336//! icm_region_desc.region1.rcfg.set_algo(icm_algorithm::SHA1);
337//! // Activate Compare Digest (should be true when comparing memory)
338//! icm_region_desc.region1.rcfg.set_cdwbn(true);
339//! // Digest Mismatch Interrupt Disable (enabled)
340//! icm_region_desc.region1.rcfg.set_dmien(false);
341//!
342//! // Set Region Mismatch Interrupt
343//! icm_region1.set_rdm_int();
344//!
345//! // Setup region 2 to monitor memory
346//! icm_region_desc
347//!     .region2
348//!     .set_region_address(&message_region2_sha224);
349//! icm_region_desc.region2.rcfg.reset_region_configuration_to_default();
350//! icm_region_desc.region2.rcfg.set_algo(icm_algorithm::SHA224);
351//! // Activate Compare Digest (should be true when comparing memory)
352//! icm_region_desc.region2.rcfg.set_cdwbn(true);
353//! // Digest Mismatch Interrupt Disable (enabled)
354//! icm_region_desc.region2.rcfg.set_dmien(false);
355//!
356//! // Set Region Mismatch Interrupt
357//! icm_region2.set_rdm_int();
358//!
359//! // Setup region 3 to monitor memory
360//! icm_region_desc
361//!     .region3
362//!     .set_region_address(&message_region3_sha256);
363//! icm_region_desc.region3.rcfg.reset_region_configuration_to_default();
364//! icm_region_desc.region3.rcfg.set_algo(icm_algorithm::SHA256);
365//! // Activate Compare Digest (should be true when comparing memory)
366//! icm_region_desc.region3.rcfg.set_cdwbn(true);
367//! // Digest Mismatch Interrupt Disable (enabled)
368//! icm_region_desc.region3.rcfg.set_dmien(false);
369//! // Wrap
370//! icm_region_desc.region3.rcfg.set_wrap(true);
371//!
372//! // Set Region Mismatch Interrupt
373//! icm_region3.set_rdm_int();
374//!
375//! // Modify regions to trigger interrupts
376//! message_region0_sha1[3] = 0xDEAD_BEEF;
377//! message_region1_sha1[4] = 0xDEAD_BEEF;
378//! message_region2_sha224[5] = 0xDEAD_BEEF;
379//! message_region3_sha256[6] = 0xDEAD_BEEF;
380//!
381//! icm.enable()
382use crate::pac::icm::uasr::Uratselect;
383
384use paste::paste;
385use seq_macro::seq;
386
387use bitflags::bitflags;
388
389use crate::pac::icm::*;
390use crate::typelevel::Sealed;
391use core::marker::PhantomData;
392
393/// Reexport the User SHA Algorithm
394pub use crate::icm::cfg::Ualgoselect as icm_algorithm;
395
396// Convenient bitflags representing select parts of
397// the status interrupt register `ICM->ISR`
398
399bitflags! {
400    /// Region Hash Completed interrupt
401    ///
402    /// Bit number matches with region number
403    pub struct RegionHashCompleted: u8 {
404        const R0 = 1;
405        const R1 = 2;
406        const R2 = 4;
407        const R3 = 8;
408    }
409}
410bitflags! {
411    /// Region Digest Mismatch interrupt
412    ///
413    /// Bit number matches with region number
414    pub struct RegionDigestMismatch: u8 {
415        const R0 = 1;
416        const R1 = 2;
417        const R2 = 4;
418        const R3 = 8;
419    }
420}
421
422bitflags! {
423    /// Region Bus Error interrupt
424    ///
425    /// Bit number matches with region number
426    pub struct RegionBusError: u8 {
427        const R0 = 1;
428        const R1 = 2;
429        const R2 = 4;
430        const R3 = 8;
431    }
432}
433
434bitflags! {
435    /// Region Wrap Condition detected interrupt
436    ///
437    /// Bit number matches with region number
438    pub struct RegionWrapConditionDetected: u8 {
439        const R0 = 1;
440        const R1 = 2;
441        const R2 = 4;
442        const R3 = 8;
443    }
444}
445bitflags! {
446    /// Region End Condition detected interrupt
447    ///
448    /// Bit number matches with region number
449    pub struct RegionEndConditionDetected: u8 {
450        const R0 = 1;
451        const R1 = 2;
452        const R2 = 4;
453        const R3 = 8;
454    }
455}
456bitflags! {
457    /// Region Status Update detected interrupt
458    ///
459    /// Bit number matches with region number
460    pub struct RegionStatusUpdatedDetected: u8 {
461        const R0 = 1;
462        const R1 = 2;
463        const R2 = 4;
464        const R3 = 8;
465    }
466}
467
468bitfield::bitfield! {
469    /// Struct useful for returning the interrupt status
470    /// of the ICM. Provides methods for easy parsing of
471    /// all the regions or via the `bitmask` argument
472    /// narrow it down to the specific set of [`RegionNum`]
473    /// of interest.
474    #[derive(Default)]
475    pub struct Interrupt(u32);
476    impl Debug;
477    u8;
478    get_rhc, _: 3, 0;
479    get_rdm, _: 7, 4;
480    get_rbe, _: 11, 8;
481    get_rwc, _: 15, 12;
482    get_rec, _: 19, 16;
483    get_rsu, _: 23, 20;
484    get_urad, _: 24, 24;
485}
486
487impl Interrupt {
488    /// Region Status Updated interrupt status
489    #[inline]
490    pub fn get_rsu_int(&self) -> RegionStatusUpdatedDetected {
491        RegionStatusUpdatedDetected::from_bits_truncate(self.get_rsu())
492    }
493
494    /// Region End bit Condition Detected interrupt status
495    #[inline]
496    pub fn get_rec_int(&self) -> RegionEndConditionDetected {
497        RegionEndConditionDetected::from_bits_truncate(self.get_rec())
498    }
499
500    /// Region Wrap Condition detected interrupt status
501    #[inline]
502    pub fn get_rwc_int(&self) -> RegionWrapConditionDetected {
503        RegionWrapConditionDetected::from_bits_truncate(self.get_rwc())
504    }
505
506    /// Region Bus Error interrupt status
507    #[inline]
508    pub fn get_rbe_int(&self) -> RegionBusError {
509        RegionBusError::from_bits_truncate(self.get_rbe())
510    }
511
512    /// Region Digest Mis interrupt status
513    #[inline]
514    pub fn get_rdm_int(&self) -> RegionDigestMismatch {
515        RegionDigestMismatch::from_bits_truncate(self.get_rdm())
516    }
517
518    /// Region Hash Completed interrupt status
519    #[inline]
520    pub fn get_rhc_int(&self) -> RegionHashCompleted {
521        RegionHashCompleted::from_bits_truncate(self.get_rhc())
522    }
523}
524
525/// Struct useful for returning the interrupt status
526/// of the ICM. Provides methods for easy parsing of
527/// the region specific [`RegionNum`]
528pub struct RegionInterrupt<I: RegionNum> {
529    region: PhantomData<I>,
530    interrupt: Interrupt,
531}
532
533macro_rules! match_on_interrupt_status {
534    ($self:ident, $name:ident) => {
535        paste! {
536            matches!($self.interrupt.[<get_$name>]() & $self.mask(), 1)
537        }
538    };
539}
540
541impl<I: RegionNum> RegionInterrupt<I> {
542    /// Used to mask out the correct bit based on [`RegionNum`]
543    #[inline]
544    fn mask(&self) -> u8 {
545        1 << I::NUM
546    }
547
548    /// Region Status Updated interrupt status
549    #[inline]
550    pub fn get_rsu_int(&self) -> bool {
551        match_on_interrupt_status!(self, rsu)
552    }
553
554    /// Region End bit Condition Detected interrupt status
555    #[inline]
556    pub fn get_rec_int(&self) -> bool {
557        match_on_interrupt_status!(self, rec)
558    }
559
560    /// Region Wrap Condition detected interrupt status
561    #[inline]
562    pub fn get_rwc_int(&self) -> bool {
563        match_on_interrupt_status!(self, rwc)
564    }
565
566    /// Region Bus Error interrupt status
567    #[inline]
568    pub fn get_rbe_int(&self) -> bool {
569        match_on_interrupt_status!(self, rbe)
570    }
571
572    /// Region Digest Mismatch interrupt status
573    #[inline]
574    pub fn get_rdm_int(&self) -> bool {
575        match_on_interrupt_status!(self, rdm)
576    }
577
578    /// Region Hash Completed interrupt status
579    #[inline]
580    pub fn get_rhc_int(&self) -> bool {
581        match_on_interrupt_status!(self, rhc)
582    }
583}
584
585/// Region provides access to region-specific
586/// settings like interrupts and status
587pub struct Region<I: RegionNum> {
588    region: PhantomData<I>,
589}
590
591macro_rules! match_on_interrupt_mask {
592    ($self:ident, $name:ident) => {
593        paste! {
594            matches!($self.imr().read().[<$name>]().bits() & $self.mask(), 1)
595        }
596    };
597}
598macro_rules! match_on_interrupt_status {
599    ($self:ident, $name:ident) => {
600        paste! {
601            matches!($self.isr().read().[<$name>]().bits() & $self.mask(), 1)
602        }
603    };
604}
605
606impl<I: RegionNum> Region<I> {
607    pub(super) fn new() -> Self {
608        Self {
609            region: PhantomData,
610        }
611    }
612
613    /// Used to mask out the correct bit based on [`RegionNum`]
614    #[inline]
615    fn mask(&self) -> u8 {
616        1 << I::NUM
617    }
618
619    /// Provides the base pointer to the [``] registers
620    ///
621    /// # Safety
622    ///
623    /// Only one [Region] accessible at any given time
624    #[inline]
625    fn icm(&self) -> &RegisterBlock {
626        unsafe { &*crate::pac::Icm::ptr() }
627    }
628
629    /// Control
630    #[inline]
631    fn ctrl(&self) -> &Ctrl {
632        self.icm().ctrl()
633    }
634
635    /// Interrupt Disable
636    #[inline]
637    fn idr(&self) -> &Idr {
638        self.icm().idr()
639    }
640
641    /// Interrupt Enable
642    #[inline]
643    fn ier(&self) -> &Ier {
644        self.icm().ier()
645    }
646
647    /// Interrupt Mask
648    #[inline]
649    fn imr(&self) -> &Imr {
650        self.icm().imr()
651    }
652
653    /// Interrupt Status
654    #[inline]
655    fn isr(&self) -> &Isr {
656        self.icm().isr()
657    }
658
659    /// Status
660    #[inline]
661    fn sr(&self) -> &Sr {
662        self.icm().sr()
663    }
664
665    // Beginning of helper functions
666
667    /// Enable this memory monitor region
668    #[inline]
669    pub fn enable_monitoring(&self) {
670        // Each bit in the register represents one of the
671        // four memory regions. Writing 0 does not change
672        // the state of the region, to disable the regon,
673        // writing to `rmdis` is required.
674        self.ctrl().write(|w| unsafe { w.rmen().bits(self.mask()) });
675    }
676
677    /// Returns true if the region monitoring is active and a check value has
678    /// been calculated and written to the hash area
679    #[inline]
680    pub fn get_monitoring_status(&self) -> bool {
681        // If the region monitor disabled bit is set,
682        // then the region monitoring is disabled
683        self.sr().read().rmdis().bits() & self.mask() != 1
684    }
685
686    /// Returns true if the `RMEN` register has been set to one for the region
687    #[inline]
688    pub fn get_monitoring_raw_status(&self) -> bool {
689        // If the region monitor disabled bit is set,
690        // then the region monitoring is disabled
691        self.sr().read().rawrmdis().bits() & self.mask() != 1
692    }
693
694    /// Disable the memory monitor region
695    #[inline]
696    pub fn disable_monitoring(&self) {
697        // Each bit in the register represents one of the
698        // four memory regions. Writing 0 does not change
699        // the state of the region, to enable the region,
700        // writing to `rmen` is required.
701        self.ctrl()
702            .write(|w| unsafe { w.rmdis().bits(self.mask()) });
703    }
704
705    /// Trigger recalculation of the memory monitor region
706    #[inline]
707    pub fn trigger_rehash(&self) {
708        self.ctrl()
709            .write(|w| unsafe { w.rehash().bits(self.mask()) });
710    }
711
712    /// Set Region Status Updated interrupt enable
713    #[inline]
714    pub fn set_rsu_int(&self) {
715        self.ier().write(|w| unsafe { w.rsu().bits(self.mask()) });
716    }
717
718    /// Set Region End bit Condition Detected interrupt enable
719    #[inline]
720    pub fn set_rec_int(&self) {
721        self.ier().write(|w| unsafe { w.rec().bits(self.mask()) });
722    }
723
724    /// Set Region Wrap Condition detected interrupt enable
725    #[inline]
726    pub fn set_rwc_int(&self) {
727        self.ier().write(|w| unsafe { w.rwc().bits(self.mask()) });
728    }
729
730    /// Set Region Bus Error interrupt enable
731    #[inline]
732    pub fn set_rbe_int(&self) {
733        self.ier().write(|w| unsafe { w.rbe().bits(self.mask()) });
734    }
735
736    /// Set Region Digest Mismatch interrupt enable
737    #[inline]
738    pub fn set_rdm_int(&self) {
739        self.ier().write(|w| unsafe { w.rdm().bits(self.mask()) });
740    }
741
742    /// Set Region Hash Completed interrupt enable
743    #[inline]
744    pub fn set_rhc_int(&self) {
745        self.ier().write(|w| unsafe { w.rhc().bits(self.mask()) });
746    }
747
748    /// Disable Region Status Updated interrupt enable
749    #[inline]
750    pub fn disable_rsu_int(&self) {
751        self.idr().write(|w| unsafe { w.rsu().bits(self.mask()) });
752    }
753
754    /// Disable Region End bit Condition Detected interrupt enable
755    #[inline]
756    pub fn disable_rec_int(&self) {
757        self.idr().write(|w| unsafe { w.rec().bits(self.mask()) });
758    }
759
760    /// Disable Region Wrap Condition detected interrupt enable
761    #[inline]
762    pub fn disable_rwc_int(&self) {
763        self.idr().write(|w| unsafe { w.rwc().bits(self.mask()) });
764    }
765
766    /// Disable Region Bus Error interrupt enable
767    #[inline]
768    pub fn disable_rbe_int(&self) {
769        self.idr().write(|w| unsafe { w.rbe().bits(self.mask()) });
770    }
771
772    /// Disable Region Digest Mismatch interrupt enable
773    #[inline]
774    pub fn disable_rdm_int(&self) {
775        self.idr().write(|w| unsafe { w.rdm().bits(self.mask()) });
776    }
777
778    /// Disable Region Hash Completed interrupt enable
779    #[inline]
780    pub fn disable_rhc_int(&self) {
781        self.idr().write(|w| unsafe { w.rhc().bits(self.mask()) });
782    }
783
784    /// Get Region Status Updated interrupt enable mask
785    #[inline]
786    pub fn get_rsu_int_mask(&self) -> bool {
787        match_on_interrupt_mask!(self, rsu)
788    }
789
790    /// Get Region End bit Condition Detected interrupt enable mask
791    #[inline]
792    pub fn get_rec_int_mask(&self) -> bool {
793        match_on_interrupt_mask!(self, rec)
794    }
795
796    /// Get Region Wrap Condition detected interrupt enable mask
797    #[inline]
798    pub fn get_rwc_int_mask(&self) -> bool {
799        match_on_interrupt_mask!(self, rwc)
800    }
801
802    /// Get Region Bus Error interrupt enable mask
803    #[inline]
804    pub fn get_rbe_int_mask(&self) -> bool {
805        match_on_interrupt_mask!(self, rbe)
806    }
807
808    /// Get Region Digest Mismatch interrupt enable mask
809    #[inline]
810    pub fn get_rdm_int_mask(&self) -> bool {
811        match_on_interrupt_mask!(self, rdm)
812    }
813
814    /// Get Region Hash Completed interrupt enable mask
815    #[inline]
816    pub fn get_rhc_int_mask(&self) -> bool {
817        match_on_interrupt_mask!(self, rhc)
818    }
819
820    /// Region Status Updated interrupt status
821    #[inline]
822    pub fn get_rsu_int(&self) -> bool {
823        match_on_interrupt_status!(self, rsu)
824    }
825
826    /// Region End bit Condition Detected interrupt status
827    #[inline]
828    pub fn get_rec_int(&self) -> bool {
829        match_on_interrupt_status!(self, rec)
830    }
831
832    /// Region Wrap Condition detected interrupt status
833    #[inline]
834    pub fn get_rwc_int(&self) -> bool {
835        match_on_interrupt_status!(self, rwc)
836    }
837
838    /// Region Bus Error interrupt status
839    #[inline]
840    pub fn get_rbe_int(&self) -> bool {
841        match_on_interrupt_status!(self, rbe)
842    }
843
844    /// Region Digest Mismatch interrupt status
845    #[inline]
846    pub fn get_rdm_int(&self) -> bool {
847        match_on_interrupt_status!(self, rdm)
848    }
849
850    /// Region Hash Completed interrupt status
851    #[inline]
852    pub fn get_rhc_int(&self) -> bool {
853        match_on_interrupt_status!(self, rhc)
854    }
855
856    /// When reading the interrupt (ISR) register, it is cleared
857    ///
858    /// This might result in unexpected results for example
859    /// when sequentially trying to determine which interrupt triggered.
860    ///
861    /// This is an alternative, return all the data from the register
862    /// and parse later with the designated `get_[name]_int` functions.
863    #[inline]
864    pub fn get_interrupt_status(&mut self) -> RegionInterrupt<I> {
865        let interrupt = Interrupt(self.isr().read().bits());
866        RegionInterrupt {
867            region: PhantomData,
868            interrupt,
869        }
870    }
871}
872
873/// ICM Peripheral
874///
875/// Encapsulates the PAC which acts as a token
876/// and provides an interface to the ICM hardware
877pub struct Icm {
878    /// ICM pac register providing hardware access
879    icm: crate::pac::Icm,
880}
881
882impl Icm {
883    /// Create the interface for the ICM peripheral
884    ///
885    /// Don't forget to enable the `APB` bus for ICM
886    ///
887    /// `AHB` bus is on by default at reset
888    ///
889    /// Clock::v1
890    /// `mclk.apbcmask.modify(|_, w| w.icm_().set_bit());`
891    ///
892    /// Clock::v2
893    /// `tokens.apbs.icm.enable();`
894    #[inline]
895    pub fn new(icm: crate::pac::Icm) -> Self {
896        Self { icm }
897    }
898
899    // Register Interface
900
901    /// Integrity Check Module
902    #[inline]
903    fn icm(&self) -> &RegisterBlock {
904        &self.icm
905    }
906
907    /// Configuration
908    #[inline]
909    fn cfg(&self) -> &Cfg {
910        self.icm().cfg()
911    }
912
913    /// Control
914    #[inline]
915    fn ctrl(&self) -> &Ctrl {
916        self.icm().ctrl()
917    }
918
919    /// Region Descriptor Area Start Address
920    #[inline]
921    fn dscr(&self) -> &Dscr {
922        self.icm().dscr()
923    }
924
925    /// Region Hash Area Start Address
926    #[inline]
927    fn hash(&self) -> &Hash {
928        self.icm().hash()
929    }
930
931    /// Interrupt Disable
932    #[inline]
933    fn idr(&self) -> &Idr {
934        self.icm().idr()
935    }
936
937    /// Interrupt Enable
938    #[inline]
939    fn ier(&self) -> &Ier {
940        self.icm().ier()
941    }
942
943    /// Interrupt Mask
944    #[inline]
945    fn imr(&self) -> &Imr {
946        self.icm().imr()
947    }
948
949    /// Interrupt Status
950    #[inline]
951    fn isr(&self) -> &Isr {
952        self.icm().isr()
953    }
954
955    /// Status
956    #[inline]
957    fn sr(&self) -> &Sr {
958        self.icm().sr()
959    }
960
961    /// Undefined Access Status
962    #[inline]
963    fn uasr(&self) -> &Uasr {
964        self.icm().uasr()
965    }
966
967    // User interface for ICM
968
969    /// Enable the ICM peripheral
970    #[inline]
971    pub fn enable(&mut self) {
972        self.ctrl().write(|w| w.enable().set_bit());
973    }
974
975    /// Get enabled status of the ICM peripheral
976    #[inline]
977    pub fn icm_status(&self) -> bool {
978        self.sr().read().enable().bit_is_set()
979    }
980
981    /// Disable the ICM peripheral
982    #[inline]
983    pub fn disable(&mut self) {
984        self.ctrl().write(|w| w.disable().set_bit());
985    }
986
987    /// Reset the ICM controller
988    ///
989    /// Does not seem to clear DSCR, HASH addr
990    ///
991    /// The only way to clear the `URAD` and `URAT` fields
992    /// is by resetting the ICM controller
993    #[inline]
994    pub fn swrst(&mut self) {
995        self.ctrl().write(|w| w.swrst().set_bit());
996    }
997
998    /// Destroy the ICM peripheral and return the underlying ICM register
999    #[inline]
1000    pub fn destroy(self) -> crate::pac::Icm {
1001        self.icm
1002    }
1003
1004    // Region specifics
1005
1006    #[inline]
1007    pub fn enable_region<N: RegionNum>(&mut self) -> Region<N> {
1008        Region::<N>::new()
1009    }
1010
1011    /// Enable region0
1012    ///
1013    /// Creates an [`Region`] which provides region specific
1014    /// settings
1015    #[inline]
1016    pub fn enable_region0(&mut self) -> Region<Region0> {
1017        Region::new()
1018    }
1019    /// Enable region1
1020    ///
1021    /// Creates an [`Region`] which provides region specific
1022    /// settings
1023    #[inline]
1024    pub fn enable_region1(&mut self) -> Region<Region1> {
1025        Region::new()
1026    }
1027    /// Enable region2
1028    ///
1029    /// Creates an [`Region`] which provides region specific
1030    /// settings
1031    #[inline]
1032    pub fn enable_region2(&mut self) -> Region<Region2> {
1033        Region::new()
1034    }
1035    /// Enable region3
1036    ///
1037    /// Creates an [`Region`] which provides region specific
1038    /// settings
1039    #[inline]
1040    pub fn enable_region3(&mut self) -> Region<Region3> {
1041        Region::new()
1042    }
1043
1044    // Configuration of ICM
1045
1046    /// Helper for setting the HASH addr
1047    ///
1048    /// Expects a raw pointer to the memory address of the beginning of the
1049    /// designated variable but expressed as a multiple of 128
1050    #[inline]
1051    pub fn set_hash_addr(&mut self, hash_addr_pointer: &HashArea) {
1052        self.hash()
1053            .write(|w| unsafe { w.hasa().bits((hash_addr_pointer as *const _) as u32 / 128) })
1054    }
1055
1056    /// Set the DSCR addr to a specific MainRegionDesc
1057    ///
1058    /// HW expects a raw pointer to the memory address of the beginning of the
1059    /// [`MainRegionDesc`] but expressed as a multiple of 64
1060    pub fn set_dscr_addr(&self, icm_region_desc: &MainRegionDesc<Region0>) {
1061        self.dscr()
1062            .write(|w| unsafe { w.dasa().bits((icm_region_desc as *const _) as u32 / 64) })
1063    }
1064
1065    /// Set the user initial hash value
1066    #[inline]
1067    pub fn set_user_initial_hash_value(&self, user_initial_hash_value: [u32; 8]) {
1068        for (index, initial_value) in user_initial_hash_value.iter().enumerate() {
1069            self.icm()
1070                .uihval(index)
1071                .write(|w| unsafe { w.val().bits(*initial_value) });
1072        }
1073    }
1074
1075    /// Set the user hashing algorithm
1076    #[inline]
1077    pub fn set_user_algorithm(self, algo: icm_algorithm) {
1078        self.cfg().write(|w| w.ualgo().variant(algo));
1079    }
1080
1081    /// Activate user hash mode
1082    ///
1083    /// Allows providing
1084    /// * hash initial value
1085    /// * Hash algorithm
1086    ///
1087    /// Disables the `ALGO` field in [`MainRegionDesc`]
1088    ///
1089    /// Set initial hash value via [`Icm::set_user_initial_hash_value()`]
1090    /// Set hash algorithm via [`Icm::set_user_algorithm()`]
1091    #[inline]
1092    pub fn set_user_configurable_hash(&self, user_configurable_hash: bool) {
1093        self.cfg().write(|w| w.uihash().bit(user_configurable_hash));
1094    }
1095
1096    /// Control dual input buffer
1097    ///
1098    /// Enabling dual input buffering allow for better performance
1099    /// at the cost of higher bandwith requirements on the system bus
1100    #[inline]
1101    pub fn set_dual_input_buffer(&self, dualbuffer: bool) {
1102        self.cfg().write(|w| w.dualbuff().bit(dualbuffer));
1103    }
1104
1105    /// Automatic switch to Compare Digest
1106    ///
1107    /// When activated, after the first Main List pass the ICM controller
1108    /// automatically switches to active monitoring.
1109    ///
1110    /// `CDWBN` and `WBDIS` bits has no effects, to terminate the monitoring a
1111    /// `1` needs to be written to End of Monitoring (`RCFG.EOM`)
1112    #[inline]
1113    pub fn set_ascd(&self, automaticswitch: bool) {
1114        self.cfg().write(|w| w.ascd().bit(automaticswitch));
1115    }
1116
1117    /// Bus burden control
1118    ///
1119    /// Set a delay between block transfers, calculated as
1120    ///
1121    /// `2.pow(busburden)`
1122    ///
1123    /// Maximum delay is 32768 cycles
1124    #[inline]
1125    pub fn set_busburden(&self, busburden: u8) {
1126        self.cfg().write(|w| unsafe { w.bbc().bits(busburden) });
1127    }
1128
1129    /// Secondary List Branching Disable
1130    ///
1131    /// * If set to false, allow secondary lists
1132    /// * If set to true, secondary lists are forbidden, `NEXT` and `RNEXT` is
1133    ///   always considered 0.
1134    #[inline]
1135    pub fn set_slbdis(&self, disable_secondary_lists: bool) {
1136        self.cfg()
1137            .write(|w| w.slbdis().bit(disable_secondary_lists));
1138    }
1139
1140    /// End of Monitoring Disable
1141    ///
1142    /// * If set to false, End of Monitoring is permitter
1143    /// * If set to true, End of Monitoring is forbidden, the EOM bit in RCFG
1144    ///   has no effect.
1145    #[inline]
1146    pub fn set_eomdis(&self, disable_eom: bool) {
1147        self.cfg().write(|w| w.eomdis().bit(disable_eom));
1148    }
1149
1150    /// Write Back Disable
1151    ///
1152    /// * If set to false, Write Back Operations are permitted
1153    /// * If set to true, Write Back Operations are forbidden, `CDWBN` bit is
1154    ///   internally set to 1 and cannot be modified by a linked list element.
1155    ///   The `CDWBN` bit of the `RCFG` structure member has no effect.
1156    #[inline]
1157    pub fn set_wbdis(&self, disable_eom: bool) {
1158        self.cfg().write(|w| w.wbdis().bit(disable_eom));
1159    }
1160
1161    // Security and tamper settings
1162
1163    /// Set Undefined Register Access Detection interrupt enable
1164    #[inline]
1165    pub fn set_urad_int(self) {
1166        self.ier().write(|w| unsafe { w.rsu().bits(1) });
1167    }
1168
1169    /// Disable Undefined Register Access Detection interrupt enable
1170    #[inline]
1171    pub fn disable_urad_int(self) {
1172        self.idr().write(|w| unsafe { w.rsu().bits(1) });
1173    }
1174
1175    /// Get Undefined Register Access Detection interrupt mask
1176    #[inline]
1177    pub fn get_urad_int_mask(&self) -> bool {
1178        self.imr().read().urad().bit()
1179    }
1180
1181    /// Get Undefined Register Access Detection interrupt status
1182    #[inline]
1183    pub fn get_urad_int(&self) -> bool {
1184        self.isr().read().urad().bit()
1185    }
1186
1187    /// Get Undefined Register Access Trace
1188    ///
1189    /// This field is only reset by `swrst`
1190    #[inline]
1191    pub fn get_urat(&self) -> Uratselect {
1192        self.uasr().read().urat().variant().unwrap()
1193    }
1194
1195    /// When reading the interrupt (ISR) register, it is cleared
1196    ///
1197    /// This might result in unexpected results for example
1198    /// when sequentially trying to determine which interrupt triggered.
1199    ///
1200    /// This is an alternative, return all the data from the register
1201    /// and parse later with the designated `get_[name]_int` functions.
1202    #[inline]
1203    pub fn get_interrupt_status(&mut self) -> Interrupt {
1204        let interrupt_vector = self.isr().read().bits();
1205        Interrupt(interrupt_vector)
1206    }
1207    /// Trigger recalculation of memory monitor region specified
1208    /// by the bitmask:
1209    /// 0b0001 = region0
1210    /// 0b0010 = region1
1211    /// 0b0100 = region2
1212    /// 0b1000 = region3
1213    /// ...
1214    /// 0b1111 = all regions
1215    #[inline]
1216    pub fn trigger_rehash(&self, bitmask: u8) {
1217        self.ctrl().write(|w| unsafe { w.rehash().bits(bitmask) });
1218    }
1219}
1220
1221/// Trait providing numerical identifier and
1222/// offset for each ICM Region
1223///
1224/// ICM supports 4 memory regions
1225pub trait RegionNum: Sealed {
1226    /// Numerical ID of the memory region
1227    const NUM: usize;
1228    /// Memory offset
1229    const OFFSET: u32;
1230}
1231
1232seq!(N in 0..=3 {
1233    paste! {
1234        #[doc = "ICM Region " N]
1235        pub enum Region~N {}
1236        impl Sealed for Region~N {}
1237        impl RegionNum for Region~N {
1238            const NUM: usize = N;
1239            #[allow(clippy::identity_op)]
1240            #[allow(clippy::erasing_op)]
1241            const OFFSET: u32 = 0x10 * N;
1242        }
1243    }
1244});
1245
1246/// Functions required by [`MainRegionDesc`]
1247///
1248/// Both Main List descriptors and Secondary List descriptors
1249pub trait RegionDesc {
1250    /// Set the [`RegionAddress`] start of the region memory region
1251    fn set_region_address<T>(&mut self, addr: *const T);
1252    /// Set the specific region configuration
1253    fn set_region_configuration(&mut self, cfg: RegionConfiguration);
1254    /// Set the link to next region descriptor
1255    fn set_region_next(&mut self, next: RegionNext);
1256    /// Reset RegionConfiguration to default values
1257    fn reset_region_configuration_to_default(&mut self);
1258}
1259
1260/// Helper for creating the Region Descriptor structure
1261///
1262/// It is also possible to construct the Region manually,
1263/// but then care has to be taken to point `rnext` to the appropriate
1264/// place in memory, here the hardware assumption of 0x10
1265/// offset to the next descriptor is ensured.
1266///
1267/// Follows C-structure conventions and is 64-byte aligned
1268///
1269/// >**Important**
1270/// >
1271/// >ICM engine will **read** wherever this
1272/// >is instantiated in memory, based on the [`Icm::set_dscr_addr()`]
1273/// >so the user must ensure that this variable lives long enough or is
1274/// >static
1275#[repr(C)]
1276#[repr(align(64))]
1277pub struct Regions {
1278    /// MainRegionDesc0
1279    pub region0: MainRegionDesc<Region0>,
1280    /// MainRegionDesc1
1281    pub region1: MainRegionDesc<Region1>,
1282    /// MainRegionDesc2
1283    pub region2: MainRegionDesc<Region2>,
1284    /// MainRegionDesc3
1285    pub region3: MainRegionDesc<Region3>,
1286}
1287
1288impl Regions {
1289    pub const fn default() -> Self {
1290        let region0 = MainRegionDesc::new_region0();
1291        let region1 = MainRegionDesc::new_region1();
1292        let region2 = MainRegionDesc::new_region2();
1293        let region3 = MainRegionDesc::new_region3();
1294        Self {
1295            region0,
1296            region1,
1297            region2,
1298            region3,
1299        }
1300    }
1301}
1302
1303/// Structure ICM Region Descriptor area.
1304///
1305/// Follows C-structure conventions and is 16-byte aligned,
1306/// being a part of the 64-bytes making up [`Region`]
1307#[repr(C)]
1308#[repr(align(16))]
1309pub struct MainRegionDesc<N: RegionNum> {
1310    /// Numerical Region Identifier
1311    num: PhantomData<N>,
1312    /// The first byte address of the Region.
1313    pub raddr: RegionAddress,
1314    /// Configuration Structure Member.
1315    pub rcfg: RegionConfiguration,
1316    /// Control Structure Member.
1317    pub rctrl: RegionControl,
1318    /// Next Address Structure Member.
1319    pub rnext: RegionNext,
1320}
1321
1322impl MainRegionDesc<Region0> {
1323    /// Helper for setting the DSCR addr to a the first MainRegionDesc
1324    ///
1325    /// See [`Icm::set_dscr_addr()`] for the regular workflow
1326    ///
1327    /// HW expects a raw pointer to the memory address of the beginning of the
1328    /// [`MainRegionDesc`] but expressed as a multiple of 64
1329    pub fn set_dscr_addr(&self, icm: &Icm) {
1330        icm.dscr()
1331            .write(|w| unsafe { w.dasa().bits((self as *const _) as u32 / 64) })
1332    }
1333}
1334
1335seq!(N in 0..=3 {
1336    paste! {
1337        #[doc = "Create region descriptor " N]
1338        impl MainRegionDesc<Region~N> {
1339            const fn new_region~N() -> Self {
1340                MainRegionDesc {
1341                    num: PhantomData,
1342                    raddr: RegionAddress::default(),
1343                    rcfg: RegionConfiguration::default(),
1344                    rctrl: RegionControl::default(),
1345                    rnext: RegionNext::default(),
1346                }
1347            }
1348        }
1349    }
1350});
1351
1352impl<N: RegionNum> RegionDesc for MainRegionDesc<N> {
1353    /// Set [`RegionAddress`]
1354    #[inline]
1355    fn set_region_address<T>(&mut self, addr: *const T) {
1356        self.raddr.set_region_address(addr);
1357    }
1358    /// Set [`RegionConfiguration`]
1359    #[inline]
1360    fn set_region_configuration(&mut self, cfg: RegionConfiguration) {
1361        self.rcfg = cfg;
1362    }
1363    /// Reset [`RegionConfiguration`] to default values
1364    #[inline]
1365    fn reset_region_configuration_to_default(&mut self) {
1366        self.rcfg = RegionConfiguration::default();
1367    }
1368    /// Set [`RegionNext`]
1369    #[inline]
1370    fn set_region_next(&mut self, next: RegionNext) {
1371        self.rnext = next;
1372    }
1373}
1374
1375impl<N: RegionNum> MainRegionDesc<N> {
1376    /// The length of data for the ICM engine to transfer,
1377    /// expressed as number of `blocks - 1`.
1378    #[inline]
1379    pub fn set_rctrl(mut self, ctrl: RegionControl) {
1380        self.rctrl = ctrl;
1381    }
1382}
1383
1384/// Structure ICM Secondary Region Descriptor area.
1385///
1386/// Follows C-structure conventions and is 16-byte aligned
1387///
1388/// Used to build the linked lists for non-contiguous memory
1389#[repr(C)]
1390#[repr(align(16))]
1391pub struct SecondaryRegionDesc {
1392    /// the first byte address of the Region.
1393    pub raddr: RegionAddress,
1394    /// Configuration Structure Member.
1395    pub rcfg: RegionConfiguration,
1396    /// Not used in Secondary Region Descriptor
1397    _pad: u32,
1398    /// Next Address Structure Member.
1399    pub rnext: RegionNext,
1400}
1401
1402impl RegionDesc for SecondaryRegionDesc {
1403    fn set_region_address<T>(&mut self, addr: *const T) {
1404        self.raddr.set_region_address(addr);
1405    }
1406    /// Set [`RegionConfiguration`]
1407    #[inline]
1408    fn set_region_configuration(&mut self, cfg: RegionConfiguration) {
1409        self.rcfg = cfg;
1410    }
1411    /// Reset [`RegionConfiguration`] to default values
1412    #[inline]
1413    fn reset_region_configuration_to_default(&mut self) {
1414        self.rcfg = RegionConfiguration::default();
1415    }
1416    /// Set [`RegionNext`]
1417    #[inline]
1418    fn set_region_next(&mut self, next: RegionNext) {
1419        self.rnext = next;
1420    }
1421}
1422
1423impl SecondaryRegionDesc {
1424    pub const fn default() -> Self {
1425        SecondaryRegionDesc {
1426            raddr: RegionAddress::default(),
1427            rcfg: RegionConfiguration::default(),
1428            _pad: 0,
1429            rnext: RegionNext::default(),
1430        }
1431    }
1432}
1433
1434/// ICM Hash Area
1435///
1436/// Follows C-structure conventions and is 128-byte aligned
1437///
1438/// >**Important**
1439/// >
1440/// >ICM engine will **read** or **write** to wherever this
1441/// >is instantiated in memory, based on the [`Icm::set_hash_addr()`]
1442/// >so the user must ensure that this variable lives long enough or is
1443/// >static
1444#[derive(Debug)]
1445#[repr(C)]
1446#[repr(align(128))]
1447pub struct HashArea {
1448    pub region0: [u32; 8],
1449    pub region1: [u32; 8],
1450    pub region2: [u32; 8],
1451    pub region3: [u32; 8],
1452}
1453
1454impl HashArea {
1455    pub const fn default() -> Self {
1456        HashArea {
1457            region0: [0; 8],
1458            region1: [0; 8],
1459            region2: [0; 8],
1460            region3: [0; 8],
1461        }
1462    }
1463}
1464
1465/// Region Start Address Structure
1466///
1467/// Follows C-structure conventions
1468#[derive(Clone, Copy)]
1469#[repr(C)]
1470pub struct RegionAddress {
1471    pub raddr: u32,
1472}
1473
1474impl RegionAddress {
1475    pub fn set_region_address<T>(&mut self, raddr: *const T) {
1476        self.raddr = raddr as u32;
1477    }
1478    const fn default() -> Self {
1479        // Unsure what a good RegionAddress default should be,
1480        // this is at least easily spotted when debugging...
1481        RegionAddress {
1482            raddr: 0xDEADBEEF_u32,
1483        }
1484    }
1485}
1486
1487/*
1488#[derive(Clone, Copy)]
1489#[repr(C)]
1490pub struct RegionConfiguration {
1491    rcfg: u32,
1492}
1493*/
1494
1495bitfield::bitfield! {
1496    /// Region Configuration Structure
1497    ///
1498    /// Follows C-structure conventions
1499    #[derive(Clone, Copy)]
1500    #[repr(C)]
1501    pub struct RegionConfiguration(u32);
1502    impl Debug;
1503    u8;
1504    /// Compare Digest or Write Back Digest
1505    ///
1506    /// * true: in Compare Digest mode.
1507    /// * false: in Write Back Digest mode.
1508    #[inline]
1509    pub get_cdwbn, set_cdwbn: 0;
1510    /// Wrap Command
1511    ///
1512    /// * true: next region descriptor address loaded is `DSCR`.
1513    /// * false: the next region descriptor address is `current + 0x10`.
1514    #[inline]
1515    pub
1516    get_wrap, set_wrap: 1;
1517    /// End of Monitoring
1518    ///
1519    /// * true: the current descriptor terminates the Main List, WRAP bit has
1520    /// no effect.
1521    /// * false: the current descriptor does not terminate the
1522    /// monitoring.
1523    #[inline]
1524    pub
1525    get_eom, set_eom:  2;
1526    /// Region Hash Completed Interrupt Disable
1527    /// * true: the `RHC` flag remains cleared even if the setting condition is
1528    /// met.
1529    /// * false: the `RHC` flag is set when the field `NEXT = 0` is
1530    /// found in main or secondary list.
1531    #[inline]
1532    pub
1533    get_rhien, set_rhien: 4;
1534    /// Digest Mismatch Interrupt Disable
1535    ///
1536    /// * true: the `RBE` flag remains cleared even if the setting condition is
1537    /// met.
1538    /// * false: the `RBE` flag is set when the hash value just
1539    /// calculated from the processed region differs from expected hash
1540    /// value.
1541    #[inline]
1542    pub
1543    get_dmien, set_dmien: 5;
1544    /// Bus Error Interrupt Disable
1545    ///
1546    /// * true: the flag remains cleared even if the setting condition is met.
1547    /// * false: the flag is set when an error is reported on the sysstem bus
1548    /// by the bus MATRIX.
1549    #[inline]
1550    pub
1551    get_beien, set_beien: 6;
1552    /// Wrap Condition Interrupt Disable
1553    ///
1554    /// * true: the `RWC` flag remains cleared even if the setting condition is
1555    /// met.
1556    /// * false: the `RWC` flag is set when the WRAP is encountered.
1557    #[inline]
1558    pub get_wcien, set_wcien: 7;
1559    /// End Bit Condition Interrupt Enable
1560    ///
1561    /// * true: the `REC` flag remains cleared even if the setting condition is
1562    /// met.
1563    /// * false: the `REC` flag is set when the descriptor having the
1564    /// `EOM` bit set is processed.
1565    #[inline]
1566    pub get_ecien, set_ecien: 8;
1567    /// Monitoring Status Updated Condition Interrupt Enable
1568    ///
1569    /// * true: the `RSU` flag remains cleared even if the condition is met.
1570    /// * false: the `RSU` flag is set when the corresponding descriptor is
1571    /// loaded from memory to ICM.
1572    #[inline]
1573    pub get_suien, set_suien: 9;
1574    /// Processing Delay
1575    ///
1576    /// Allows setting short or long delay.
1577    ///
1578    /// See [`ProcessingDelay`]
1579    #[inline]
1580    pub get_procdly, set_procdly: 10;
1581    get_algo_bits, set_algo_bits: 14, 12;
1582}
1583
1584impl RegionConfiguration {
1585    const fn default() -> Self {
1586        //RegionConfiguration { rcfg: 0x3F0 }
1587        RegionConfiguration(0x3F0)
1588    }
1589}
1590
1591impl RegionConfiguration {
1592    /// User SHA Algorithm
1593    ///
1594    /// Allow setting this regions [`icm_algorithm`].
1595    #[inline]
1596    pub fn set_algo(&mut self, value: icm_algorithm) {
1597        self.set_algo_bits(value.into());
1598    }
1599
1600    /// User SHA Algorithm
1601    ///
1602    /// Get the current user sha algorithm
1603    #[inline]
1604    pub fn get_algo(&mut self) -> icm_algorithm {
1605        match self.get_algo_bits() {
1606            2 => icm_algorithm::Sha224,
1607            4 => icm_algorithm::Sha256,
1608            _ => icm_algorithm::Sha1,
1609        }
1610    }
1611    /// Reset the [`RegionConfiguration`] to default values
1612    ///
1613    /// Useful if changing between hashing and monitoring, etc.
1614    #[inline]
1615    pub fn reset_region_configuration_to_default(&mut self) {
1616        self.0 = 0x3F0_u32;
1617    }
1618}
1619
1620/// Processing Delay
1621///
1622/// For a given SHA algorithm, the runtime period has two possible lengths
1623pub enum ProcessingDelay {
1624    /// Shortest processing delay
1625    ///
1626    /// `SHA1`: 85
1627    ///
1628    /// `SHA224`: 72
1629    ///
1630    /// `SHA256`: 72
1631    Shortest = 0,
1632    /// Longest processing delay
1633    ///
1634    /// `SHA1`: 209
1635    ///
1636    /// `SHA224`: 194
1637    ///
1638    /// `SHA256`: 194
1639    Longest = 1,
1640}
1641
1642/// Region Control Structure
1643///
1644/// Follows C-structure conventions
1645#[derive(Clone, Copy)]
1646#[repr(C)]
1647pub struct RegionControl {
1648    pub trsize: u16,
1649}
1650
1651impl RegionControl {
1652    const fn default() -> Self {
1653        RegionControl { trsize: 0 }
1654    }
1655}
1656
1657/// Region Next Address Structure
1658///
1659/// Is the same as RegionAddress<N+1>
1660///
1661/// Follows C-structure conventions
1662#[derive(Clone, Copy)]
1663#[repr(C)]
1664pub struct RegionNext {
1665    rnext: u32,
1666}
1667
1668impl RegionNext {
1669    pub fn set_region_next(&mut self, rnext: &impl RegionDesc) {
1670        self.rnext = (rnext as *const _) as u32;
1671    }
1672
1673    const fn default() -> Self {
1674        RegionNext { rnext: 0 }
1675    }
1676}