[PATCH v4 07/16] efi_loader: capsule: add capsule_on_disk support

AKASHI Takahiro takahiro.akashi at linaro.org
Thu Jul 30 04:13:26 CEST 2020


Heinrich,

On Thu, Jul 23, 2020 at 05:50:09PM +0200, Heinrich Schuchardt wrote:
> On 22.07.20 08:05, AKASHI Takahiro wrote:
> > Capsule data can be loaded into the system either via UpdateCapsule
> > runtime service or files on a file system (of boot device).
> > The latter case is called "capsules on disk", and actual updates will
> > take place at the next boot time.
> >
> > In this commit, we will support capsule on disk mechanism.
> >
> > Please note that U-Boot itself has no notion of "boot device" and
> > all the capsule files to be executed will be detected only if they
> > are located in a specific directory, \EFI\UpdateCapsule, on a device
> > that is identified as a boot device by "BootXXXX" variables.
> >
> > Signed-off-by: AKASHI Takahiro <takahiro.akashi at linaro.org>
> > ---
> >  common/main.c                |   4 +
> >  include/efi_loader.h         |  16 ++
> >  lib/efi_loader/Kconfig       |  22 ++
> >  lib/efi_loader/efi_capsule.c | 510 +++++++++++++++++++++++++++++++++++
> >  lib/efi_loader/efi_setup.c   |   8 +
> >  5 files changed, 560 insertions(+)
> >
> > diff --git a/common/main.c b/common/main.c
> > index 62ab3344e529..71fb749be4f4 100644
> > --- a/common/main.c
> > +++ b/common/main.c
> > @@ -16,6 +16,7 @@
> >  #include <init.h>
> >  #include <net.h>
> >  #include <version.h>
> > +#include <efi_loader.h>
> >
> >  static void run_preboot_environment_command(void)
> >  {
> > @@ -50,6 +51,9 @@ void main_loop(void)
> >  	if (IS_ENABLED(CONFIG_USE_PREBOOT))
> >  		run_preboot_environment_command();
> >
> > +	if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY))
> > +		efi_launch_capsules();
> > +
> >  	s = bootdelay_process();
> >  	if (cli_process_fdt(&s))
> >  		cli_secure_boot_cmd(s);
> > diff --git a/include/efi_loader.h b/include/efi_loader.h
> > index a754fb0ed460..7e00bf3b33f3 100644
> > --- a/include/efi_loader.h
> > +++ b/include/efi_loader.h
> > @@ -808,6 +808,18 @@ efi_status_t EFIAPI efi_query_capsule_caps(
> >  		u64 *maximum_capsule_size,
> >  		u32 *reset_type);
> >
> > +#ifdef CONFIG_EFI_CAPSULE_ON_DISK
> 
> This #ifdef seems unnecessary. No code will invoke efi_launch_capsules()
> if CONFIG_EFI_CAPSULE_ON_DISK is not set.

Okay, I agree that this kind of #ifdef be removed from a header.

