Examples
There is a separate directory with examples called firmware-action-example. It is a great source of information to get started.
In addition, the main repository also contains multiple examples (even though rather simple ones) defined in .github/workflows/example.yml. These are there to function as tests to verify the functionality, as such they are made with this specific task in mind. Please take that into account when going though them.
Coreboot
Tip
Coreboot - GitHub CI
build-coreboot: needs: - changes - skip-check strategy: fail-fast: false matrix: coreboot-version: ['24.02.01'] arch: ['amd64', 'arm64'] runs-on: ${{ matrix.arch == 'arm64' && 'ARM64' || 'ubuntu-latest' }} if: ${{ ! (github.event_name == 'pull_request_review' && github.actor != 'github-actions[bot]') && needs.skip-check.outputs.changes == 'true' }} # Skip if pull_request_review on PR not made by a bot steps: - name: Cleanup run: | rm -rf ./* || true rm -rf ./.??* || true - name: Checkout uses: actions/checkout@v7 - name: Restore cached coreboot repo uses: actions/cache/restore@v6 id: cache-repo with: path: ./my_super_dooper_awesome_coreboot key: coreboot-${{ matrix.coreboot-version }}-example - name: Clone coreboot repo if: steps.cache-repo.outputs.cache-hit != 'true' run: | git clone --branch "${{ matrix.coreboot-version }}" --depth 1 https://review.coreboot.org/coreboot my_super_dooper_awesome_coreboot - name: Store coreboot repo in cache uses: actions/cache/save@v6 if: steps.cache-repo.outputs.cache-hit != 'true' with: path: ./my_super_dooper_awesome_coreboot key: coreboot-${{ matrix.coreboot-version }}-example - name: Move my defconfig into place (filename must not contain '.defconfig') run: | mv "tests/coreboot_${{ matrix.coreboot-version }}/seabios.defconfig" "seabios_defconfig" - name: firmware-action uses: ./ # uses: 9elements/firmware-action with: config: |- tests/example_config__coreboot.json tests/example_config__uroot.json target: 'coreboot-example' recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' enable-cache: 'true' auto-download-artifacts: 'true' auto-upload-artifacts: 'true' env: COREBOOT_VERSION: ${{ matrix.coreboot-version }} UROOT_VERSION: 'dummy'
Tip
Coreboot - Configuration file
{ "coreboot": { "coreboot-example": { "depends": null, "sdk_url": "ghcr.io/9elements/firmware-action/coreboot_${COREBOOT_VERSION}:main", "repo_path": "my_super_dooper_awesome_coreboot/", "defconfig_path": "seabios_defconfig", "output_dir": "output-coreboot/", "container_output_dirs": null, "container_output_files": ["build/coreboot.rom", "defconfig"], "blobs": {}, "container_input_dir": "inputs/", "input_dirs": null, "input_files": null } } }
Linux Kernel
Tip
Linux Kernel - GitHub CI
build-linux: needs: - changes - skip-check strategy: fail-fast: false matrix: linux-version: ['6.12'] arch: ['amd64', 'arm64'] runs-on: ${{ matrix.arch == 'arm64' && 'ARM64' || 'ubuntu-latest' }} if: ${{ ! (github.event_name == 'pull_request_review' && github.actor != 'github-actions[bot]') && needs.skip-check.outputs.changes == 'true' }} # Skip if pull_request_review on PR not made by a bot steps: - name: Cleanup run: | rm -rf ./* || true rm -rf ./.??* || true - name: Checkout uses: actions/checkout@v7 - name: Restore cached linux source id: cache-repo uses: actions/cache/restore@v6 with: path: ./linux-${{ matrix.linux-version }}.tar.xz key: linux-${{ matrix.linux-version }}-example - name: Prepare linux kernel run: | # Download source files wget --quiet --continue "https://cdn.kernel.org/pub/linux/kernel/v${LINUX_MAJOR_VERSION}.x/linux-${{ matrix.linux-version }}.tar.xz" wget --quiet "https://cdn.kernel.org/pub/linux/kernel/v${LINUX_MAJOR_VERSION}.x/linux-${{ matrix.linux-version }}.tar.sign" unxz --keep "linux-${{ matrix.linux-version }}.tar.xz" >/dev/null # Verify GPG signature gpg2 --locate-keys torvalds@kernel.org gregkh@kernel.org gpg2 --verify "linux-${{ matrix.linux-version }}.tar.sign" # Extract tar -xvf "linux-${{ matrix.linux-version }}.tar" env: LINUX_MAJOR_VERSION: 6 - name: Store linux source in cache uses: actions/cache/save@v6 if: steps.cache-repo.outputs.cache-hit != 'true' with: path: ./linux-${{ matrix.linux-version }}.tar.xz key: linux-${{ matrix.linux-version }}-example - name: Move my defconfig into place (filename must not contain '.defconfig') run: | mv "tests/linux_${{ matrix.linux-version }}/linux.defconfig" "ci_defconfig" - name: firmware-action uses: ./ # uses: 9elements/firmware-action with: config: |- tests/example_config__uroot.json tests/example_config__linux.json target: 'linux-example' recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' enable-cache: 'true' auto-download-artifacts: 'true' auto-upload-artifacts: 'true' env: LINUX_VERSION: ${{ matrix.linux-version }} SYSTEM_ARCH: ${{ matrix.arch }} UROOT_VERSION: 'dummy'
Tip
Linux Kernel - Configuration file
{ "linux": { "linux-example": { "depends": null, "sdk_url": "ghcr.io/9elements/firmware-action/linux_${LINUX_VERSION}:main", "arch": "${SYSTEM_ARCH}", "repo_path": "linux-${LINUX_VERSION}/", "defconfig_path": "ci_defconfig", "output_dir": "output-linux/", "container_output_dirs": null, "container_output_files": ["vmlinux", "defconfig"], "gcc_version": "", "container_input_dir": "inputs/", "input_dirs": null, "input_files": null } } }
Edk2
Tip
Edk2 - GitHub CI
build-edk2: runs-on: ubuntu-latest needs: - changes - skip-check strategy: fail-fast: false matrix: edk2-version: ['edk2-stable202211'] # TODO if: ${{ ! (github.event_name == 'pull_request_review' && github.actor != 'github-actions[bot]') && needs.skip-check.outputs.changes == 'true' }} # Skip if pull_request_review on PR not made by a bot steps: - name: Cleanup run: | rm -rf ./* || true rm -rf ./.??* || true - name: Checkout uses: actions/checkout@v7 - name: Restore cached edk2 repo uses: actions/cache/restore@v6 id: cache-repo with: path: ./Edk2 key: edk2-${{ matrix.edk2-version }}-example - name: Clone edk2 repo if: steps.cache-repo.outputs.cache-hit != 'true' run: | git clone --recurse-submodules --branch "${{ matrix.edk2-version }}" --depth 1 https://github.com/tianocore/edk2.git Edk2 - name: Prepare file with build arguments run: | echo "-D BOOTLOADER=COREBOOT -D TPM_ENABLE=TRUE -D NETWORK_IPXE=TRUE" > "edk2_config.cfg" - name: Store edk2 repo in cache uses: actions/cache/save@v6 if: steps.cache-repo.outputs.cache-hit != 'true' with: path: ./Edk2 key: edk2-${{ matrix.edk2-version }}-example - name: Get versions of edk2 id: edk2_versions run: | echo "ver_current=$( echo ${{ matrix.edk2-version }} | tr -cd '0-9' )" >> "${GITHUB_OUTPUT}" echo "ver_breaking=$( echo 'edk2-stable202305' | tr -cd '0-9' )" >> "${GITHUB_OUTPUT}" - name: Use GCC5 for old edk2 id: gcc_toolchain # GCC5 is deprecated since edk2-stable202305 # For more information see https://github.com/9elements/firmware-action/issues/340 run: | if [[ ! ${{ steps.edk2_versions.outputs.ver_current }} < ${{ steps.edk2_versions.outputs.ver_breaking }} ]]; then echo "gcc_toolchain_version=GCC" >> "${GITHUB_OUTPUT}" else echo "gcc_toolchain_version=GCC5" >> "${GITHUB_OUTPUT}" fi - name: firmware-action uses: ./ # uses: 9elements/firmware-action with: config: 'tests/example_config__edk2.json' target: 'edk2-example' recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' enable-cache: 'true' auto-download-artifacts: 'true' auto-upload-artifacts: 'true' env: EDK2_VERSION: ${{ matrix.edk2-version }} GCC_TOOLCHAIN_VERSION: ${{ steps.gcc_toolchain.outputs.gcc_toolchain_version }}
Tip
Edk2 - Configuration file
{ "edk2": { "edk2-example": { "depends": null, "sdk_url": "ghcr.io/9elements/firmware-action/${EDK2_VERSION}:main", "arch": "X64", "repo_path": "Edk2/", "defconfig_path": "edk2_config.cfg", "output_dir": "output-edk2/", "container_output_dirs": ["Build/"], "container_output_files": null, "build_command": "set -Eeo pipefail; source ./edksetup.sh; build -a X64 -p UefiPayloadPkg/UefiPayloadPkg.dsc -b DEBUG -t ${GCC_TOOLCHAIN_VERSION}", "container_input_dir": "inputs/", "input_dirs": null, "input_files": null } } }
Firmware Stitching
Tip
Firmware Stitching - GitHub CI
build-stitching: needs: - changes - skip-check strategy: fail-fast: false matrix: coreboot-version: ['4.19'] arch: ['amd64', 'arm64'] runs-on: ${{ matrix.arch == 'arm64' && 'ARM64' || 'ubuntu-latest' }} if: ${{ ! (github.event_name == 'pull_request_review' && github.actor != 'github-actions[bot]') && needs.skip-check.outputs.changes == 'true' }} # Skip if pull_request_review on PR not made by a bot steps: - name: Cleanup run: | rm -rf ./* || true rm -rf ./.??* || true - name: Checkout uses: actions/checkout@v7 - name: Restore cached coreboot-blobs repo uses: actions/cache/restore@v6 id: cache-repo with: path: ./stitch key: coreboot-blobs-${{ matrix.coreboot-version }}-example - name: Clone blobs repo if: steps.cache-repo.outputs.cache-hit != 'true' run: | git clone --depth 1 https://review.coreboot.org/blobs stitch - name: Store coreboot-blobs repo in cache uses: actions/cache/save@v6 if: steps.cache-repo.outputs.cache-hit != 'true' with: path: ./stitch key: coreboot-blobs-${{ matrix.coreboot-version }}-example - name: firmware-action uses: ./ # uses: 9elements/firmware-action with: config: 'tests/example_config__firmware_stitching.json' target: 'stitching-example' recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' enable-cache: 'true' auto-download-artifacts: 'true' auto-upload-artifacts: 'true' env: COREBOOT_VERSION: ${{ matrix.coreboot-version }}
Tip
Firmware Stitching - Configuration file
{ "firmware_stitching": { "stitching-example": { "depends": null, "sdk_url": "ghcr.io/9elements/firmware-action/coreboot_${COREBOOT_VERSION}:main", "repo_path": "stitch/", "container_output_dirs": null, "container_output_files": ["new_descriptor.bin"], "output_dir": "output-stitch/", "base_file_path": "stitch/mainboard/intel/emeraldlake2/descriptor.bin", "platform": "", "ifdtool_entries": [ { "path": "stitch/mainboard/intel/emeraldlake2/me.bin", "target_region": "ME", "optional_arguments": null } ], "container_input_dir": "inputs/", "input_dirs": null, "input_files": null } } }
u-root
Tip
u-root - GitHub CI
build-uroot: needs: - changes - skip-check strategy: fail-fast: false matrix: uroot-version: ['0.15.0'] arch: ['amd64', 'arm64'] runs-on: ${{ matrix.arch == 'arm64' && 'ARM64' || 'ubuntu-latest' }} if: ${{ ! (github.event_name == 'pull_request_review' && github.actor != 'github-actions[bot]') && needs.skip-check.outputs.changes == 'true' }} # Skip if pull_request_review on PR not made by a bot steps: - name: Cleanup run: | rm -rf ./* || true rm -rf ./.??* || true - name: Checkout uses: actions/checkout@v7 - name: Restore cached u-root repo uses: actions/cache/restore@v6 id: cache-repo with: path: ./u-root key: u-root-${{ matrix.uroot-version }}-example - name: Clone u-root repo if: steps.cache-repo.outputs.cache-hit != 'true' run: | git clone --depth 1 --branch v${{ matrix.uroot-version }} https://github.com/u-root/u-root.git || true - name: Store u-root repo in cache uses: actions/cache/save@v6 if: steps.cache-repo.outputs.cache-hit != 'true' with: path: ./u-root key: u-root-${{ matrix.uroot-version }}-example - name: firmware-action uses: ./ # uses: 9elements/firmware-action with: config: 'tests/example_config__uroot.json' target: 'u-root-example' recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' enable-cache: 'true' auto-download-artifacts: 'true' auto-upload-artifacts: 'true' env: UROOT_VERSION: ${{ matrix.uroot-version }}
Tip
u-root - Configuration file
{ "u-root": { "u-root-example": { "depends": null, "sdk_url": "ghcr.io/9elements/firmware-action/uroot_${UROOT_VERSION}:main", "repo_path": "u-root/", "output_dir": "output-uroot/", "container_output_dirs": null, "container_output_files": ["initramfs.cpio"], "build_command": "set -Eeuo pipefail; go build; GOARCH=amd64 ./u-root -defaultsh gosh -o initramfs.cpio boot coreboot-app ./cmds/core/* ./cmds/boot/*", "container_input_dir": "inputs/", "input_dirs": null, "input_files": null } } }
u-boot
Tip
u-boot - GitHub CI
build-uboot: needs: - changes - skip-check strategy: fail-fast: false matrix: uboot-version: ['2025.01'] arch: ['amd64', 'arm64'] runs-on: ${{ matrix.arch == 'arm64' && 'ARM64' || 'ubuntu-latest' }} if: ${{ ! (github.event_name == 'pull_request_review' && github.actor != 'github-actions[bot]') && needs.skip-check.outputs.changes == 'true' }} # Skip if pull_request_review on PR not made by a bot steps: - name: Cleanup run: | rm -rf ./* || true rm -rf ./.??* || true - name: Checkout uses: actions/checkout@v7 - name: Restore cached u-boot repo uses: actions/cache/restore@v6 id: cache-repo with: path: ./u-boot key: u-boot-${{ matrix.uboot-version }}-example - name: Clone u-boot repo if: steps.cache-repo.outputs.cache-hit != 'true' run: | git clone https://source.denx.de/u-boot/u-boot.git cd u-boot git fetch -a git checkout "v${{ matrix.uboot-version }}" - name: Store u-boot repo in cache uses: actions/cache/save@v6 if: steps.cache-repo.outputs.cache-hit != 'true' with: path: ./u-boot key: u-boot-${{ matrix.uboot-version }}-example - name: Move my defconfig into place (filename must not contain '.defconfig') run: | mv "tests/uboot_${{ matrix.uboot-version }}/uboot.defconfig" "uboot_defconfig" - name: firmware-action uses: ./ # uses: 9elements/firmware-action with: config: 'tests/example_config__uboot.json' target: 'u-boot-example' recursive: 'false' compile: ${{ needs.changes.outputs.compile }} debug: 'true' enable-cache: 'true' auto-download-artifacts: 'true' auto-upload-artifacts: 'true' env: UBOOT_VERSION: ${{ matrix.uboot-version }}
Tip
u-boot - Configuration file
{ "u-boot": { "u-boot-example": { "depends": null, "sdk_url": "ghcr.io/9elements/firmware-action/uboot_${UBOOT_VERSION}:main", "arch": "arm64", "repo_path": "u-boot/", "defconfig_path": "uboot_defconfig", "output_dir": "output-uboot/", "container_output_dirs": null, "container_output_files": ["u-boot", "u-boot.cfg", "u-boot.elf"], "container_input_dir": "inputs/", "input_dirs": null, "input_files": null } } }
Universal
Tip
Universal - GitHub CI
build-universal: needs: - changes - skip-check runs-on: ubuntu-latest if: ${{ ! (github.event_name == 'pull_request_review' && github.actor != 'github-actions[bot]') && needs.skip-check.outputs.changes == 'true' }} # Skip if pull_request_review on PR not made by a bot steps: - name: Cleanup run: | rm -rf ./* || true rm -rf ./.??* || true - name: Checkout uses: actions/checkout@v7 - name: firmware-action uses: ./ # uses: 9elements/firmware-action with: config: 'tests/example_config__universal.json' target: 'universal-example' recursive: 'false' compile: ${{ needs.changes.outputs.compile }} - name: Get artifacts uses: actions/upload-artifact@v7 with: name: universal path: output-universal retention-days: 14
Tip
Universal - Configuration file
{ "universal": { "universal-example": { "depends": null, "sdk_url": "golang:latest", "repo_path": "./", "container_output_dirs": null, "container_output_files": ["test.txt"], "output_dir": "output-universal/", "input_dirs": null, "input_files": null, "container_input_dir": "inputs/", "build_commands": ["echo 'hello world'", "touch test.txt"] } } }