opentitanlib/otp/
alert_handler.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use crate::otp::alert_handler_regs::*;
6use crate::otp::lc_state::LcStateVal;
7use crate::otp::otp_img::OtpRead;
8
9use anyhow::{Context, Result, bail};
10use crc::{Crc, Digest};
11
12/// ALERT_HANDLER_ALERT_CLASS related register values.
13#[derive(Clone, Copy, Debug, PartialEq)]
14struct AlertClassRegs {
15    regwen: u32,
16    ctrl: u32,
17    accum_thresh: u32,
18    timeout_cyc: u32,
19    phase_cycs: [u32; ALERT_HANDLER_PARAM_N_PHASES as usize],
20}
21
22/// Register values for alert_handler used in CRC32 calculation.
23#[derive(Debug, PartialEq)]
24pub struct AlertRegs {
25    /// ALERT_HANDLER_LOC_ALERT_REGWEN
26    regwen: [u32; ALERT_HANDLER_ALERT_REGWEN_MULTIREG_COUNT as usize],
27    /// ALERT_HANDLER_ALERT_EN_SHADOWED
28    en: [u32; ALERT_HANDLER_ALERT_EN_SHADOWED_MULTIREG_COUNT as usize],
29    /// ALERT_HANDLER_ALERT_CLASS_SHADOWED
30    class: [u32; ALERT_HANDLER_ALERT_CLASS_SHADOWED_MULTIREG_COUNT as usize],
31    /// ALERT_HANDLER_LOC_ALERT_REGWEN
32    loc_regwen: [u32; ALERT_HANDLER_LOC_ALERT_REGWEN_MULTIREG_COUNT as usize],
33    /// ALERT_HANDLER_LOC_ALERT_EN_SHADOWED
34    loc_en: [u32; ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_MULTIREG_COUNT as usize],
35    /// ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED
36    loc_class: [u32; ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_MULTIREG_COUNT as usize],
37    /// Alert handler class registers
38    class_regs: [AlertClassRegs; ALERT_HANDLER_PARAM_N_CLASSES as usize],
39}
40
41// TODO: Use bindgen to produce the following enum definitions.
42/// Alert classification values.
43///
44/// Based on values generated by sparse-fsm-encode.py and defined in
45/// sw/device/silicon_creator/lib/drivers/alert.h as alert_class_t.
46#[derive(strum::FromRepr)]
47#[repr(u8)]
48enum AlertClass {
49    X = 0x94,
50    A = 0xee,
51    B = 0x64,
52    C = 0xa7,
53    D = 0x32,
54}
55
56impl AlertClass {
57    fn index(&self) -> usize {
58        match self {
59            AlertClass::A => 0,
60            AlertClass::B => 1,
61            AlertClass::C => 2,
62            AlertClass::D => 3,
63            AlertClass::X => 0,
64        }
65    }
66
67    fn from_index(index: usize) -> Self {
68        match index {
69            0 => AlertClass::A,
70            1 => AlertClass::B,
71            2 => AlertClass::C,
72            3 => AlertClass::D,
73            _ => AlertClass::X,
74        }
75    }
76}
77
78#[derive(strum::FromRepr)]
79#[repr(u8)]
80enum AlertEnable {
81    None = 0xa9,
82    Enabled = 0x07,
83    Locked = 0xd2,
84}
85
86#[derive(strum::FromRepr)]
87#[repr(u8)]
88enum AlertEscalate {
89    None = 0xd1,
90    Phase0 = 0xb9,
91    Phase1 = 0xcb,
92    Phase2 = 0x25,
93    Phase3 = 0x76,
94}
95
96struct AlertClassConfig {
97    enabled: AlertEnable,
98    escalate: AlertEscalate,
99    accum_thresh: u32,
100    timeout_cyc: u32,
101    phase_cycs: [u32; ALERT_HANDLER_PARAM_N_PHASES as usize],
102}
103
104impl Default for AlertClassRegs {
105    fn default() -> Self {
106        AlertClassRegs {
107            regwen: 1,
108            ctrl: 0,
109            accum_thresh: 0,
110            timeout_cyc: 0,
111            phase_cycs: [0; ALERT_HANDLER_PARAM_N_PHASES as usize],
112        }
113    }
114}
115
116impl Default for AlertRegs {
117    fn default() -> Self {
118        AlertRegs {
119            regwen: [1; ALERT_HANDLER_ALERT_REGWEN_MULTIREG_COUNT as usize],
120            loc_regwen: [1; ALERT_HANDLER_LOC_ALERT_REGWEN_MULTIREG_COUNT as usize],
121            en: [0; ALERT_HANDLER_ALERT_EN_SHADOWED_MULTIREG_COUNT as usize],
122            class: [0; ALERT_HANDLER_ALERT_CLASS_SHADOWED_MULTIREG_COUNT as usize],
123            loc_en: [0; ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_MULTIREG_COUNT as usize],
124            loc_class: [0; ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_MULTIREG_COUNT as usize],
125            class_regs: [Default::default(); ALERT_HANDLER_PARAM_N_CLASSES as usize],
126        }
127    }
128}
129
130impl AlertRegs {
131    /// Compute the CRC32 of the internal register values to match the value produced by
132    /// `sw/device/silicon_creator/lib/drivers/alert.h:alert_config_crc32`.
133    pub fn crc32(self) -> u32 {
134        let crc = new_crc();
135        let mut digest = crc.digest();
136        self.crc32_add(&mut digest);
137        digest.finalize()
138    }
139
140    /// Create the set of alert_handler register values from a given lifecycle state and OTP.
141    ///
142    /// The internal fields of `AlertRegs` should match those produced on the device after
143    /// alert_handler is configured in `sw/device/silicon_creator/lib/shutdown.h:shutdown_init`.
144    pub fn try_new<T: OtpRead>(lc_state: LcStateVal, otp: &T) -> Result<Self> {
145        let mut alert = AlertRegs::default();
146
147        let lc_shift = match lc_state {
148            LcStateVal::Prod => 0,
149            LcStateVal::ProdEnd => 1,
150            LcStateVal::Dev => 2,
151            LcStateVal::Rma => 3,
152            LcStateVal::Test => return Ok(alert),
153        };
154
155        let class_enable = otp.read32("OWNER_SW_CFG_ROM_ALERT_CLASS_EN")?;
156        let class_escalate = otp.read32("OWNER_SW_CFG_ROM_ALERT_ESCALATION")?;
157
158        for i in 0..ALERT_HANDLER_ALERT_CLASS_SHADOWED_MULTIREG_COUNT as usize {
159            let value = otp.read32_offset("OWNER_SW_CFG_ROM_ALERT_CLASSIFICATION", i * 4)?;
160            let cls = AlertClass::from_repr(value.to_le_bytes()[lc_shift])
161                .with_context(|| format!("invalid alert class value {value:#010x}"))?;
162            let enable = AlertEnable::from_repr(class_enable.to_le_bytes()[cls.index()])
163                .with_context(|| format!("invalid class enable value {value:#010x}"))?;
164            alert.configure(i, cls, enable)?;
165        }
166
167        for i in 0..ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_MULTIREG_COUNT as usize {
168            let value = otp.read32_offset("OWNER_SW_CFG_ROM_LOCAL_ALERT_CLASSIFICATION", i * 4)?;
169            let cls = AlertClass::from_repr(value.to_le_bytes()[lc_shift])
170                .with_context(|| format!("invalid alert class value {value:#010x}"))?;
171            let enable = AlertEnable::from_repr(class_enable.to_le_bytes()[cls.index()])
172                .with_context(|| format!("invalid class enable value {value:#010x}"))?;
173            alert.local_configure(i, cls, enable)?;
174        }
175
176        for i in 0..ALERT_HANDLER_PARAM_N_CLASSES as usize {
177            let mut phase_cycs = [0; ALERT_HANDLER_PARAM_N_PHASES as usize];
178            for phase in 0..ALERT_HANDLER_PARAM_N_PHASES as usize {
179                phase_cycs[phase] = otp.read32_offset(
180                    "OWNER_SW_CFG_ROM_ALERT_PHASE_CYCLES",
181                    (i * phase_cycs.len() + phase) * 4,
182                )?;
183            }
184            let config = AlertClassConfig {
185                enabled: AlertEnable::from_repr(class_enable.to_le_bytes()[i])
186                    .with_context(|| format!("invalid class enable value {class_enable:#010x}"))?,
187                escalate: AlertEscalate::from_repr(class_escalate.to_le_bytes()[i]).with_context(
188                    || format!("invalid class escalate value {class_escalate:#010x}"),
189                )?,
190                accum_thresh: otp.read32_offset("OWNER_SW_CFG_ROM_ALERT_ACCUM_THRESH", i * 4)?,
191                timeout_cyc: otp.read32_offset("OWNER_SW_CFG_ROM_ALERT_TIMEOUT_CYCLES", i * 4)?,
192                phase_cycs,
193            };
194            alert.class_configure(AlertClass::from_index(i), &config)?;
195        }
196
197        Ok(alert)
198    }
199
200    fn configure(&mut self, index: usize, cls: AlertClass, enabled: AlertEnable) -> Result<()> {
201        if index >= ALERT_HANDLER_ALERT_CLASS_SHADOWED_MULTIREG_COUNT as usize {
202            bail!("Bad alert index {}", index);
203        }
204
205        self.class[index] = match cls {
206            AlertClass::A => ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSA,
207            AlertClass::B => ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSB,
208            AlertClass::C => ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSC,
209            AlertClass::D => ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSD,
210            AlertClass::X => return Ok(()),
211        };
212
213        match enabled {
214            AlertEnable::None => {}
215            AlertEnable::Enabled => self.en[index] = 1,
216            AlertEnable::Locked => {
217                self.en[index] = 1;
218                self.regwen[index] = 0;
219            }
220        };
221
222        Ok(())
223    }
224
225    fn local_configure(
226        &mut self,
227        index: usize,
228        cls: AlertClass,
229        enabled: AlertEnable,
230    ) -> Result<()> {
231        if index >= ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_MULTIREG_COUNT as usize {
232            bail!("Bad local alert index {}", index);
233        }
234
235        self.loc_class[index] = match cls {
236            AlertClass::A => ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSA,
237            AlertClass::B => ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSB,
238            AlertClass::C => ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSC,
239            AlertClass::D => ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSD,
240            AlertClass::X => return Ok(()),
241        };
242
243        match enabled {
244            AlertEnable::None => {}
245            AlertEnable::Enabled => self.loc_en[index] = 1,
246            AlertEnable::Locked => {
247                self.loc_en[index] = 1;
248                self.loc_regwen[index] = 0;
249            }
250        };
251
252        Ok(())
253    }
254
255    fn class_configure(&mut self, cls: AlertClass, config: &AlertClassConfig) -> Result<()> {
256        let index = match cls {
257            AlertClass::A => 0,
258            AlertClass::B => 1,
259            AlertClass::C => 2,
260            AlertClass::D => 3,
261            AlertClass::X => bail!("Bad class"),
262        };
263
264        let mut reg = 0_u32;
265
266        // TODO(lowRISC/opentitan#15443): Fix this lint (clippy::erasing_op):
267        //reg |= (0 & ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E0_MASK)
268        //    << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E0_OFFSET;
269        reg |= (1 & ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E1_MASK)
270            << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E1_OFFSET;
271        reg |= (2 & ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E2_MASK)
272            << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E2_OFFSET;
273        reg |= (3 & ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E3_MASK)
274            << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E3_OFFSET;
275
276        match config.enabled {
277            AlertEnable::None => {}
278            AlertEnable::Enabled => {
279                reg |= 1 << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_BIT;
280            }
281            AlertEnable::Locked => {
282                reg |= 1 << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_LOCK_BIT;
283                reg |= 1 << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_BIT;
284            }
285        }
286
287        match config.escalate {
288            AlertEscalate::Phase0 => {
289                reg |= 1 << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E0_BIT;
290            }
291            AlertEscalate::Phase1 => {
292                reg |= 1 << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E0_BIT;
293                reg |= 1 << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E1_BIT;
294            }
295            AlertEscalate::Phase2 => {
296                reg |= 1 << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E0_BIT;
297                reg |= 1 << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E1_BIT;
298                reg |= 1 << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E2_BIT;
299            }
300            AlertEscalate::Phase3 => {
301                reg |= 1 << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E0_BIT;
302                reg |= 1 << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E1_BIT;
303                reg |= 1 << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E2_BIT;
304                reg |= 1 << ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E3_BIT;
305            }
306            AlertEscalate::None => {}
307        }
308
309        self.class_regs[index].ctrl = reg;
310        self.class_regs[index].accum_thresh = config.accum_thresh;
311        self.class_regs[index].timeout_cyc = config.timeout_cyc;
312        self.class_regs[index].phase_cycs = config.phase_cycs;
313
314        Ok(())
315    }
316}
317
318trait Crc32Add {
319    fn crc32_add(self, digest: &mut Digest<u32>);
320}
321
322impl Crc32Add for u32 {
323    fn crc32_add(self, digest: &mut Digest<u32>) {
324        digest.update(self.to_le_bytes().as_slice())
325    }
326}
327
328impl<T: Crc32Add, const N: usize> Crc32Add for [T; N] {
329    fn crc32_add(self, digest: &mut Digest<u32>) {
330        self.into_iter().for_each(|v| v.crc32_add(digest));
331    }
332}
333
334impl Crc32Add for AlertClassRegs {
335    fn crc32_add(self, digest: &mut Digest<u32>) {
336        self.regwen.crc32_add(digest);
337        self.ctrl.crc32_add(digest);
338        self.accum_thresh.crc32_add(digest);
339        self.timeout_cyc.crc32_add(digest);
340        self.phase_cycs.crc32_add(digest);
341    }
342}
343
344impl Crc32Add for AlertRegs {
345    fn crc32_add(self, digest: &mut Digest<u32>) {
346        self.regwen.crc32_add(digest);
347        self.en.crc32_add(digest);
348        self.class.crc32_add(digest);
349        self.loc_regwen.crc32_add(digest);
350        self.loc_en.crc32_add(digest);
351        self.loc_class.crc32_add(digest);
352        self.class_regs.crc32_add(digest);
353    }
354}
355
356fn new_crc() -> Crc<u32> {
357    Crc::<u32>::new(&crc::CRC_32_ISO_HDLC)
358}
359
360#[cfg(test)]
361mod test {
362    use super::*;
363
364    // Register values dumped from device after alert_handler initialization.
365    const TEST_REGS: AlertRegs = AlertRegs {
366        regwen: [
367            0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
368            0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
369            0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
370            0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
371            0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
372            0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
373            0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
374            0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
375            0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
376        ],
377        en: [
378            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
379            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
380            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
381            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
382            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
383            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
384            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
385            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
386            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
387        ],
388        class: [
389            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
390            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
391            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
392            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
393            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
394            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
395            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
396            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
397            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
398        ],
399        loc_regwen: [
400            0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
401        ],
402        loc_en: [
403            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
404        ],
405        loc_class: [
406            0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
407        ],
408        class_regs: [
409            AlertClassRegs {
410                regwen: 0x00000001,
411                ctrl: 0x00003900,
412                accum_thresh: 0x00000000,
413                timeout_cyc: 0x00000000,
414                phase_cycs: [0x00000000, 0x0000000a, 0x0000000a, 0xffffffff],
415            },
416            AlertClassRegs {
417                regwen: 0x00000001,
418                ctrl: 0x00003900,
419                accum_thresh: 0x00000000,
420                timeout_cyc: 0x00000000,
421                phase_cycs: [0x00000000, 0x0000000a, 0x0000000a, 0xffffffff],
422            },
423            AlertClassRegs {
424                regwen: 0x00000001,
425                ctrl: 0x00003900,
426                accum_thresh: 0x00000000,
427                timeout_cyc: 0x00000000,
428                phase_cycs: [0x00000000, 0x00000000, 0x00000000, 0x00000000],
429            },
430            AlertClassRegs {
431                regwen: 0x00000001,
432                ctrl: 0x00003900,
433                accum_thresh: 0x00000000,
434                timeout_cyc: 0x00000000,
435                phase_cycs: [0x00000000, 0x00000000, 0x00000000, 0x00000000],
436            },
437        ],
438    };
439
440    struct TestOtpAlertsDisabled {}
441
442    // OTP values that corrispond to the above `TEST_REG` values.
443    impl OtpRead for TestOtpAlertsDisabled {
444        fn read32_offset(&self, name: &str, offset: usize) -> Result<u32> {
445            Ok(match name {
446                "OWNER_SW_CFG_ROM_ALERT_CLASS_EN" => 0xa9a9a9a9,
447                "OWNER_SW_CFG_ROM_ALERT_ESCALATION" => 0xd1d1d1d1,
448                "OWNER_SW_CFG_ROM_ALERT_CLASSIFICATION"
449                | "OWNER_SW_CFG_ROM_LOCAL_ALERT_CLASSIFICATION" => 0x94949494,
450                "OWNER_SW_CFG_ROM_ALERT_PHASE_CYCLES" => [
451                    0x00000000, 0x0000000a, 0x0000000a, 0xffffffff, // Class 0
452                    0x00000000, 0x0000000a, 0x0000000a, 0xffffffff, // Class 1
453                    0x00000000, 0x00000000, 0x00000000, 0x00000000, // Class 2
454                    0x00000000, 0x00000000, 0x00000000, 0x00000000, // Class 3
455                ][offset / 4],
456                "OWNER_SW_CFG_ROM_ALERT_ACCUM_THRESH" | "OWNER_SW_CFG_ROM_ALERT_TIMEOUT_CYCLES" => {
457                    0x00000000
458                }
459                _ => panic!("No such OTP value {}", name),
460            })
461        }
462    }
463
464    struct TestOtpAlertsEnabled {}
465
466    // OTP values with `*_CLASS_EN` vales set to `kAlertEnableEnabled`
467    impl OtpRead for TestOtpAlertsEnabled {
468        fn read32_offset(&self, name: &str, offset: usize) -> Result<u32> {
469            Ok(match name {
470                "OWNER_SW_CFG_ROM_ALERT_CLASS_EN" => 0x07070707,
471                "OWNER_SW_CFG_ROM_ALERT_ESCALATION" => 0xd1d1d1d1,
472                "OWNER_SW_CFG_ROM_ALERT_CLASSIFICATION"
473                | "OWNER_SW_CFG_ROM_LOCAL_ALERT_CLASSIFICATION" => 0x94949494,
474                "OWNER_SW_CFG_ROM_ALERT_PHASE_CYCLES" => [
475                    0x00000000, 0x0000000a, 0x0000000a, 0xffffffff, // Class 0
476                    0x00000000, 0x0000000a, 0x0000000a, 0xffffffff, // Class 1
477                    0x00000000, 0x00000000, 0x00000000, 0x00000000, // Class 2
478                    0x00000000, 0x00000000, 0x00000000, 0x00000000, // Class 3
479                ][offset / 4],
480                "OWNER_SW_CFG_ROM_ALERT_ACCUM_THRESH" | "OWNER_SW_CFG_ROM_ALERT_TIMEOUT_CYCLES" => {
481                    0x00000000
482                }
483                _ => panic!("No such OTP value {}", name),
484            })
485        }
486    }
487
488    // A sanity test to make sure the correct CRC algorithm is being used.
489    //
490    // These values are taken from the CRC32 unit tests in
491    // `sw/device/lib/base/crc32_unittest.cc`.
492    #[test]
493    fn test_new_crc() {
494        let crc = new_crc();
495        let mut digest = crc.digest();
496        digest.update(b"123456789");
497        assert_eq!(digest.finalize(), 0xcbf43926);
498
499        let crc = new_crc();
500        let mut digest = crc.digest();
501        digest.update(b"The quick brown fox jumps over the lazy dog");
502        assert_eq!(digest.finalize(), 0x414fa339);
503
504        let crc = new_crc();
505        let mut digest = crc.digest();
506        digest.update(b"\xfe\xca\xfe\xca\x02\xb0\xad\x1b");
507        assert_eq!(digest.finalize(), 0x9508ac14);
508    }
509
510    #[test]
511    fn test_crc_from_regs() {
512        assert_eq!(TEST_REGS.crc32(), 0xd812e34);
513    }
514
515    #[test]
516    fn test_regs_from_otp() {
517        assert_eq!(
518            TEST_REGS,
519            AlertRegs::try_new(LcStateVal::Dev, &TestOtpAlertsDisabled {}).unwrap()
520        );
521    }
522
523    #[test]
524    fn test_crc_disabled() {
525        assert_eq!(
526            AlertRegs::try_new(LcStateVal::Dev, &TestOtpAlertsDisabled {})
527                .unwrap()
528                .crc32(),
529            0xd812e34
530        );
531    }
532
533    #[test]
534    fn test_crc_enabled() {
535        assert_eq!(
536            AlertRegs::try_new(LcStateVal::Dev, &TestOtpAlertsEnabled {})
537                .unwrap()
538                .crc32(),
539            0xa2fb8402
540        );
541    }
542}