Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 82c3768b authored by Ard Biesheuvel's avatar Ard Biesheuvel Committed by Ingo Molnar
Browse files

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: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: default avatarMatt 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: default avatarIngo Molnar <mingo@kernel.org>
parent 41b0c376
Loading
Loading
Loading
Loading
+17 −24
Original line number Original line Diff line number Diff line
@@ -21,7 +21,7 @@
#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;
@@ -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");