Skip to content

Use BOOTED_IMAGE to warn when using wrong A/B image#712

Draft
evan-oxide wants to merge 1 commit into
masterfrom
evan/booted-image-id-humility
Draft

Use BOOTED_IMAGE to warn when using wrong A/B image#712
evan-oxide wants to merge 1 commit into
masterfrom
evan/booted-image-id-humility

Conversation

@evan-oxide

@evan-oxide evan-oxide commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

The companion hubris PR is oxidecomputer/hubris#2591.

Both this and Laura's PR #711 are trying to address issue #709 - we can choose to merge one or combine both approaches in some way.

This PR's approach is to make the hubris kernel record the image ID and name in the BOOTED_IMAGE variable so that humility can tell which A/B image is actually running on the RoT. Humility now uses that image ID to check whether an archive matches what's running on the target, and uses the image name to warn when flashing an image to the inactive slot.

New behavior:

  • If you run humility tasks etc with an A archive and a target running a B image, it will:

    • fail with an ID mismatch error, if it can read BOOTED_IMAGE
    • log a "can't read BOOTED_IMAGE" warning and fall back to reading the ID from FLASH, if it can't
  • If you're flashing an A image and a target running a B image, it will:

    • log a "you're probably doing this by accident" warning, if it can read BOOTED_IMAGE
    • be silent, if it can't

Note that it never blocks you from flashing and doesn't change the logic of whether an archive needs to be re-flashed.

Tradeoffs

  • This approach is very unlikely to have false-positive errors/warnings, but can easily have false negatives if the address of BOOTED_IMAGE drifts between versions (or the image is too old, or the kernel never booted). Hopefully it will work often enough to be useful. Or should we try to make the linker give BOOTED_IMAGE a fixed address?
  • It uses an extra 24 bytes of RAM.

Testing:

Lightly tested on a grapefruit's RoT and SP. If folks like this approach then I'll keep testing more combos and edge cases. Also CI tests will fail because I haven't yet added the line humility: can't detect booted image, reading image ID from FLASH (BOOTED_IMAGE not in archive's symbol table) to 415 unit tests.

Comment on lines -2098 to +2101
if deltas > 0 || id.len() != self.imageid.1.len() {
if id != self.imageid.1 {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I can't think of any reason why the original code would need to do that manual comparison instead of just using !=. Hope I'm not missing something.


if n == ntasks as u32 {
//
// Check the CURRENT_TASK_PTR; it's non-zero iff we have booted

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We could start using BOOTED_IMAGE for this too. But maybe it's better to use CURRENT_TASK_PTR because that's set at the end of kernel startup, while BOOTED_IMAGE is set at the beginning of kernel startup.

"can't detect booted image, reading image ID from FLASH ({})",
err
);
self.read_image_id_from_flash(core)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It might be worth checking the PC location here as part of the fallback when we can't read BOOTED_IMAGE. In addition to requiring the flash ID to match, we could either fail or warn if the PC suggests this is the wrong image slot.

@labbott

labbott commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

I think this is more complete than just the PC check which is a bit hacky.

It also occurs to me this is reimplementing the bootleby decision log for the RoT https://github.com/oxidecomputer/bootleby/blob/bdf56dd950b934360df596ed5b2d8b8813c92168/src/bin/bootleby.rs#L201-L207 , https://github.com/oxidecomputer/bootleby/blob/bdf56dd950b934360df596ed5b2d8b8813c92168/memory.x#L39 (see oxidecomputer/hubris#2066 as well). Didn't think of this until I finished reviewing this work!

We don't have a problem with the SP so part of me says that we should just read the decision log in humility. Do you see any value in having the same information for the SP even though everything is just "default"?

@evan-oxide

evan-oxide commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

We don't have a problem with the SP so part of me says that we should just read the decision log in humility. Do you see any value in having the same information for the SP even though everything is just "default"?

Oh cool, it would be nice to reuse an existing feature. Questions / concerns:

  1. Is it valuable for humility's validation process to be target agnostic and not have to check a bootleby-specific thing when it sees that the target is an RoT? Or is that not a big deal?

  2. It looks like the log doesn't include which slot bootleby actually picked, so humility would need to duplicate the override logic, which is not too bad. I think it does mean that if bootleby added a new higher-priority override to the log then humility could guess the wrong slot - oh wait there's a version byte that protects against that.

  3. Humility needs to know how bootleby's slot boolean maps to an actual archive. It could check image_name == "a", but hopefully there's a nicer way that doesn't require hardcoding a name string.

But if none of those seem like a big deal, then I think it would be fine to use the bootleby log instead of BOOTED_IMAGE. And the fact that it has a fixed address in RAM is great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants