Skip to main content

ra_hal/
write_protect.rs

1//! Conveniences for registers that are gated by a write protect flag.
2
3#[cfg(gpt)]
4use crate::pac::gpt;
5#[cfg(iic)]
6use crate::pac::iic;
7use crate::pac::{
8    common::{RW, Reg},
9    pfs::regs::Pin,
10    system::vals::{Prc0, Prc1},
11};
12
13/// Manages write protection at the peripheral level.
14pub trait ProtectedPeripheral {
15    /// # Returns
16    /// * `true` if this peripheral is currently write protected.
17    fn is_protected(&self) -> bool;
18
19    /// Disables write protection for a peripheral for the duration of the closure.
20    fn protected_write<F>(&self, func: F)
21    where
22        F: Fn();
23}
24
25/// Provides a function to disable write protection for a single modify operation on a register.
26pub trait ProtectedModify<T: Copy> {
27    /// Performs a modify operation on a register, disabling WP before and enabling it after.
28    fn protected_modify(&self, f: impl FnOnce(&mut T));
29
30    /// # Returns
31    /// * `true` if this register is currently write protected.
32    fn is_protected(&self) -> bool {
33        true
34    }
35}
36
37/// Provides a function to disable write protection for a single write operation on a register.
38pub trait ProtectedWrite<T: Copy> {
39    /// Performs a write operation on a register, disabling WP before and enabling it after.
40    fn protected_write(&self, f: impl FnOnce(&mut T));
41}
42
43#[cfg(iic)]
44impl ProtectedModify<iic::regs::Icmr3> for Reg<iic::regs::Icmr3, RW> {
45    #[inline]
46    fn is_protected(&self) -> bool {
47        !self.read().ackwp()
48    }
49
50    #[inline]
51    fn protected_modify(&self, func: impl FnOnce(&mut iic::regs::Icmr3)) {
52        let protected = self.is_protected();
53
54        if protected {
55            self.modify(|w| w.set_ackwp(true));
56        }
57
58        self.modify(func);
59
60        if protected {
61            self.modify(|w| w.set_ackwp(false));
62        }
63    }
64}
65
66impl ProtectedModify<Pin> for Reg<Pin, RW> {
67    #[inline]
68    fn is_protected(&self) -> bool {
69        let pfs = crate::pac::PFS;
70        let pwpr = cfg_select! {
71          all(trust_zone_v2, secure) => pfs.pwpr_s(),
72          _ => pfs.pwpr()
73        };
74
75        !pwpr.read().pfswe()
76    }
77
78    fn protected_modify(&self, func: impl FnOnce(&mut Pin)) {
79        // ยง 19.2.6
80
81        let pfs = crate::pac::PFS;
82        let protected = self.is_protected();
83
84        let pwpr = cfg_select! {
85          all(trust_zone_v2, secure) => pfs.pwpr_s(),
86          _ => pfs.pwpr()
87        };
88
89        if protected {
90            trace!("PFS WriteProt: {}", pfs.pwpr().read());
91
92            pwpr.modify(|w| w.set_b0wi(false));
93            pwpr.modify(|w| w.set_pfswe(true));
94
95            #[cfg(feature = "strict-assert")]
96            assert!(pwpr.read().pfswe());
97        }
98
99        self.modify(func);
100
101        if protected {
102            pwpr.modify(|w| w.set_b0wi(false));
103            pwpr.modify(|w| w.set_pfswe(false));
104
105            #[cfg(feature = "strict-assert")]
106            assert!(!pwpr.read().pfswe());
107            trace!("PFS WriteProt: {}", pwpr.read());
108        }
109    }
110}
111
112impl ProtectedPeripheral for crate::pac::system::System {
113    fn protected_write<F>(&self, func: F)
114    where
115        F: Fn(),
116    {
117        use crate::pac::system::vals::Prc0;
118
119        let prcr = cfg_select! {
120            all(trust_zone_v2, secure) => self.prcr_s(),
121            _ => self.prcr()
122        };
123
124        let protected = self.is_protected();
125
126        if protected {
127            trace!("SYSTEM WriteProt: {}", prcr.read());
128            prcr.write(|w| {
129                w.set_prkey(crate::pac::system::vals::Prkey::ProtectKey);
130                w.set_prc0(Prc0::NotProtected);
131                w.set_prc1(Prc1::NotProtected);
132            });
133        }
134
135        func();
136
137        if protected {
138            prcr.write(|w| {
139                w.set_prkey(crate::pac::system::vals::Prkey::ProtectKey);
140                w.set_prc0(Prc0::Protected);
141                w.set_prc1(Prc1::Protected);
142            });
143            trace!("SYSTEM WriteProt: {}", prcr.read());
144        }
145    }
146
147    #[inline]
148    fn is_protected(&self) -> bool {
149        let prcr = cfg_select! {
150            all(trust_zone_v2, secure) => self.prcr_s(),
151            _ => self.prcr()
152        };
153
154        let status = prcr.read();
155        status.prc0() == Prc0::Protected || status.prc1() == Prc1::Protected
156    }
157}
158
159/// Note that write protection is disabled by default for timers.
160#[cfg(gpt)]
161impl ProtectedPeripheral for gpt::Gpt {
162    fn protected_write<F>(&self, func: F)
163    where
164        F: Fn(),
165    {
166        use gpt::vals::Prkey;
167
168        let protected = self.is_protected();
169
170        if protected {
171            self.gtwp().write(|w| {
172                w.set_wp(false);
173                w.set_prkey(Prkey::ProtectKey);
174            });
175            trace!("WP: {}", self.gtwp().read());
176        }
177
178        func();
179
180        if protected {
181            self.gtwp().write(|w| {
182                w.set_wp(true);
183                w.set_prkey(Prkey::ProtectKey);
184            });
185            trace!("WP: {}", self.gtwp().read());
186        }
187    }
188
189    #[inline]
190    fn is_protected(&self) -> bool {
191        self.gtwp().read().wp()
192    }
193}