> > +#define EFI_CAPSULE_DIR L"\\EFI\\UpdateCapsule\\"
> > +
> > +/* Hook at initialization */
> > +efi_status_t efi_launch_capsules(void);
> > +#else
> > +static inline efi_status_t efi_launch_capsules(void)
> > +{
> > +	return EFI_SUCCESS;
> > +}
> > +#endif /* CONFIG_EFI_CAPSULE_ON_DISK */
> > +
> >  #else /* CONFIG_IS_ENABLED(EFI_LOADER) */
> >
> >  /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
> > @@ -824,6 +836,10 @@ static inline void efi_set_bootdev(const char *dev, const char *devnr,
> >  				   const char *path) { }
> >  static inline void efi_net_set_dhcp_ack(void *pkt, int len) { }
> >  static inline void efi_print_image_infos(void *pc) { }
> > +static inline efi_status_t efi_launch_capsules(void)
> > +{
> > +	return EFI_SUCCESS;
> > +}
> >
> >  #endif /* CONFIG_IS_ENABLED(EFI_LOADER) */
> >
> > diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
> > index ee9ebe348ad9..6e35cbe64c7f 100644
> > --- a/lib/efi_loader/Kconfig
> > +++ b/lib/efi_loader/Kconfig
> > @@ -104,6 +104,28 @@ config EFI_RUNTIME_UPDATE_CAPSULE
> >  	  Select this option if you want to use UpdateCapsule and
> >  	  QueryCapsuleCapabilities API's.
> >
> > +config EFI_CAPSULE_ON_DISK
> > +	bool "Enable capsule-on-disk support"
> > +	select EFI_HAVE_CAPSULE_SUPPORT
> > +	default n
> > +	help
> > +	  Select this option if you want to use capsule-on-disk feature,
> > +	  that is, capsules can be fetched and executed from files
> > +	  under a specific directory on UEFI system partition instead of
> > +	  via UpdateCapsule API.
> > +
> > +config EFI_CAPSULE_ON_DISK_EARLY
> > +	bool "Initiate capsule-on-disk at U-Boot boottime"
> > +	depends on EFI_CAPSULE_ON_DISK
> > +	default y
> > +	select EFI_SETUP_EARLY
> > +	help
> > +	  Normally, without this option enabled, capsules will be
> > +	  executed only at the first time of invoking one of efi command.
> > +	  If this option is enabled, capsules will be enforced to be
> > +	  executed as part of U-Boot initialisation so that they will
> > +	  surely take place whatever is set to distro_bootcmd.
> > +
> >  config EFI_DEVICE_PATH_TO_TEXT
> >  	bool "Device path to text protocol"
> >  	default y
> > diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
> > index cfe422bee924..2a224546dd11 100644
> > --- a/lib/efi_loader/efi_capsule.c
> > +++ b/lib/efi_loader/efi_capsule.c
> > @@ -10,10 +10,16 @@
> >  #include <efi_loader.h>
> >  #include <fs.h>
> >  #include <malloc.h>
> > +#include <mapmem.h>
> >  #include <sort.h>
> >
> >  const efi_guid_t efi_guid_capsule_report = EFI_CAPSULE_REPORT_GUID;
> >
> > +#ifdef CONFIG_EFI_CAPSULE_ON_DISK
> > +/* for file system access */
> > +static struct efi_file_handle *bootdev_root;
> > +#endif
> > +
> >  /**
> >   * get_last_capsule - get the last capsule number
> >   *
> > @@ -166,3 +172,507 @@ efi_status_t EFIAPI efi_query_capsule_caps(
> >  out:
> >  	return EFI_EXIT(ret);
> >  }
> > +
> > +#ifdef CONFIG_EFI_CAPSULE_ON_DISK
> > +/**
> > + * get_dp_device - retrieve a device  path from boot variable
> > + * @boot_var:	Boot variable name
> > + * @device_dp	Device path
> > + *
> > + * Retrieve a device patch from boot variable, @boot_var.
> > + *
> > + * Return:	status code
> > + */
> > +static efi_status_t get_dp_device(u16 *boot_var,
> > +				  struct efi_device_path **device_dp)
> > +{
> > +	void *buf = NULL;
> > +	efi_uintn_t size;
> > +	struct efi_load_option lo;
> > +	struct efi_device_path *file_dp;
> > +	efi_status_t ret;
> > +
> > +	size = 0;
> > +	ret = EFI_CALL(efi_get_variable(boot_var, &efi_global_variable_guid,
> > +					NULL, &size, NULL));
> > +	if (ret == EFI_BUFFER_TOO_SMALL) {
> > +		buf = malloc(size);
> > +		if (!buf)
> > +			return EFI_OUT_OF_RESOURCES;
> > +		ret = EFI_CALL(efi_get_variable(boot_var,
> > +						&efi_global_variable_guid,
> > +						NULL, &size, buf));
> > +	}
> > +	if (ret != EFI_SUCCESS)
> > +		return ret;
> > +
> > +	efi_deserialize_load_option(&lo, buf, &size);
> > +
> > +	if (lo.attributes & LOAD_OPTION_ACTIVE) {
> > +		efi_dp_split_file_path(lo.file_path, device_dp, &file_dp);
> > +		efi_free_pool(file_dp);
> > +
> > +		ret = EFI_SUCCESS;
> > +	} else {
> > +		ret = EFI_NOT_FOUND;
> > +	}
> > +
> > +	free(buf);
> > +
> > +	return ret;
> > +}
> > +
> > +/**
> > + * device_is_present_and_system_part - check if a device exists
> > + * @dp		Device path
> > + *
> > + * Check if a device pointed to by the device path, @dp, exists and is
> > + * located in UEFI system partition.
> > + *
> > + * Return:	true - yes, false - no
> > + */
> > +static bool device_is_present_and_system_part(struct efi_device_path *dp)
> > +{
> > +	efi_handle_t handle;
> > +
> > +	handle = efi_dp_find_obj(dp, NULL);
> > +	if (!handle)
> > +		return false;
> > +
> > +	return efi_disk_is_system_part(handle);
> > +}
> > +
> > +/**
> > + * find_boot_device - identify the boot device
> > + *
> > + * Identify the boot device from boot-related variables as UEFI
> > + * specification describes and put its handle into bootdev_root.
> 
> If none of the Boot* variables is defined we should still be able to do
> a capsule update. Please, use efi_system_partition as fallback.

My implementation is fully compliant with 8.5.6.
Is there any additional requirement in UEFI specification?

> > + *
> > + * Return:	status code
> > + */
> > +static efi_status_t find_boot_device(void)
> > +{
> > +	char boot_var[9];
> > +	u16 boot_var16[9], *p, bootnext, *boot_order = NULL;
> > +	efi_uintn_t size;
> > +	int i, num;
> > +	struct efi_simple_file_system_protocol *volume;
> > +	struct efi_device_path *boot_dev = NULL;
> > +	efi_status_t ret;
> > +
> > +	/* find active boot device in BootNext */
> > +	bootnext = 0;
> > +	size = sizeof(bootnext);
> > +	ret = EFI_CALL(efi_get_variable(L"BootNext",
> 
> 
> Please, avoid EFI_CALL. Use efi_get_variable_int().

Sure.

> 
> > +					(efi_guid_t *)&efi_global_variable_guid,
> > +					NULL, &size, &bootnext));
> > +	if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
> > +		/* BootNext does exist here */
> > +		if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16)) {
> > +			printf("BootNext must be 16-bit integer\n");
> > +			goto skip;
> > +		}
> > +		sprintf((char *)boot_var, "Boot%04X", bootnext);
> > +		p = boot_var16;
> > +		utf8_utf16_strcpy(&p, boot_var);
> 
> We have this type of conversion in multiple places. Both for BootXXXX as
> well as for CapsuleXXXX. Both in capsule updates as well as in
> try_load_entry().
> 
> Please, provide a libary function.

