Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5ba535a
Add `read_panic_message` kipc
hawkw Dec 3, 2025
1313935
Update kipc.rs
hawkw Dec 3, 2025
07460ec
review feedback + tidiness
hawkw Dec 3, 2025
68a2fb7
CLIPPY DAMAGE
hawkw Dec 3, 2025
2ab7a43
Merge branch 'master' into eliza/read-panic-message
hawkw Dec 4, 2025
8a221c1
Merge branch 'master' into eliza/read-panic-message
hawkw Dec 18, 2025
425c221
add note on UTF-8 truncation
hawkw Dec 29, 2025
3748fda
Update kipc.adoc
hawkw Dec 30, 2025
09fe93f
Update kipc.adoc
hawkw Dec 30, 2025
e468ef7
Update main.rs
hawkw Dec 30, 2025
7b4a6bb
More of @cbiffle's docs suggestions
hawkw Dec 30, 2025
2d9b1d2
line wrapping, docs links
hawkw Jan 5, 2026
fb2af3f
improve docs/naming for invalid buffers
hawkw Jan 5, 2026
5193057
@cbiffle convinced me to return Utf8Chunks
hawkw Jan 5, 2026
1439da0
jefe: Add mechanism for notifying another task on task faults
hawkw Jan 5, 2026
9c08e49
ereportulator: explicit panic for testing
hawkw Jan 5, 2026
a4798c9
packrat: wire up task fault notification
hawkw Jan 5, 2026
384307a
packrat: draw most of the rest of the owl
hawkw Jan 5, 2026
e608474
packrat: finish ereports
hawkw Jan 5, 2026
596c8cd
you bastards, you blew it all up!
hawkw Jan 5, 2026
d5fde83
i am stupid and also dumb
hawkw Jan 5, 2026
d145efc
don't bind unused variable
hawkw Jan 5, 2026
f4e5713
properly(?) handle invalid utf8
hawkw Jan 5, 2026
bc6268d
pwease dead-code eliminate me 🥺🥺🥺
hawkw Jan 5, 2026
a9ef212
Merge branch 'master' into eliza/fault-ereport
hawkw Jan 6, 2026
d3ff2bb
embiggen oxcon g0 dongle
hawkw Jan 6, 2026
f7d6231
Revert "pwease dead-code eliminate me 🥺🥺🥺"
hawkw Jan 6, 2026
525fce9
timestamp is now dead code
hawkw Jan 6, 2026
b906b4e
more commentary
hawkw Jan 6, 2026
b405002
clippy tidiness
hawkw Jan 6, 2026
b31df43
Merge branch 'master' into eliza/fault-ereport
hawkw Jan 6, 2026
7980493
Merge branch 'master' into eliza/fault-ereport
hawkw Jan 6, 2026
3eeb290
don't skip faults when the task has been restarted
hawkw Jan 6, 2026
f031658
ensmallerate a couple imports
hawkw Jan 6, 2026
75538b7
clippy fix when ereports are turned off
hawkw Jan 6, 2026
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
4 changes: 4 additions & 0 deletions app/cosmo/base.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ net = "jefe-state-change"
host_sp_comms = "jefe-state-change"
spd = "jefe-state-change"

[tasks.jefe.config.on-task-fault]
packrat = "task-faulted"

[tasks.jefe.config.allowed-callers]
set_state = ["cosmo_seq"]
set_reset_reason = ["sys"]
Expand Down Expand Up @@ -133,6 +136,7 @@ start = true
# task-slots is explicitly empty: packrat should not send IPCs!
task-slots = []
features = ["cosmo", "ereport"]
notifications = ["task-faulted"]

[tasks.rng_driver]
features = ["h753", "ereport"]
Expand Down
4 changes: 4 additions & 0 deletions app/gimlet/base.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ net = "jefe-state-change"
host_sp_comms = "jefe-state-change"
spd = "jefe-state-change"

[tasks.jefe.config.on-task-fault]
packrat = "task-faulted"

[tasks.jefe.config.allowed-callers]
set_state = ["gimlet_seq"]
set_reset_reason = ["sys"]
Expand Down Expand Up @@ -127,6 +130,7 @@ start = true
# task-slots is explicitly empty: packrat should not send IPCs!
task-slots = []
features = ["gimlet", "ereport"]
notifications = ["task-faulted"]

[tasks.thermal]
name = "task-thermal"
Expand Down
4 changes: 4 additions & 0 deletions app/gimletlet/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ request_reset = ["hiffy", "control_plane_agent", "udprpc"]
[tasks.jefe.config.on-state-change]
host_sp_comms = "jefe-state-change"

[tasks.jefe.config.on-task-fault]
packrat = "task-faulted"

[tasks.sys]
# Enable EXTI in the sys task so that we can notify sprot when the RoT
# raises an IRQ.
Expand Down Expand Up @@ -51,6 +54,7 @@ start = true
task-slots = []
stacksize = 1096
features = ["ereport"]
notifications = ["task-faulted"]

[tasks.control_plane_agent]
name = "task-control-plane-agent"
Expand Down
4 changes: 4 additions & 0 deletions app/grapefruit/app-dev.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ interrupts = {"uart8.irq" = "usart-irq"}
[tasks.packrat]
stacksize = 1096
features = ["ereport"]
notifications = ["task-faulted"]

[tasks.jefe.config.on-task-fault]
packrat = "task-faulted"

[tasks.snitch]
name = "task-snitch"
Expand Down
2 changes: 1 addition & 1 deletion app/oxcon2023g0/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ board = "oxcon2023g0"

[kernel]
name = "oxcon2023g0"
requires = {flash = 11680, ram = 1296}
requires = {flash = 11776, ram = 1296}
stacksize = 640

[tasks.jefe]
Expand Down
4 changes: 4 additions & 0 deletions app/psc/base.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ extern-regions = ["sram1", "sram2", "sram3", "sram4"]
[tasks.jefe.config.on-state-change]
net = "jefe-state-change"

[tasks.jefe.config.on-task-fault]
packrat = "task-faulted"

[tasks.jefe.config.allowed-callers]
set_reset_reason = ["sys"]
request_reset = ["hiffy", "control_plane_agent"]
Expand Down Expand Up @@ -123,6 +126,7 @@ start = true
# task-slots is explicitly empty: packrat should not send IPCs!
task-slots = []
features = ["ereport"]
notifications = ["task-faulted"]

[tasks.sequencer]
name = "drv-psc-seq-server"
Expand Down
4 changes: 4 additions & 0 deletions app/sidecar/base.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ extern-regions = ["sram1", "sram2", "sram3", "sram4"]
set_reset_reason = ["sys"]
request_reset = ["hiffy", "control_plane_agent"]

[tasks.jefe.config.on-task-fault]
packrat = "task-faulted"

[tasks.sys]
name = "drv-stm32xx-sys"
features = ["h753", "exti", "no-panic"]
Expand Down Expand Up @@ -262,6 +265,7 @@ start = true
# task-slots is explicitly empty: packrat should not send IPCs!
task-slots = []
features = ["ereport"]
notifications = ["task-faulted"]

[tasks.sequencer]
name = "drv-sidecar-seq-server"
Expand Down
7 changes: 7 additions & 0 deletions idl/ereportulator.idol
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,12 @@ Interface(
),
idempotent: true,
),
"panicme": (
doc: "Make the ereportulator panic",
args: {
},
reply: Simple("()"),
idempotent: true,
),
}
)
6 changes: 0 additions & 6 deletions sys/kern/src/kipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,12 +482,6 @@ fn find_faulted_task(
message: USlice<u8>,
response: USlice<u8>,
) -> Result<NextTask, UserError> {
if caller != 0 {
return Err(UserError::Unrecoverable(FaultInfo::SyscallUsage(
UsageError::NotSupervisor,
)));
}

let index = deserialize_message::<u32>(&tasks[caller], message)? as usize;

// Note: we explicitly permit index == tasks.len(), which causes us to wrap
Expand Down
1 change: 1 addition & 0 deletions sys/num-tasks/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {

if build_util::has_feature("task-enum") {
writeln!(task_file, "#[allow(non_camel_case_types)]").unwrap();
writeln!(task_file, "#[derive(Copy, Clone)]").unwrap();
writeln!(task_file, "pub enum Task {{").unwrap();
for line in task_enum {
writeln!(task_file, "{line}").unwrap();
Expand Down
2 changes: 1 addition & 1 deletion task/ereportulator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"

[dependencies]
userlib = { path = "../../sys/userlib" }
userlib = { path = "../../sys/userlib", features = ["panic-messages"] }
idol-runtime.workspace = true
zerocopy.workspace = true
zerocopy-derive.workspace = true
Expand Down
7 changes: 7 additions & 0 deletions task/ereportulator/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,13 @@ impl idl::InOrderEreportulatorImpl for ServerImpl {

Ok(())
}

fn panicme(
&mut self,
_msg: &RecvMessage,
) -> Result<(), RequestError<Infallible>> {
panic!("im dead lol")
}
}

impl idol_runtime::NotificationHandler for ServerImpl {
Expand Down
67 changes: 48 additions & 19 deletions task/jefe/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use anyhow::{Context, Result};
use serde::Deserialize;
use std::collections::{BTreeMap, BTreeSet};
use std::io::Write;
use std::io::{self, Write};

fn main() -> Result<()> {
build_util::expose_m_profile()?;
Expand Down Expand Up @@ -35,29 +35,21 @@ fn main() -> Result<()> {
let mut out =
std::fs::File::create(dest_path).context("creating jefe_config.rs")?;

let task = "hubris_num_tasks::Task";
{
let count = cfg.on_state_change.len();
gen_mailing_list(
"STATE_CHANGE_MAILING_LIST",
&cfg.on_state_change,
&mut out,
)
.context("generating state change mailing list")?;

writeln!(
out,
"pub(crate) const MAILING_LIST: [({task}, u32); {count}] = [",
)?;
for (name, rec) in cfg.on_state_change {
writeln!(
out,
" ({task}::{name}, crate::notifications::{name}::{}_MASK),",
rec.to_ascii_uppercase().replace('-', "_"),
)?;
}
writeln!(out, "];")?;
}
gen_mailing_list("FAULT_MAILING_LIST", &cfg.on_task_fault, &mut out)
.context("generating task fault mailing list")?;

{
let count = cfg.tasks_to_hold.len();
writeln!(out, "pub(crate) const HELD_TASKS: [{task}; {count}] = [",)?;
writeln!(out, "pub(crate) const HELD_TASKS: [{TASK}; {count}] = [",)?;
for name in cfg.tasks_to_hold {
writeln!(out, " {task}::{name},")?;
writeln!(out, " {TASK}::{name},")?;
}
writeln!(out, "];")?;
}
Expand All @@ -67,6 +59,37 @@ fn main() -> Result<()> {
Ok(())
}

const TASK: &str = "hubris_num_tasks::Task";

/// Generates a "mailing list" of tasks to notify on a given event (such as a
/// state change or a task fault), from a `BTreeMap` mapping task names to
/// notification names.
///
/// The generated mailing list will be a `[(hubris_num_tasks::Task, u32)]` array
/// named `list_name`.
fn gen_mailing_list(
list_name: &str,
list: &BTreeMap<String, String>,
out: &mut impl std::io::Write,
) -> io::Result<()> {
let count = list.len();

writeln!(
out,
"pub(crate) const {list_name}: [({TASK}, u32); {count}] = [",
)?;
for (name, rec) in list {
writeln!(
out,
" ({TASK}::{name}, crate::notifications::{name}::{}_MASK),",
rec.to_ascii_uppercase().replace('-', "_"),
)?;
}
writeln!(out, "];")?;

Ok(())
}

/// Jefe task-level configuration.
#[derive(Deserialize, Default)]
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
Expand All @@ -75,6 +98,12 @@ struct Config {
/// notification name (in the target task)
#[serde(default)]
on_state_change: BTreeMap<String, String>,

/// Task requests to be notified when a task faults, as a map from task name to
/// notification name (in the target task)
#[serde(default)]
on_task_fault: BTreeMap<String, String>,

/// Map of operation names to tasks allowed to call them.
#[serde(default)]
allowed_callers: BTreeMap<String, Vec<String>>,
Expand Down
8 changes: 4 additions & 4 deletions task/jefe/src/external.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,10 @@ static JEFE_EXTERNAL_ERRORS: AtomicU32 = AtomicU32::new(0);
/// potentially modifying the passed array. Returns a boolean to indicate if
/// a valid external request was received.
///
pub(crate) fn check(states: &mut [TaskStatus], now: u64) {
pub(crate) fn check(states: &mut [TaskStatus]) {
// This wrapper is responsible for updating operation counters, and allowing
// the inner function to use Result for convenience.
match check_inner(states, now) {
match check_inner(states) {
Ok(true) => {
JEFE_EXTERNAL_REQUESTS.fetch_add(1, Ordering::SeqCst);
}
Expand All @@ -119,7 +119,7 @@ pub(crate) fn check(states: &mut [TaskStatus], now: u64) {
}

// Implementation factor of `check` that can use Result.
fn check_inner(states: &mut [TaskStatus], now: u64) -> Result<bool, Error> {
fn check_inner(states: &mut [TaskStatus]) -> Result<bool, Error> {
if JEFE_EXTERNAL_KICK.swap(0, Ordering::SeqCst) == 0 {
return Ok(false);
}
Expand Down Expand Up @@ -170,7 +170,7 @@ fn check_inner(states: &mut [TaskStatus], now: u64) -> Result<bool, Error> {
// task to clear a held fault.
state.disposition = Disposition::Restart;
if matches!(state.state, TaskState::HoldFault) {
state.state = TaskState::Running { started_at: now };
state.state = TaskState::Running;
kipc::reinit_task(ndx, true);
}
}
Expand Down
Loading