1use anyhow::{Result, bail};
6use serde::Deserialize;
7use std::fs;
8use std::path::Path;
9
10#[derive(Deserialize, Debug)]
12pub struct LcSecded {
13 data_width: usize,
15 ecc_width: usize,
17 ecc_matrix: Vec<Vec<u8>>,
19}
20
21#[derive(Deserialize, Debug)]
23pub struct LcState {
24 secded: LcSecded,
25}
26
27#[repr(u32)]
28#[derive(Copy, Clone)]
29pub enum LcStateVal {
30 Test = 0xb2865fbb,
31 Dev = 0x0b5a75e0,
32 Prod = 0x65f2520f,
33 ProdEnd = 0x91b9b68a,
34 Rma = 0xcf8cfaab,
35}
36
37impl LcSecded {
38 pub fn new(in_file: &Path) -> Result<LcSecded> {
39 let json_text = fs::read_to_string(in_file)?;
40 let res: LcState = deser_hjson::from_str(&json_text)?;
41 if res.secded.ecc_matrix.len() != res.secded.ecc_width {
42 bail!("Bad ecc matrix length {}", res.secded.ecc_matrix.len());
43 }
44 Ok(res.secded)
45 }
46
47 fn bit_index(data: &[u8], index: usize) -> bool {
48 let byte = index / 8;
49 let bit = index % 8;
50 data[byte] & (1 << bit) != 0
51 }
52
53 pub fn ecc_encode(&self, mut data: Vec<u8>) -> Result<Vec<u8>> {
54 if data.len() * 8 != self.data_width {
55 bail!("Bad data length for ecc {}", data.len() * 8);
56 }
57 let data_len = data.len();
58 data.resize(data_len + self.ecc_byte_len(), 0);
59 for (i, matrix) in self.ecc_matrix.iter().enumerate() {
60 let mut bit = false;
61 for j in matrix {
62 bit ^= Self::bit_index(&data, *j as usize);
63 }
64 if bit {
65 let byte = i / 8 + data_len;
66 let bit = i % 8;
67 data[byte] |= 1 << bit;
68 }
69 }
70
71 Ok(data)
72 }
73
74 pub fn ecc_byte_len(&self) -> usize {
75 if self.ecc_width == 0 {
76 0
77 } else {
78 (self.ecc_width - 1) / 8 + 1
79 }
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use crate::util::testdata;
87 use anyhow::Result;
88 use deser_hjson::from_str;
89 use std::fs::read_to_string;
90
91 #[test]
92 fn test_lc_state_deserialize() -> Result<()> {
93 let _: LcState = from_str(&read_to_string(testdata("otp/lc_ctrl_state.hjson"))?)?;
94 Ok(())
95 }
96
97 #[test]
98 fn test_ecc_encode() {
99 let secded = LcSecded {
100 data_width: 16,
101 ecc_width: 6,
102 ecc_matrix: vec![
103 vec![0, 1, 3, 4, 6, 8, 10, 11, 13, 15], vec![0, 2, 3, 5, 6, 9, 10, 12, 13], vec![1, 2, 3, 7, 8, 9, 10, 14, 15], vec![4, 5, 6, 7, 8, 9, 10], vec![11, 12, 13, 14, 15], vec![
109 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
110 ], ],
112 };
113
114 let zero: Vec<u8> = vec![0, 0];
115 let a5a5: Vec<u8> = vec![0xa5, 0xa5];
116 let fcc5: Vec<u8> = vec![0xfc, 0xc5];
117 assert_eq!(vec![0u8, 0, 0], secded.ecc_encode(zero).unwrap());
118 assert_eq!(vec![0xa5u8, 0xa5, 0x27], secded.ecc_encode(a5a5).unwrap());
119 assert_eq!(vec![0x0fcu8, 0xc5, 0x06], secded.ecc_encode(fcc5).unwrap())
120 }
121}