diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a7293c25b..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 @@ -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 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/hubris.rs b/humility-core/src/hubris.rs index bfbf8c7c4..49ad25d38 100644 --- a/humility-core/src/hubris.rs +++ b/humility-core/src/hubris.rs @@ -2387,6 +2387,34 @@ 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) + { + // 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 \ + be 4 bytes, found to be {} bytes", + member, structure.name, structure.goff, bt.size + )); + } } else { return Err(anyhow!( "expected {} in struct {} ({}) to \ 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-doppel/src/lib.rs b/humility-doppel/src/lib.rs index 16d70fc1e..65adfc309 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,72 @@ pub enum SchedState { InRecv(Option), } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Addr { + /// A 32-bit target address + Bits32(u32), + /// A 64-bit target address + 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 { + // 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) => 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)) => 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:?}." + ); + } + } + } + other => { + bail!( + "Attempted to load an address, but found none of the \ + usual suspects, instead found {other:?}." + ); + } + }; + Ok(res) + } +} + #[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 +229,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 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 {