From f8b2ffcc4a0b46207d055e09f442233b347aa2db Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Tue, 2 Jun 2026 20:57:59 +0300 Subject: [PATCH 01/21] payloads/external/Makefile.mk: remove duplicated options "payloads/external/edk2: configure capsule updates" should have been dropped when rebasing onto 2024.12, it introduces the duplicates. Change-Id: Ia9950f38eec002e979e491d648f1520fbdb39e74 Upstream-Status: Inappropriate [Dasharo downstream] Signed-off-by: Sergii Dmytruk --- payloads/external/Makefile.mk | 2 -- 1 file changed, 2 deletions(-) diff --git a/payloads/external/Makefile.mk b/payloads/external/Makefile.mk index 90cb652a267..bb6cad6c274 100644 --- a/payloads/external/Makefile.mk +++ b/payloads/external/Makefile.mk @@ -284,8 +284,6 @@ $(obj)/UEFIPAYLOAD.fd: $(DOTCONFIG) $(IPXE_EFI) CONFIG_CPU_MAX_TEMPERATURE=$(CONFIG_CPU_MAX_TEMPERATURE) \ CONFIG_EDK2_USE_LAPTOP_LID_LIB=$(CONFIG_EDK2_USE_LAPTOP_LID_LIB) \ CONFIG_EDK2_USE_UEFIVAR_BACKED_TPM_PPI=$(CONFIG_EDK2_USE_UEFIVAR_BACKED_TPM_PPI) \ - CONFIG_DRIVERS_EFI_UPDATE_CAPSULES=$(CONFIG_DRIVERS_EFI_UPDATE_CAPSULES) \ - CONFIG_DRIVERS_EFI_MAIN_FW_GUID=$(CONFIG_DRIVERS_EFI_MAIN_FW_GUID) \ CONFIG_EDK2_ENABLE_FAST_BOOT_FEATURE=$(CONFIG_EDK2_ENABLE_FAST_BOOT_FEATURE) \ CONFIG_EDK2_ENABLE_QUIET_BOOT_FEATURE=$(CONFIG_EDK2_ENABLE_QUIET_BOOT_FEATURE) \ CONFIG_EDK2_USB_PORT_POWER_OPTION=$(CONFIG_EDK2_USB_PORT_POWER_OPTION) \ From 7a3ccc90daf4ecadf5b683441169e49a3a634e5c Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Tue, 2 Jun 2026 21:06:09 +0300 Subject: [PATCH 02/21] drivers/efi,ec/dasharo,payloads/edk: introduce CONFIG_DRIVERS_EFI_EC_FW_* CONFIG_DRIVERS_EFI_EC_FW_GUID is a counterpart of CONFIG_DRIVERS_EFI_MAIN_FW_GUID but for EC. When empty (the default), implies absence of EC or a method of updates other than a dedicated capsule. The option's value is passed to EDK as CAPSULE_EC_FW_GUID macro. Requires EC_DASHARO_EC to be able to query EC's version. CONFIG_EC_DASHARO_EC_UPDATE now depends on CONFIG_DRIVERS_EFI_MAIN_FW_GUID being empty to avoid performing updates in two different ways. CONFIG_DRIVERS_EFI_EC_FW_LSV and CONFIG_DRIVERS_EFI_EC_FW_SIZE were added mostly for completeness to match the information that's published for the main firmware. They are exposed by coreboot as is and don't need to be filled. However, CONFIG_DRIVERS_EFI_EC_FW_SIZE may be useful to check that coreboot and EDK are in agreement about EC. Upstream-Status: Inappropriate [Dasharo downstream] Change-Id: Ia6054440af41069e797675a027fe7548fcb097e8 Signed-off-by: Sergii Dmytruk --- payloads/external/Makefile.mk | 3 ++- payloads/external/edk2/Makefile | 1 + src/drivers/efi/Kconfig | 31 +++++++++++++++++++++++++++++++ src/ec/dasharo/ec/Kconfig | 1 + 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/payloads/external/Makefile.mk b/payloads/external/Makefile.mk index bb6cad6c274..3d65e57ba7f 100644 --- a/payloads/external/Makefile.mk +++ b/payloads/external/Makefile.mk @@ -308,7 +308,8 @@ $(obj)/UEFIPAYLOAD.fd: $(DOTCONFIG) $(IPXE_EFI) CONFIG_VGA_BIOS_FILE=$(CONFIG_VGA_BIOS_FILE) \ CONFIG_BOOTSPLASH_REGION_LOGO_FILE=$(CONFIG_BOOTSPLASH_REGION_LOGO_FILE) \ CONFIG_EDK2_AP_INIT_TIMEOUT=$(call int-multiply, $(CONFIG_MAX_CPUS) 100000) \ - CONFIG_EDK2_MAX_CPUS=$(CONFIG_MAX_CPUS) + CONFIG_EDK2_MAX_CPUS=$(CONFIG_MAX_CPUS) \ + CONFIG_DRIVERS_EFI_EC_FW_GUID=$(CONFIG_DRIVERS_EFI_EC_FW_GUID) $(obj)/ShimmedUniversalPayload.elf: $(DOTCONFIG) $(MAKE) -C payloads/external/edk2 UniversalPayload \ diff --git a/payloads/external/edk2/Makefile b/payloads/external/edk2/Makefile index d224875f2ec..3abd74fd69a 100644 --- a/payloads/external/edk2/Makefile +++ b/payloads/external/edk2/Makefile @@ -127,6 +127,7 @@ endif ifeq ($(CONFIG_DRIVERS_EFI_UPDATE_CAPSULES),y) BUILD_STR += -D CAPSULE_SUPPORT=TRUE BUILD_STR += -D CAPSULE_MAIN_FW_GUID=$(CONFIG_DRIVERS_EFI_MAIN_FW_GUID) +BUILD_STR += -D CAPSULE_EC_FW_GUID=$(CONFIG_DRIVERS_EFI_EC_FW_GUID) ifeq ($(CONFIG_EDK2_CAPSULE_DOES_NOT_SURVIVE_RESET),y) BUILD_STR += --pcd gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset=FALSE BUILD_STR += --pcd gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleOnDiskSupport=TRUE diff --git a/src/drivers/efi/Kconfig b/src/drivers/efi/Kconfig index 4f86be35d3e..348acf6bf49 100644 --- a/src/drivers/efi/Kconfig +++ b/src/drivers/efi/Kconfig @@ -39,6 +39,37 @@ config DRIVERS_EFI_MAIN_FW_LSV that is allowed to replace the current one. Can be used to forbid bugged versions. +config DRIVERS_EFI_EC_FW_GUID + string "GUID of the EC firmware" + default "" + # version of an EC can't be hard-coded, hence must depend on a way to query it + depends on DRIVERS_EFI_FW_INFO && EC_DASHARO_EC + help + GUID used to identify EC firmware kind for the purposes of updates. + An empty value implies there is no EC or it's not updated via a dedicated + capsule. + +config DRIVERS_EFI_EC_FW_LSV + hex "Lowest supported EC firmware version" + range 0x00000000 0xFFFFFFFF + default 0x00000000 + depends on DRIVERS_EFI_EC_FW_GUID != "" + help + 32-bit unsigned integer representing lowest EC firmware version number + that is allowed to replace the current one. Can be used to forbid + bugged versions. + +config DRIVERS_EFI_EC_FW_SIZE + hex "Size of the EC firmware" + # the upper limit is chosen at random merely to exclude obviously wrong values, + # the lower limit and default value are zero because nothing in coreboot depends on + # knowing the size + range 0x00000000 0x00100000 + default 0x00000000 + depends on DRIVERS_EFI_EC_FW_GUID != "" + help + Size of EC firmware image in bytes. + config DRIVERS_EFI_UPDATE_CAPSULES bool "Include EFI update capsules driver" depends on DRIVERS_EFI_VARIABLE_STORE && SMMSTORE_V2 && DRIVERS_EFI_FW_INFO diff --git a/src/ec/dasharo/ec/Kconfig b/src/ec/dasharo/ec/Kconfig index 0cd44db30fc..03026b359ea 100644 --- a/src/ec/dasharo/ec/Kconfig +++ b/src/ec/dasharo/ec/Kconfig @@ -19,6 +19,7 @@ config EC_DASHARO_EC_DGPU config EC_DASHARO_EC_UPDATE bool "Update the embedded controller firmware" default n + depends on DRIVERS_EFI_EC_FW_GUID = "" config EC_DASHARO_EC_UPDATE_FILE depends on EC_DASHARO_EC_UPDATE From e886fa5fafadb3be1d8cc2bc32818b9f784d15a1 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Wed, 3 Jun 2026 16:38:32 +0300 Subject: [PATCH 03/21] drivers/efi,coreboot_tables.h: publish Dasharo EC information The version is queried from EC and date there is parsed into a 32-bit integer version (so two releases on the same day look identical). GUID, LSV and size come from Kconfig options. Upstream-Status: Inappropriate [Dasharo downstream] Change-Id: Icfa91b9d95b6a4d289a060fa4647b6e3c73a5e11 Signed-off-by: Sergii Dmytruk --- .../include/commonlib/coreboot_tables.h | 1 + src/drivers/efi/info.c | 116 +++++++++++++++++- src/include/boot/coreboot_tables.h | 2 +- 3 files changed, 117 insertions(+), 2 deletions(-) diff --git a/src/commonlib/include/commonlib/coreboot_tables.h b/src/commonlib/include/commonlib/coreboot_tables.h index 102748a512d..441274dacbf 100644 --- a/src/commonlib/include/commonlib/coreboot_tables.h +++ b/src/commonlib/include/commonlib/coreboot_tables.h @@ -93,6 +93,7 @@ enum { LB_TAG_ROOT_BRIDGE_INFO = 0x0048, LB_TAG_LOGO = 0x00a0, LB_TAG_BOOT_INFO = 0x00a1, + LB_TAG_EFI_EC_FW_INFO = 0x00a2, /* The following options are CMOS-related */ LB_TAG_CMOS_OPTION_TABLE = 0x00c8, LB_TAG_OPTION = 0x00c9, diff --git a/src/drivers/efi/info.c b/src/drivers/efi/info.c index fc1cfea573b..647066fd100 100644 --- a/src/drivers/efi/info.c +++ b/src/drivers/efi/info.c @@ -1,12 +1,15 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include +#include #include +#include +#include #include #include #include -void lb_efi_fw_info(struct lb_header *header) +static void add_main_fw_info(struct lb_header *header) { uint8_t guid[16]; struct lb_efi_fw_info *fw_info; @@ -26,3 +29,114 @@ void lb_efi_fw_info(struct lb_header *header) fw_info->lowest_supported_version = CONFIG_DRIVERS_EFI_MAIN_FW_LSV; fw_info->fw_size = CONFIG_ROM_SIZE; } + +static enum cb_err parse_int(const char **str, int *value) +{ + const char *s = *str; + + if (!isdigit(*s)) { + printk(BIOS_WARNING, "%s(): not a digit: '%c'\n", __func__, *s); + return CB_ERR; + } + + *value = 0; + while (isdigit(*s)) { + *value *= 10; + *value += *s++ - '0'; + } + + *str = s; + return CB_SUCCESS; +} + +static enum cb_err parse_char(const char **str, char ch) +{ + if (**str != ch) { + printk(BIOS_WARNING, "%s(): not a '%c': '%c'\n", __func__, ch, **str); + return CB_ERR; + } + + ++*str; + return CB_SUCCESS; +} + +static enum cb_err parse_ec_version(const char *str, uint32_t *version) +{ + /* + * Expected string version format: {year}-{month}-{day}_{git commit hash prefix} + * + * Year, month and day are expected to be in decimal. In practice they + * take up 4, 2 and 2 characters respectively and each field is padded + * with zeroes on the left but parsing doesn't depend on that and + * allows weird values. Commit hash is ignored, merely checking for + * `_` separator. + * + * Returned integer version: (year << 16) | (month << 8) | day + */ + + int year = 0; + int month = 0; + int day = 0; + if (parse_int(&str, &year) != CB_SUCCESS || parse_char(&str, '-') != CB_SUCCESS || + parse_int(&str, &month) != CB_SUCCESS || parse_char(&str, '-') != CB_SUCCESS || + parse_int(&str, &day) != CB_SUCCESS || parse_char(&str, '_') != CB_SUCCESS) + return CB_ERR; + + *version = ((year & 0xffff) << 16) | ((month & 0xff) << 8) | (day & 0xff); + return CB_SUCCESS; +} + +static void add_ec_fw_info(struct lb_header *header) +{ + uint8_t guid[16]; + uint32_t ec_version; + char ec_version_str[256]; + struct lb_efi_fw_info *fw_info; + + const char *guid_str; + uint32_t lsv; + uint32_t fw_size; + + /* CONFIG_DRIVERS_EFI_EC_* options may be absent, so some preprocessor is necessary, but + * keeping it to a minimum */ +#ifdef CONFIG_DRIVERS_EFI_EC_FW_GUID + guid_str = CONFIG_DRIVERS_EFI_EC_FW_GUID; + lsv = CONFIG_DRIVERS_EFI_EC_FW_LSV; + fw_size = CONFIG_DRIVERS_EFI_EC_FW_SIZE; +#else + /* No EC or its updates aren't done using capsules. */ + return; +#endif + + if (parse_uuid(guid, guid_str)) { + printk(BIOS_WARNING, "%s(): failed to parse EC firmware's GUID: '%s'\n", + __func__, guid_str); + return; + } + + if (dasharo_ec_read_version((uint8_t *)ec_version_str) != 0) { + printk(BIOS_WARNING, "%s(): failed to query EC firmware's version\n", __func__); + return; + } + + if (parse_ec_version(ec_version_str, &ec_version) != CB_SUCCESS) { + printk(BIOS_WARNING, "%s(): failed to parse EC firmware's version: '%s'\n", + __func__, ec_version_str); + return; + } + + fw_info = (struct lb_efi_fw_info *)lb_new_record(header); + fw_info->tag = LB_TAG_EFI_EC_FW_INFO; + fw_info->size = sizeof(*fw_info); + + memcpy(fw_info->guid, guid, sizeof(guid)); + fw_info->version = ec_version; + fw_info->lowest_supported_version = lsv; + fw_info->fw_size = fw_size; +} + +void lb_efi_fw_info(struct lb_header *header) +{ + add_main_fw_info(header); + add_ec_fw_info(header); +} diff --git a/src/include/boot/coreboot_tables.h b/src/include/boot/coreboot_tables.h index be737b0bb92..8c017eb8f98 100644 --- a/src/include/boot/coreboot_tables.h +++ b/src/include/boot/coreboot_tables.h @@ -27,7 +27,7 @@ enum cb_err fill_lb_pcie(struct lb_pcie *pcie); /* Define this in mainboard.c to add board-specific table entries. */ void lb_board(struct lb_header *header); -/* Adds LB_TAG_EFI_FW_INFO table entry. */ +/* Adds LB_TAG_EFI_FW_INFO and LB_TAG_EFI_EC_FW_INFO table entries. */ void lb_efi_fw_info(struct lb_header *header); /* Adds LB_TAG_CAPSULE table entries. */ From 5509a28ca5158f73247a53b77bfab58bc7ffd673 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Wed, 3 Jun 2026 16:41:31 +0300 Subject: [PATCH 04/21] payloads/edk2/Kconfig.dasharo: bump EDK for EC capsules Upstream-Status: Inappropriate [Dasharo downstream] Change-Id: I92de68aa4714c849e5da7cc51a4359dafcfb368a Signed-off-by: Sergii Dmytruk --- payloads/external/edk2/Kconfig.dasharo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/payloads/external/edk2/Kconfig.dasharo b/payloads/external/edk2/Kconfig.dasharo index 8f99cfd9627..30639855aea 100644 --- a/payloads/external/edk2/Kconfig.dasharo +++ b/payloads/external/edk2/Kconfig.dasharo @@ -4,7 +4,7 @@ config EDK2_REPOSITORY default "https://github.com/Dasharo/edk2" config EDK2_TAG_OR_REV - default "61ce35c29bb384240028d4319755b5759affbbe1" + default "00a34ad6795e6638462c2787254d689c15992a6b" config EDK2_SYSTEM76_EC_LOGGING bool "Enable edk2 logging to System76 EC" From 6c3afd6e4bdd19a19e8aa9eba30ae3a408efe095 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Tue, 9 Jun 2026 00:30:51 +0300 Subject: [PATCH 05/21] capsule.sh: extract $v2_capsule in make_subcommand() Upstream-Status: Inappropriate [Dasharo downstream] Change-Id: Ibeaecdae26b9504b90837ff075a0ace6ee0ec3d3 Signed-off-by: Sergii Dmytruk --- capsule.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/capsule.sh b/capsule.sh index 9fe2de18ab4..314bd13f816 100755 --- a/capsule.sh +++ b/capsule.sh @@ -290,6 +290,11 @@ function make_subcommand() { build_type=DEBUG fi + local v2_capsule=no + if [ "${CONFIG_EDK2_CAPSULES_V2:-n}${CONFIG_EDK2_CAPSULES_V2_TRANSITION:-n}" = yn ]; then + v2_capsule=yes + fi + local json_file json_file=$(mktemp --tmpdir --suffix -cap.json XXXXXXXX) trap "$(printf 'rm -f -- %q %q' "$json_file" "$cap_file.inner")" EXIT @@ -311,7 +316,7 @@ EOF local opt_root_cert=$root_cert local opt_sub_cert=$sub_cert local opt_sign_cert=$sign_cert - if [ "${CONFIG_EDK2_CAPSULES_V2:-n}${CONFIG_EDK2_CAPSULES_V2_TRANSITION:-n}" = yn ]; then + if [ "$v2_capsule" = yes ]; then # The inner capsule is always signed with the test key. Not signing it # at all doesn't work because FmpDxe doesn't accept unsigned payloads at # least due to Image->AuthInfo.Hdr.wRevision check in @@ -344,7 +349,7 @@ EOF } EOF - if [ "${CONFIG_EDK2_CAPSULES_V2:-n}${CONFIG_EDK2_CAPSULES_V2_TRANSITION:-n}" = yn ]; then + if [ "$v2_capsule" = yes ]; then # The capsule created above is the inner capsule. Make it and then # update JSON file to point at it as a payload. if ! "$generate_capsule" --encode \ From 1bdf80945a81d6c99cb293c51cf040dbc91101dc Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Tue, 9 Jun 2026 00:58:14 +0300 Subject: [PATCH 06/21] capsule.sh: clean up handling of drivers by make subcommand Use an array of drivers and avoid writing JSON file in chunks. Change-Id: If9f897460e661f3d6dcf2ca127a37702444118b2 Upstream-Status: Inappropriate [Dasharo downstream] Signed-off-by: Sergii Dmytruk --- capsule.sh | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/capsule.sh b/capsule.sh index 314bd13f816..46746353b52 100755 --- a/capsule.sh +++ b/capsule.sh @@ -299,19 +299,17 @@ function make_subcommand() { json_file=$(mktemp --tmpdir --suffix -cap.json XXXXXXXX) trap "$(printf 'rm -f -- %q %q' "$json_file" "$cap_file.inner")" EXIT - cat > "$json_file" << EOF -{ - "EmbeddedDrivers": [ -EOF + local build_dir=${edk_workspace}/Build/DasharoPayloadPkgX64/${build_type}_GCC/X64 # Ensure the charger check driver module is first + local drivers=() if [ "$include_battery_check" = 1 ]; then - cat >> "$json_file" << EOF - { - "Driver": "${edk_workspace}/Build/DasharoPayloadPkgX64/${build_type}_GCC/X64/CapsuleChargerCheckDxe.efi" - }, -EOF + drivers+=( "${build_dir}/CapsuleChargerCheckDxe.efi" ) fi + drivers+=( + "${build_dir}/CapsuleSplashDxe.efi" + "${build_dir}/FmpDxe.efi" + ) local opt_root_cert=$root_cert local opt_sub_cert=$sub_cert @@ -326,13 +324,10 @@ EOF opt_sign_cert=${edk_basetools}/Source/Python/Pkcs7Sign/TestCert.pem fi - cat >> "$json_file" << EOF - { - "Driver": "${edk_workspace}/Build/DasharoPayloadPkgX64/${build_type}_GCC/X64/CapsuleSplashDxe.efi" - }, - { - "Driver": "${edk_workspace}/Build/DasharoPayloadPkgX64/${build_type}_GCC/X64/FmpDxe.efi" - } + cat > "$json_file" << EOF +{ + "EmbeddedDrivers": [ +$(printf ' { "Driver": "%s" },\n' "${drivers[@]}" | sed '$s/,$//') ], "Payloads": [ { From 4960119740ff89ea75395a57ce734fc71fdf012a Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Tue, 9 Jun 2026 01:14:01 +0300 Subject: [PATCH 07/21] capsule.sh: extract build_capsule() out of make_subcommand() Pass all capsule-specific information in parameters. Change-Id: I6ec636c236e4074ba0115b4867be3c247717edfc Upstream-Status: Inappropriate [Dasharo downstream] Signed-off-by: Sergii Dmytruk --- capsule.sh | 173 +++++++++++++++++++++++++++++------------------------ 1 file changed, 95 insertions(+), 78 deletions(-) diff --git a/capsule.sh b/capsule.sh index 46746353b52..773697f239b 100755 --- a/capsule.sh +++ b/capsule.sh @@ -229,65 +229,19 @@ function check_generate_capsule() { fi } -function make_subcommand() { - if [ ! -f .config ]; then - die "no '.config' file in current directory" - fi - if [ ! -f build/coreboot.rom ]; then - die "no 'build/coreboot.rom'; the firmware wasn't built?" - fi - if [ ! build/coreboot.rom -nt .config ]; then - die "'build/coreboot.rom' is not newer than .config'; need a re-build?" - fi - - check_generate_capsule - - source_coreboot_config - require_capsule_support - - # Option names match terminology of GenerateCapsule which conveniently start - # with different letters: - # * t - trusted - # * o - other - # * s - signer - - local root_cert sub_cert sign_cert include_battery_check - while getopts "t:o:s:b" OPTION; do - case $OPTION in - t) root_cert="$OPTARG" ;; - o) sub_cert="$OPTARG" ;; - s) sign_cert="$OPTARG" ;; - b) include_battery_check=1 ;; - *) exit 1 ;; - esac - done - - check_cert root "$root_cert" - check_cert sub "$sub_cert" - check_cert sign "$sign_cert" +# This function assumes .config has been sourced. +function build_capsule() { + local payload=$1 + local guid=$2 + local version=$3 + local lsv=$4 + local -n drivers=$5 + local cap_file=$6 - local cap_file=${CONFIG_MAINBOARD_DIR//[\/-]/_} - if [[ ${CONFIG_MAINBOARD_PART_NUMBER} =~ DDR4 ]]; then - cap_file+=_ddr4 - fi - cap_file+=_${CONFIG_LOCALVERSION} - cap_file+=.cap - - local cap_flags="--capflag PersistAcrossReset" + local cap_flags=( --capflag PersistAcrossReset ) # Capsules on AMD boards do not survive resets - if [ "$CONFIG_EDK2_CAPSULE_DOES_NOT_SURVIVE_RESET" == y ]; then - cap_flags="" - fi - - if [ -e "$cap_file" ]; then - confirm "Overwrite already existing '$cap_file'?" - fi - - local build_type - if [ "$CONFIG_EDK2_RELEASE" = y ]; then - build_type=RELEASE - else - build_type=DEBUG + if [ "$CONFIG_EDK2_CAPSULE_DOES_NOT_SURVIVE_RESET" = y ]; then + cap_flags=() fi local v2_capsule=no @@ -299,18 +253,6 @@ function make_subcommand() { json_file=$(mktemp --tmpdir --suffix -cap.json XXXXXXXX) trap "$(printf 'rm -f -- %q %q' "$json_file" "$cap_file.inner")" EXIT - local build_dir=${edk_workspace}/Build/DasharoPayloadPkgX64/${build_type}_GCC/X64 - - # Ensure the charger check driver module is first - local drivers=() - if [ "$include_battery_check" = 1 ]; then - drivers+=( "${build_dir}/CapsuleChargerCheckDxe.efi" ) - fi - drivers+=( - "${build_dir}/CapsuleSplashDxe.efi" - "${build_dir}/FmpDxe.efi" - ) - local opt_root_cert=$root_cert local opt_sub_cert=$sub_cert local opt_sign_cert=$sign_cert @@ -331,10 +273,10 @@ $(printf ' { "Driver": "%s" },\n' "${drivers[@]}" | sed '$s/,$//') ], "Payloads": [ { - "Payload": "build/coreboot.rom", - "Guid": "${CONFIG_DRIVERS_EFI_MAIN_FW_GUID}", - "FwVersion": "${CONFIG_DRIVERS_EFI_MAIN_FW_VERSION}", - "LowestSupportedVersion": "${CONFIG_DRIVERS_EFI_MAIN_FW_LSV}", + "Payload": "${payload}", + "Guid": "${guid}", + "FwVersion": "${version}", + "LowestSupportedVersion": "${lsv}", "OpenSslSignerPrivateCertFile": "${opt_sign_cert}", "OpenSslOtherPublicCertFile": "${opt_sub_cert}", @@ -348,7 +290,7 @@ EOF # The capsule created above is the inner capsule. Make it and then # update JSON file to point at it as a payload. if ! "$generate_capsule" --encode \ - $cap_flags \ + "${cap_flags[@]}" \ --json-file "$json_file" \ --output "$cap_file.inner"; then die "GenerateCapsule failed" @@ -360,9 +302,9 @@ EOF "Payloads": [ { "Payload": "$cap_file.inner", - "Guid": "${CONFIG_DRIVERS_EFI_MAIN_FW_GUID}", - "FwVersion": "${CONFIG_DRIVERS_EFI_MAIN_FW_VERSION}", - "LowestSupportedVersion": "${CONFIG_DRIVERS_EFI_MAIN_FW_LSV}", + "Guid": "${guid}", + "FwVersion": "${version}", + "LowestSupportedVersion": "${lsv}", "OpenSslSignerPrivateCertFile": "${sign_cert}", "OpenSslOtherPublicCertFile": "${sub_cert}", @@ -376,11 +318,86 @@ EOF # Linux doesn't support InitiateReset flag, omitting it to rely on manual # warm reset if ! "$generate_capsule" --encode \ - $cap_flags \ + "${cap_flags[@]}" \ --json-file "$json_file" \ --output "$cap_file"; then die "GenerateCapsule failed" fi +} + +function make_subcommand() { + if [ ! -f .config ]; then + die "no '.config' file in current directory" + fi + if [ ! -f build/coreboot.rom ]; then + die "no 'build/coreboot.rom'; the firmware wasn't built?" + fi + if [ ! build/coreboot.rom -nt .config ]; then + die "'build/coreboot.rom' is not newer than .config'; need a re-build?" + fi + + check_generate_capsule + + source_coreboot_config + require_capsule_support + + # Option names match terminology of GenerateCapsule which conveniently start + # with different letters: + # * t - trusted + # * o - other + # * s - signer + + local root_cert sub_cert sign_cert include_battery_check + while getopts "t:o:s:b" OPTION; do + case $OPTION in + t) root_cert="$OPTARG" ;; + o) sub_cert="$OPTARG" ;; + s) sign_cert="$OPTARG" ;; + b) include_battery_check=1 ;; + *) exit 1 ;; + esac + done + + check_cert root "$root_cert" + check_cert sub "$sub_cert" + check_cert sign "$sign_cert" + + local cap_file=${CONFIG_MAINBOARD_DIR//[\/-]/_} + if [[ ${CONFIG_MAINBOARD_PART_NUMBER} =~ DDR4 ]]; then + cap_file+=_ddr4 + fi + cap_file+=_${CONFIG_LOCALVERSION} + cap_file+=.cap + + if [ -e "$cap_file" ]; then + confirm "Overwrite already existing '$cap_file'?" + fi + + local build_type + if [ "$CONFIG_EDK2_RELEASE" = y ]; then + build_type=RELEASE + else + build_type=DEBUG + fi + + local build_dir=${edk_workspace}/Build/DasharoPayloadPkgX64/${build_type}_GCC/X64 + + # Ensure the charger check driver module is first + local embedded_drivers=() + if [ "$include_battery_check" = 1 ]; then + embedded_drivers+=( "${build_dir}/CapsuleChargerCheckDxe.efi" ) + fi + embedded_drivers+=( + "${build_dir}/CapsuleSplashDxe.efi" + "${build_dir}/FmpDxe.efi" + ) + + build_capsule 'build/coreboot.rom' \ + "$CONFIG_DRIVERS_EFI_MAIN_FW_GUID" \ + "$CONFIG_DRIVERS_EFI_MAIN_FW_VERSION" \ + "$CONFIG_DRIVERS_EFI_MAIN_FW_LSV" \ + embedded_drivers \ + "$cap_file" echo "Created the capsule at '$cap_file'" } From 900fa8554242c5ae4939a72c0d9b6aeecd294622 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Tue, 9 Jun 2026 01:27:09 +0300 Subject: [PATCH 08/21] capsule.sh: pass certs to build_capsule() as well Change-Id: Ic7bdc0a2b84780ca8f76d6727b92126609dfd3d2 Upstream-Status: Inappropriate [Dasharo downstream] Signed-off-by: Sergii Dmytruk --- capsule.sh | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/capsule.sh b/capsule.sh index 773697f239b..3b55949cd32 100755 --- a/capsule.sh +++ b/capsule.sh @@ -236,7 +236,8 @@ function build_capsule() { local version=$3 local lsv=$4 local -n drivers=$5 - local cap_file=$6 + local -n certs=$6 + local cap_file=$7 local cap_flags=( --capflag PersistAcrossReset ) # Capsules on AMD boards do not survive resets @@ -253,9 +254,9 @@ function build_capsule() { json_file=$(mktemp --tmpdir --suffix -cap.json XXXXXXXX) trap "$(printf 'rm -f -- %q %q' "$json_file" "$cap_file.inner")" EXIT - local opt_root_cert=$root_cert - local opt_sub_cert=$sub_cert - local opt_sign_cert=$sign_cert + local opt_root_cert=${certs[root]} + local opt_sub_cert=${certs[sub]} + local opt_sign_cert=${certs[sign]} if [ "$v2_capsule" = yes ]; then # The inner capsule is always signed with the test key. Not signing it # at all doesn't work because FmpDxe doesn't accept unsigned payloads at @@ -296,6 +297,7 @@ EOF die "GenerateCapsule failed" fi + # The outer capsule is signed with the key passed by the user. cat > "$json_file" << EOF { "EmbeddedDrivers": [], @@ -306,9 +308,9 @@ EOF "FwVersion": "${version}", "LowestSupportedVersion": "${lsv}", - "OpenSslSignerPrivateCertFile": "${sign_cert}", - "OpenSslOtherPublicCertFile": "${sub_cert}", - "OpenSslTrustedPublicCertFile": "${root_cert}" + "OpenSslSignerPrivateCertFile": "${certs[sign]}", + "OpenSslOtherPublicCertFile": "${certs[sub]}", + "OpenSslTrustedPublicCertFile": "${certs[root]}" } ] } @@ -347,20 +349,21 @@ function make_subcommand() { # * o - other # * s - signer - local root_cert sub_cert sign_cert include_battery_check + local -A cap_certs + local include_battery_check while getopts "t:o:s:b" OPTION; do case $OPTION in - t) root_cert="$OPTARG" ;; - o) sub_cert="$OPTARG" ;; - s) sign_cert="$OPTARG" ;; + t) cap_certs[root]="$OPTARG" ;; + o) cap_certs[sub]="$OPTARG" ;; + s) cap_certs[sign]="$OPTARG" ;; b) include_battery_check=1 ;; *) exit 1 ;; esac done - check_cert root "$root_cert" - check_cert sub "$sub_cert" - check_cert sign "$sign_cert" + check_cert root "${cap_certs[root]}" + check_cert sub "${cap_certs[sub]}" + check_cert sign "${cap_certs[sign]}" local cap_file=${CONFIG_MAINBOARD_DIR//[\/-]/_} if [[ ${CONFIG_MAINBOARD_PART_NUMBER} =~ DDR4 ]]; then @@ -397,6 +400,7 @@ function make_subcommand() { "$CONFIG_DRIVERS_EFI_MAIN_FW_VERSION" \ "$CONFIG_DRIVERS_EFI_MAIN_FW_LSV" \ embedded_drivers \ + cap_certs \ "$cap_file" echo "Created the capsule at '$cap_file'" From 2e33b6317e74708926ec0bb21ea517dc6e930576 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Tue, 9 Jun 2026 18:45:19 +0300 Subject: [PATCH 09/21] capsule.sh: add -e option to "make" for EC ROMs The option results in the use of EC-specific Kconfig options. It also takes path to the EC file as its argument. Version of the ROM is derived from a string that the file contains (`76EC_VERSION=...`). There is an additional ROM size check and "_ec" infix between version, but otherwise the behaviour is identical to main firmware capsules. The paths to DXE's that are firmware-specific are updated to include GUID as there can be multiple instances now. Change-Id: I4a7037fdd686d8f703f812d5733973c58df8e9c3 Upstream-Status: Inappropriate [Dasharo downstream] Signed-off-by: Sergii Dmytruk --- capsule.sh | 83 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 12 deletions(-) diff --git a/capsule.sh b/capsule.sh index 3b55949cd32..9a146f16749 100755 --- a/capsule.sh +++ b/capsule.sh @@ -50,6 +50,7 @@ function print_usage() { echo ' -o subroot-certificate-file' echo ' -s signing-certificate-file' echo ' -b (the flag adds battery check DXE into the capsule)' + echo ' [-e ec-rom-file] (make an EC firmware capsule)' echo ' resign resign an existing capsule with a different key' echo ' -t root-certificate-file' echo ' -o subroot-certificate-file' @@ -327,6 +328,28 @@ EOF fi } +# Prints version of an EC ROM derived from the file or dies. +# The implementation of version conversion must be kept in sync with +# parse_ec_version() in src/drivers/efi/info.c +function extract_ec_version() { + local ec_rom_file=$1 + + local ver + ver=$(strings "$ec_rom_file" | \ + sed -n '/^76EC_VERSION/s/.*=\([0-9]\{4\}\(-[0-9][0-9]\)\{2\}\).*/\1/p' | \ + head -1) + + if [ -z "$ver" ]; then + die "Failed to extract 76EC_VERSION from '$ec_rom_file'" + fi + + local y=${ver::4} + local m=${ver:5:2} + local d=${ver:8:2} + + echo $(( ((10#$y & 0xffff) << 16) | ((10#$m & 0xff) << 8) | (10#$d & 0xff) )) +} + function make_subcommand() { if [ ! -f .config ]; then die "no '.config' file in current directory" @@ -343,20 +366,21 @@ function make_subcommand() { source_coreboot_config require_capsule_support - # Option names match terminology of GenerateCapsule which conveniently start - # with different letters: + # Option names for key files match terminology of GenerateCapsule which, + # conveniently, has words starting with different letters: # * t - trusted # * o - other # * s - signer local -A cap_certs - local include_battery_check - while getopts "t:o:s:b" OPTION; do + local include_battery_check ec_rom_file + while getopts "t:o:s:be:" OPTION; do case $OPTION in t) cap_certs[root]="$OPTARG" ;; o) cap_certs[sub]="$OPTARG" ;; s) cap_certs[sign]="$OPTARG" ;; b) include_battery_check=1 ;; + e) ec_rom_file="$OPTARG" ;; *) exit 1 ;; esac done @@ -365,10 +389,46 @@ function make_subcommand() { check_cert sub "${cap_certs[sub]}" check_cert sign "${cap_certs[sign]}" + # Assuming a coreboot capsule at first. + local rom_file=build/coreboot.rom + local guid=$CONFIG_DRIVERS_EFI_MAIN_FW_GUID + local splash_guid=E1CBE3CC-3D32-44CF-8DB9-2A78BA16F2F6 + local version=$CONFIG_DRIVERS_EFI_MAIN_FW_VERSION + local lsv=$CONFIG_DRIVERS_EFI_MAIN_FW_LSV + + if [ -n "$ec_rom_file" ]; then + if [ -z "$CONFIG_DRIVERS_EFI_EC_FW_GUID" ]; then + die '-e is passed but CONFIG_DRIVERS_EFI_EC_FW_GUID is empty' + fi + + assert_file_exists "$ec_rom_file" + + local ec_rom_version + ec_rom_version=$(extract_ec_version "$ec_rom_file") + + local size + size=$(stat --printf %s "$ec_rom_file") + if [ "$size" -ne $(( $CONFIG_DRIVERS_EFI_EC_FW_SIZE )) ]; then + die "$(printf "'%s' is 0x%x bytes in size instead of 0x%x" \ + "$ec_rom_file" \ + "$size" \ + "$CONFIG_DRIVERS_EFI_EC_FW_SIZE")" + fi + + rom_file=$ec_rom_file + guid=$CONFIG_DRIVERS_EFI_EC_FW_GUID + splash_guid=8C675702-A60D-462C-B950-12F00FFDFFF3 + version=$ec_rom_version + lsv=$CONFIG_DRIVERS_EFI_EC_FW_LSV + fi + local cap_file=${CONFIG_MAINBOARD_DIR//[\/-]/_} if [[ ${CONFIG_MAINBOARD_PART_NUMBER} =~ DDR4 ]]; then cap_file+=_ddr4 fi + if [ -n "$ec_rom_file" ]; then + cap_file+=_ec + fi cap_file+=_${CONFIG_LOCALVERSION} cap_file+=.cap @@ -391,16 +451,15 @@ function make_subcommand() { embedded_drivers+=( "${build_dir}/CapsuleChargerCheckDxe.efi" ) fi embedded_drivers+=( - "${build_dir}/CapsuleSplashDxe.efi" - "${build_dir}/FmpDxe.efi" + # Can't use the same GUID more than once and can't easily derive it + # either, so CapsuleSplashDxe has hard-coded GUIDs for main/EC firmware + # and one of them is selected above. + "${build_dir}/DasharoPayloadPkg/CapsuleSplashDxe/${splash_guid}/OUTPUT/CapsuleSplashDxe.efi" + "${build_dir}/FmpDevicePkg/FmpDxe/${guid}/OUTPUT/FmpDxe.efi" ) - build_capsule 'build/coreboot.rom' \ - "$CONFIG_DRIVERS_EFI_MAIN_FW_GUID" \ - "$CONFIG_DRIVERS_EFI_MAIN_FW_VERSION" \ - "$CONFIG_DRIVERS_EFI_MAIN_FW_LSV" \ - embedded_drivers \ - cap_certs \ + build_capsule "$rom_file" "$guid" "$version" "$lsv" \ + embedded_drivers cap_certs \ "$cap_file" echo "Created the capsule at '$cap_file'" From e13e27b5087470213837f7011aaf7163648f8c4d Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Tue, 9 Jun 2026 18:54:05 +0300 Subject: [PATCH 10/21] capsule.sh: improve help of make command's -b flag Mainly make it clear that the flag is optional. Change-Id: I88bb3c953c14f69ab6da7b99f80486ac22cb7a23 Upstream-Status: Inappropriate [Dasharo downstream] Signed-off-by: Sergii Dmytruk --- capsule.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/capsule.sh b/capsule.sh index 9a146f16749..7895b007c95 100755 --- a/capsule.sh +++ b/capsule.sh @@ -49,7 +49,7 @@ function print_usage() { echo ' -t root-certificate-file' echo ' -o subroot-certificate-file' echo ' -s signing-certificate-file' - echo ' -b (the flag adds battery check DXE into the capsule)' + echo ' [-b] (include battery check DXE in the capsule)' echo ' [-e ec-rom-file] (make an EC firmware capsule)' echo ' resign resign an existing capsule with a different key' echo ' -t root-certificate-file' From 70cbba96b52f485f3fb72fce718ace4abc16af16 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Tue, 9 Jun 2026 19:01:18 +0300 Subject: [PATCH 11/21] capsule.sh: add -y flag to make command It suppresses confirmation prompt when the destination file exists, making using `capsule.sh` from scripts easier. Change-Id: Ib9539126c9923a27d2c4f89c899e17a89cecd32e Upstream-Status: Inappropriate [Dasharo downstream] Signed-off-by: Sergii Dmytruk --- capsule.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/capsule.sh b/capsule.sh index 7895b007c95..e5c6fa61ae2 100755 --- a/capsule.sh +++ b/capsule.sh @@ -50,6 +50,7 @@ function print_usage() { echo ' -o subroot-certificate-file' echo ' -s signing-certificate-file' echo ' [-b] (include battery check DXE in the capsule)' + echo ' [-y] (overwrite destination without prompting)' echo ' [-e ec-rom-file] (make an EC firmware capsule)' echo ' resign resign an existing capsule with a different key' echo ' -t root-certificate-file' @@ -373,13 +374,14 @@ function make_subcommand() { # * s - signer local -A cap_certs - local include_battery_check ec_rom_file - while getopts "t:o:s:be:" OPTION; do + local include_battery_check overwrite_output ec_rom_file + while getopts "t:o:s:be:y" OPTION; do case $OPTION in t) cap_certs[root]="$OPTARG" ;; o) cap_certs[sub]="$OPTARG" ;; s) cap_certs[sign]="$OPTARG" ;; b) include_battery_check=1 ;; + y) overwrite_output=1 ;; e) ec_rom_file="$OPTARG" ;; *) exit 1 ;; esac @@ -432,7 +434,7 @@ function make_subcommand() { cap_file+=_${CONFIG_LOCALVERSION} cap_file+=.cap - if [ -e "$cap_file" ]; then + if [ "$overwrite_output" != 1 ] && [ -e "$cap_file" ]; then confirm "Overwrite already existing '$cap_file'?" fi From 3ab4d629e4cf478915a2f9c50470c2db3e231258 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Tue, 9 Jun 2026 19:06:52 +0300 Subject: [PATCH 12/21] capsule.sh: add -c flag to make command It makes using `capsule.sh` from scripts easier by not requiring them to find out name of the created file on their own. Change-Id: I35d26cab253f3c2b340b034b59c0c7d235dbc466 Upstream-Status: Inappropriate [Dasharo downstream] Signed-off-by: Sergii Dmytruk --- capsule.sh | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/capsule.sh b/capsule.sh index e5c6fa61ae2..43a2cf435c6 100755 --- a/capsule.sh +++ b/capsule.sh @@ -52,6 +52,7 @@ function print_usage() { echo ' [-b] (include battery check DXE in the capsule)' echo ' [-y] (overwrite destination without prompting)' echo ' [-e ec-rom-file] (make an EC firmware capsule)' + echo ' [-c cap-file] (destination file name, generated if omitted)' echo ' resign resign an existing capsule with a different key' echo ' -t root-certificate-file' echo ' -o subroot-certificate-file' @@ -374,8 +375,8 @@ function make_subcommand() { # * s - signer local -A cap_certs - local include_battery_check overwrite_output ec_rom_file - while getopts "t:o:s:be:y" OPTION; do + local include_battery_check overwrite_output ec_rom_file cap_file + while getopts "t:o:s:be:yc:" OPTION; do case $OPTION in t) cap_certs[root]="$OPTARG" ;; o) cap_certs[sub]="$OPTARG" ;; @@ -383,6 +384,7 @@ function make_subcommand() { b) include_battery_check=1 ;; y) overwrite_output=1 ;; e) ec_rom_file="$OPTARG" ;; + c) cap_file="$OPTARG" ;; *) exit 1 ;; esac done @@ -424,15 +426,17 @@ function make_subcommand() { lsv=$CONFIG_DRIVERS_EFI_EC_FW_LSV fi - local cap_file=${CONFIG_MAINBOARD_DIR//[\/-]/_} - if [[ ${CONFIG_MAINBOARD_PART_NUMBER} =~ DDR4 ]]; then - cap_file+=_ddr4 - fi - if [ -n "$ec_rom_file" ]; then - cap_file+=_ec + if [ -z "$cap_file" ]; then + cap_file=${CONFIG_MAINBOARD_DIR//[\/-]/_} + if [[ ${CONFIG_MAINBOARD_PART_NUMBER} =~ DDR4 ]]; then + cap_file+=_ddr4 + fi + if [ -n "$ec_rom_file" ]; then + cap_file+=_ec + fi + cap_file+=_${CONFIG_LOCALVERSION} + cap_file+=.cap fi - cap_file+=_${CONFIG_LOCALVERSION} - cap_file+=.cap if [ "$overwrite_output" != 1 ] && [ -e "$cap_file" ]; then confirm "Overwrite already existing '$cap_file'?" From 69d10c740835503eccb53684cb9ee0e9bd079703 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Mon, 15 Jun 2026 00:53:17 +0300 Subject: [PATCH 13/21] payloads/edk2: pass CONFIG_EC_DASHARO_EC_FLASH_SIZE in a PCD Size of a flash chip may be greater than the firmware image size. Change-Id: Ie37a7656d81c76f66c477033a2c423f2e141dc73 Upstream-Status: Inappropriate [Dasharo downstream] Signed-off-by: Sergii Dmytruk --- payloads/external/Makefile.mk | 3 ++- payloads/external/edk2/Makefile | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/payloads/external/Makefile.mk b/payloads/external/Makefile.mk index 3d65e57ba7f..eb865a8c627 100644 --- a/payloads/external/Makefile.mk +++ b/payloads/external/Makefile.mk @@ -309,7 +309,8 @@ $(obj)/UEFIPAYLOAD.fd: $(DOTCONFIG) $(IPXE_EFI) CONFIG_BOOTSPLASH_REGION_LOGO_FILE=$(CONFIG_BOOTSPLASH_REGION_LOGO_FILE) \ CONFIG_EDK2_AP_INIT_TIMEOUT=$(call int-multiply, $(CONFIG_MAX_CPUS) 100000) \ CONFIG_EDK2_MAX_CPUS=$(CONFIG_MAX_CPUS) \ - CONFIG_DRIVERS_EFI_EC_FW_GUID=$(CONFIG_DRIVERS_EFI_EC_FW_GUID) + CONFIG_DRIVERS_EFI_EC_FW_GUID=$(CONFIG_DRIVERS_EFI_EC_FW_GUID) \ + CONFIG_EC_DASHARO_EC_FLASH_SIZE=$(CONFIG_EC_DASHARO_EC_FLASH_SIZE) $(obj)/ShimmedUniversalPayload.elf: $(DOTCONFIG) $(MAKE) -C payloads/external/edk2 UniversalPayload \ diff --git a/payloads/external/edk2/Makefile b/payloads/external/edk2/Makefile index 3abd74fd69a..e937a47f9c6 100644 --- a/payloads/external/edk2/Makefile +++ b/payloads/external/edk2/Makefile @@ -128,6 +128,9 @@ ifeq ($(CONFIG_DRIVERS_EFI_UPDATE_CAPSULES),y) BUILD_STR += -D CAPSULE_SUPPORT=TRUE BUILD_STR += -D CAPSULE_MAIN_FW_GUID=$(CONFIG_DRIVERS_EFI_MAIN_FW_GUID) BUILD_STR += -D CAPSULE_EC_FW_GUID=$(CONFIG_DRIVERS_EFI_EC_FW_GUID) +ifneq ($(CONFIG_EC_DASHARO_EC_FLASH_SIZE),) +BUILD_STR += --pcd gDasharoPayloadPkgTokenSpaceGuid.PcdEcFlashSize=$(CONFIG_EC_DASHARO_EC_FLASH_SIZE) +endif ifeq ($(CONFIG_EDK2_CAPSULE_DOES_NOT_SURVIVE_RESET),y) BUILD_STR += --pcd gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset=FALSE BUILD_STR += --pcd gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleOnDiskSupport=TRUE From d0cb08d4500687fd0984e7922af087d4345d6a38 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Mon, 15 Jun 2026 00:59:55 +0300 Subject: [PATCH 14/21] ec/dasharo: fix return value of ec_spi_image_write() Make sure `addr` is returned on success. Previously, the code could return an positive error value. Change-Id: Ieb799ae737c0c0c07177c7315492bc6beb1b7f89 Upstream-Status: Pending Signed-off-by: Sergii Dmytruk --- src/ec/dasharo/ec/dasharo_ec.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ec/dasharo/ec/dasharo_ec.c b/src/ec/dasharo/ec/dasharo_ec.c index 3e9c7d1eb43..ca9be2ffc13 100644 --- a/src/ec/dasharo/ec/dasharo_ec.c +++ b/src/ec/dasharo/ec/dasharo_ec.c @@ -769,9 +769,16 @@ static int ec_spi_image_write(uint8_t *image, size_t size) erase_addr += SPI_SECTOR_SIZE; } + /* If we got here, it's a success. */ + rv = 0; + cleanup: free(sector); + /* Some functions return a positive value on error. */ + if (rv > 0) + rv = -rv; + return rv ? rv : addr; } From ae78a66a8ff15f995d7e126d94f5150cf4c95b63 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Mon, 15 Jun 2026 01:02:05 +0300 Subject: [PATCH 15/21] ec/dasharo: add missing sector erasure verification The handling of an incomplete last sector differed from the rest in not checking the erasure was successful. By the way, erasing the remainder of the chip at the very end also lacks verification, but maybe that was intentional. Change-Id: Id18cf668adcccaaf2f0053e7dd5aec8aa63374d6 Upstream-Status: Pending Signed-off-by: Sergii Dmytruk --- src/ec/dasharo/ec/dasharo_ec.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ec/dasharo/ec/dasharo_ec.c b/src/ec/dasharo/ec/dasharo_ec.c index ca9be2ffc13..3658687857c 100644 --- a/src/ec/dasharo/ec/dasharo_ec.c +++ b/src/ec/dasharo/ec/dasharo_ec.c @@ -736,6 +736,18 @@ static int ec_spi_image_write(uint8_t *image, size_t size) goto cleanup; } + rv = ec_spi_verify_erased_sector(addr); + if (rv) { + printk(BIOS_ERR, + "%s: ec_spi_verify_erased_sector failed, addr 0x%06x\n", + __func__, addr); + if (CONFIG(VBOOT)) + vboot_fail_and_reboot(vboot_get_context(), + VB2_RECOVERY_EC_SOFTWARE_SYNC, + EC_UPDATE_ERR_ERASE); + goto cleanup; + } + rv = ec_spi_write_at(addr, image, length); if (rv < 0) { printk(BIOS_ERR, "%s: ec_spi_write_at failed, addr 0x%06x (%d)\n", From f808b2d83e5f63728afd7ba3de8d2050b2c24863 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Mon, 15 Jun 2026 01:08:48 +0300 Subject: [PATCH 16/21] ec/dasharo: don't pass less than 2 bytes to CMD_SPI The command expects the length as the second byte and by default performs a bus write. So not writing anything to the corresponding port may result in an old value being treated as the number of bytes to write. Change-Id: Ie6cf89f2aaaf1035f8ca722791c189c8c2cd5f44 Upstream-Status: Pending Signed-off-by: Sergii Dmytruk --- src/ec/dasharo/ec/dasharo_ec.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/ec/dasharo/ec/dasharo_ec.c b/src/ec/dasharo/ec/dasharo_ec.c index 3658687857c..58762771e71 100644 --- a/src/ec/dasharo/ec/dasharo_ec.c +++ b/src/ec/dasharo/ec/dasharo_ec.c @@ -232,9 +232,12 @@ static int firmware_str(char *data, int data_len, const char *key, char *dest, i /* Reset the EC SPI bus */ static uint8_t ec_spi_reset(void) { - uint8_t reset_cmd = CMD_SPI_FLAG_DISABLE | CMD_SPI_FLAG_SCRATCH; + uint8_t reset_cmd[2] = { + [0] = CMD_SPI_FLAG_DISABLE | CMD_SPI_FLAG_SCRATCH, + [1] = 0, + }; - return dasharo_ec_smfi_cmd(CMD_SPI, sizeof(reset_cmd), &reset_cmd); + return dasharo_ec_smfi_cmd(CMD_SPI, sizeof(reset_cmd), reset_cmd); } /* @@ -863,7 +866,7 @@ static void dasharo_ec_fw_sync(void *unused) char img_version_str[64]; char cur_board_str[64]; char cur_version_str[64]; - uint8_t smfi_cmd; + uint8_t smfi_cmd[2] = { 0, 0 }; int rv; if (!CONFIG(EC_DASHARO_EC_UPDATE)) @@ -936,8 +939,8 @@ static void dasharo_ec_fw_sync(void *unused) } /* Jump to Scratch ROM */ - smfi_cmd = CMD_SPI_FLAG_SCRATCH; - if (dasharo_ec_smfi_cmd(CMD_SPI, sizeof(smfi_cmd), &smfi_cmd)) { + smfi_cmd[0] = CMD_SPI_FLAG_SCRATCH; + if (dasharo_ec_smfi_cmd(CMD_SPI, sizeof(smfi_cmd), smfi_cmd)) { /* If we failed to jump to scratch ROM, then we can probably continue booting. */ printk(BIOS_ERR, "EC: failed to jump to scratch ROM!\n"); if (CONFIG(VBOOT)) @@ -977,14 +980,14 @@ static void dasharo_ec_fw_sync(void *unused) goto cleanup; } - smfi_cmd = CMD_SPI_FLAG_DISABLE; - if (dasharo_ec_smfi_cmd(CMD_SPI, sizeof(smfi_cmd), &smfi_cmd)) { + smfi_cmd[0] = CMD_SPI_FLAG_DISABLE; + if (dasharo_ec_smfi_cmd(CMD_SPI, sizeof(smfi_cmd), smfi_cmd)) { printk(BIOS_ERR, "EC: failed to disable SPI bus!\n"); goto cleanup; } - smfi_cmd = 0; - if (dasharo_ec_smfi_cmd(CMD_RESET, sizeof(smfi_cmd), &smfi_cmd)) + smfi_cmd[0] = 0; + if (dasharo_ec_smfi_cmd(CMD_RESET, sizeof(smfi_cmd[0]), &smfi_cmd[0])) printk(BIOS_ERR, "EC: failed to trigger reset!\n"); cleanup: From 7b91c7c9dab91253531474a83eff60ee37a9b6e6 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Mon, 15 Jun 2026 01:12:46 +0300 Subject: [PATCH 17/21] ec/dasharo: update three log messages Add newline to two and specify hexadecimal base for a number in the third one. Change-Id: I1f7ca492b6b27641bc5970ab78b7ebadbe2c740d Upstream-Status: Pending Signed-off-by: Sergii Dmytruk --- src/ec/dasharo/ec/dasharo_ec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ec/dasharo/ec/dasharo_ec.c b/src/ec/dasharo/ec/dasharo_ec.c index 58762771e71..54c8d112885 100644 --- a/src/ec/dasharo/ec/dasharo_ec.c +++ b/src/ec/dasharo/ec/dasharo_ec.c @@ -879,13 +879,13 @@ static void dasharo_ec_fw_sync(void *unused) image = malloc(CONFIG_EC_DASHARO_EC_FLASH_SIZE); if (image == NULL) { - printk(BIOS_ERR, "EC: failed to allocate memory for update."); + printk(BIOS_ERR, "EC: failed to allocate memory for update.\n"); return; } image_sz = cbfs_load("ec.rom", image, CONFIG_EC_DASHARO_EC_FLASH_SIZE); if (!image_sz) { - printk(BIOS_ERR, "EC: failed to load update from CBFS."); + printk(BIOS_ERR, "EC: failed to load update from CBFS.\n"); goto cleanup; } @@ -956,7 +956,7 @@ static void dasharo_ec_fw_sync(void *unused) /* EC is now in an unknown state. It may still boot from backup. */ printk(BIOS_ALERT, "EC: update failed!\n"); } else { - printk(BIOS_INFO, "EC: wrote %x bytes\n", rv); + printk(BIOS_INFO, "EC: wrote 0x%x bytes\n", rv); } rv = ec_spi_image_verify((uint8_t *)image, image_sz); From 39e125fcde5d15b9b4536edc7a57a3f7b8166005 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Mon, 15 Jun 2026 01:17:46 +0300 Subject: [PATCH 18/21] drivers/efi/capsules.c: build accurate RAM map An EC capsule, which is smaller than 1 MiB in size, has been observed to be coalesced into memory allocated for SMM on QEMU. If that's not a defect of resource allocation for that particular board, construction of memory map is in need of improvement. Initial attempt was to add IORESOURCE_RESERVE to the mask passed to memranges_init() to not include such regions, but it didn't help because search_global_resources() invoked during the initialization doesn't take overlapping regions into account. So the second attempt was to write a version which performs two passes: add ranges on the first one and exclude reserved and subtractive on the second one. Change-Id: I8f78779e0668261af790ca744a53a9546395acd2 Upstream-Status: Pending Signed-off-by: Sergii Dmytruk --- src/drivers/efi/capsules.c | 60 ++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/src/drivers/efi/capsules.c b/src/drivers/efi/capsules.c index 2ddd6071004..a2b0a043cbc 100644 --- a/src/drivers/efi/capsules.c +++ b/src/drivers/efi/capsules.c @@ -577,7 +577,7 @@ static struct memory_range pick_buffer(uint64_t total_data_size) { struct memory_range buffer = {0}; - /* 4 * KiB is the alignment set by memranges_init(). */ + /* 4 * KiB is the alignment used in get_usable_memory(). */ total_data_size = ALIGN_UP(total_data_size, 4 * KiB); const struct range_entry *r; @@ -675,6 +675,59 @@ static void coalesce_capsules(struct block_descr block_chain, uint8_t *target) printk(BIOS_INFO, "capsules: found %d capsule(s).\n", uefi_capsule_count); } +/* A variation on search_global_resources() that builds an accurate memory map. + The crucial difference is that subtractive and reserved resources are + excluded from the map and position of such resources doesn't matter. */ +static struct memranges get_usable_memory(void) +{ + const unsigned long usable_ram_mask = + IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_CACHEABLE; + const unsigned long exclusion_mask = IORESOURCE_SUBTRACTIVE | IORESOURCE_RESERVE; + + struct memranges ranges; + memranges_init_empty_with_alignment(&ranges, NULL, 0, 12); + + for (int pass = 1; pass <= 2; ++pass) { + for (struct device *curdev = all_devices; curdev; curdev = curdev->next) { + /* Ignore disabled devices. */ + if (!curdev->enabled) + continue; + + struct resource *res; + for (res = curdev->resource_list; res; res = res->next) { + /* If it isn't the right kind of resource ignore it. */ + if ((res->flags & usable_ram_mask) != usable_ram_mask) + continue; + + /* If the resource is not assigned ignore it. */ + if (!(res->flags & IORESOURCE_ASSIGNED)) + continue; + + /* Ignore empty resources. */ + if (res->size == 0) + continue; + + if (!(res->flags & exclusion_mask)) { + if (pass == 1) { + /* First pass: adding ranges. */ + memranges_insert(&ranges, + res->base, res->size, + BM_MEM_RAM); + } + } else { + if (pass == 2) { + /* Second pass: excluding ranges. */ + memranges_create_hole(&ranges, + res->base, res->size); + } + } + } + } + } + + return ranges; +} + void efi_parse_capsules(uintptr_t *base, size_t *size) { /* EDK2 starts with 20 items and then grows the list, but it's unlikely @@ -705,10 +758,7 @@ void efi_parse_capsules(uintptr_t *base, size_t *size) if (smmstore_lookup_region(&rdev)) printk(BIOS_INFO, "capsules: no SMMSTORE region, no update capsules.\n"); - memranges_init(&memory_map, IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED | - IORESOURCE_ASSIGNED | IORESOURCE_CACHEABLE, IORESOURCE_MEM | - IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED | - IORESOURCE_CACHEABLE, BM_MEM_RAM); + memory_map = get_usable_memory(); if (!ENV_X86_64) init_pae_pagetables(&pae_page_tables); From 26314b8ad7a56462d2134acbd2de8bdf150267a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kope=C4=87?= Date: Thu, 20 Aug 2026 14:47:34 +0200 Subject: [PATCH 19/21] src/soc/intel/common/block/crashlog: Add driver for PMC SRAM device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a small driver that places the PMC SRAM BAR <4G if ENV_X86_32. This fixes accessing the CL when coreboot is built in 32bit and above 4G alloc is enabled. Upstream-Status: Pending Change-Id: I85abab5031838b59a4c7846cd207a75121fc3431 Signed-off-by: Michał Kopeć --- .../intel/common/block/crashlog/Makefile.mk | 1 + .../common/block/crashlog/crashlog_sram.c | 59 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 src/soc/intel/common/block/crashlog/crashlog_sram.c diff --git a/src/soc/intel/common/block/crashlog/Makefile.mk b/src/soc/intel/common/block/crashlog/Makefile.mk index 1f101c5c7e5..b83c13f4ad2 100644 --- a/src/soc/intel/common/block/crashlog/Makefile.mk +++ b/src/soc/intel/common/block/crashlog/Makefile.mk @@ -1,2 +1,3 @@ ## SPDX-License-Identifier: GPL-2.0-only ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_CRASHLOG) += crashlog.c +ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_CRASHLOG) += crashlog_sram.c diff --git a/src/soc/intel/common/block/crashlog/crashlog_sram.c b/src/soc/intel/common/block/crashlog/crashlog_sram.c new file mode 100644 index 00000000000..782790eda87 --- /dev/null +++ b/src/soc/intel/common/block/crashlog/crashlog_sram.c @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include +#include +#include +#include +#include + +static void crashlog_sram_read_resources(struct device *dev) +{ + struct resource *res; + + pci_dev_read_resources(dev); + + if (!ENV_X86_32) + return; + + for (res = dev->resource_list; res; res = res->next) { + if (!(res->flags & IORESOURCE_MEM)) + continue; + + /* Nothing to do for windows that are not allocated by us. */ + if (res->flags & (IORESOURCE_FIXED | IORESOURCE_ASSIGNED)) + continue; + + res->limit = 0xffffffff; + res->flags &= ~IORESOURCE_ABOVE_4G; + } +} + +static const struct device_operations crashlog_sram_ops = { + .read_resources = crashlog_sram_read_resources, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, +#if CONFIG(HAVE_ACPI_TABLES) + .write_acpi_tables = pci_rom_write_acpi_tables, + .acpi_fill_ssdt = pci_rom_ssdt, +#endif + .init = pci_dev_init, + .ops_pci = &pci_dev_ops_pci, +}; + +static const unsigned short pci_device_ids[] = { + PCI_DID_INTEL_TGL_CPU_CRASHLOG_SRAM, + PCI_DID_INTEL_TGP_PMC_CRASHLOG_SRAM, + PCI_DID_INTEL_ADL_CPU_CRASHLOG_SRAM, + PCI_DID_INTEL_ADP_S_PMC_CRASHLOG_SRAM, + PCI_DID_INTEL_ADP_P_PMC_CRASHLOG_SRAM, + PCI_DID_INTEL_ADP_N_PMC_CRASHLOG_SRAM, + PCI_DID_INTEL_RPL_CPU_CRASHLOG_SRAM, + PCI_DID_INTEL_RPP_S_PMC_CRASHLOG_SRAM, + 0, +}; + +static const struct pci_driver crashlog_sram __pci_driver = { + .ops = &crashlog_sram_ops, + .vendor = PCI_VID_INTEL, + .devices = pci_device_ids, +}; From 08925e4ccd61986f01838d87417100bc8fd3b44e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kope=C4=87?= Date: Thu, 20 Aug 2026 14:51:10 +0200 Subject: [PATCH 20/21] src/soc/intel/alderlake/crashlog.c: Harden against unreachable BAR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevent reading garbage from the CL if the BAR is inaccessible Upstream-Status: Pending Change-Id: I6fb4adb91470ac12f1fec433887c8b3d26fc45db Signed-off-by: Michał Kopeć --- src/soc/intel/alderlake/crashlog.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/soc/intel/alderlake/crashlog.c b/src/soc/intel/alderlake/crashlog.c index a85fa0144ad..1e370fa6b6e 100644 --- a/src/soc/intel/alderlake/crashlog.c +++ b/src/soc/intel/alderlake/crashlog.c @@ -47,6 +47,16 @@ static uintptr_t sram_get_bar(void) return 0; } + /* + * Crashlog SRAM is accessed through a pointer, so it has to be + * reachable. crashlog_sram_read_resources() keeps the BAR below 4G on + * 32-bit builds, this is only a safety net in case it could not. + */ + if (res->base != (uintptr_t)res->base) { + printk(BIOS_ERR, "PCH SRAM BAR at 0x%llx is not addressable!\n", res->base); + return 0; + } + /* Get the base address of the resource */ sram_bar = res->base; @@ -55,7 +65,7 @@ static uintptr_t sram_get_bar(void) bool pmc_cl_discovery(void) { - u32 tmp_bar_addr = 0, desc_table_addr = 0; + uintptr_t tmp_bar_addr = 0, desc_table_addr = 0; const struct pmc_ipc_buffer req = { 0 }; struct pmc_ipc_buffer res; @@ -243,6 +253,13 @@ bool cpu_cl_discovery(void) const struct resource *res = find_resource(SA_DEV_TMT, PCI_BASE_ADDRESS_0); printk(BIOS_DEBUG, "cpu crashlog bar addr: 0x%llX\n", res->base); + /* cl_get_cpu_bar_addr() only reads the lower half of the 64-bit BAR. */ + if (res->base != (uintptr_t)res->base) { + printk(BIOS_ERR, "CPU crashlog BAR is not addressable!\n"); + m_cpu_crashLog_present = false; + return false; + } + if (!cpu_cl_gen_discovery_table()) { printk(BIOS_ERR, "CPU crashlog discovery table not valid.\n"); m_cpu_crashLog_present = false; From 95357c70dc41f7f7064b2cce8545d8bc9fa5c1d4 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Tue, 16 Jun 2026 19:06:14 +0300 Subject: [PATCH 21/21] .github/workflows/build.yml: build any dasharo[-*] branch and PRs to it Change-Id: I6f91860dbd22b7041e0273b5c9b36a317f5b0069 Upstream-Status: Inappropriate [Dasharo downstream] Signed-off-by: Sergii Dmytruk --- .github/workflows/build.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9b57bfc6e0e..6e8cb234b64 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,10 +2,12 @@ name: Dasharo on: pull_request: branches: - - dasharo-25.12 + - dasharo + - dasharo-20* push: branches: - - dasharo-25.12 + - dasharo + - dasharo-20* tags: - '*'