efi_loader: capsule: support firmware update
A capsule tagged with the guid, EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID, is handled as a firmware update object. What efi_update_capsule() basically does is to load any firmware management protocol (or fmp) drivers contained in a capsule, find out an appropriate fmp driver and then invoke its set_image() interface against each binary in a capsule. In this commit, however, loading drivers is not supported. The result of applying a capsule is set to be stored in "CapsuleXXXX" variable, but its implementation is deferred to a fmp driver. Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
This commit is contained in:
		
							parent
							
								
									ed9349c697
								
							
						
					
					
						commit
						8d99026f06
					
				|  | @ -217,6 +217,9 @@ enum efi_reset_type { | ||||||
| #define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE	0x00020000 | #define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE	0x00020000 | ||||||
| #define CAPSULE_FLAGS_INITIATE_RESET		0x00040000 | #define CAPSULE_FLAGS_INITIATE_RESET		0x00040000 | ||||||
| 
 | 
 | ||||||
|  | #define CAPSULE_SUPPORT_AUTHENTICATION		0x0000000000000001 | ||||||
|  | #define CAPSULE_SUPPORT_DEPENDENCY		0x0000000000000002 | ||||||
|  | 
 | ||||||
| #define EFI_CAPSULE_REPORT_GUID \ | #define EFI_CAPSULE_REPORT_GUID \ | ||||||
| 	EFI_GUID(0x39b68c46, 0xf7fb, 0x441b, 0xb6, 0xec, \ | 	EFI_GUID(0x39b68c46, 0xf7fb, 0x441b, 0xb6, 0xec, \ | ||||||
| 		 0x16, 0xb0, 0xf6, 0x98, 0x21, 0xf3) | 		 0x16, 0xb0, 0xf6, 0x98, 0x21, 0xf3) | ||||||
|  | @ -225,6 +228,10 @@ enum efi_reset_type { | ||||||
| 	EFI_GUID(0xde9f0ec, 0x88b6, 0x428f, 0x97, 0x7a, \ | 	EFI_GUID(0xde9f0ec, 0x88b6, 0x428f, 0x97, 0x7a, \ | ||||||
| 		 0x25, 0x8f, 0x1d, 0xe, 0x5e, 0x72) | 		 0x25, 0x8f, 0x1d, 0xe, 0x5e, 0x72) | ||||||
| 
 | 
 | ||||||
|  | #define EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID \ | ||||||
|  | 	EFI_GUID(0x6dcbd5ed, 0xe82d, 0x4c44, 0xbd, 0xa1, \ | ||||||
|  | 		 0x71, 0x94, 0x19, 0x9a, 0xd9, 0x2a) | ||||||
|  | 
 | ||||||
| struct efi_capsule_header { | struct efi_capsule_header { | ||||||
| 	efi_guid_t capsule_guid; | 	efi_guid_t capsule_guid; | ||||||
| 	u32 header_size; | 	u32 header_size; | ||||||
|  | @ -253,6 +260,33 @@ struct efi_memory_range_capsule { | ||||||
| 	struct efi_memory_range memory_ranges[]; | 	struct efi_memory_range memory_ranges[]; | ||||||
| } __packed; | } __packed; | ||||||
| 
 | 
 | ||||||
|  | struct efi_firmware_management_capsule_header { | ||||||
|  | 	u32 version; | ||||||
|  | 	u16 embedded_driver_count; | ||||||
|  | 	u16 payload_item_count; | ||||||
|  | 	u64 item_offset_list[]; | ||||||
|  | } __packed; | ||||||
|  | 
 | ||||||
|  | struct efi_firmware_management_capsule_image_header { | ||||||
|  | 	u32 version; | ||||||
|  | 	efi_guid_t update_image_type_id; | ||||||
|  | 	u8 update_image_index; | ||||||
|  | 	u8 reserved[3]; | ||||||
|  | 	u32 update_image_size; | ||||||
|  | 	u32 update_vendor_code_size; | ||||||
|  | 	u64 update_hardware_instance; | ||||||
|  | 	u64 image_capsule_support; | ||||||
|  | } __packed; | ||||||
|  | 
 | ||||||
|  | struct efi_capsule_result_variable_fmp { | ||||||
|  | 	u16 version; | ||||||
|  | 	u8 payload_index; | ||||||
|  | 	u8 update_image_index; | ||||||
|  | 	efi_guid_t update_image_type_id; | ||||||
|  | 	// u16 capsule_file_name[];
 | ||||||
|  | 	// u16 capsule_target[];
 | ||||||
|  | } __packed; | ||||||
|  | 
 | ||||||
| #define EFI_RT_SUPPORTED_GET_TIME			0x0001 | #define EFI_RT_SUPPORTED_GET_TIME			0x0001 | ||||||
| #define EFI_RT_SUPPORTED_SET_TIME			0x0002 | #define EFI_RT_SUPPORTED_SET_TIME			0x0002 | ||||||
| #define EFI_RT_SUPPORTED_GET_WAKEUP_TIME		0x0004 | #define EFI_RT_SUPPORTED_GET_WAKEUP_TIME		0x0004 | ||||||
|  | @ -1812,4 +1846,99 @@ struct efi_signature_list { | ||||||
| /*	struct efi_signature_data signatures[...][signature_size]; */ | /*	struct efi_signature_data signatures[...][signature_size]; */ | ||||||
| } __attribute__((__packed__)); | } __attribute__((__packed__)); | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Firmware management protocol | ||||||
|  |  */ | ||||||
|  | #define EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID \ | ||||||
|  | 	EFI_GUID(0x86c77a67, 0x0b97, 0x4633, 0xa1, 0x87, \ | ||||||
|  | 		 0x49, 0x10, 0x4d, 0x06, 0x85, 0xc7) | ||||||
|  | 
 | ||||||
|  | #define IMAGE_ATTRIBUTE_IMAGE_UPDATABLE		0x0000000000000001 | ||||||
|  | #define IMAGE_ATTRIBUTE_RESET_REQUIRED		0x0000000000000002 | ||||||
|  | #define IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED	0x0000000000000004 | ||||||
|  | #define IMAGE_ATTRIBUTE_IN_USE			0x0000000000000008 | ||||||
|  | #define IMAGE_ATTRIBUTE_UEFI_IMAGE		0x0000000000000010 | ||||||
|  | #define IMAGE_ATTRIBUTE_DEPENDENCY		0x0000000000000020 | ||||||
|  | 
 | ||||||
|  | #define IMAGE_COMPATIBILITY_CHECK_SUPPORTED	0x0000000000000001 | ||||||
|  | 
 | ||||||
|  | #define IMAGE_UPDATABLE_VALID			0x0000000000000001 | ||||||
|  | #define IMAGE_UPDATABLE_INVALID			0x0000000000000002 | ||||||
|  | #define IMAGE_UPDATABLE_INVALID_TYPE		0x0000000000000004 | ||||||
|  | #define IMAGE_UPDATABLE_INVALID_OLLD		0x0000000000000008 | ||||||
|  | #define IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE	0x0000000000000010 | ||||||
|  | 
 | ||||||
|  | #define PACKAGE_ATTRIBUTE_VERSION_UPDATABLE		0x0000000000000001 | ||||||
|  | #define PACKAGE_ATTRIBUTE_RESET_REQUIRED		0x0000000000000002 | ||||||
|  | #define PACKAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED	0x0000000000000004 | ||||||
|  | 
 | ||||||
|  | #define EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION	4 | ||||||
|  | 
 | ||||||
|  | typedef struct efi_firmware_image_dependencies { | ||||||
|  | 	u8 dependencies[0]; | ||||||
|  | } efi_firmware_image_dep_t; | ||||||
|  | 
 | ||||||
|  | struct efi_firmware_image_descriptor { | ||||||
|  | 	u8 image_index; | ||||||
|  | 	efi_guid_t image_type_id; | ||||||
|  | 	u64 image_id; | ||||||
|  | 	u16 *image_id_name; | ||||||
|  | 	u32 version; | ||||||
|  | 	u16 *version_name; | ||||||
|  | 	efi_uintn_t size; | ||||||
|  | 	u64 attributes_supported; | ||||||
|  | 	u64 attributes_setting; | ||||||
|  | 	u64 compatibilities; | ||||||
|  | 	u32 lowest_supported_image_version; | ||||||
|  | 	u32 last_attempt_version; | ||||||
|  | 	u32 last_attempt_status; | ||||||
|  | 	u64 hardware_instance; | ||||||
|  | 	efi_firmware_image_dep_t *dependencies; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct efi_firmware_management_protocol { | ||||||
|  | 	efi_status_t (EFIAPI *get_image_info)( | ||||||
|  | 			struct efi_firmware_management_protocol *this, | ||||||
|  | 			efi_uintn_t *image_info_size, | ||||||
|  | 			struct efi_firmware_image_descriptor *image_info, | ||||||
|  | 			u32 *descriptor_version, | ||||||
|  | 			u8 *descriptor_count, | ||||||
|  | 			efi_uintn_t *descriptor_size, | ||||||
|  | 			u32 *package_version, | ||||||
|  | 			u16 **package_version_name); | ||||||
|  | 	efi_status_t (EFIAPI *get_image)( | ||||||
|  | 			struct efi_firmware_management_protocol *this, | ||||||
|  | 			u8 image_index, | ||||||
|  | 			void *image, | ||||||
|  | 			efi_uintn_t *image_size); | ||||||
|  | 	efi_status_t (EFIAPI *set_image)( | ||||||
|  | 			struct efi_firmware_management_protocol *this, | ||||||
|  | 			u8 image_index, | ||||||
|  | 			const void *image, | ||||||
|  | 			efi_uintn_t image_size, | ||||||
|  | 			const void *vendor_code, | ||||||
|  | 			efi_status_t (*progress)(efi_uintn_t completion), | ||||||
|  | 			u16 **abort_reason); | ||||||
|  | 	efi_status_t (EFIAPI *check_image)( | ||||||
|  | 			struct efi_firmware_management_protocol *this, | ||||||
|  | 			u8 image_index, | ||||||
|  | 			const void *image, | ||||||
|  | 			efi_uintn_t *image_size, | ||||||
|  | 			u32 *image_updatable); | ||||||
|  | 	efi_status_t (EFIAPI *get_package_info)( | ||||||
|  | 			struct efi_firmware_management_protocol *this, | ||||||
|  | 			u32 *package_version, | ||||||
|  | 			u16 **package_version_name, | ||||||
|  | 			u32 *package_version_name_maxlen, | ||||||
|  | 			u64 *attributes_supported, | ||||||
|  | 			u64 *attributes_setting); | ||||||
|  | 	efi_status_t (EFIAPI *set_package_info)( | ||||||
|  | 			struct efi_firmware_management_protocol *this, | ||||||
|  | 			const void *image, | ||||||
|  | 			efi_uintn_t *image_size, | ||||||
|  | 			const void *vendor_code, | ||||||
|  | 			u32 package_version, | ||||||
|  | 			const u16 *package_version_name); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -212,6 +212,8 @@ extern const efi_guid_t efi_guid_cert_type_pkcs7; | ||||||
| extern const efi_guid_t efi_guid_rng_protocol; | extern const efi_guid_t efi_guid_rng_protocol; | ||||||
| /* GUID of capsule update result */ | /* GUID of capsule update result */ | ||||||
| extern const efi_guid_t efi_guid_capsule_report; | extern const efi_guid_t efi_guid_capsule_report; | ||||||
|  | /* GUID of firmware management protocol */ | ||||||
|  | extern const efi_guid_t efi_guid_firmware_management_protocol; | ||||||
| 
 | 
 | ||||||
| extern unsigned int __efi_runtime_start, __efi_runtime_stop; | extern unsigned int __efi_runtime_start, __efi_runtime_stop; | ||||||
| extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop; | extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop; | ||||||
|  |  | ||||||
|  | @ -127,6 +127,14 @@ config EFI_CAPSULE_ON_DISK_EARLY | ||||||
| 	  executed as part of U-Boot initialisation so that they will | 	  executed as part of U-Boot initialisation so that they will | ||||||
| 	  surely take place whatever is set to distro_bootcmd. | 	  surely take place whatever is set to distro_bootcmd. | ||||||
| 
 | 
 | ||||||
|  | config EFI_CAPSULE_FIRMWARE_MANAGEMENT | ||||||
|  | 	bool "Capsule: Firmware Management Protocol" | ||||||
|  | 	depends on EFI_HAVE_CAPSULE_SUPPORT | ||||||
|  | 	default y | ||||||
|  | 	help | ||||||
|  | 	  Select this option if you want to enable capsule-based | ||||||
|  | 	  firmware update using Firmware Management Protocol. | ||||||
|  | 
 | ||||||
| config EFI_DEVICE_PATH_TO_TEXT | config EFI_DEVICE_PATH_TO_TEXT | ||||||
| 	bool "Device path to text protocol" | 	bool "Device path to text protocol" | ||||||
| 	default y | 	default y | ||||||
|  |  | ||||||
|  | @ -15,6 +15,10 @@ | ||||||
| #include <sort.h> | #include <sort.h> | ||||||
| 
 | 
 | ||||||
| const efi_guid_t efi_guid_capsule_report = EFI_CAPSULE_REPORT_GUID; | const efi_guid_t efi_guid_capsule_report = EFI_CAPSULE_REPORT_GUID; | ||||||
|  | static const efi_guid_t efi_guid_firmware_management_capsule_id = | ||||||
|  | 		EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; | ||||||
|  | const efi_guid_t efi_guid_firmware_management_protocol = | ||||||
|  | 		EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID; | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_EFI_CAPSULE_ON_DISK | #ifdef CONFIG_EFI_CAPSULE_ON_DISK | ||||||
| /* for file system access */ | /* for file system access */ | ||||||
|  | @ -85,9 +89,214 @@ void set_capsule_result(int index, struct efi_capsule_header *capsule, | ||||||
| 			       EFI_VARIABLE_RUNTIME_ACCESS, | 			       EFI_VARIABLE_RUNTIME_ACCESS, | ||||||
| 			       sizeof(result), &result); | 			       sizeof(result), &result); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		printf("EFI: creating %ls failed\n", variable_name16); | 		log_err("EFI: creating %ls failed\n", variable_name16); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT | ||||||
|  | /**
 | ||||||
|  |  * efi_fmp_find - search for Firmware Management Protocol drivers | ||||||
|  |  * @image_type:		Image type guid | ||||||
|  |  * @instance:		Instance number | ||||||
|  |  * @handles:		Handles of FMP drivers | ||||||
|  |  * @no_handles:		Number of handles | ||||||
|  |  * | ||||||
|  |  * Search for Firmware Management Protocol drivers, matching the image | ||||||
|  |  * type, @image_type and the machine instance, @instance, from the list, | ||||||
|  |  * @handles. | ||||||
|  |  * | ||||||
|  |  * Return: | ||||||
|  |  * * Protocol instance	- on success | ||||||
|  |  * * NULL		- on failure | ||||||
|  |  */ | ||||||
|  | static struct efi_firmware_management_protocol * | ||||||
|  | efi_fmp_find(efi_guid_t *image_type, u64 instance, efi_handle_t *handles, | ||||||
|  | 	     efi_uintn_t no_handles) | ||||||
|  | { | ||||||
|  | 	efi_handle_t *handle; | ||||||
|  | 	struct efi_firmware_management_protocol *fmp; | ||||||
|  | 	struct efi_firmware_image_descriptor *image_info, *desc; | ||||||
|  | 	efi_uintn_t info_size, descriptor_size; | ||||||
|  | 	u32 descriptor_version; | ||||||
|  | 	u8 descriptor_count; | ||||||
|  | 	u32 package_version; | ||||||
|  | 	u16 *package_version_name; | ||||||
|  | 	bool found = false; | ||||||
|  | 	int i, j; | ||||||
|  | 	efi_status_t ret; | ||||||
|  | 
 | ||||||
|  | 	for (i = 0, handle = handles; i < no_handles; i++, handle++) { | ||||||
|  | 		ret = EFI_CALL(efi_handle_protocol( | ||||||
|  | 				*handle, | ||||||
|  | 				&efi_guid_firmware_management_protocol, | ||||||
|  | 				(void **)&fmp)); | ||||||
|  | 		if (ret != EFI_SUCCESS) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		/* get device's image info */ | ||||||
|  | 		info_size = 0; | ||||||
|  | 		image_info = NULL; | ||||||
|  | 		descriptor_version = 0; | ||||||
|  | 		descriptor_count = 0; | ||||||
|  | 		descriptor_size = 0; | ||||||
|  | 		package_version = 0; | ||||||
|  | 		package_version_name = NULL; | ||||||
|  | 		ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, | ||||||
|  | 						   image_info, | ||||||
|  | 						   &descriptor_version, | ||||||
|  | 						   &descriptor_count, | ||||||
|  | 						   &descriptor_size, | ||||||
|  | 						   &package_version, | ||||||
|  | 						   &package_version_name)); | ||||||
|  | 		if (ret != EFI_BUFFER_TOO_SMALL) | ||||||
|  | 			goto skip; | ||||||
|  | 
 | ||||||
|  | 		image_info = malloc(info_size); | ||||||
|  | 		if (!image_info) | ||||||
|  | 			goto skip; | ||||||
|  | 
 | ||||||
|  | 		ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, | ||||||
|  | 						   image_info, | ||||||
|  | 						   &descriptor_version, | ||||||
|  | 						   &descriptor_count, | ||||||
|  | 						   &descriptor_size, | ||||||
|  | 						   &package_version, | ||||||
|  | 						   &package_version_name)); | ||||||
|  | 		if (ret != EFI_SUCCESS || | ||||||
|  | 		    descriptor_version != EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) | ||||||
|  | 			goto skip; | ||||||
|  | 
 | ||||||
|  | 		/* matching */ | ||||||
|  | 		for (j = 0, desc = image_info; j < descriptor_count; | ||||||
|  | 		     j++, desc = (void *)desc + descriptor_size) { | ||||||
|  | 			log_debug("+++ desc[%d] index: %d, name: %ls\n", | ||||||
|  | 				  j, desc->image_index, desc->image_id_name); | ||||||
|  | 			if (!guidcmp(&desc->image_type_id, image_type) && | ||||||
|  | 			    (!instance || | ||||||
|  | 			     !desc->hardware_instance || | ||||||
|  | 			      desc->hardware_instance == instance)) | ||||||
|  | 				found = true; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | skip: | ||||||
|  | 		efi_free_pool(package_version_name); | ||||||
|  | 		free(image_info); | ||||||
|  | 		EFI_CALL(efi_close_protocol( | ||||||
|  | 				(efi_handle_t)fmp, | ||||||
|  | 				&efi_guid_firmware_management_protocol, | ||||||
|  | 				NULL, NULL)); | ||||||
|  | 		if (found) | ||||||
|  | 			return fmp; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * efi_capsule_update_firmware - update firmware from capsule | ||||||
|  |  * @capsule_data:	Capsule | ||||||
|  |  * | ||||||
|  |  * Update firmware, using a capsule, @capsule_data. Loading any FMP | ||||||
|  |  * drivers embedded in a capsule is not supported. | ||||||
|  |  * | ||||||
|  |  * Return:		status code | ||||||
|  |  */ | ||||||
|  | static efi_status_t efi_capsule_update_firmware( | ||||||
|  | 		struct efi_capsule_header *capsule_data) | ||||||
|  | { | ||||||
|  | 	struct efi_firmware_management_capsule_header *capsule; | ||||||
|  | 	struct efi_firmware_management_capsule_image_header *image; | ||||||
|  | 	size_t capsule_size; | ||||||
|  | 	void *image_binary, *vendor_code; | ||||||
|  | 	efi_handle_t *handles; | ||||||
|  | 	efi_uintn_t no_handles; | ||||||
|  | 	int item; | ||||||
|  | 	struct efi_firmware_management_protocol *fmp; | ||||||
|  | 	u16 *abort_reason; | ||||||
|  | 	efi_status_t ret = EFI_SUCCESS; | ||||||
|  | 
 | ||||||
|  | 	/* sanity check */ | ||||||
|  | 	if (capsule_data->header_size < sizeof(*capsule) || | ||||||
|  | 	    capsule_data->header_size >= capsule_data->capsule_image_size) | ||||||
|  | 		return EFI_INVALID_PARAMETER; | ||||||
|  | 
 | ||||||
|  | 	capsule = (void *)capsule_data + capsule_data->header_size; | ||||||
|  | 	capsule_size = capsule_data->capsule_image_size | ||||||
|  | 			- capsule_data->header_size; | ||||||
|  | 
 | ||||||
|  | 	if (capsule->version != 0x00000001) | ||||||
|  | 		return EFI_UNSUPPORTED; | ||||||
|  | 
 | ||||||
|  | 	handles = NULL; | ||||||
|  | 	ret = EFI_CALL(efi_locate_handle_buffer( | ||||||
|  | 			BY_PROTOCOL, | ||||||
|  | 			&efi_guid_firmware_management_protocol, | ||||||
|  | 			NULL, &no_handles, (efi_handle_t **)&handles)); | ||||||
|  | 	if (ret != EFI_SUCCESS) | ||||||
|  | 		return EFI_UNSUPPORTED; | ||||||
|  | 
 | ||||||
|  | 	/* Payload */ | ||||||
|  | 	for (item = capsule->embedded_driver_count; | ||||||
|  | 	     item < capsule->embedded_driver_count | ||||||
|  | 		    + capsule->payload_item_count; item++) { | ||||||
|  | 		/* sanity check */ | ||||||
|  | 		if ((capsule->item_offset_list[item] + sizeof(*image) | ||||||
|  | 				 >= capsule_size)) { | ||||||
|  | 			log_err("EFI: A capsule has not enough data\n"); | ||||||
|  | 			ret = EFI_INVALID_PARAMETER; | ||||||
|  | 			goto out; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		image = (void *)capsule + capsule->item_offset_list[item]; | ||||||
|  | 
 | ||||||
|  | 		if (image->version != 0x00000003) { | ||||||
|  | 			ret = EFI_UNSUPPORTED; | ||||||
|  | 			goto out; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* find a device for update firmware */ | ||||||
|  | 		/* TODO: should we pass index as well, or nothing but type? */ | ||||||
|  | 		fmp = efi_fmp_find(&image->update_image_type_id, | ||||||
|  | 				   image->update_hardware_instance, | ||||||
|  | 				   handles, no_handles); | ||||||
|  | 		if (!fmp) { | ||||||
|  | 			log_err("EFI Capsule: driver not found for firmware type: %pUl, hardware instance: %lld\n", | ||||||
|  | 				&image->update_image_type_id, | ||||||
|  | 				image->update_hardware_instance); | ||||||
|  | 			ret = EFI_UNSUPPORTED; | ||||||
|  | 			goto out; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* do update */ | ||||||
|  | 		image_binary = (void *)image + sizeof(*image); | ||||||
|  | 		vendor_code = image_binary + image->update_image_size; | ||||||
|  | 
 | ||||||
|  | 		abort_reason = NULL; | ||||||
|  | 		ret = EFI_CALL(fmp->set_image(fmp, image->update_image_index, | ||||||
|  | 					      image_binary, | ||||||
|  | 					      image->update_image_size, | ||||||
|  | 					      vendor_code, NULL, | ||||||
|  | 					      &abort_reason)); | ||||||
|  | 		if (ret != EFI_SUCCESS) { | ||||||
|  | 			log_err("EFI Capsule: firmware update failed: %ls\n", | ||||||
|  | 				abort_reason); | ||||||
|  | 			efi_free_pool(abort_reason); | ||||||
|  | 			goto out; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | out: | ||||||
|  | 	efi_free_pool(handles); | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | #else | ||||||
|  | static efi_status_t efi_capsule_update_firmware( | ||||||
|  | 		struct efi_capsule_header *capsule_data) | ||||||
|  | { | ||||||
|  | 	return EFI_UNSUPPORTED; | ||||||
|  | } | ||||||
|  | #endif /* CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT */ | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * efi_update_capsule() - process information from operating system |  * efi_update_capsule() - process information from operating system | ||||||
|  * @capsule_header_array:	Array of virtual address pointers |  * @capsule_header_array:	Array of virtual address pointers | ||||||
|  | @ -118,9 +327,29 @@ efi_status_t EFIAPI efi_update_capsule( | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = EFI_UNSUPPORTED; | 	ret = EFI_SUCCESS; | ||||||
| 	for (i = 0, capsule = *capsule_header_array; i < capsule_count; | 	for (i = 0, capsule = *capsule_header_array; i < capsule_count; | ||||||
| 	     i++, capsule = *(++capsule_header_array)) { | 	     i++, capsule = *(++capsule_header_array)) { | ||||||
|  | 		/* sanity check */ | ||||||
|  | 		if (capsule->header_size < sizeof(*capsule) || | ||||||
|  | 		    capsule->capsule_image_size < sizeof(*capsule)) { | ||||||
|  | 			log_err("EFI: A capsule has not enough data\n"); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		log_debug("Capsule[%d] (guid:%pUl)\n", | ||||||
|  | 			  i, &capsule->capsule_guid); | ||||||
|  | 		if (!guidcmp(&capsule->capsule_guid, | ||||||
|  | 			     &efi_guid_firmware_management_capsule_id)) { | ||||||
|  | 			ret  = efi_capsule_update_firmware(capsule); | ||||||
|  | 		} else { | ||||||
|  | 			log_err("EFI: not support capsule type: %pUl\n", | ||||||
|  | 				&capsule->capsule_guid); | ||||||
|  | 			ret = EFI_UNSUPPORTED; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (ret != EFI_SUCCESS) | ||||||
|  | 			goto out; | ||||||
| 	} | 	} | ||||||
| out: | out: | ||||||
| 	return EFI_EXIT(ret); | 	return EFI_EXIT(ret); | ||||||
|  | @ -265,7 +494,7 @@ static efi_status_t find_boot_device(void) | ||||||
| 	if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) { | 	if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) { | ||||||
| 		/* BootNext does exist here */ | 		/* BootNext does exist here */ | ||||||
| 		if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16)) { | 		if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16)) { | ||||||
| 			printf("BootNext must be 16-bit integer\n"); | 			log_err("BootNext must be 16-bit integer\n"); | ||||||
| 			goto skip; | 			goto skip; | ||||||
| 		} | 		} | ||||||
| 		sprintf((char *)boot_var, "Boot%04X", bootnext); | 		sprintf((char *)boot_var, "Boot%04X", bootnext); | ||||||
|  | @ -323,7 +552,7 @@ out: | ||||||
| 		u16 *path_str; | 		u16 *path_str; | ||||||
| 
 | 
 | ||||||
| 		path_str = efi_dp_str(boot_dev); | 		path_str = efi_dp_str(boot_dev); | ||||||
| 		EFI_PRINT("EFI Capsule: bootdev is %ls\n", path_str); | 		log_debug("EFI Capsule: bootdev is %ls\n", path_str); | ||||||
| 		efi_free_pool(path_str); | 		efi_free_pool(path_str); | ||||||
| 
 | 
 | ||||||
| 		volume = efi_fs_from_path(boot_dev); | 		volume = efi_fs_from_path(boot_dev); | ||||||
|  | @ -363,7 +592,7 @@ static efi_status_t efi_capsule_scan_dir(u16 ***files, unsigned int *num) | ||||||
| 
 | 
 | ||||||
| 	ret = find_boot_device(); | 	ret = find_boot_device(); | ||||||
| 	if (ret == EFI_NOT_FOUND) { | 	if (ret == EFI_NOT_FOUND) { | ||||||
| 		EFI_PRINT("EFI Capsule: bootdev is not set\n"); | 		log_debug("EFI Capsule: bootdev is not set\n"); | ||||||
| 		*num = 0; | 		*num = 0; | ||||||
| 		return EFI_SUCCESS; | 		return EFI_SUCCESS; | ||||||
| 	} else if (ret != EFI_SUCCESS) { | 	} else if (ret != EFI_SUCCESS) { | ||||||
|  | @ -619,20 +848,19 @@ efi_status_t efi_launch_capsules(void) | ||||||
| 
 | 
 | ||||||
| 	/* Launch capsules */ | 	/* Launch capsules */ | ||||||
| 	for (i = 0, ++index; i < nfiles; i++, index++) { | 	for (i = 0, ++index; i < nfiles; i++, index++) { | ||||||
| 		EFI_PRINT("capsule from %ls ...\n", files[i]); | 		log_debug("capsule from %ls ...\n", files[i]); | ||||||
| 		if (index > 0xffff) | 		if (index > 0xffff) | ||||||
| 			index = 0; | 			index = 0; | ||||||
| 		ret = efi_capsule_read_file(files[i], &capsule); | 		ret = efi_capsule_read_file(files[i], &capsule); | ||||||
| 		if (ret == EFI_SUCCESS) { | 		if (ret == EFI_SUCCESS) { | ||||||
| 			ret = EFI_CALL(efi_update_capsule(&capsule, 1, 0)); | 			ret = EFI_CALL(efi_update_capsule(&capsule, 1, 0)); | ||||||
| 			if (ret != EFI_SUCCESS) | 			if (ret != EFI_SUCCESS) | ||||||
| 				printf("EFI Capsule update failed at %ls\n", | 				log_err("EFI Capsule update failed at %ls\n", | ||||||
| 					files[i]); | 					files[i]); | ||||||
| 
 | 
 | ||||||
| 			free(capsule); | 			free(capsule); | ||||||
| 		} else { | 		} else { | ||||||
| 			printf("EFI: reading capsule failed: %ls\n", | 			log_err("EFI: reading capsule failed: %ls\n", files[i]); | ||||||
| 			       files[i]); |  | ||||||
| 		} | 		} | ||||||
| 		/* create CapsuleXXXX */ | 		/* create CapsuleXXXX */ | ||||||
| 		set_capsule_result(index, capsule, ret); | 		set_capsule_result(index, capsule, ret); | ||||||
|  | @ -640,7 +868,7 @@ efi_status_t efi_launch_capsules(void) | ||||||
| 		/* delete a capsule either in case of success or failure */ | 		/* delete a capsule either in case of success or failure */ | ||||||
| 		ret = efi_capsule_delete_file(files[i]); | 		ret = efi_capsule_delete_file(files[i]); | ||||||
| 		if (ret != EFI_SUCCESS) | 		if (ret != EFI_SUCCESS) | ||||||
| 			printf("EFI: deleting a capsule file failed: %ls\n", | 			log_err("EFI: deleting a capsule file failed: %ls\n", | ||||||
| 				files[i]); | 				files[i]); | ||||||
| 	} | 	} | ||||||
| 	efi_capsule_scan_done(); | 	efi_capsule_scan_done(); | ||||||
|  |  | ||||||
|  | @ -159,6 +159,10 @@ static efi_status_t efi_init_os_indications(void) | ||||||
| 		os_indications_supported |= | 		os_indications_supported |= | ||||||
| 			EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED; | 			EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED; | ||||||
| 
 | 
 | ||||||
|  | 	if (IS_ENABLED(CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT)) | ||||||
|  | 		os_indications_supported |= | ||||||
|  | 			EFI_OS_INDICATIONS_FMP_CAPSULE_SUPPORTED; | ||||||
|  | 
 | ||||||
| 	return efi_set_variable_int(L"OsIndicationsSupported", | 	return efi_set_variable_int(L"OsIndicationsSupported", | ||||||
| 				    &efi_global_variable_guid, | 				    &efi_global_variable_guid, | ||||||
| 				    EFI_VARIABLE_BOOTSERVICE_ACCESS | | 				    EFI_VARIABLE_BOOTSERVICE_ACCESS | | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue