Skip to content
Merged
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
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,16 @@ hif = { git = "https://github.com/oxidecomputer/hif" }
humpty = { git = "https://github.com/oxidecomputer/humpty", version = "0.1.3" }
idol = {git = "https://github.com/oxidecomputer/idolatry.git"}
idt8a3xxxx = { git = "https://github.com/oxidecomputer/idt8a3xxxx" }
ipcc-data = { git = "https://github.com/oxidecomputer/ipcc-rs" }
measurement-token = { git = "https://github.com/oxidecomputer/lpc55_support", default-features = false }
pmbus = { git = "https://github.com/oxidecomputer/pmbus" }
serialport = { git = "https://github.com/jgallagher/serialport-rs", branch = "illumos-support" }
spd = { git = "https://github.com/oxidecomputer/spd" }
tlvc = { git = "https://github.com/oxidecomputer/tlvc" }
tlvc-text = {git = "https://github.com/oxidecomputer/tlvc"}
turin-post-decoder = { git = "https://github.com/oxidecomputer/turin-post-decoder" }
vsc7448-info = { git = "https://github.com/oxidecomputer/vsc7448.git" }
vsc7448-types = { git = "https://github.com/oxidecomputer/vsc7448.git" }
ipcc-data = { git = "https://github.com/oxidecomputer/ipcc-rs" }

#
# We depend on the oxide-stable branch of Oxide's fork of probe-rs to assure
Expand Down
41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -986,7 +986,7 @@ within Humility, use `-L` (`--list-functions`).
### `humility host`
`humility host` pretty-prints host state, which is sent to the SP over IPCC.

It is only functional on a Gimlet SP image.
It is only functional on a Gimlet or Cosmo SP image.

#### `humility host last-panic`
Pretty prints the value of `LAST_HOST_PANIC`
Expand Down Expand Up @@ -1042,6 +1042,45 @@ humility: reading LAST_HOST_BOOT_FAIL
[0; 4096]
```

#### `humility host cosmo last-post-code`
Pretty-prints the last POST code seen by the sequencer FPGA (Cosmo only)
```console
$ humility host cosmo last-post-code
humility: attached to 0483:374f:002A001C4D46500F20373033 via ST-Link V3
Bootloader Code: 0xed80000f
Source: ASP TEE
Status: BL_ERR_BOUNDARY_CHECK (0x0f)
Detail: Out of Boundary Condition Reached
```

#### `humility host cosmo post-codes`
Pretty-prints all last POST codes seen by the sequencer FPGA (Cosmo only)
```console
$ humility host cosmo post-codes
humility: attached to 0483:374f:002A001C4D46500F20373033 via ST-Link V3
Bootloader Code: 0xee1000b3
Source: ASP BL2
Status: BL_SUCCESS_BYPASS_IDEVID_CHECK (0xb3)
Detail: IDEVID validation failed but bypassed (unsecure)
Bootloader Code: 0xee1000a0
Source: ASP BL2
Status: BL_SUCCESS_C_MAIN (0xa0)
Detail: Successfully entered C Main
Bootloader Code: 0xee1000a3
Source: ASP BL2
Status: BL_SUCCESS_DETECT_BOOT_MODE (0xa3)
Detail: Boot Mode detected and sent to slaves
Bootloader Code: 0xee1000a2
Source: ASP BL2
Status: BL_SUCCESS_DERIVE_HMAC_KEY (0xa2)
Detail: HMAC key derived
Bootloader Code: 0xee1000a2
Source: ASP BL2
Status: BL_SUCCESS_DERIVE_HMAC_KEY (0xa2)
Detail: HMAC key derived
# etc...
```


### `humility hydrate`

Expand Down
8 changes: 6 additions & 2 deletions cmd/host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ description = "Pretty-printing of host state"

[dependencies]
anyhow.workspace = true
clap.workspace = true
chrono.workspace = true
clap.workspace = true
hif.workspace = true
ipcc-data.workspace = true
turin-post-decoder.workspace = true

humility.workspace = true
humility-cmd.workspace = true
humility-cli.workspace = true
humility-cmd.workspace = true
humility-doppel.workspace = true
humility-hiffy.workspace = true
humility-idol.workspace = true
humility-log.workspace = true
224 changes: 222 additions & 2 deletions cmd/host/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! ## `humility host`
//! `humility host` pretty-prints host state, which is sent to the SP over IPCC.
//!
//! It is only functional on a Gimlet SP image.
//! It is only functional on a Gimlet or Cosmo SP image.
//!
//! ### `humility host last-panic`
//! Pretty prints the value of `LAST_HOST_PANIC`
Expand Down Expand Up @@ -60,15 +60,56 @@
//! humility: reading LAST_HOST_BOOT_FAIL
//! [0; 4096]
//! ```
//!
//! ### `humility host cosmo last-post-code`
//! Pretty-prints the last POST code seen by the sequencer FPGA (Cosmo only)
//! ```console
//! $ humility host cosmo last-post-code
//! humility: attached to 0483:374f:002A001C4D46500F20373033 via ST-Link V3
//! Bootloader Code: 0xed80000f
//! Source: ASP TEE
//! Status: BL_ERR_BOUNDARY_CHECK (0x0f)
//! Detail: Out of Boundary Condition Reached
//! ```
//!
//! ### `humility host cosmo post-codes`
//! Pretty-prints all last POST codes seen by the sequencer FPGA (Cosmo only)
//! ```console
//! $ humility host cosmo post-codes
//! humility: attached to 0483:374f:002A001C4D46500F20373033 via ST-Link V3
//! Bootloader Code: 0xee1000b3
//! Source: ASP BL2
//! Status: BL_SUCCESS_BYPASS_IDEVID_CHECK (0xb3)
//! Detail: IDEVID validation failed but bypassed (unsecure)
//! Bootloader Code: 0xee1000a0
//! Source: ASP BL2
//! Status: BL_SUCCESS_C_MAIN (0xa0)
//! Detail: Successfully entered C Main
//! Bootloader Code: 0xee1000a3
//! Source: ASP BL2
//! Status: BL_SUCCESS_DETECT_BOOT_MODE (0xa3)
//! Detail: Boot Mode detected and sent to slaves
//! Bootloader Code: 0xee1000a2
//! Source: ASP BL2
//! Status: BL_SUCCESS_DERIVE_HMAC_KEY (0xa2)
//! Detail: HMAC key derived
//! Bootloader Code: 0xee1000a2
//! Source: ASP BL2
//! Status: BL_SUCCESS_DERIVE_HMAC_KEY (0xa2)
//! Detail: HMAC key derived
//! # etc...
//! ```