While I don't think it's really worth, but I will try.


> > +
> > +		ret = get_dp_device(boot_var16, &boot_dev);
> > +		if (ret == EFI_SUCCESS) {
> > +			if (device_is_present_and_system_part(boot_dev)) {
> > +				goto out;
> > +			} else {
> > +				efi_free_pool(boot_dev);
> > +				boot_dev = NULL;
> > +			}
> > +		}
> > +	}
> > +
> > +skip:
> > +	/* find active boot device in BootOrder */
> > +	size = 0;
> > +	ret = EFI_CALL(efi_get_variable(L"BootOrder", &efi_global_variable_guid,
> > +					NULL, &size, NULL));
> > +	if (ret == EFI_BUFFER_TOO_SMALL) {
> > +		boot_order = malloc(size);
> > +		if (!boot_order) {
> > +			ret = EFI_OUT_OF_RESOURCES;
> > +			goto out;
> > +		}
> > +
> > +		ret = EFI_CALL(efi_get_variable(
> > +					L"BootOrder", &efi_global_variable_guid,
> > +					NULL, &size, boot_order));
> > +	}
> > +	if (ret != EFI_SUCCESS)
> > +		goto out;
> > +
> > +	/* check in higher order */
> > +	num = size / sizeof(u16);
> > +	for (i = 0; i < num; i++) {
> > +		sprintf((char *)boot_var, "Boot%04X", boot_order[i]);
> > +		p = boot_var16;
> > +		utf8_utf16_strcpy(&p, boot_var);
> > +		ret = get_dp_device(boot_var16, &boot_dev);
> > +		if (ret != EFI_SUCCESS)
> > +			continue;
> > +
> > +		if (device_is_present_and_system_part(boot_dev))
> > +			break;
> > +
> > +		efi_free_pool(boot_dev);
> > +		boot_dev = NULL;
> > +	}
> > +out:
> > +	if (boot_dev) {
> > +		u16 *path_str;
> > +
> > +		path_str = efi_dp_str(boot_dev);
> > +		EFI_PRINT("EFI Capsule: bootdev is %ls\n", path_str);
> > +		efi_free_pool(path_str);
> > +
> > +		volume = efi_fs_from_path(boot_dev);
> > +		if (!volume)
> > +			ret = EFI_DEVICE_ERROR;
> > +		else
> > +			ret = EFI_CALL(volume->open_volume(volume,
> > +							   &bootdev_root));
> > +		efi_free_pool(boot_dev);
> > +	} else {
> > +		ret = EFI_NOT_FOUND;
> > +	}
> > +	free(boot_order);
> > +
> > +	return ret;
> > +}
> > +
> > +/**
> > + * efi_capsule_scan_dir - traverse a capsule directory in boot device
> > + * @files:	Array of file names
> > + * @num:	Number of elements in @files
> > + *
> > + * Traverse a capsule directory in boot device.
> > + * Called by initialization code, and returns an array of capsule file
> > + * names in @files.
> > + *
> > + * Return:	status code
> > + */
> > +static efi_status_t efi_capsule_scan_dir(u16 ***files, int *num)
> > +{
> > +	struct efi_file_handle *dirh;
> > +	struct efi_file_info *dirent;
> > +	efi_uintn_t dirent_size, tmp_size;
> > +	int count;
> > +	u16 **tmp_files;
> > +	efi_status_t ret;
> > +
> > +	ret = find_boot_device();
> > +	if (ret == EFI_NOT_FOUND) {
> > +		EFI_PRINT("EFI Capsule: bootdev is not set\n");
> > +		*num = 0;
> > +		return EFI_SUCCESS;
> > +	} else if (ret != EFI_SUCCESS) {
> > +		return EFI_DEVICE_ERROR;
> > +	}
> > +
> > +	/* count capsule files */
> > +	ret = EFI_CALL((*bootdev_root->open)(bootdev_root, &dirh,
> > +					     EFI_CAPSULE_DIR,
> > +					     EFI_FILE_MODE_READ, 0));
> > +	if (ret != EFI_SUCCESS) {
> > +		*num = 0;
> > +		return EFI_SUCCESS;
> > +	}
> > +
> > +	dirent_size = 256;
> > +	dirent = malloc(dirent_size);
> > +	if (!dirent)
> > +		return EFI_OUT_OF_RESOURCES;
> > +
> > +	count = 0;
> > +	while (1) {
> > +		tmp_size = dirent_size;
> > +		ret = EFI_CALL((*dirh->read)(dirh, &tmp_size, dirent));
> > +		if (ret == EFI_BUFFER_TOO_SMALL) {
> > +			dirent = realloc(dirent, tmp_size);
> > +			if (!dirent) {
> > +				ret = EFI_OUT_OF_RESOURCES;
> > +				goto err;
> > +			}
> > +			dirent_size = tmp_size;
> > +			ret = EFI_CALL((*dirh->read)(dirh, &tmp_size, dirent));
> > +		}
> > +		if (ret != EFI_SUCCESS)
> > +			goto err;
> > +		if (!tmp_size)
> > +			break;
> > +
> > +		if (!(dirent->attribute & EFI_FILE_DIRECTORY) &&
> > +		    u16_strcmp(dirent->file_name, L".") &&
> > +		    u16_strcmp(dirent->file_name, L".."))
> > +			count++;
> > +	}
> > +
> > +	ret = EFI_CALL((*dirh->setpos)(dirh, 0));
> > +	if (ret != EFI_SUCCESS)
> > +		goto err;
> > +
> > +	/* make a list */
> > +	tmp_files = malloc(count * sizeof(*files));
> > +	if (!tmp_files) {
> > +		ret = EFI_OUT_OF_RESOURCES;
> > +		goto err;
> > +	}
> > +
> > +	count = 0;
> > +	while (1) {
> > +		tmp_size = dirent_size;
> > +		ret = EFI_CALL((*dirh->read)(dirh, &tmp_size, dirent));
> > +		if (ret != EFI_SUCCESS)
> > +			goto err;
> > +		if (!tmp_size)
> > +			break;
> > +
> > +		if (!(dirent->attribute & EFI_FILE_DIRECTORY) &&
> > +		    u16_strcmp(dirent->file_name, L".") &&
> > +		    u16_strcmp(dirent->file_name, L".."))
> > +			tmp_files[count++] = u16_strdup(dirent->file_name);
> > +	}
> > +	/* ignore an error */
> > +	EFI_CALL((*dirh->close)(dirh));
> > +
> > +	/* in ascii order */
> > +	/* FIXME: u16 version of strcasecmp */
> > +	qsort(tmp_files, count, sizeof(*tmp_files),
> > +	      (int (*)(const void *, const void *))strcasecmp);
> > +	*files = tmp_files;
> > +	*num = count;
> > +	ret = EFI_SUCCESS;
> > +err:
> > +	free(dirent);
> > +
> > +	return ret;
> > +}
> > +
> > +/**
> > + * efi_capsule_read_file - read in a capsule file
> > + * @filename:	File name
> > + * @capsule:	Pointer to buffer for capsule
> > + *
> > + * Read a capsule file and put its content in @capsule.
> > + *
> > + * Return:	status code
> > + */
> > +static efi_status_t efi_capsule_read_file(u16 *filename,
> 
> const u16 *filename

Okay.

> > +					  struct efi_capsule_header **capsule)
> > +{
> > +	struct efi_file_handle *dirh, *fh;
> > +	struct efi_file_info *file_info = NULL;
> > +	struct efi_capsule_header *buf = NULL;
> > +	efi_uintn_t size;
> > +	efi_status_t ret;
> > +
> > +	ret = EFI_CALL((*bootdev_root->open)(bootdev_root, &dirh,
> > +					     EFI_CAPSULE_DIR,
> > +					     EFI_FILE_MODE_READ, 0));
> > +	if (ret != EFI_SUCCESS)
> > +		return ret;
> > +	ret = EFI_CALL((*dirh->open)(dirh, &fh, filename,
> > +				     EFI_FILE_MODE_READ, 0));
> > +	/* ignore an error */
> > +	EFI_CALL((*dirh->close)(dirh));
> > +	if (ret != EFI_SUCCESS)
> > +		return ret;
> > +
> > +	/* file size */
> > +	size = 0;
> > +	ret = EFI_CALL((*fh->getinfo)(fh, &efi_file_info_guid,
> > +				      &size, file_info));
> > +	if (ret == EFI_BUFFER_TOO_SMALL) {
> > +		file_info = malloc(size);
> > +		if (!file_info) {
> > +			ret = EFI_OUT_OF_RESOURCES;
> > +			goto err;
> > +		}
> > +		ret = EFI_CALL((*fh->getinfo)(fh, &efi_file_info_guid,
> > +					      &size, file_info));
> > +	}
> > +	if (ret != EFI_SUCCESS)
> > +		goto err;
> > +	size = file_info->file_size;
> > +	free(file_info);
> > +	buf = malloc(size);
> > +	if (!buf) {
> > +		ret = EFI_OUT_OF_RESOURCES;
> > +		goto err;
> > +	}
> > +
> > +	/* fetch data */
> > +	ret = EFI_CALL((*fh->read)(fh, &size, buf));
> > +	if (ret == EFI_SUCCESS) {
> > +		if (size >= buf->capsule_image_size) {
> > +			*capsule = buf;
> > +		} else {
> > +			free(buf);
> > +			ret = EFI_INVALID_PARAMETER;
> > +		}
> > +	} else {
> > +		free(buf);
> > +	}
> > +err:
> > +	EFI_CALL((*fh->close)(fh));
> > +
> > +	return ret;
> > +}
> > +
> > +/**
> > + * efi_capsule_delete_file - delete a capsule file
> > + * @filename:	File name
> > + *
> > + * Delete a capsule file from capsule directory.
> > + *
> > + * Return:	status code
> > + */
> > +static efi_status_t efi_capsule_delete_file(u16 *filename)
> 
> const u16 *filename

