Skip to content

[action] [PR:4602] [sonic-installer] Add dedicated SONiC-BMC U-Boot bootloader#386

Merged
mssonicbld merged 1 commit into
Azure:202608from
mssonicbld:cherry/msft-202608/4602
Jul 1, 2026
Merged

[action] [PR:4602] [sonic-installer] Add dedicated SONiC-BMC U-Boot bootloader#386
mssonicbld merged 1 commit into
Azure:202608from
mssonicbld:cherry/msft-202608/4602

Conversation

@mssonicbld

Copy link
Copy Markdown
Collaborator

Address issue - sonic-net/sonic-utilities#4548

What I did

Added a dedicated BmcUbootBootloader so sonic-installer manages SONiC-BMC boot state correctly. SONiC-BMC platforms (ASPEED AST2700) run U-Boot with a two-slot environment, which the generic UbootBootloader does not model — on a BMC it previously fell through to that generic handler and operated on the wrong environment variables.

Specifically:

  • New sonic_installer/bootloader/bmc_uboot.py (BmcUbootBootloader, NAME = 'bmc-uboot'), selected via utilities_common.chassis.is_bmc().
  • Registered first in BOOTLOADERS so a stray /host/grub/grub.cfg cannot preempt it, and guarded UbootBootloader.detect() to exclude BMC.
  • Full two-slot lifecycle: list, set-default, set-next-boot, install, remove, cleanup, verify-next-image, set-fips/get-fips, binary-version, plus a BMC-specific verify_image_platform (fails closed).
  • Unit tests in tests/installer_bootloader_bmc_uboot_test.py (12 tests).

No change to sonic_installer/main.py — the work is confined to the bootloader plugin and its test.

How I did it

BmcUbootBootloader subclasses OnieInstallerBootloader and models the ASPEED AST2700 two-slot U-Boot environment:

Concept Slot 1 Slot 2
version var sonic_version_1 sonic_version_2
boot command run sonic_image_1 run sonic_image_2
kernel args linuxargs linuxargs_old

Empty slots are written/read as the marker None (also accepts NONE/empty, case-insensitively).

  • Boot selection (Aboot-style contract): set-default writes the persistent boot_next and clears the one-shot boot_once; set-next-boot writes only boot_once. get_next_image() resolves boot_once first (it wins, matching U-Boot bootcmd), then boot_next, and surfaces an empty/unrecognized selector as a raw string so a broken boot state stays visible rather than being masked.
  • Install: install_image() runs the image's own installer (bash <image>, which performs the slot rotation and sets boot_next) and then clears any stale boot_once that would otherwise shadow the new default.
  • Remove: remove_image() repoints boot_once/boot_next to the surviving slot before clearing the removed slot's version + auxiliary vars and deleting its rootfs; it refuses to remove the only populated slot.
  • FIPS: set-fips/get-fips rewrite the sonic_fips= token in the target slot's linuxargs/linuxargs_old only (per-slot isolation).
  • Platform check: verify_image_platform() mirrors the GRUB approach — extracts installer/platforms_asic from the image and matches the running device_info.get_platform() with grep -Fxq (whole-line). It fails closed: compatible only when grep matches, so a malformed/manifest-less payload is rejected rather than silently accepted.

How to verify it

On a SONiC-BMC (ASPEED AST2700) board, the dedicated bootloader is auto-selected and the full command surface was exercised end-to-end, cross-checking the U-Boot environment (fw_printenv) and, across real reboots, /proc/cmdline:

  • sonic-installer list / verify-next-image reflect the two-slot state.
  • set-default <img> sets boot_next and clears boot_once; set-next-boot <img> sets a one-shot boot_once that U-Boot consumes on the next reboot and then reverts to boot_next.
  • install <bmc.bin> rotates the new image into a slot and boots it after reboot.
  • remove / cleanup clear the slot's vars, repoint the boot selectors, and delete the rootfs.
  • set-fips/get-fips toggle sonic_fips= in the correct per-slot args.
  • A wrong-platform (switch) image is rejected by verify_image_platform; --skip-platform-check overrides it.

Signed-off-by: Sonic Build Admin sonicbld@microsoft.com

Previous command output (if the output of a command-line utility has changed)

New command output (if the output of a command-line utility has changed)

Address issue - sonic-net/sonic-utilities#4548

#### What I did

Added a **dedicated `BmcUbootBootloader`** so `sonic-installer` manages SONiC-BMC boot state correctly. SONiC-BMC platforms (ASPEED AST2700) run U-Boot with a **two-slot** environment, which the generic `UbootBootloader` does not model — on a BMC it previously fell through to that generic handler and operated on the wrong environment variables.

Specifically:
- New `sonic_installer/bootloader/bmc_uboot.py` (`BmcUbootBootloader`, `NAME = 'bmc-uboot'`), selected via `utilities_common.chassis.is_bmc()`.
- Registered **first** in `BOOTLOADERS` so a stray `/host/grub/grub.cfg` cannot preempt it, and guarded `UbootBootloader.detect()` to exclude BMC.
- Full two-slot lifecycle: `list`, `set-default`, `set-next-boot`, `install`, `remove`, `cleanup`, `verify-next-image`, `set-fips`/`get-fips`, `binary-version`, plus a BMC-specific `verify_image_platform` (fails closed).
- Unit tests in `tests/installer_bootloader_bmc_uboot_test.py` (12 tests).

No change to `sonic_installer/main.py` — the work is confined to the bootloader plugin and its test.

#### How I did it

`BmcUbootBootloader` subclasses `OnieInstallerBootloader` and models the ASPEED AST2700 two-slot U-Boot environment:

| Concept | Slot 1 | Slot 2 |
|---------|--------|--------|
| version var | `sonic_version_1` | `sonic_version_2` |
| boot command | `run sonic_image_1` | `run sonic_image_2` |
| kernel args | `linuxargs` | `linuxargs_old` |

Empty slots are written/read as the marker `None` (also accepts `NONE`/empty, case-insensitively).

- **Boot selection (Aboot-style contract):** `set-default` writes the persistent `boot_next` and clears the one-shot `boot_once`; `set-next-boot` writes only `boot_once`. `get_next_image()` resolves `boot_once` first (it wins, matching U-Boot `bootcmd`), then `boot_next`, and surfaces an empty/unrecognized selector as a raw string so a broken boot state stays visible rather than being masked.
- **Install:** `install_image()` runs the image's own installer (`bash <image>`, which performs the slot rotation and sets `boot_next`) and then clears any stale `boot_once` that would otherwise shadow the new default.
- **Remove:** `remove_image()` repoints `boot_once`/`boot_next` to the surviving slot before clearing the removed slot's version + auxiliary vars and deleting its rootfs; it refuses to remove the only populated slot.
- **FIPS:** `set-fips`/`get-fips` rewrite the `sonic_fips=` token in the target slot's `linuxargs`/`linuxargs_old` only (per-slot isolation).
- **Platform check:** `verify_image_platform()` mirrors the GRUB approach — extracts `installer/platforms_asic` from the image and matches the running `device_info.get_platform()` with `grep -Fxq` (whole-line). It **fails closed**: compatible only when grep matches, so a malformed/manifest-less payload is rejected rather than silently accepted.

#### How to verify it

On a SONiC-BMC (ASPEED AST2700) board, the dedicated bootloader is auto-selected and the full command surface was exercised end-to-end, cross-checking the U-Boot environment (`fw_printenv`) and, across real reboots, `/proc/cmdline`:

- `sonic-installer list` / `verify-next-image` reflect the two-slot state.
- `set-default <img>` sets `boot_next` and clears `boot_once`; `set-next-boot <img>` sets a one-shot `boot_once` that U-Boot consumes on the next reboot and then reverts to `boot_next`.
- `install <bmc.bin>` rotates the new image into a slot and boots it after reboot.
- `remove` / `cleanup` clear the slot's vars, repoint the boot selectors, and delete the rootfs.
- `set-fips`/`get-fips` toggle `sonic_fips=` in the correct per-slot args.
- A wrong-platform (switch) image is rejected by `verify_image_platform`; `--skip-platform-check` overrides it.

Signed-off-by: Sonic Build Admin <sonicbld@microsoft.com>

#### Previous command output (if the output of a command-line utility has changed)

#### New command output (if the output of a command-line utility has changed)
@mssonicbld

Copy link
Copy Markdown
Collaborator Author

Original PR: sonic-net/sonic-utilities#4602

@mssonicbld

Copy link
Copy Markdown
Collaborator Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines could not run because the pipeline triggers exclude this branch/path.

@mssonicbld mssonicbld merged commit 96f0bc9 into Azure:202608 Jul 1, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant