firewire_dice_protocols/tcat/
config_rom.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! Parser for Configuration ROM according to specification defined by TCAT for ASICs of DICE.
5//!
6//! The module includes structure, enumeration, and trait and its implementaion to parse
7//! configuration ROM according to specification defined by TCAT for ASICs of DICE.
8
9use ieee1212_config_rom::*;
10
11/// Identifier in bus information block of Configuration ROM.
12#[derive(Default, Debug, Clone, Copy)]
13pub struct Identifier {
14    /// The numeric identifier of vendor, usually Organizationally Unique Identifier (OUI)
15    /// registered in IEEE.
16    pub vendor_id: u32,
17    /// The numeric value of category.
18    pub category: u8,
19    /// The numeric identifier of product.
20    pub product_id: u16,
21    /// The serial number.
22    pub serial: u32,
23}
24
25/// Data in root directory block of Configuration ROM.
26#[derive(Default, Debug, Clone, Copy)]
27pub struct RootData<'a> {
28    /// The numeric identifier of vendor, usually Organizationally Unique Identifier (OUI)
29    /// registered in IEEE.
30    pub vendor_id: u32,
31    /// The name of vendor.
32    pub vendor_name: &'a str,
33    /// The numeric identifier of product.
34    pub product_id: u32,
35    /// The name of product.
36    pub product_name: &'a str,
37}
38
39/// Data in unit directory block of Configuration ROM.
40#[derive(Default, Debug, Clone, Copy)]
41pub struct UnitData<'a> {
42    /// The numeric identifier of model.
43    pub model_id: u32,
44    /// The name of model.
45    pub model_name: &'a str,
46    /// The specifier identifier.
47    pub specifier_id: u32,
48    /// Version.
49    pub version: u32,
50}
51
52const VENDOR_ID_MASK: u32 = 0xffffff00;
53const VENDOR_ID_SHIFT: usize = 8;
54const CATEGORY_MASK: u32 = 0x000000ff;
55const CATEGORY_SHIFT: usize = 0;
56const PRODUCT_ID_MASK: u32 = 0xffc00000;
57const PRODUCT_ID_SHIFT: usize = 22;
58const SERIAL_MASK: u32 = 0x003fffff;
59const SERIAL_SHIFT: usize = 0;
60
61/// Parser of configuration ROM which has layout specific to DICE.
62pub trait DiceConfigRom<'a> {
63    /// Get identifier.
64    fn get_identifier(&self) -> Option<Identifier>;
65    /// Get data in root directory.
66    fn get_root_data(&'a self) -> Option<RootData<'a>>;
67    /// Get data in unit directory.
68    fn get_unit_data(&'a self) -> Vec<UnitData<'a>>;
69}
70
71impl<'a> DiceConfigRom<'a> for ConfigRom<'a> {
72    fn get_identifier(&self) -> Option<Identifier> {
73        if self.bus_info.len() < 12 {
74            None
75        } else {
76            let mut quadlet = [0; 4];
77
78            quadlet.copy_from_slice(&self.bus_info[8..12]);
79            let val = u32::from_be_bytes(quadlet);
80            let vendor_id = (val & VENDOR_ID_MASK) >> VENDOR_ID_SHIFT;
81            let category = ((val & CATEGORY_MASK) >> CATEGORY_SHIFT) as u8;
82
83            quadlet.copy_from_slice(&self.bus_info[12..16]);
84            let val = u32::from_be_bytes(quadlet);
85            let product_id = ((val & PRODUCT_ID_MASK) >> PRODUCT_ID_SHIFT) as u16;
86            let serial = (val & SERIAL_MASK) >> SERIAL_SHIFT;
87
88            Some(Identifier {
89                vendor_id,
90                category,
91                product_id,
92                serial,
93            })
94        }
95    }
96
97    fn get_root_data(&'a self) -> Option<RootData<'a>> {
98        let (vendor_id, vendor_name) = detect_desc_text(&self.root, KeyType::Vendor)?;
99        let (product_id, product_name) = detect_desc_text(&self.root, KeyType::Model)?;
100        let data = RootData {
101            vendor_id,
102            vendor_name,
103            product_id,
104            product_name,
105        };
106        Some(data)
107    }
108
109    fn get_unit_data(&'a self) -> Vec<UnitData<'a>> {
110        self.root
111            .iter()
112            .filter_map(|entry| {
113                let entries = EntryDataAccess::<&[Entry]>::get(entry, KeyType::Unit)?;
114                let specifier_id = entries
115                    .iter()
116                    .find_map(|entry| EntryDataAccess::<u32>::get(entry, KeyType::SpecifierId))?;
117                let version = entries
118                    .iter()
119                    .find_map(|entry| EntryDataAccess::<u32>::get(entry, KeyType::Version))?;
120                let (model_id, model_name) = detect_desc_text(entries, KeyType::Model)?;
121                let data = UnitData {
122                    model_id,
123                    model_name,
124                    specifier_id,
125                    version,
126                };
127                Some(data)
128            })
129            .collect()
130    }
131}
132
133fn detect_desc_text<'a>(entries: &'a [Entry], key_type: KeyType) -> Option<(u32, &'a str)> {
134    let mut peekable = entries.iter().peekable();
135
136    while let Some(entry) = peekable.next() {
137        let result = EntryDataAccess::<u32>::get(entry, key_type).and_then(|value| {
138            peekable.peek().and_then(|&next| {
139                EntryDataAccess::<&str>::get(next, KeyType::Descriptor).map(|name| (value, name))
140            })
141        });
142
143        if result.is_some() {
144            return result;
145        }
146    }
147
148    None
149}