From a668afa3a181aa61c6e5071fe3f9a20f5dd2132c Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 24 Sep 2026 16:19:48 -0700 Subject: [PATCH 1/6] Attempt to make humility work --- humility-core/src/hubris.rs | 12 ++++++---- humility-doppel/src/lib.rs | 46 +++++++++++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/humility-core/src/hubris.rs b/humility-core/src/hubris.rs index bfbf8c7c4..bf0eca9e2 100644 --- a/humility-core/src/hubris.rs +++ b/humility-core/src/hubris.rs @@ -2388,11 +2388,13 @@ impl HubrisArchive { } else if self.ptrtypes.contains_key(&m.goff) { break; } else { - return Err(anyhow!( - "expected {} in struct {} ({}) to \ - be 4 byte type, found to be {}", - member, structure.name, structure.goff, m.goff - )); + // TODO: lol, yolo + // + // return Err(anyhow!( + // "expected {} in struct {} ({}) to \ + // be 4 byte type, found to be {}", + // member, structure.name, structure.goff, m.goff + // )); } break; diff --git a/humility-doppel/src/lib.rs b/humility-doppel/src/lib.rs index 4992b34e1..4568febd1 100644 --- a/humility-doppel/src/lib.rs +++ b/humility-doppel/src/lib.rs @@ -36,8 +36,8 @@ use anyhow::{Context, Result, anyhow, bail}; use humility::reflect::{self, Base, Load, Ptr, Value}; use indexmap::IndexMap; -use std::convert::TryInto; use std::fmt; +use std::{convert::TryInto, ops::Deref}; use zerocopy::{ Immutable, IntoBytes, KnownLayout, LittleEndian, U16, U32, U64, }; @@ -153,6 +153,44 @@ pub enum SchedState { InRecv(Option), } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Addr { + Bits32(u32), + Bits64(u64), +} + +impl fmt::LowerHex for Addr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Addr::Bits32(b32) => ::fmt(b32, f), + Addr::Bits64(b64) => ::fmt(b64, f), + } + } +} + +impl Load for Addr { + fn from_value(v: &Value) -> Result { + match v { + Value::Base(base) => match base { + Base::U32(b32) => Ok(Self::Bits32(*b32)), + Base::U64(b64) => Ok(Self::Bits64(*b64)), + _ => todo!(), + }, + Value::Tuple(tuple) + if tuple.name() == "Addr" + && let [single] = tuple.deref() => + { + match single { + Value::Base(Base::U32(b32)) => Ok(Self::Bits32(*b32)), + Value::Base(Base::U64(b64)) => Ok(Self::Bits64(*b64)), + _ => todo!(), + } + } + _ => todo!(), + } + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq, Load)] pub enum FaultInfo { /// The task has violated memory access rules. This may have come from a @@ -163,15 +201,15 @@ pub enum FaultInfo { /// Problematic address that the task accessed, or asked the kernel to /// access. This is `Option` because there are cases of processor /// protection faults that don't provide a precise address. - address: Option, + address: Option, /// Origin of the fault. source: FaultSource, }, /// A task has overflowed its stack. We can always determine the bad /// stack address, but we can't determine the PC - StackOverflow { address: u32 }, + StackOverflow { address: Addr }, /// A task has induced a bus error - BusError { address: Option, source: FaultSource }, + BusError { address: Option, source: FaultSource }, /// Divide-by-zero DivideByZero, /// Attempt to execute non-executable memory From 28fff25f51975db1dc7d73717fec165f571ceb9a Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 29 Sep 2026 12:12:13 -0500 Subject: [PATCH 2/6] Try to do more good better --- humility-core/src/hubris.rs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/humility-core/src/hubris.rs b/humility-core/src/hubris.rs index bf0eca9e2..5c74b4a46 100644 --- a/humility-core/src/hubris.rs +++ b/humility-core/src/hubris.rs @@ -2387,14 +2387,23 @@ impl HubrisArchive { } } else if self.ptrtypes.contains_key(&m.goff) { break; + } else if let Ok(s) = self.lookup_struct(m.goff) + && let Some(nt) = s.newtype() + && let Some(bt) = self.basetypes.get(&nt) + { + if bt.size != 4 { + return Err(anyhow!( + "expected {} in struct {} ({}) to \ + be 4 bytes, found to be {} bytes", + member, structure.name, structure.goff, bt.size + )); + } } else { - // TODO: lol, yolo - // - // return Err(anyhow!( - // "expected {} in struct {} ({}) to \ - // be 4 byte type, found to be {}", - // member, structure.name, structure.goff, m.goff - // )); + return Err(anyhow!( + "expected {} in struct {} ({}) to \ + be 4 byte type, found to be {}", + member, structure.name, structure.goff, m.goff + )); } break; From 5360db4bac818767cb7288ec15c0ec719592c48e Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 29 Sep 2026 12:43:23 -0500 Subject: [PATCH 3/6] Cleanups for merge-ability --- humility-core/src/hubris.rs | 17 ++++++++++++++ humility-doppel/src/lib.rs | 46 +++++++++++++++++++++++++++++-------- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/humility-core/src/hubris.rs b/humility-core/src/hubris.rs index 5c74b4a46..49ad25d38 100644 --- a/humility-core/src/hubris.rs +++ b/humility-core/src/hubris.rs @@ -2391,6 +2391,23 @@ impl HubrisArchive { && let Some(nt) = s.newtype() && let Some(bt) = self.basetypes.get(&nt) { + // This exists to accomodate the work-in-progress target- + // bitwidth agnosticism. + // + // See https://github.com/oxidecomputer/hubris/issues/2706, + // as well as + // https://github.com/oxidecomputer/hubris/pull/2703 for + // details on what these changes support. We look for EITHER + // a 4-byte primitive (which can be `u32` or `usize`, + // depending on context), OR a newtype `Addr(usize)`, which + // is what the above changes introduce. + // + // THIS part of the code does not **yet** support 8-byte + // primitives like `u64` or `usize`-on-64-bit-targets. + // + // As of 2026-09-29, AJM is not quite sure what the code + // in this conditional block is guarding against, other than + // accidental type confusion? It is from long long ago. if bt.size != 4 { return Err(anyhow!( "expected {} in struct {} ({}) to \ diff --git a/humility-doppel/src/lib.rs b/humility-doppel/src/lib.rs index 4568febd1..d8e0bedc7 100644 --- a/humility-doppel/src/lib.rs +++ b/humility-doppel/src/lib.rs @@ -155,7 +155,9 @@ pub enum SchedState { #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Addr { + /// A 32-bit target address Bits32(u32), + /// A 64-bit target address Bits64(u64), } @@ -170,24 +172,50 @@ impl fmt::LowerHex for Addr { impl Load for Addr { fn from_value(v: &Value) -> Result { - match v { + // This exists to accomodate the work-in-progress target-bitwidth + // agnosticism. + // + // See https://github.com/oxidecomputer/hubris/issues/2706, as well as + // https://github.com/oxidecomputer/hubris/pull/2703 for details on + // what these changes support. We look for EITHER a 4-byte or 8-byte + // primitive (which can be any of `u32`, `u64`, or `usize`, depending + // on context), OR a newtype `Addr(usize)`, which is what the above + // changes introduce. + let res = match v { Value::Base(base) => match base { - Base::U32(b32) => Ok(Self::Bits32(*b32)), - Base::U64(b64) => Ok(Self::Bits64(*b64)), - _ => todo!(), + Base::U32(b32) => Self::Bits32(*b32), + Base::U64(b64) => Self::Bits64(*b64), + other => { + bail!( + "expected an address to EITHER be a 4-byte or 8-byte \ + primitive, instead found {other:?}." + ); + } }, Value::Tuple(tuple) if tuple.name() == "Addr" && let [single] = tuple.deref() => { match single { - Value::Base(Base::U32(b32)) => Ok(Self::Bits32(*b32)), - Value::Base(Base::U64(b64)) => Ok(Self::Bits64(*b64)), - _ => todo!(), + Value::Base(Base::U32(b32)) => Self::Bits32(*b32), + Value::Base(Base::U64(b64)) => Self::Bits64(*b64), + other => { + bail!( + "expected an `Addr` newtype to contain EITHER a \ + 4-byte or 8-byte primitive, instead found \ + {other:?}." + ); + } } } - _ => todo!(), - } + other => { + bail!( + "Attempted to load an address, but found none of the \ + usual suspects, instead found {other:?}." + ); + } + }; + Ok(res) } } From d4f02288ef7c21210e647a4bd485175079e9e6da Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 29 Sep 2026 13:38:58 -0500 Subject: [PATCH 4/6] Bump up rust version --- .github/workflows/ci.yaml | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a7293c25b..7b5acdb34 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -101,7 +101,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: "1.91" # must match Cargo.toml + toolchain: "1.98.1" # must match Cargo.toml components: clippy override: true - uses: Swatinem/rust-cache@v1 diff --git a/Cargo.toml b/Cargo.toml index e500974a2..a49b609ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,7 +88,7 @@ resolver = "2" [workspace.package] edition = "2024" -rust-version = "1.91" # if this changes, edit ci.yaml as well! +rust-version = "1.98.1" # if this changes, edit ci.yaml as well! [workspace.dependencies] # `git`-based deps From 6452d9195e668914dc8cc20cc4fb4a92497e1631 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 29 Sep 2026 13:42:17 -0500 Subject: [PATCH 5/6] One more --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7b5acdb34..1ae159d9a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -28,7 +28,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: "1.91" # must match Cargo.toml + toolchain: "1.98.1" # must match Cargo.toml override: true - uses: Swatinem/rust-cache@v1 - uses: actions-rs/cargo@v1 From 946001aca3e7a457e27fe7774678020f22ea13eb Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 29 Sep 2026 13:53:31 -0500 Subject: [PATCH 6/6] Clippy fixes --- cmd/doc/src/lib.rs | 2 +- cmd/hash/src/lib.rs | 2 +- cmd/map/src/lib.rs | 2 +- cmd/pmbus/src/lib.rs | 3 +-- cmd/rebootleby/src/lib.rs | 6 +++--- cmd/stackmargin/src/lib.rs | 2 +- humility-core/src/mem.rs | 2 +- humility-spd/src/lib.rs | 6 ++++-- 8 files changed, 13 insertions(+), 12 deletions(-) diff --git a/cmd/doc/src/lib.rs b/cmd/doc/src/lib.rs index 68f472352..875a51281 100644 --- a/cmd/doc/src/lib.rs +++ b/cmd/doc/src/lib.rs @@ -48,7 +48,7 @@ fn doc(subargs: DocArgs, _context: &mut ExecutionContext) -> Result<()> { skin.table.align = Alignment::Center; skin.code_block.align = Alignment::Center; let text = FmtText::from_text(&skin, text, Some(80)); - println!("{}", &text); + println!("{}", text); if let Some(ref cmd) = subargs.command { skin.print_text(&format!( diff --git a/cmd/hash/src/lib.rs b/cmd/hash/src/lib.rs index dbd707e78..ddee89e66 100644 --- a/cmd/hash/src/lib.rs +++ b/cmd/hash/src/lib.rs @@ -245,7 +245,7 @@ fn hash(subargs: HashArgs, context: &mut ExecutionContext) -> Result<()> { _ => None, }, )?; - println!("returned results={:?}", &results); + println!("returned results={:?}", results); match &results[0] { Ok(buf) => { print_hash(buf); diff --git a/cmd/map/src/lib.rs b/cmd/map/src/lib.rs index 9acb25aee..b924484c6 100644 --- a/cmd/map/src/lib.rs +++ b/cmd/map/src/lib.rs @@ -82,7 +82,7 @@ fn mapcmd(_args: MapArgs, context: &mut ExecutionContext) -> Result<()> { "DESC", "LOW", "HIGH", "SIZE", "ATTR", "ID", ); - for (_, region) in regions.iter() { + for region in regions.values() { let name = { let mut names = vec![]; diff --git a/cmd/pmbus/src/lib.rs b/cmd/pmbus/src/lib.rs index a41e1dba2..e0c9f7592 100644 --- a/cmd/pmbus/src/lib.rs +++ b/cmd/pmbus/src/lib.rs @@ -1731,8 +1731,7 @@ impl PmbusWorker for IdolWorker<'_> { &dev.port == harg.port && dev.controller == harg.controller && Some(dev.address) == harg.address - && dev.mux.and_then(|mux| dev.segment.map(|s| (mux, s))) - == harg.mux + && dev.mux.zip(dev.segment) == harg.mux }) .ok_or_else(|| anyhow!("could not find device matching {harg:?}"))? .0; diff --git a/cmd/rebootleby/src/lib.rs b/cmd/rebootleby/src/lib.rs index 0ad6f01c0..4a60b7554 100644 --- a/cmd/rebootleby/src/lib.rs +++ b/cmd/rebootleby/src/lib.rs @@ -198,14 +198,14 @@ impl FlashHack<'_> { word_address: u32, contents: &[u8; 512], ) -> Result<()> { - for (i, chunk) in contents.chunks_exact(16).enumerate() { + for (i, chunk) in contents.as_chunks::<16>().0.iter().enumerate() { debug!(self.log, "writing {word_address:#x?} chunk {i}"); self.clear_status_flags()?; self.set_word_range(i as u32, i as u32)?; - for (j, word) in chunk.chunks_exact(4).enumerate() { + for (j, word) in chunk.as_chunks::<4>().0.iter().enumerate() { self.poke_and_check( DATAW0 + j as u32 * 4, - u32::from_le_bytes(word.try_into().unwrap()), + u32::from_le_bytes(*word), )?; } diff --git a/cmd/stackmargin/src/lib.rs b/cmd/stackmargin/src/lib.rs index c6c62f803..ccf857d99 100644 --- a/cmd/stackmargin/src/lib.rs +++ b/cmd/stackmargin/src/lib.rs @@ -94,7 +94,7 @@ fn stackmargin( |o| u32::from_le_bytes(taskblock[o..o + 4].try_into().unwrap()); let find = |addr| { - for (_, region) in regions.iter() { + for region in regions.values() { if addr > region.base && addr <= region.base + region.size { return Ok(region); } diff --git a/humility-core/src/mem.rs b/humility-core/src/mem.rs index bc2743de5..be2a39b27 100644 --- a/humility-core/src/mem.rs +++ b/humility-core/src/mem.rs @@ -182,7 +182,7 @@ fn load_registers(r: &[u8]) -> Result> { bail!("bad length {} in registers note", r.len()); } let mut registers = HashMap::new(); - for (i, chunk) in r.chunks_exact(8).enumerate() { + for (i, chunk) in r.as_chunks::<8>().0.iter().enumerate() { let (id, val) = chunk.split_at(4); // We unwrap here because it can only fail if the length is wrong, // but we've explicitly broken a chunk of 8 into two chunks of 4, diff --git a/humility-spd/src/lib.rs b/humility-spd/src/lib.rs index 45f749b80..94bb634ec 100644 --- a/humility-spd/src/lib.rs +++ b/humility-spd/src/lib.rs @@ -61,7 +61,9 @@ pub fn spd_lookup( ); } Ok(Some( - buf.chunks_exact(GIMLET_SPD_SIZE) + buf.as_chunks::() + .0 + .iter() .map(|chunk| SpdData(chunk.to_vec())) .collect(), )) @@ -94,7 +96,7 @@ pub fn spd_lookup( ); } let mut out = Vec::with_capacity(a.len() / GIMLET_SPD_SIZE); - for vs in a.chunks_exact(GIMLET_SPD_SIZE) { + for vs in a.as_chunks::().0.iter() { let mut chunk = Vec::with_capacity(GIMLET_SPD_SIZE); for v in vs { let Value::Base(Base::U8(b)) = v else {