consortium_cfg/lib.rs
1// Copyright 2026 Ethan Wu
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// SPDX-License-Identifier: Apache-2.0
16
17//! Turns a `Consortium.toml` manifest into validated configuration, generated Rust,
18//! and Linux integration artifacts.
19//!
20//! This is the crate that makes Consortium's "explicit cross-core contracts" idea
21//! pay off. A manifest declares what the system *is* — which cores exist, which
22//! memory windows they share, which doorbell rings which — and this crate checks
23//! that against the chip's real capabilities, then emits the bring-up code and
24//! device-tree nodes that make it so. Firmware and application authors never write
25//! the address arithmetic, the UIO ids, or the doorbell wiring by hand.
26//!
27//! # Pipeline
28//!
29//! ```text
30//! Consortium.toml
31//! └─ session parse + resolve the chip database + validate → Session
32//! └─ bridge lower into the components IR → ShmNode, BellA, …
33//! └─ components each IR node generates its own output
34//! ├─ Rust tokens ─ render ─→ src/consortium.gen.rs
35//! ├─ DTS nodes ────────→ merged tree or .dtso
36//! └─ Kconfig / boot / systemd fragments
37//! ```
38//!
39//! | Stage | Module | Produces |
40//! | --------------- | -------------- | ------------------------------------------- |
41//! | Parse, validate | [`session`] | [`Session`] — manifest bound to its chip database |
42//! | Lower | [`bridge`] | The [`components`] IR, with addresses and UIO ids resolved |
43//! | Generate | [`components`] | Rust tokens, DTS nodes, UIO/Kconfig fragments |
44//! | Format | [`render()`](render()) | Formatted Rust source |
45//!
46//! [`consortium-builder`] drives this and adds compilation, staging, and packaging.
47//!
48//! [`consortium-builder`]: https://docs.rs/consortium-builder
49//!
50//! # What validation catches
51//!
52//! [`Session::from_toml`] resolves `[profile] chip` through the embedded databases
53//! in `consortium-data` and then rejects manifests that ask for things the chip
54//! cannot do — the errors in [`CfgError`] are the interesting part of this crate's
55//! contract:
56//!
57//! - a doorbell the chip does not have, or a doorbell channel out of its range;
58//! - a channel whose party is not a visible core, or has no declared endpoint;
59//! - two channels claiming the same doorbell channel;
60//! - memory regions out of bounds, overlapping, or misaligned for the MPU;
61//! - debug regions that collide with IPC regions;
62//! - a peripheral owned by a core that cannot reach it — checked against the
63//! per-core chip map, so the filter is the peripherals that core's CMSIS view
64//! actually contains;
65//! - `[peripheral.*]` with `secure = true`, since the chip HAL's singletons carry
66//! only the non-secure alias.
67//!
68//! Catching these at manifest-parse time is the point: each would otherwise be a
69//! silent bus error or a link that never wakes.
70//!
71//! # Where the fixed decisions live
72//!
73//! [`bridge`] pins the AP-side address layout so the firmware, NVIC, and Linux DTS
74//! outputs cannot disagree:
75//!
76//! - every device — the aggregate IPC shared-memory device, one per distinct
77//! doorbell, and the aggregate debug-ring device — gets its `uioN` id by
78//! ascending mapped base, so ids follow the memory map the kernel enumerates;
79//! - within the IPC device a region's `mmap_id` is its index in channel-declaration
80//! order, and a doorbell always exposes its register window as `mmap_id` 0.
81//!
82//! # Generated code
83//!
84//! The output is `src/consortium.gen.rs` in each endpoint crate, which the crate
85//! `include!`s. It defines `Config`, endpoint-local `Peripherals` and `Channels`,
86//! and synchronous `init(config)`. Init performs local platform bring-up and
87//! installs unsplit transports; application code connects each channel token
88//! independently before use.
89//!
90//! Because a generated crate cannot be `cargo check`ed before the pipeline has run,
91//! the melt-pot endpoint crates are excluded from the workspace.
92//!
93//! # Adding to the schema
94//!
95//! Work outward, because each step's tests depend on the previous: schema types in
96//! `consortium-cfg-common` → validation in [`session`] → lowering in [`bridge`] →
97//! codegen in [`components`]. Then update the snapshot tests under `tests/`.
98//!
99//! `Consortium.example.*.toml` and [`session`]'s own tests are the best references
100//! for current syntax — older melt-pot manifests drift.
101
102pub mod bridge;
103pub mod components;
104pub mod error;
105pub mod render;
106pub mod session;
107
108pub use render::render;
109
110// The chip-family database and per-core chip maps live in `consortium-data`.
111// Re-export them under their historical paths so existing `crate::database` /
112// `crate::chipmap` references keep resolving.
113pub use consortium_data::{chipmap, database, signal};
114
115pub use consortium_cfg_common::config;
116pub use error::CfgError;
117pub use session::Session;