forked from mirrors/linux
		
	efi/capsule-loader: Use page addresses rather than struct page pointers
To give some leeway to code that handles non-standard capsule headers, let's keep an array of page addresses rather than struct page pointers. This gives special implementations of efi_capsule_setup_info() the opportunity to mangle the payload a bit before it is presented to the firmware, without putting any knowledge of the nature of such quirks into the generic code. Tested-by: Bryan O'Donoghue <pure.logic@nexus-software.ie> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Matt Fleming <matt@codeblueprint.co.uk> 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-10-ard.biesheuvel@linaro.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
		
							parent
							
								
									3fabd628d5
								
							
						
					
					
						commit
						2a457fb31d
					
				
					 3 changed files with 14 additions and 9 deletions
				
			
		| 
						 | 
					@ -20,6 +20,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NO_FURTHER_WRITE_ACTION -1
 | 
					#define NO_FURTHER_WRITE_ACTION -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef phys_to_page
 | 
				
			||||||
 | 
					#define phys_to_page(x)		pfn_to_page((x) >> PAGE_SHIFT)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * efi_free_all_buff_pages - free all previous allocated buffer pages
 | 
					 * efi_free_all_buff_pages - free all previous allocated buffer pages
 | 
				
			||||||
 * @cap_info: pointer to current instance of capsule_info structure
 | 
					 * @cap_info: pointer to current instance of capsule_info structure
 | 
				
			||||||
| 
						 | 
					@ -31,7 +35,7 @@
 | 
				
			||||||
static void efi_free_all_buff_pages(struct capsule_info *cap_info)
 | 
					static void efi_free_all_buff_pages(struct capsule_info *cap_info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	while (cap_info->index > 0)
 | 
						while (cap_info->index > 0)
 | 
				
			||||||
		__free_page(cap_info->pages[--cap_info->index]);
 | 
							__free_page(phys_to_page(cap_info->pages[--cap_info->index]));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cap_info->index = NO_FURTHER_WRITE_ACTION;
 | 
						cap_info->index = NO_FURTHER_WRITE_ACTION;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -161,12 +165,12 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
 | 
				
			||||||
			goto failed;
 | 
								goto failed;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cap_info->pages[cap_info->index++] = page;
 | 
							cap_info->pages[cap_info->index++] = page_to_phys(page);
 | 
				
			||||||
		cap_info->page_bytes_remain = PAGE_SIZE;
 | 
							cap_info->page_bytes_remain = PAGE_SIZE;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							page = phys_to_page(cap_info->pages[cap_info->index - 1]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	page = cap_info->pages[cap_info->index - 1];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	kbuff = kmap(page);
 | 
						kbuff = kmap(page);
 | 
				
			||||||
	kbuff += PAGE_SIZE - cap_info->page_bytes_remain;
 | 
						kbuff += PAGE_SIZE - cap_info->page_bytes_remain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -214,7 +214,7 @@ efi_capsule_update_locked(efi_capsule_header_t *capsule,
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Return 0 on success, a converted EFI status code on failure.
 | 
					 * Return 0 on success, a converted EFI status code on failure.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int efi_capsule_update(efi_capsule_header_t *capsule, struct page **pages)
 | 
					int efi_capsule_update(efi_capsule_header_t *capsule, phys_addr_t *pages)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 imagesize = capsule->imagesize;
 | 
						u32 imagesize = capsule->imagesize;
 | 
				
			||||||
	efi_guid_t guid = capsule->guid;
 | 
						efi_guid_t guid = capsule->guid;
 | 
				
			||||||
| 
						 | 
					@ -249,10 +249,11 @@ int efi_capsule_update(efi_capsule_header_t *capsule, struct page **pages)
 | 
				
			||||||
		sglist = kmap(sg_pages[i]);
 | 
							sglist = kmap(sg_pages[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (j = 0; j < SGLIST_PER_PAGE && count > 0; j++) {
 | 
							for (j = 0; j < SGLIST_PER_PAGE && count > 0; j++) {
 | 
				
			||||||
			u64 sz = min_t(u64, imagesize, PAGE_SIZE);
 | 
								u64 sz = min_t(u64, imagesize,
 | 
				
			||||||
 | 
									       PAGE_SIZE - (u64)*pages % PAGE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			sglist[j].length = sz;
 | 
								sglist[j].length = sz;
 | 
				
			||||||
			sglist[j].data = page_to_phys(*pages++);
 | 
								sglist[j].data = *pages++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			imagesize -= sz;
 | 
								imagesize -= sz;
 | 
				
			||||||
			count--;
 | 
								count--;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -143,7 +143,7 @@ struct capsule_info {
 | 
				
			||||||
	long			index;
 | 
						long			index;
 | 
				
			||||||
	size_t			count;
 | 
						size_t			count;
 | 
				
			||||||
	size_t			total_size;
 | 
						size_t			total_size;
 | 
				
			||||||
	struct page		**pages;
 | 
						phys_addr_t		*pages;
 | 
				
			||||||
	size_t			page_bytes_remain;
 | 
						size_t			page_bytes_remain;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1415,7 +1415,7 @@ extern int efi_capsule_supported(efi_guid_t guid, u32 flags,
 | 
				
			||||||
				 size_t size, int *reset);
 | 
									 size_t size, int *reset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int efi_capsule_update(efi_capsule_header_t *capsule,
 | 
					extern int efi_capsule_update(efi_capsule_header_t *capsule,
 | 
				
			||||||
			      struct page **pages);
 | 
								      phys_addr_t *pages);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_EFI_RUNTIME_MAP
 | 
					#ifdef CONFIG_EFI_RUNTIME_MAP
 | 
				
			||||||
int efi_runtime_map_init(struct kobject *);
 | 
					int efi_runtime_map_init(struct kobject *);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue