forked from mirrors/linux
		
	efi/capsule-loader: Use a cached copy of the capsule header
Instead of kmapping the capsule data twice, copy the capsule header into the capsule info struct we keep locally. This is an improvement by itself, but will also enable handling of non-standard header formats more easily. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Reviewed-by: Matt Fleming <matt@codeblueprint.co.uk> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/20170602135207.21708-7-ard.biesheuvel@linaro.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
		
							parent
							
								
									41b0c37695
								
							
						
					
					
						commit
						82c3768b8d
					
				
					 1 changed files with 17 additions and 24 deletions
				
			
		| 
						 | 
					@ -21,13 +21,13 @@
 | 
				
			||||||
#define NO_FURTHER_WRITE_ACTION -1
 | 
					#define NO_FURTHER_WRITE_ACTION -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct capsule_info {
 | 
					struct capsule_info {
 | 
				
			||||||
	bool		header_obtained;
 | 
						efi_capsule_header_t	header;
 | 
				
			||||||
	int		reset_type;
 | 
						int			reset_type;
 | 
				
			||||||
	long		index;
 | 
						long			index;
 | 
				
			||||||
	size_t		count;
 | 
						size_t			count;
 | 
				
			||||||
	size_t		total_size;
 | 
						size_t			total_size;
 | 
				
			||||||
	struct page	**pages;
 | 
						struct page		**pages;
 | 
				
			||||||
	size_t		page_bytes_remain;
 | 
						size_t			page_bytes_remain;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -56,7 +56,6 @@ static void efi_free_all_buff_pages(struct capsule_info *cap_info)
 | 
				
			||||||
static int efi_capsule_setup_info(struct capsule_info *cap_info,
 | 
					static int efi_capsule_setup_info(struct capsule_info *cap_info,
 | 
				
			||||||
				  void *kbuff, size_t hdr_bytes)
 | 
									  void *kbuff, size_t hdr_bytes)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	efi_capsule_header_t *cap_hdr;
 | 
					 | 
				
			||||||
	size_t pages_needed;
 | 
						size_t pages_needed;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
	void *temp_page;
 | 
						void *temp_page;
 | 
				
			||||||
| 
						 | 
					@ -66,8 +65,9 @@ static int efi_capsule_setup_info(struct capsule_info *cap_info,
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Reset back to the correct offset of header */
 | 
						/* Reset back to the correct offset of header */
 | 
				
			||||||
	cap_hdr = kbuff - cap_info->count;
 | 
						kbuff -= cap_info->count;
 | 
				
			||||||
	pages_needed = ALIGN(cap_hdr->imagesize, PAGE_SIZE) >> PAGE_SHIFT;
 | 
						memcpy(&cap_info->header, kbuff, sizeof(cap_info->header));
 | 
				
			||||||
 | 
						pages_needed = ALIGN(cap_info->header.imagesize, PAGE_SIZE) / PAGE_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pages_needed == 0) {
 | 
						if (pages_needed == 0) {
 | 
				
			||||||
		pr_err("invalid capsule size");
 | 
							pr_err("invalid capsule size");
 | 
				
			||||||
| 
						 | 
					@ -75,15 +75,16 @@ static int efi_capsule_setup_info(struct capsule_info *cap_info,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check if the capsule binary supported */
 | 
						/* Check if the capsule binary supported */
 | 
				
			||||||
	ret = efi_capsule_supported(cap_hdr->guid, cap_hdr->flags,
 | 
						ret = efi_capsule_supported(cap_info->header.guid,
 | 
				
			||||||
				    cap_hdr->imagesize,
 | 
									    cap_info->header.flags,
 | 
				
			||||||
 | 
									    cap_info->header.imagesize,
 | 
				
			||||||
				    &cap_info->reset_type);
 | 
									    &cap_info->reset_type);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
		pr_err("capsule not supported\n");
 | 
							pr_err("capsule not supported\n");
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cap_info->total_size = cap_hdr->imagesize;
 | 
						cap_info->total_size = cap_info->header.imagesize;
 | 
				
			||||||
	temp_page = krealloc(cap_info->pages,
 | 
						temp_page = krealloc(cap_info->pages,
 | 
				
			||||||
			     pages_needed * sizeof(void *),
 | 
								     pages_needed * sizeof(void *),
 | 
				
			||||||
			     GFP_KERNEL | __GFP_ZERO);
 | 
								     GFP_KERNEL | __GFP_ZERO);
 | 
				
			||||||
| 
						 | 
					@ -91,7 +92,6 @@ static int efi_capsule_setup_info(struct capsule_info *cap_info,
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cap_info->pages = temp_page;
 | 
						cap_info->pages = temp_page;
 | 
				
			||||||
	cap_info->header_obtained = true;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -104,15 +104,8 @@ static int efi_capsule_setup_info(struct capsule_info *cap_info,
 | 
				
			||||||
static ssize_t efi_capsule_submit_update(struct capsule_info *cap_info)
 | 
					static ssize_t efi_capsule_submit_update(struct capsule_info *cap_info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
	void *cap_hdr_temp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cap_hdr_temp = vmap(cap_info->pages, cap_info->index,
 | 
						ret = efi_capsule_update(&cap_info->header, cap_info->pages);
 | 
				
			||||||
			VM_MAP, PAGE_KERNEL);
 | 
					 | 
				
			||||||
	if (!cap_hdr_temp)
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = efi_capsule_update(cap_hdr_temp, cap_info->pages);
 | 
					 | 
				
			||||||
	vunmap(cap_hdr_temp);
 | 
					 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
		pr_err("capsule update failed\n");
 | 
							pr_err("capsule update failed\n");
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
| 
						 | 
					@ -192,7 +185,7 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
 | 
				
			||||||
	cap_info->page_bytes_remain -= write_byte;
 | 
						cap_info->page_bytes_remain -= write_byte;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Setup capsule binary info structure */
 | 
						/* Setup capsule binary info structure */
 | 
				
			||||||
	if (!cap_info->header_obtained) {
 | 
						if (cap_info->header.headersize == 0) {
 | 
				
			||||||
		ret = efi_capsule_setup_info(cap_info, kbuff,
 | 
							ret = efi_capsule_setup_info(cap_info, kbuff,
 | 
				
			||||||
					     cap_info->count + write_byte);
 | 
										     cap_info->count + write_byte);
 | 
				
			||||||
		if (ret)
 | 
							if (ret)
 | 
				
			||||||
| 
						 | 
					@ -203,7 +196,7 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
 | 
				
			||||||
	kunmap(page);
 | 
						kunmap(page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Submit the full binary to efi_capsule_update() API */
 | 
						/* Submit the full binary to efi_capsule_update() API */
 | 
				
			||||||
	if (cap_info->header_obtained &&
 | 
						if (cap_info->header.headersize > 0 &&
 | 
				
			||||||
	    cap_info->count >= cap_info->total_size) {
 | 
						    cap_info->count >= cap_info->total_size) {
 | 
				
			||||||
		if (cap_info->count > cap_info->total_size) {
 | 
							if (cap_info->count > cap_info->total_size) {
 | 
				
			||||||
			pr_err("capsule upload size exceeded header defined size\n");
 | 
								pr_err("capsule upload size exceeded header defined size\n");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue