Skip to content

Support your machine (Arm)

This page suggests a step-by-step guide of the things to do in order to have Welma booting on your Arm-based machine.

Step 1: Set up your Yocto layer

  • Start from the OEM's BSP layers: bootloader, kernel, ...

    • Remove dependencies to unnecessary layers, in order to ease maintenance. Typically:
      • for imx-based boards: remove meta-freescale-*, meta-imx
      • for arm-based boards: remove meta-arm
      • remove the vendor's layers that are not BSP-related: demonstration distro, sdk
      • and so on...
    • Keep TF-A (or ATF), OP-TEE
    • Work in a layer repository named meta-welma-<vendor>. Create:
      • conf/layer.conf (if the layer is a new layer)
      • conf/machine/$MACHINE.conf
      • conf/templates/$MACHINE/local.conf.sample
      • conf/templates/$MACHINE/bblayers.conf.sample
  • Define your partition layout (boot, sysro, appro, sysrw)

    • Give priority to storing the bootloader on eMMC, in user partition
    • Create files/partitions-$MACHINE.conf (and have WELMA_PARTITIONS point to it, which is already the case with its default value).
    • Create wic/$MACHINE.wks.in, with A/B partitions (and have WKS_FILE point to it)
      • Allocate an extra partition for the bootflags
    • In conf/machine/$MACHINE.conf, define the BOOTFLAGS_ parameters, that indicate how userspace programs can locate the bootflags. Eg:
      BOOTFLAGS_PATH ?= "/dev/mmcblk2p1"
      BOOTFLAGS_OFFSET ?= "0x0"
      BOOTFLAGS_OFFSET_COPY ?= "0x200"
      

Step 2: Have Welma boot to initramfs

  • U-Boot:

Create the default environment file distro-bootcmd.env:

Example of minimal default environment for machine sm2s-imx8plus-mbep5
/* Machine-specific parameters */
bootmedia=mmc
bootdev=2  /* mmc device number */
bootpart=1 /* partition where 'fitImage' is located */
fit_loadaddr=0x48000000
console=ttymxc1,115200
fdt_module=undefined /* will be populated by u-boot (in board_late_init) */
fit_config_and_fdt_overlays=#conf-overlay-hdmi.dtb#conf-overlay-baseboard-ep5.dtb#conf-overlay-sm2s-imx8plus-mbep5.dtb

evaluate_bootflags=echo Placeholder for evaluate_bootflags;
set_swk1_in_bootargs=echo Placeholder for set_swk1_in_bootargs;

boot_welma=
    run evaluate_bootflags;
    load ${bootmedia} ${bootdev}:${bootpart} ${fit_loadaddr} fitImage;
    setenv bootargs "${bootargs} console=${console}";
    run set_swk1_in_bootargs;
    bootm ${fit_loadaddr}#conf-${fdt_module}${fit_config_and_fdt_overlays};

distro_bootcmd=run boot_welma;

Have this default environment file integrated in u-boot binary (CONFIG_ENV_SOURCE_FILE).

  • Kernel FIT image (meta-welma/recipes-welma/fitimage/welma-fitimage.bb): define in conf/machine/$MACHINE.conf parameters that will be used by this recipe:

    • KERNEL_DEVICETREE: include dtb and overlays
    • Find available memory regions in RAM and set load addresses for kernel, fdt, fdt overlays, ramdisk. These addresses will be used in the memory context of U-Boot. Eg:
      UBOOT_DTB_LOADADDRESS  = "0x50000000"
      UBOOT_DTBO_LOADADDRESS = "0x51000000"
      UBOOT_LOADADDRESS      = "0x40480000"
      UBOOT_RD_LOADADDRESS   = "0x43800000"
      
  • Kernel: inherit kernel-uboot-deploy

  • Install the bootloader and all partitions on your board.

  • Boot: you should now see your board boot until a kernel panic error, which will be fixed in the next step.

    ...
    U-Boot ...
    ...
    Hit any key to stop autoboot: ...
    ...
    ## Loading kernel from FIT Image at ...
    ...
    ## Loading ramdisk from FIT Image at ...
    ...
    ## Loading fdt from FIT Image at ...
    ...
    Starting kernel ...
    [    0.000000] Booting Linux on physical CPU 0x0000000000 ...
    ...
    [    2.878750] Run /init as init process
    [    2.915409] initramfs: Starting
    [    3.022323] initramfs: ERROR: no active partition for (sysro / ...). Expect undefined behaviour.
    [    3.005157] initramfs: ERROR: no active partition for (boot /boot ...). Expect undefined behaviour.
    [    3.044028] initramfs: ERROR: no active partition for (appro /app ...). Expect undefined behaviour.
    [    3.183040] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000100
    

Step 3: Have U-Boot support A/B partitions

  • U-Boot:

    • Add the command bootflags (in cmd/bootflags.c) and have it configured. Eg:

      CONFIG_CMD_BOOTFLAGS=y
      CONFIG_BOOTFLAGS_INTERFACE="mmc"
      CONFIG_BOOTFLAGS_DEVICE=2
      CONFIG_BOOTFLAGS_OFFSET=0x300000
      CONFIG_BOOTFLAGS_OFFSET_COPY=0x300200
      
      These must be consistent with the partition layout defined at step 1.

    • distro-bootcmd.env: add bootflags logic:

      • Recover if a previous bootflags writing was interrupted
      • Initialize if no valid bootflags are found
      • Roll back if this is the second attempt to boot in test mode
      • Select the kernel FIT image partition to boot on
/* Machine-specific parameters */
bootflags_default_partitions=0x15 /* partitions number 1:3:5 */

