Custom kernel on OpenBMC eMMC system

This post has instructions for creating an ITS and using it to build a signed FIT for booting on a OpenBMC system that requires a signed kernel FIT.

Background

Some of the Power10 systems from IBM use OpenBMC for their management processors. These run the AST2600 BMC, and have eMMC as the boot media and root file system.

The system contains two sides, a and b, that are selected by a u-boot script depending on the u-boot environment variable ‘bootside’. This maps to the following GPT disk layout:

  --- - ----- -------- -------- -------- -------- ------ -------- -------
 |GPT| | env | boot-a | boot-b | rofs-a | rofs-b | rwfs | hostfw |GPT-sec|
  --- - ----- -------- -------- -------- -------- ------ -------- -------
         1MB    64MB     64MB     1GB      1GB     7GB     5GB

(From (https://github.com/openbmc/openbmc/blob/master/meta-aspeed/wic/emmc-aspeed.wks.in))

In addition, OpenBMC now uses the u-boot ‘vboot’ feature to verify the image it loads. u-boot contains a public key that is used to verify the signatures present in the FIT image.

For the public OpenBMC tree, a hardcoded key pair is used for development. This means we can build our own kernels and sign them with that key, and load them on machines that run development builds of OpenBMC.

Prerequisites

To do this we need an Image Signing Tree (.its) that describes how to sign the image. We can use the one from the build artifacts or write our own:

/dts-v1/;

/ {
        description = "How good are computers?";
        #address-cells = <1>;

        images {
                kernel-1 {
                        description = "Linux kernel";
                        data = /incbin/("arch/arm/boot/zImage");
                        type = "kernel";
                        arch = "arm";
                        os = "linux";
                        compression = "none";
                        load = <0x80001000>;
                        entry = <0x80001000>;
                        hash-1 {
                                algo = "sha512";
                        };
                };
                fdt-aspeed-bmc-ibm-rainier.dtb {
                        description = "Flattened Device Tree blob";
                        data = /incbin/("arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dtb");
                        type = "flat_dt";
                        arch = "arm";
                        compression = "none";
                        hash-1 {
                                algo = "sha512";
                        };
                };
                ramdisk-1 {
                        description = "obmc-phosphor-initramfs";
                        data = /incbin/("obmc-phosphor-initramfs-p10bmc.cpio.xz");
                        type = "ramdisk";
                        arch = "arm";
                        os = "linux";
                        compression = "none";
                        hash-1 {
                                algo = "sha512";
                        };
                };
	};

        configurations {
                default = "conf-aspeed-bmc-ibm-rainier.dtb";
                conf-aspeed-bmc-ibm-rainier.dtb {
			description = "1 Linux kernel, FDT blob, ramdisk";
			kernel = "kernel-1";
			fdt = "fdt-aspeed-bmc-ibm-rainier.dtb";
			ramdisk = "ramdisk-1";
                        hash-1 {
                                algo = "sha512";
                        };
                        signature-1 {
                                algo = "sha512,rsa4096";
                                key-name-hint = "rsa_oem_fitimage_key";
				sign-images = "kernel", "fdt", "ramdisk";
                        };
                };
	};
};

Place this as p10bmc.its in your kernel build tree.

Also download the signing key from the openbmc repository, and an initramfs from CI.

Place rsa_oem_fitimage_key.key and obmc-phosphor-initramfs-p10bmc.cpio.xz in your kernel build tree too.

Signing

With all of these pieces in place we can produce a signed FIT:

mkimage -k . -f p10bmc.its image.fit

The output should look as follows:

FIT description: How good are computers?
Created:         Fri Sep  3 12:04:12 2021
 Image 0 (kernel-1)
  Description:  Linux kernel
  Created:      Fri Sep  3 12:04:12 2021
  Type:         Kernel Image
  Compression:  uncompressed
  Data Size:    3812160 Bytes = 3722.81 KiB = 3.64 MiB
  Architecture: ARM
  OS:           Linux
  Load Address: 0x80001000
  Entry Point:  0x80001000
  Hash algo:    sha512
  Hash value:   1b1e6428c8f0b18dd2b92ddabe751fa99e786e301ea0017a65823c81db77ed8be66798599d9673d76a03c712aedcbddd44d63ce955ca1b92e44033f22805762e
 Image 1 (fdt-aspeed-bmc-ibm-rainier.dtb)
  Description:  Flattened Device Tree blob
  Created:      Fri Sep  3 12:04:12 2021
  Type:         Flat Device Tree
  Compression:  uncompressed
  Data Size:    57116 Bytes = 55.78 KiB = 0.05 MiB
  Architecture: ARM
  Hash algo:    sha512
  Hash value:   1e9d2c7ab1df61e42ba91b020634b0d4fc1e8998433126f7a11166a10fb8651a269ef9a3498602e7f8ddf17bd7cbaa3e5ae17a8698cb89c3350a599b5ae67753
 Image 2 (ramdisk-1)
  Description:  obmc-phosphor-initramfs
  Created:      Fri Sep  3 12:04:12 2021
  Type:         RAMDisk Image
  Compression:  uncompressed
  Data Size:    2883560 Bytes = 2815.98 KiB = 2.75 MiB
  Architecture: ARM
  OS:           Linux
  Load Address: unavailable
  Entry Point:  unavailable
  Hash algo:    sha512
  Hash value:   b7dc3392eec60dfb4c25cc678d2bb00e01c404ccf1212a3a08beedd051cf7ad533c46d11bf5651c9a06a8f116f41e47bbcdf56107f65339ae27ee49816066c0d
 Default Configuration: 'conf-aspeed-bmc-ibm-rainier.dtb'
 Configuration 0 (conf-aspeed-bmc-ibm-rainier.dtb)
  Description:  1 Linux kernel, FDT blob, ramdisk
  Kernel:       kernel-1
  Init Ramdisk: ramdisk-1
  FDT:          fdt-aspeed-bmc-ibm-rainier.dtb
  Hash algo:    sha512
  Hash value:   unavailable
  Sign algo:    sha512,rsa4096:rsa_oem_fitimage_key
  Sign value:   <big number>
  Timestamp:    Fri Sep  3 12:04:12 2021

Tips

I modify my its to point to a location where I keep copies of the initramfs so I can test various kernel trees without copying files around. Similarly I modify the -k key argument to point to a local checkout of the OpenBMC source tree to save copying it around.

Booting

The easiest method of using your shiny signed FIT is to install it in /boot on a live machine.

Check to see which side is the current:

fw_printenv bootside
bootside=a

Copy it over, mount the boot partition and copy in the new FIT:

scp p10bmc.fit bmc:
ssh bmc
mount /dev/disk/by-partlabel/boot-a /boot
mv /boot/fitimage{,.old}
mv p10bmc.fit /boot/fitImage
reboot
Written on September 3, 2021