[PATCH 1/2] esrtdump: add dumping for esrt table (LP: #1532103)

Colin Ian King colin.king at canonical.com
Fri Jan 8 10:31:32 UTC 2016


Thanks Ivan, this is a useful extra tool. Comments below...

On 08/01/16 08:12, Ivan Hu wrote:
> EFI System Resource Table (ESRT) provides an optional mechanism for identifying
> device and system firmware resources for the purposes of targeting firmware
> updates to those resources, which was defined on UEFI spec. 2.5, chapter 22.3.
> Add dumping for this UEFI resoure table.
                            "resource"
> 
> Signed-off-by: Ivan Hu <ivan.hu at canonical.com>
> ---
>  src/Makefile.am              |   3 +-
>  src/lib/include/fwts_uefi.h  |  14 +++
>  src/uefi/esrtdump/esrtdump.c | 197 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 213 insertions(+), 1 deletion(-)
>  create mode 100644 src/uefi/esrtdump/esrtdump.c
> 
> diff --git a/src/Makefile.am b/src/Makefile.am
> index f257a7f..2de2585 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -129,7 +129,8 @@ fwts_SOURCES = main.c 				\
>  	uefi/securebootcert/securebootcert.c	\
>  	uefi/uefivarinfo/uefivarinfo.c		\
>  	uefi/uefibootpath/uefibootpath.c	\
> -	uefi/uefirtauthvar/uefirtauthvar.c
> +	uefi/uefirtauthvar/uefirtauthvar.c	\
> +	uefi/esrtdump/esrtdump.c
>  
>  fwts_LDFLAGS = -lm `pkg-config --libs glib-2.0 gio-2.0`
>  
> diff --git a/src/lib/include/fwts_uefi.h b/src/lib/include/fwts_uefi.h
> index 7919006..1a6b20b 100644
> --- a/src/lib/include/fwts_uefi.h
> +++ b/src/lib/include/fwts_uefi.h
> @@ -97,6 +97,20 @@ enum {
>  #define EFI_OS_INDICATIONS_FMP_CAPSULE_SUPPORTED 		0x0000000000000008
>  #define EFI_OS_INDICATIONS_CAPSULE_RESULT_VAR_SUPPORTED		0x0000000000000010
>  
> +#define ESRT_FW_TYPE_UNKNOWN		0x00000000
> +#define ESRT_FW_TYPE_SYSTEMFIRMWARE	0x00000001
> +#define ESRT_FW_TYPE_DEVICEFIRMWARE	0x00000002
> +#define ESRT_FW_TYPE_UEFIDRIVER		0x00000003
> +
> +#define LAST_ATTEMPT_STATUS_SUCCESS			0x00000000
> +#define LAST_ATTEMPT_STATUS_ERR_UNSUCCESSFUL		0x00000001
> +#define LAST_ATTEMPT_STATUS_ERR_INSUFFICIENT_RESOURCES	0x00000002
> +#define LAST_ATTEMPT_STATUS_ERR_INCORRECT_VERSION	0x00000003
> +#define LAST_ATTEMPT_STATUS_ERR_INVALID_FORMAT		0x00000004
> +#define LAST_ATTEMPT_STATUS_ERR_AUTH_ERROR		0x00000005
> +#define LAST_ATTEMPT_STATUS_ERR_PWR_EVT_AC		0x00000006
> +#define LAST_ATTEMPT_STATUS_ERR_PWR_EVT_BATT		0x00000007
> +
>  #define EFI_CERT_SHA256_GUID \
>  { 0xc1c41626, 0x504c, 0x4092, { 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 }}
>  
> diff --git a/src/uefi/esrtdump/esrtdump.c b/src/uefi/esrtdump/esrtdump.c
> new file mode 100644
> index 0000000..c342819
> --- /dev/null
> +++ b/src/uefi/esrtdump/esrtdump.c
> @@ -0,0 +1,197 @@
> +/*
> + * Copyright (C) 2016 Canonical
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + */
> +
> +#include <sys/types.h>
> +#include <dirent.h>
> +
> +#include "fwts.h"
> +#include "fwts_uefi.h"
> +
> +#define FWTS_ESRT_DIR_PATH		"/sys/firmware/efi/esrt/entries"
> +#define FWTS_ESRT_RES_COUNT_PATH	"/sys/firmware/efi/esrt/fw_resource_count"
> +#define FWTS_ESRT_RES_COUNT_MAX_PATH	"/sys/firmware/efi/esrt/fw_resource_count_max"
> +#define FWTS_ESRT_RES_VERSION_PATH	"/sys/firmware/efi/esrt/fw_resource_version"
> +
> +static int esrtdump_init(fwts_framework *fw)
> +{
> +	if (fwts_firmware_detect() != FWTS_FIRMWARE_UEFI) {
> +		fwts_log_info(fw, "Cannot detect any UEFI firmware. Aborted.");
> +		return FWTS_ABORTED;
> +	}
> +	return FWTS_OK;
> +}
> +
> +static int get_entries_info(fwts_framework *fw)
> +{
> +	DIR *dir;
> +	struct dirent *entry;
> +
> +	if (!(dir = opendir(FWTS_ESRT_DIR_PATH))) {
> +		fwts_log_error(fw, "Cannot open directory %s", FWTS_ESRT_DIR_PATH);
> +		return FWTS_ERROR;
> +	}
> +
> +	do {
> +		entry = readdir(dir);
> +		if (entry && strstr(entry->d_name, "entry")) {
> +			char path[PATH_MAX];
> +			char *str, *str_info;
> +			int count = -1;
> +
> +			fwts_log_info_verbatum(fw, "%s", entry->d_name);
> +
> +			snprintf(path, sizeof(path), FWTS_ESRT_DIR_PATH "/%s/fw_class", entry->d_name);
> +			if ((str = fwts_get(path)) == NULL) {
> +				fwts_log_error(fw, "Failed to get FwClass");
> +			} else {
> +				fwts_log_info_verbatum(fw, "    FwClass: %s", str);

fwts_get() allocates the string on the heap, so one needs to free it
after each successful call using free(str);

valgrind --leak-check shows a bunch of these leaks

==17510== 3 bytes in 1 blocks are definitely lost in loss record 1 of 240
==17510==    at 0x4C2BBCF: malloc (in
/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==17510==    by 0x5B26389: strdup (strdup.c:42)
==17510==    by 0x566E159: fwts_get (fwts_get.c:45)
==17510==    by 0x44A42D: esrtdump_test1 (esrtdump.c:165)
==17510==    by 0x566C6E0: fwts_framework_run_test (fwts_framework.c:656)
==17510==    by 0x566C6E0: fwts_framework_tests_run (fwts_framework.c:717)
==17510==    by 0x566DD72: fwts_framework_args (fwts_framework.c:1528)
==17510==    by 0x404AE9: main (main.c:29)



> +			}
> +
> +			snprintf(path, sizeof(path), FWTS_ESRT_DIR_PATH "/%s/fw_type", entry->d_name);
> +			if ((fwts_get_int(path, &count)) != FWTS_OK) {
> +				fwts_log_error(fw, "Failed to get FwType");
> +			} else {
> +				switch (count) {
> +				case ESRT_FW_TYPE_UNKNOWN:
> +					str_info = "(Unknown)";
> +					break;
> +				case ESRT_FW_TYPE_SYSTEMFIRMWARE:
> +					str_info = "(System Firmware)";
> +					break;
> +				case ESRT_FW_TYPE_DEVICEFIRMWARE:
> +					str_info = "(Device Firmware)";
> +					break;
> +				case ESRT_FW_TYPE_UEFIDRIVER:
> +					str_info = "(UEFI Driver)";
> +					break;
> +				default:
> +					str_info = "";
> +					break;
> +				}
> +				fwts_log_info_verbatum(fw, "    FwType: %d %s", count, str_info);
> +			}
> +
> +			snprintf(path, sizeof(path), FWTS_ESRT_DIR_PATH "/%s/fw_version", entry->d_name);
> +			if ((str = fwts_get(path)) == NULL) {
> +				fwts_log_error(fw, "Failed to get FwVersion");
> +			} else {
> +				fwts_log_info_verbatum(fw, "    FwVersion: %s", str);

free required

> +			}
> +
> +			snprintf(path, sizeof(path), FWTS_ESRT_DIR_PATH "/%s/lowest_supported_fw_version", entry->d_name);
> +			if ((str = fwts_get(path)) == NULL) {
> +				fwts_log_error(fw, "Failed to get LowestSupportedFwVersion");
> +			} else {
> +				fwts_log_info_verbatum(fw, "    LowestSupportedFwVersion: %s", str);


free required

> +			}
> +
> +			snprintf(path, sizeof(path), FWTS_ESRT_DIR_PATH "/%s/capsule_flags", entry->d_name);
> +			if ((str = fwts_get(path)) == NULL) {
> +				fwts_log_error(fw, "Failed to get CapsuleFlags");
> +			} else {
> +				fwts_log_info_verbatum(fw, "    CapsuleFlags: %s", str);


free required

> +			}
> +
> +			snprintf(path, sizeof(path), FWTS_ESRT_DIR_PATH "/%s/last_attempt_version", entry->d_name);
> +			if ((str = fwts_get(path)) == NULL) {
> +				fwts_log_error(fw, "Failed to get LastAttemptVersion");
> +			} else {
> +				fwts_log_info_verbatum(fw, "    LastAttemptVersion: %s", str);


free required

> +			}
> +
> +			snprintf(path, sizeof(path), FWTS_ESRT_DIR_PATH "/%s/last_attempt_status", entry->d_name);
> +			if ((fwts_get_int(path, &count)) != FWTS_OK) {
> +				fwts_log_error(fw, "Failed to get LastAttemptStatus");
> +			} else {
> +				switch (count) {
> +				case LAST_ATTEMPT_STATUS_SUCCESS:
> +					str_info = "(Success)";
> +					break;
> +				case LAST_ATTEMPT_STATUS_ERR_UNSUCCESSFUL:
> +					str_info = "(Unsuccessful)";
> +					break;
> +				case LAST_ATTEMPT_STATUS_ERR_INSUFFICIENT_RESOURCES:
> +					str_info = "(Insufficient Resources)";
> +					break;
> +				case LAST_ATTEMPT_STATUS_ERR_INCORRECT_VERSION:
> +					str_info = "(Incorrect Version)";
> +					break;
> +				case LAST_ATTEMPT_STATUS_ERR_INVALID_FORMAT:
> +					str_info = "(Invalid Format)";
> +					break;
> +				case LAST_ATTEMPT_STATUS_ERR_AUTH_ERROR:
> +					str_info = "(Auth Error)";
> +					break;
> +				case LAST_ATTEMPT_STATUS_ERR_PWR_EVT_AC:
> +					str_info = "(PWR EVT AC)";
> +					break;
> +				case LAST_ATTEMPT_STATUS_ERR_PWR_EVT_BATT:
> +					str_info = "(PWR EVT BATT)";
> +					break;
> +				default:
> +					str_info = "";
> +					break;
> +				}
> +				fwts_log_info_verbatum(fw, "    LastAttemptStatus: %d %s", count, str_info);
> +			}
> +		}
> +	} while (entry);
> +
> +	closedir(dir);
> +	return FWTS_OK;
> +}
> +
> +static int esrtdump_test1(fwts_framework *fw)
> +{
> +	char *str;
> +	int ret;
> +
> +	if ((str = fwts_get(FWTS_ESRT_RES_COUNT_PATH)) == NULL)
> +		fwts_log_error(fw, "Failed to get FwResourceCount");
> +	else
> +		fwts_log_info(fw, "  FwResourceCount: %s", str);

free required

> +
> +	if ((str = fwts_get(FWTS_ESRT_RES_COUNT_MAX_PATH)) == NULL)
> +		fwts_log_error(fw, "Failed to get FwResourceCountMax");
> +	else
> +		fwts_log_info(fw, "  FwResourceCountMax: %s", str);

free required

> +
> +	if ((str = fwts_get(FWTS_ESRT_RES_VERSION_PATH)) == NULL)
> +		fwts_log_error(fw, "Failed to get FwResourceVersion");
> +	else
> +		fwts_log_info(fw, "  FwResourceVersion: %s", str);

free required

> +
> +	/* find entries */
> +	ret = get_entries_info(fw);
> +
> +	return ret;

stylistically, why not do:

	return get_entries_info(fw);

and remove the ret altogether

> +}
> +
> +static fwts_framework_minor_test esrtdump_tests[] = {
> +	{ esrtdump_test1, "Dump ESRT Table." },
> +	{ NULL, NULL }
> +};
> +
> +static fwts_framework_ops esrtdump_ops = {
> +	.description = "Dump ESRT table.",
> +	.init        = esrtdump_init,
> +	.minor_tests = esrtdump_tests
> +};
> +
> +FWTS_REGISTER("esrtdump", &esrtdump_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_UTILS | FWTS_FLAG_ROOT_PRIV)
> 

I ran this on a UEFI enabled test box and I get:

Test 1 of 1: Dump ESRT Table.
 FwResourceCount: 1
 FwResourceCountMax: 1
 FwResourceVersion: 1
entry0
    FwClass: 819b858e-c52c-402f-80e1-5b311b6c1959
    FwType: 1 (System Firmware)
    FwVersion: 1
    LowestSupportedFwVersion: 1
    CapsuleFlags: 0x1
    LastAttemptVersion: 1
    LastAttemptStatus: 0 (Success)

This is OK, however, the fwts style is to align the data and indent by
two chars for each hierarchy level, for example, the CMOS dump:

Installed H/W: (CMOS 0x14): 0xff
  Maths Coprocessor:      0x1 (Installed)
  Keyboard:               0x1 (Installed)
  Display Adaptor:        0x1 (Installed)
  Primary Display:        0x3 (Monochrome)
  Floppy Drives:          0x03 (4 drives)

so perhaps the output could be more like:

Test 1 of 1: Dump ESRT Table.
  FwResourceCount:         1
  FwResourceCountMax:      1
  FwResourceVersion:       1

entry0:
  FwClass:                  819b858e-c52c-402f-80e1-5b311b6c1959
  FwType:                   1 (System Firmware)
  FwVersion:                1
  LowestSupportedFwVersion: 1
  CapsuleFlags:             0x1
  LastAttemptVersion:       1
  LastAttemptStatus:        0 (Success)


Colin.



More information about the fwts-devel mailing list