evaluate_bootflags=
    bootflags check; /* Recover from a previous interrupted writing */
    bootflags read;  /* Load bootflags_test_mode
                      *      bootflags_test_count
                      *      bootflags_first_active_partition */

    if test $? != 0; then
        /* bootflags not present or corrupted, initialize with default */
        bootflags init $bootflags_default_partitions;
        /* has also updated the values in memory (as bootflags read does) */
    fi;

    if test $bootflags_test_mode = 1; then
        echo "Test mode";
        if test $bootflags_test_count -ge 1; then
            /* cancel test and back to normal mode */
            echo "Revert to normal mode.";
            bootflags abort-test;
            /* has also updated the values in memory (as bootflags read does) */
        else
            bootflags increment-test-count;
        fi;
    else
        echo "Normal mode";
    fi;

    bootpart=${bootflags_first_active_partition}; /* Select boot partition */

Step 4: Minimal working set of facilities

At this point you have to make sure:

  • The Linux commands reboot and reboot -f get your board to reboot.
  • Your board has one ethernet interface configured with a static IP address. Example:
    # ip address
    ...
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
        link/ether 10:e7:7a:e1:93:9a brd ff:ff:ff:ff:ff:ff
        inet 169.254.0.1/16 brd 169.254.255.255 scope link eth0
           valid_lft forever preferred_lft forever
    [...]
        inet6 fe80::1/10 scope link
           valid_lft forever preferred_lft forever
    [...]
    
  • Your development image can be reached by SSH. Eg:

    $ ssh root@169.254.0.1
    Last login: Fri Jul 19 06:49:53 2024
    stm32mp15-disco-welma:~#
    
    For this, you may need to configure the network (routes) of your PC.

  • U-Boot can download an image via TFTP and install it on the mass memory of the board. This is needed for Welma's automatic testing. Eg:

    STM32MP> setenv ipaddr 192.168.1.20
    STM32MP> setenv serverip 192.168.1.12
    
    STM32MP> tftp welma/demo-image-headless-dev-stm32mp15-disco-welma.wic.gz
    Using ethernet@5800a000 device
    TFTP from server 192.168.1.12; our IP address is 192.168.1.20
    Filename 'welma/demo-image-headless-dev-stm32mp15-disco-welma.wic.gz'.
    Load address: 0xc2000000
    Loading: #################################################################
             #################################################################
             ########
             4.6 MiB/s
    done
    Bytes transferred = 2024248 (1ee338 hex)
    
    STM32MP> mmcid=0
    STM32MP> gzwrite mmc $mmcid $loadaddr $filesize
    

  • You have a documented procedure to install the image on the device for the first time (eg: with UUU, dfu-util, fastboot)

Step 5: Watchdog

  • U-Boot: start the watchdog timer before starting the kernel, with a timeout of 60 s (to give the kernel time to start)

It is also useful to have the wdt command (CMD_WDT=y), for testing (see https://docs.u-boot.org/en/latest/usage/cmd/wdt.html).

  • Linux kernel:

    • Activate the driver to support the watchdog device
    • Have the kernel ping the watchdog device until a userspace program takes over (for at most 4 min) and do not stop the watchdog timer when this userspace program closes /dev/watchdog:
  • Userspace:

    • Configure systemd to service the watchdog device (/dev/watchdog0).
WATCHDOG_HANDLE_BOOT_ENABLED=y
WATCHDOG_NOWAYOUT=y
WATCHDOG_OPEN_TIMEOUT=240

Notes:

  • If your board has more than one HW watchdog device, make sure to use the same watchdog device in U-Boot and Linux kernel & userspace.

Step 6: Populate the license digest

  • WELMA_LIC_DIGEST_BOOT: add the recipes of the packages included in the bootloader

Step 7: Support secure boot

  • In conf/templates/$MACHINE/local.conf.sample, set WELMA_SECURE_BOOT = "1"

  • U-Boot: Provision SWK1 in U-Boot

    • Add the command fdt get hexvalue (in cmd/fdt.c)
    • distro-bootcmd.env: add SWK1 public key to bootargs
      set_swk1_in_bootargs=
          fdt addr ${fdtcontroladdr};
          fdt get hexvalue rsa_exponent /signature/key-SWK1 rsa,exponent;
          fdt get hexvalue rsa_modulus /signature/key-SWK1 rsa,modulus;
          setenv bootargs "${bootargs} swk1=rsa_exponent:0x${rsa_exponent};rsa_modulus:0x${rsa_modulus}"
      
    • do_compile:append(): have SWK1 injected using the script inject-pubkey-uboot-dtb
  • U-Boot: Be sure to use the standard U-Boot mechanism for authenticating the kernel FIT image. Some vendor's versions of U-Boot use another specific mechanism (such as HAB on imx-based boards), and you should deactivate that.

  • Kernel: CONFIG_DM_VERITY=y

  • imx-boot (for machines that have this bootloader):

    • In the Yocto build, have it signed and provisioned with development keys, using welma-signing-tools
    • Have the offsets of the signed blocks collected
    • Have fuse-bootcmd.scr generated
    • In conf/machine/$MACHINE.conf, set BOOT_SIGNING_MECHANISM = "imx"
  • bootloader (other than imx-boot):

    • Activate (or write) the code for authenticating each stage until U-Boot
    • Create the tools for signing out of Yocto
    • Have it signed in the Yocto build with development keys
    • Provision the needed public keys as well (in Yocto and out of Yocto)

Step 8: Support secure storage (OP-TEE)

This support should be provided the bootloader which must integrate and launch OP-TEE OS.

In Linux, use xtest (from package optee-test) to check correct support.

Step 9: Production bootloader

Production image should not have an interactive bootloader.

Make sure to apply a minimal u-boot configuration when IMAGE_FEATURES contains development.

This minimal configuration should at least include CONFIG_BOOTDELAY=-2 to boot without offering any commandline.