Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions services/orchestrator/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,11 +259,11 @@ impl<R, G> DeviceConfig<R, G> {
/// the proof, and downstream conversions (the orchestrator's chain of
/// trust) need no failure path of their own.
#[derive(Debug, Clone, Copy)]
pub struct DeviceTable<R: 'static, G: 'static> {
devices: &'static [DeviceConfig<R, G>],
pub struct DeviceTable<R: 'static, G: 'static, const N: usize> {
devices: &'static [DeviceConfig<R, G>; N],
}

impl<R, G> DeviceTable<R, G> {
impl<R, G, const N: usize> DeviceTable<R, G, N> {
/// Declares the board's device table. `const`, so a bad table is a
/// build error.
///
Expand All @@ -276,10 +276,10 @@ impl<R, G> DeviceTable<R, G> {
/// dangling and self dependencies: a dependency is always walked
/// before its dependents).
#[must_use]
pub const fn new(devices: &'static [DeviceConfig<R, G>]) -> Self {
assert!(!devices.is_empty(), "device table must not be empty");
pub const fn new(devices: &'static [DeviceConfig<R, G>; N]) -> Self {
assert!(N != 0, "device table must not be empty");
assert!(
devices.len() <= u8::MAX as usize,
N <= u8::MAX as usize,
"device table exceeds the orchestrator's cursor bound"
);
let mut i = 0;
Expand Down Expand Up @@ -313,7 +313,7 @@ impl<R, G> DeviceTable<R, G> {

/// The devices, in declaration order — which is the boot order.
#[must_use]
pub const fn devices(&self) -> &'static [DeviceConfig<R, G>] {
pub const fn devices(&self) -> &'static [DeviceConfig<R, G>; N] {
self.devices
}
}
Expand Down Expand Up @@ -394,7 +394,7 @@ mod tests {
#[test]
#[should_panic(expected = "device table must not be empty")]
fn rejects_an_empty_table() {
let _ = DeviceTable::new(&[] as &[DeviceConfig<u8, u8>]);
let _ = DeviceTable::new(&[] as &[DeviceConfig<u8, u8>; 0]);
}

#[test]
Expand Down
13 changes: 3 additions & 10 deletions services/orchestrator/sm/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,17 +358,8 @@ impl<const N: usize> Chain<N> {
/// home yet — nothing consumes it — so every component gets the default
/// region.
///
/// # Panics
///
/// Panics if `N` is smaller than the table. Unreachable when `N` is
/// derived from the same table (`table.devices().len()`), which is the
/// only intended call shape.
pub fn from_table<R, G: 'static>(table: &orchestrator_config::DeviceTable<R, G>) -> Self {
pub fn from_table<R, G: 'static>(table: &orchestrator_config::DeviceTable<R, G, N>) -> Self {
let devices = table.devices();
assert!(
devices.len() <= N,
"chain capacity N is smaller than the device table"
);
let mut entries = heapless::Vec::new();
for (i, device) in devices.iter().enumerate() {
let depends_on = device.depends_on().map(|dep| {
Expand All @@ -384,6 +375,8 @@ impl<const N: usize> Chain<N> {
recovery_region: RegionId::new(0),
depends_on,
};
// `DeviceTable<R, G, N>` and `Chain<N>` share the same const
// capacity, so this push cannot fail.
let _ = entries.push((ComponentId::new(i as u8), attrs));
}
Self { entries }
Expand Down
4 changes: 2 additions & 2 deletions services/orchestrator/sm/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1566,9 +1566,9 @@ fn chain_derives_from_device_table() {
&[CHECKPOINT],
)
.with_depends_on("root");
const TABLE: DeviceTable<u8, u8> = DeviceTable::new(&[ROOT, LEAF]);
const TABLE: DeviceTable<u8, u8, 2> = DeviceTable::new(&[ROOT, LEAF]);

let entries = Chain::<CAPACITY>::from_table(&TABLE).into_entries();
let entries = Chain::<2>::from_table(&TABLE).into_entries();
assert_eq!(
entries.as_slice(),
&[
Expand Down
2 changes: 1 addition & 1 deletion target/mock/devices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub enum MockSignal {
///
/// The mock board's reset controller addresses reset lines by plain index,
/// so the reset id type is `u8`.
pub const MANAGED_DEVICES: DeviceTable<u8, MockSignal> = DeviceTable::new(&[
pub const MANAGED_DEVICES: DeviceTable<u8, MockSignal, 2> = DeviceTable::new(&[
// Direct-flash SPI device (BMC archetype): the eRoT fronts its flash.
// No iRoT, so the eRoT's check is the only trust gate (Passive), and
// the platform is pointless without its BMC (Required). Single
Expand Down