use anyhow::{Result, anyhow};
use anyhow::{Result, anyhow, bail};
use chrono::DateTime;
use clap::{CommandFactory, Parser};

use humility::{core::Core, hubris::HubrisArchive, reflect, reflect::Load};
use humility_cli::{ExecutionContext, Subcommand};
use humility_cmd::{Archive, Attach, Command, CommandKind, Validate};
use humility_doppel as doppel;
use humility_hiffy::HiffyContext;
use humility_idol::HubrisIdol;
use humility_log::msg;

#[derive(Parser, Debug)]
Expand All @@ -77,6 +118,25 @@ enum HostCommand {
BootFail,
/// Print the last host panic
LastPanic,
/// Cosmo-specific host commands
Cosmo {
#[clap(subcommand)]
cmd: CosmoHostCommand,
},
}

#[derive(Parser, Debug)]
enum CosmoHostCommand {
/// Prints the most recent POST code
LastPostCode {
#[clap(long)]
raw: bool,
},
/// Dumps the POST code buffer
PostCodes {
#[clap(long)]
raw: bool,
},
}
Comment on lines +128 to 140
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding the subcommand, I think this will make things much clearer to the user.


#[derive(Parser, Debug)]
Expand Down Expand Up @@ -285,6 +345,158 @@ fn print_panic(d: Vec<u8>) -> Result<()> {
Ok(())
}

/// Print a warning message if the archive is not for a `cosmo` board
fn check_post_code_target(hubris: &HubrisArchive) {
if !hubris.manifest.board.as_ref().is_some_and(|b| b.contains("cosmo")) {
humility::warn!(
"POST code buffer is only present on 'cosmo' hardware{}; \
hiffy may fail and time out",
if let Some(board) = &hubris.manifest.board {
format!(" but this is a '{board}'")
} else {
String::new()
}
Comment on lines +354 to +358
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cute!

)
}
}

