Skip to content

Commit d7fd204

Browse files
committed
host: fix last-panic/boot-fail commands
Memory layout changed in Hubris.
1 parent 3f249da commit d7fd204

File tree

8 files changed

+138
-23
lines changed

8 files changed

+138
-23
lines changed

Cargo.lock

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ name = "humility"
1717
#
1818
# Be sure to check in and push all of the files that change. Happy versioning!
1919
#
20-
version = "0.11.6"
20+
version = "0.11.7"
2121
authors = ["Bryan Cantrill <[email protected]>"]
2222
edition = "2018"
2323
license = "MPL-2.0"

cmd/host/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ zerocopy.workspace = true
1414
humility.workspace = true
1515
humility-cmd.workspace = true
1616
humility-cli.workspace = true
17+
humility-doppel.workspace = true
1718
humility-log.workspace = true

cmd/host/src/lib.rs

Lines changed: 115 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,14 @@
5353
//! [0; 4096]
5454
//! ```
5555
56-
use anyhow::{bail, Context, Result};
56+
use anyhow::{anyhow, bail, Context, Result};
5757
use clap::{CommandFactory, Parser};
5858
use zerocopy::FromBytes;
5959

60-
use humility::{core::Core, hubris::HubrisArchive};
60+
use humility::{core::Core, hubris::HubrisArchive, reflect, reflect::Load};
6161
use humility_cli::{ExecutionContext, Subcommand};
6262
use humility_cmd::{Archive, Attach, Command, CommandKind, Validate};
63+
use humility_doppel as doppel;
6364
use humility_log::{msg, warn};
6465

6566
#[derive(Parser, Debug)]
@@ -77,35 +78,115 @@ struct HostArgs {
7778
cmd: HostCommand,
7879
}
7980

80-
fn read_var(
81+
static SEPARATE_HOST_BOOT_FAIL_NAME: &str = "LAST_HOST_BOOT_FAIL";
82+
83+
static SEPARATE_LAST_HOST_PANIC_NAME: &str = "LAST_HOST_PANIC";
84+
85+
static HOST_STATE_BUF_NAME: &str =
86+
"task_host_sp_comms::ServerImpl::claim_static_resources::BUFS";
87+
88+
/// Mirror type of the internal buf struct in `host_sp_comms`. Must be kept in
89+
/// (partial) sync with that structure (fields that are present need to match,
90+
/// other fields can be ignored).
91+
#[derive(Load)]
92+
struct HostStateBuf {
93+
last_boot_fail: Vec<u8>,
94+
last_panic: Vec<u8>,
95+
}
96+
97+
fn read_uqvar(
8198
hubris: &HubrisArchive,
8299
core: &mut dyn Core,
83100
name: &str,
84-
) -> Result<Vec<u8>> {
85-
msg!("reading {name}");
86-
let var = hubris
87-
.lookup_variable(name)
88-
.context(format!("could not find {name}; is this a Gimlet image?"))?;
101+
) -> Result<Option<Vec<u8>>> {
102+
let Some(var) = hubris.lookup_variable(name).ok() else {
103+
return Ok(None);
104+
};
89105

90106
let mut buf: Vec<u8> = vec![0u8; var.size];
91107

92108
core.halt()?;
93109
core.read_8(var.addr, buf.as_mut_slice())?;
94110
core.run()?;
95111

96-
Ok(buf)
112+
Ok(Some(buf))
97113
}
98114

99-
fn host_boot_fail(hubris: &HubrisArchive, core: &mut dyn Core) -> Result<()> {
100-
let d = read_var(hubris, core, "LAST_HOST_BOOT_FAIL")?;
101-
if d.iter().all(|&c| c == 0) {
102-
println!("[0; {}]", d.len());
115+
fn read_qualified_state_buf(
116+
hubris: &HubrisArchive,
117+
core: &mut dyn Core,
118+
name: &str,
119+
) -> Result<Option<HostStateBuf>> {
120+
let Some(var) = hubris.lookup_qualified_variable(name).ok() else {
121+
return Ok(None);
122+
};
123+
124+
let var_ty = hubris.lookup_type(var.goff)?;
125+
126+
let mut buf: Vec<u8> = vec![0u8; var.size];
127+
128+
core.halt()?;
129+
core.read_8(var.addr, &mut buf)?;
130+
core.run()?;
131+
132+
let v = reflect::load_value(hubris, &buf, var_ty, 0)?;
133+
let as_static_cell = doppel::ClaimOnceCell::from_value(&v)?;
134+
Ok(Some(HostStateBuf::from_value(&as_static_cell.cell.value)?))
135+
}
136+
137+
fn print_escaped_ascii(mut bytes: &[u8]) {
138+
// Drop trailing NULs to avoid escaping them and cluttering up our output.
139+
while let Some((&b'\0', prefix)) = bytes.split_last() {
140+
bytes = prefix;
141+
}
142+
143+
if bytes.is_empty() {
144+
println!("Message contains no non-NUL bytes, not printing.");
145+
return;
103146
} else {
104-
match std::str::from_utf8(&d) {
105-
Ok(s) => println!("{}", s.trim_matches('\0')),
106-
Err(e) => println!("{:?}\n (could not decode: {e})", d),
147+
println!("Message is {} bytes long:", bytes.len());
148+
}
149+
150+
let mut buf = String::new();
151+
for &b in bytes {
152+
match b {
153+
b'\\' => {
154+
// Escape any backslashes in the original, so that any escapes
155+
// _we_ emit are unambiguous.
156+
buf.push_str("\\\\");
157+
}
158+
b'\n' | b'\r' | b'\t' | 0x20..=0x7E => {
159+
// Pass through basic text characters that we expect we might
160+
// see in a message.
161+
buf.push(b as char);
162+
}
163+
_ => {
164+
// Escape any other non-printable characters.
165+
buf.push_str("\\x");
166+
buf.push_str(&format!("{b:02X}"));
167+
}
107168
}
108169
}
170+
println!("{buf}");
171+
}
172+
173+
fn host_boot_fail(hubris: &HubrisArchive, core: &mut dyn Core) -> Result<()> {
174+
// Try old name:
175+
let d = read_uqvar(hubris, core, SEPARATE_HOST_BOOT_FAIL_NAME)?;
176+
if let Some(d) = d {
177+
print_escaped_ascii(&d);
178+
return Ok(());
179+
}
180+
// Try new name
181+
let buf = read_qualified_state_buf(hubris, core, HOST_STATE_BUF_NAME)?
182+
.ok_or_else(|| {
183+
anyhow!(
184+
"Could not find host boot variables under any known name; \
185+
is this a Gimlet image?"
186+
)
187+
})?;
188+
189+
print_escaped_ascii(&buf.last_boot_fail[..]);
109190

110191
Ok(())
111192
}
@@ -149,8 +230,25 @@ struct IpccPanicStack {
149230
}
150231

151232
fn host_last_panic(hubris: &HubrisArchive, core: &mut dyn Core) -> Result<()> {
152-
let d = read_var(hubris, core, "LAST_HOST_PANIC")?;
233+
// Try original name:
234+
let d = read_uqvar(hubris, core, SEPARATE_LAST_HOST_PANIC_NAME)?;
235+
if let Some(d) = d {
236+
return print_panic(d);
237+
}
238+
239+
// Try new name:
240+
let buf = read_qualified_state_buf(hubris, core, HOST_STATE_BUF_NAME)?
241+
.ok_or_else(|| {
242+
anyhow!(
243+
"Could not find host boot variables under any known name; \
244+
is this a Gimlet image?"
245+
)
246+
})?;
247+
248+
print_panic(buf.last_panic)
249+
}
153250

251+
fn print_panic(d: Vec<u8>) -> Result<()> {
154252
// Fix for https://github.com/oxidecomputer/hubris/issues/1554
155253
//
156254
// In some cases, `ipd_cause` is unambiguous based on the first byte;

humility-core/src/hubris.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,6 +1899,16 @@ impl HubrisArchive {
18991899
}
19001900
}
19011901

1902+
pub fn lookup_qualified_variable(
1903+
&self,
1904+
name: &str,
1905+
) -> Result<&HubrisVariable> {
1906+
match self.qualified_variables.get(name) {
1907+
Some(variable) => Ok(variable),
1908+
None => Err(anyhow!("variable {} not found", name)),
1909+
}
1910+
}
1911+
19021912
pub fn lookup_variables(&self, name: &str) -> Result<&Vec<HubrisVariable>> {
19031913
match self.variables.get_vec(name) {
19041914
None => Err(anyhow!("variable {} not found", name)),

humility-doppel/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,11 @@ pub enum CounterVariant {
384384
Nested(Counters),
385385
}
386386

387+
#[derive(Clone, Debug, Load)]
388+
pub struct ClaimOnceCell {
389+
pub cell: UnsafeCell,
390+
}
391+
387392
#[derive(Clone, Debug, Load)]
388393
pub struct StaticCell {
389394
pub cell: UnsafeCell,

tests/cmd/chip.trycmd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ For more information try --help
1313

1414
```
1515
$ humility --chip this-can-be-anything -V
16-
humility 0.11.6
16+
humility 0.11.7
1717

1818
```
1919

@@ -28,7 +28,7 @@ For more information try --help
2828

2929
```
3030
$ humility -c apx432 -V
31-
humility 0.11.6
31+
humility 0.11.7
3232

3333
```
3434

tests/cmd/version.trycmd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ Long version flag:
22

33
```
44
$ humility --version
5-
humility 0.11.6
5+
humility 0.11.7
66

77
```
88

99
Short version flag:
1010

1111
```
1212
$ humility -V
13-
humility 0.11.6
13+
humility 0.11.7
1414

1515
```

0 commit comments

Comments
 (0)