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}