Okay.

> 
> > +{
> > +	struct efi_file_handle *dirh, *fh;
> > +	efi_status_t ret;
> > +
> > +	ret = EFI_CALL((*bootdev_root->open)(bootdev_root, &dirh,
> > +					     EFI_CAPSULE_DIR,
> > +					     EFI_FILE_MODE_READ, 0));
> > +	if (ret != EFI_SUCCESS)
> > +		return ret;
> > +	ret = EFI_CALL((*dirh->open)(dirh, &fh, filename,
> > +				     EFI_FILE_MODE_READ, 0));
> > +	/* ignore an error */
> > +	EFI_CALL((*dirh->close)(dirh));
> > +
> > +	ret = EFI_CALL((*fh->delete)(fh));
> > +
> > +	return ret;
> > +}
> > +
> > +/**
> > + * efi_capsule_scan_done - reset a scan help function
> > + *
> > + * Reset a scan help function
> > + */
> > +static void efi_capsule_scan_done(void)
> > +{
> > +	EFI_CALL((*bootdev_root->close)(bootdev_root));
> > +	bootdev_root = NULL;
> > +}
> > +
> > +/**
> > + * arch_efi_load_capsule_drivers - initialize capsule drivers
> > + *
> > + * Architecture or board specific initialization routine
> > + *
> > + * Return:	status code
> > + */
> > +efi_status_t __weak arch_efi_load_capsule_drivers(void)
> > +{
> > +	return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + * efi_launch_capsule - launch capsules
> > + *
> > + * Launch all the capsules in system at boot time.
> > + * Called by efi init code
> > + *
> > + * Return:	status codde
> > + */
> > +efi_status_t efi_launch_capsules(void)
> > +{
> > +	u64 os_indications;
> > +	efi_uintn_t size;
> > +	struct efi_capsule_header *capsule = NULL;
> > +	u16 **files;
> > +	int nfiles, num, i;
> > +	char variable_name[12];
> > +	u16 variable_name16[12], *p;
> > +	efi_status_t ret;
> > +
> > +	size = sizeof(os_indications);
> > +	ret = EFI_CALL(efi_get_variable(L"OsIndications",
> > +					&efi_global_variable_guid,
> > +					NULL, &size, &os_indications));
> > +	if (ret != EFI_SUCCESS ||
> > +	    !(os_indications
> > +	      & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED))
> > +		return EFI_SUCCESS;
> > +
> > +	num = get_last_capsule();
> > +
> > +	/* Load capsule drivers */
> > +	ret = arch_efi_load_capsule_drivers();
> > +	if (ret != EFI_SUCCESS)
> > +		return ret;
> > +
> > +	/*
> > +	 * Find capsules on disk.
> > +	 * All the capsules are collected at the beginning because
> > +	 * capsule files will be removed instantly.
> > +	 */
> > +	nfiles = 0;
> > +	files = NULL;
> > +	ret = efi_capsule_scan_dir(&files, &nfiles);
> > +	if (ret != EFI_SUCCESS)
> > +		return ret;
> > +	if (!nfiles)
> > +		return EFI_SUCCESS;
> > +
> > +	/* Launch capsules */
> > +	for (i = 0, ++num; i < nfiles; i++, num++) {
> > +		EFI_PRINT("capsule from %ls ...\n", files[i]);
> > +		if (num > 0xffff)
> > +			num = 0;
> > +		ret = efi_capsule_read_file(files[i], &capsule);
> > +		if (ret == EFI_SUCCESS) {
> > +			ret = EFI_CALL(efi_update_capsule(&capsule, 1, 0));
> > +			if (ret != EFI_SUCCESS)
> > +				printf("EFI Capsule update failed at %ls\n",
> > +				       files[i]);
> > +
> > +			free(capsule);
> > +		} else {
> > +			printf("EFI: reading capsule failed: %ls\n",
> > +			       files[i]);
> > +		}
> > +		/* create CapsuleXXXX */
> > +		set_capsule_result(num, capsule, ret);
> > +
> > +		/* delete a capsule either in case of success or failure */
> > +		ret = efi_capsule_delete_file(files[i]);
> > +		if (ret != EFI_SUCCESS)
> > +			printf("EFI: deleting a capsule file failed: %ls\n",
> > +			       files[i]);
> > +	}
> > +	efi_capsule_scan_done();
> > +
> > +	for (i = 0; i < nfiles; i++)
> > +		free(files[i]);
> > +	free(files);
> > +
> > +	/* CapsuleMax */
> > +	p = variable_name16;
> > +	utf8_utf16_strncpy(&p, "CapsuleFFFF", 11);
> > +	EFI_CALL(efi_set_variable(L"CapsuleMax", &efi_guid_capsule_report,
> > +				  EFI_VARIABLE_BOOTSERVICE_ACCESS |
> > +				  EFI_VARIABLE_RUNTIME_ACCESS,
> > +				  22, variable_name16));
> 
> The variable must be read-only. Please, use efi_set_variable_int.

Okay.

> The variable should be set in efi_setup.c. It does not depend on the
> execution of capsule updates.

No.
Since efi_launch_capsules() is only called once (and CapsuleMax is only
useful if capsule updates are enabled), moving the code to efi_setup.c
doesn't make any difference.

> > +
> > +	/* CapsuleLast */
> > +	sprintf(variable_name, "Capsule%04X", num - 1);
> > +	p = variable_name16;
> > +	utf8_utf16_strncpy(&p, variable_name, 11);
> > +	EFI_CALL(efi_set_variable(L"CapsuleLast", &efi_guid_capsule_report,
> 
> The variable must be read-only. Please, use efi_set_variable_int.

Okay.

-Takahiro Akashi

> Best regards
> 
> Heinrich
> 
> > +				  EFI_VARIABLE_NON_VOLATILE |
> > +				  EFI_VARIABLE_BOOTSERVICE_ACCESS |
> > +				  EFI_VARIABLE_RUNTIME_ACCESS,
> > +				  22, variable_name16));
> > +
> > +	return ret;
> > +}
> > +#endif /* CONFIG_EFI_CAPSULE_ON_DISK */
> > diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
> > index 2fc0c5d091b8..a0eb81f079e1 100644
> > --- a/lib/efi_loader/efi_setup.c
> > +++ b/lib/efi_loader/efi_setup.c
> > @@ -132,6 +132,10 @@ static efi_status_t efi_init_os_indications(void)
> >  		os_indications_supported |=
> >  			EFI_OS_INDICATIONS_CAPSULE_RESULT_VAR_SUPPORTED;
> >
> > +	if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK))
> > +		os_indications_supported |=
> > +			EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED;
> > +
> >  	return efi_set_variable_int(L"OsIndicationsSupported",
> >  				    &efi_global_variable_guid,
> >  				    EFI_VARIABLE_BOOTSERVICE_ACCESS |
> > @@ -243,6 +247,10 @@ efi_status_t efi_init_obj_list(void)
> >  	if (ret != EFI_SUCCESS)
> >  		goto out;
> >
> > +	/* Execute capsules after reboot */
> > +	if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK) &&
> > +	    !IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY))
> > +		ret = efi_launch_capsules();
> >  out:
> >  	efi_obj_list_initialized = ret;
> >  	return ret;
> >
> 


More information about the U-Boot mailing list