fn host_post_codes(
hubris: &HubrisArchive,
core: &mut dyn Core,
raw: bool,
) -> Result<()> {
check_post_code_target(hubris);
use hif::*;

let mut context = HiffyContext::new(hubris, core, 5000)?;
let op = hubris.get_idol_command("Sequencer.post_code_buffer_len")?;
let value = humility_hiffy::hiffy_call(
hubris,
core,
&mut context,
&op,
&[],
None,
None,
)?;
let Ok(reflect::Value::Base(reflect::Base::U32(count))) = value else {
bail!(
"Got bad value from post_code_buffer_len: \
expected U32, got {value:?}"
);
};

let op = hubris.get_idol_command("Sequencer.get_post_code")?;
let handle_value = |v| {
let Ok(reflect::Value::Base(reflect::Base::U32(v))) = v else {
bail!("Got bad value from get_post_code: expected U32, got {v:?}");
};
if raw {
println!("{v:08x}");
} else {
let decoded = turin_post_decoder::decode(v);
let detail = decoded.lines().join("\n");
println!("{detail}");
}
Ok(())
};

// For network-attached systems, function calls are cheap and we can just
// spam them. For debugger-attached systems, we'll want to run a HIF loop
// to avoid dispatch overhead.
Comment on lines +404 to +406
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing this is a very noticeable lag?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yeah it's terrible – 10+ seconds to read a full 4K codes.

if core.is_net() {
for index in 0..count {
let value = humility_hiffy::hiffy_call(
hubris,
core,
&mut context,
&op,
&[("index", humility_idol::IdolArgument::Scalar(index as u64))],
None,
None,
)?;
handle_value(value)?;
}
} else {
let send = context.get_function("Send", 4)?;
let ret_size = hubris.typesize(op.ok)? as u32;
assert_eq!(ret_size, 4);

// Each returned value is a FunctionResult::Success(&[..]), which
// encodes as 6 bytes: 1 byte variant tag, 1 byte slice length, 4 bytes
// of u32.
let max_chunk_size = context.rstack_size() / 6;

// Write a little program to read all of the post codes
for start in (0..count).step_by(max_chunk_size) {
let end = (start + max_chunk_size as u32).min(count);
let label = Target(0);
let mut ops = vec![
Op::Push32(op.task.task()), // task id
Op::Push16(op.code), // opcode
Op::Push32(start), // Starting index
Op::Push32(0), // Comparison target (dummy)
Op::Label(label), // loop start
];
{
// block representing the hiffy loop
ops.push(Op::Drop); // Drop comparison target

// Expand u32 -> [u8; 4], since that's expected by `send`
ops.push(Op::Expand32);
ops.push(Op::Push(4)); // Payload size
ops.push(Op::Push32(ret_size)); // Return size
ops.push(Op::Call(send.id));
ops.push(Op::DropN(2)); // Drop payload and return size
ops.push(Op::Collect32);
ops.push(Op::Push(1)); // Increment by four
ops.push(Op::Add); // index += 1
ops.push(Op::Push32(end)); // Comparison target
ops.push(Op::BranchGreaterThan(label)); // Jump to loop start
}
ops.push(Op::DropN(4)); // Cleanup
ops.push(Op::Done); // Finish

for r in context.run(core, ops.as_slice(), None)? {
let v = humility_hiffy::hiffy_decode(hubris, &op, r)?;
handle_value(v)?;
}
}
}
Ok(())
}

fn host_last_post_code(
hubris: &HubrisArchive,
core: &mut dyn Core,
raw: bool,
) -> Result<()> {
check_post_code_target(hubris);

let mut context = HiffyContext::new(hubris, core, 5000)?;
let op = hubris.get_idol_command("Sequencer.last_post_code")?;
let value = humility_hiffy::hiffy_call(
hubris,
core,
&mut context,
&op,
&[],
None,
None,
)?;
let Ok(reflect::Value::Base(reflect::Base::U32(v))) = value else {
bail!("Got bad value from last_post_code: expected U32, got {value:?}");
};
if raw {
println!("{v:08x}");
} else {
let decoded = turin_post_decoder::decode(v);
let detail = decoded.lines().join("\n");
println!("{detail}");
}
Ok(())
}

fn host(context: &mut ExecutionContext) -> Result<()> {
let Subcommand::Other(subargs) = context.cli.cmd.as_ref().unwrap();
let subargs = HostArgs::try_parse_from(subargs)?;
Expand All @@ -294,6 +506,14 @@ fn host(context: &mut ExecutionContext) -> Result<()> {
match subargs.cmd {
HostCommand::BootFail => host_boot_fail(hubris, core),
HostCommand::LastPanic => host_last_panic(hubris, core),
HostCommand::Cosmo { cmd } => match cmd {
CosmoHostCommand::PostCodes { raw } => {
host_post_codes(hubris, core, raw)
}
CosmoHostCommand::LastPostCode { raw } => {
host_last_post_code(hubris, core, raw)
Comment on lines +511 to +514
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder somewhat if we ought to change the function names to also say "cosmo" in them, but it's not important to me.

}
},
}
}

Expand Down
Loading