Skip to main content

dml_config/
lib.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use fidl_fuchsia_board_dml_config as fbdc;
6use fidl_fuchsia_driver_metadata as fdr;
7
8// Re-export FIDL types for convenience
9pub use fbdc::{AggregateEntry, BoardConfig, Device, ResourceEntry, StaticMetadata};
10
11#[derive(Debug, Clone, Default)]
12pub struct Mmio {
13    pub name: Option<String>,
14    pub base: u64,
15    pub length: u64,
16}
17
18#[derive(Debug, Clone, Default)]
19pub struct Irq {
20    pub name: Option<String>,
21    pub number: u32,
22    pub mode: Option<String>,
23}
24
25#[derive(Debug, Clone, Default)]
26pub struct Bti {
27    pub id: u32,
28}
29
30#[derive(Debug, Clone, Default)]
31pub struct Smc {
32    pub service_call_num_base: u32,
33    pub count: u32,
34    pub exclusive: bool,
35    pub name: Option<String>,
36}
37
38#[derive(Debug, Clone, Default)]
39pub struct BootMetadata {
40    pub zbi_type: u32,
41    pub zbi_extra: Option<u32>,
42}
43
44// Dictionary Lookup Helpers
45pub fn find_value<'a>(dict: &'a fdr::Dictionary, key: &str) -> Option<&'a fdr::DictionaryValue> {
46    dict.entries.as_ref()?.iter().find(|e| e.key == key).map(|e| &e.value)
47}
48
49pub fn get_int64(dict: &fdr::Dictionary, key: &str) -> Option<i64> {
50    match find_value(dict, key)? {
51        fdr::DictionaryValue::Int64(i) => Some(*i),
52        _ => None,
53    }
54}
55
56pub fn get_uint32(dict: &fdr::Dictionary, key: &str) -> Option<u32> {
57    get_int64(dict, key).and_then(|i| u32::try_from(i).ok())
58}
59
60pub fn get_uint64(dict: &fdr::Dictionary, key: &str) -> Option<u64> {
61    get_int64(dict, key).map(|i| i as u64)
62}
63
64pub fn get_string(dict: &fdr::Dictionary, key: &str) -> Option<String> {
65    match find_value(dict, key)? {
66        fdr::DictionaryValue::Str(s) => Some(s.clone()),
67        _ => None,
68    }
69}
70
71pub fn get_bool(dict: &fdr::Dictionary, key: &str) -> Option<bool> {
72    match find_value(dict, key)? {
73        fdr::DictionaryValue::Boolean(b) => Some(*b),
74        _ => None,
75    }
76}
77
78// Resource Parsing Helpers
79pub fn mmio_list(dict: &fdr::Dictionary) -> Vec<Mmio> {
80    let mut list = Vec::new();
81    for i in 0.. {
82        let prefix = format!("mmio.{}", i);
83        let base = get_uint64(dict, &format!("{}.base", prefix))
84            .or_else(|| get_uint64(dict, &format!("{}.address", prefix)));
85        if let Some(base) = base {
86            let length = get_uint64(dict, &format!("{}.length", prefix))
87                .or_else(|| get_uint64(dict, &format!("{}.size", prefix)))
88                .unwrap_or(0);
89            let name = get_string(dict, &format!("{}.name", prefix));
90            list.push(Mmio { name, base, length });
91        } else {
92            break;
93        }
94    }
95    list
96}
97
98pub fn irq_list(dict: &fdr::Dictionary) -> Vec<Irq> {
99    let mut list = Vec::new();
100    for i in 0.. {
101        let prefix = format!("interrupts.{}", i);
102        if let Some(number) = get_uint32(dict, &format!("{}.number", prefix)) {
103            let name = get_string(dict, &format!("{}.name", prefix));
104            let mode = get_string(dict, &format!("{}.mode", prefix));
105            list.push(Irq { name, number, mode });
106        } else {
107            break;
108        }
109    }
110    list
111}
112
113pub fn bti_list(dict: &fdr::Dictionary) -> Vec<Bti> {
114    let mut list = Vec::new();
115    for i in 0.. {
116        let prefix = format!("btis.{}", i);
117        if let Some(id) = get_uint32(dict, &format!("{}.id", prefix)) {
118            list.push(Bti { id });
119        } else {
120            break;
121        }
122    }
123    list
124}
125
126pub fn smc_list(dict: &fdr::Dictionary) -> Vec<Smc> {
127    let mut list = Vec::new();
128    for i in 0.. {
129        let prefix = format!("smcs.{}", i);
130        if let Some(service_call_num_base) =
131            get_uint32(dict, &format!("{}.service_call_num_base", prefix))
132        {
133            let count = get_uint32(dict, &format!("{}.count", prefix)).unwrap_or(0);
134            let exclusive = get_bool(dict, &format!("{}.exclusive", prefix)).unwrap_or(false);
135            let name = get_string(dict, &format!("{}.name", prefix));
136            list.push(Smc { service_call_num_base, count, exclusive, name });
137        } else {
138            break;
139        }
140    }
141    list
142}
143
144pub fn boot_metadata_list(dict: &fdr::Dictionary) -> Vec<BootMetadata> {
145    let mut list = Vec::new();
146    for i in 0.. {
147        let prefix = format!("boot_metadata.{}", i);
148        if let Some(zbi_type) = get_uint32(dict, &format!("{}.zbi_type", prefix)) {
149            let zbi_extra = get_uint32(dict, &format!("{}.zbi_extra", prefix));
150            list.push(BootMetadata { zbi_type, zbi_extra });
151        } else {
152            break;
153        }
154    }
155    list
156}
157
158pub fn pdev_constraints<'a>(
159    config: &'a BoardConfig,
160    node_name: &str,
161) -> Option<&'a fdr::Dictionary> {
162    config
163        .aggregates
164        .as_ref()?
165        .iter()
166        .find(|agg| {
167            agg.provider.as_deref() == Some("pdev")
168                && agg.service.as_deref() == Some("fuchsia.hardware.platform.device.Service")
169        })
170        .and_then(|agg| {
171            agg.resources
172                .as_ref()?
173                .iter()
174                .find(|res| res.node.as_deref() == Some(node_name))
175                .and_then(|res| res.constraint.as_ref())
176        })
177}
178
179#[cfg(target_os = "fuchsia")]
180pub mod parser;