Commit 162b246e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull EFI updates from Ingo Molnar:
 "The main changes in this cycle were:

   - Rework the EFI capsule loader to allow for workarounds for
     non-compliant firmware (Ard Biesheuvel)

   - Implement a capsule loader quirk for Quark X102x (Jan Kiszka)

   - Enable SMBIOS/DMI support for the ARM architecture (Ard Biesheuvel)

   - Add CONFIG_EFI_PGT_DUMP=y support for x86-32 and kexec (Sai
     Praneeth)

   - Fixes for EFI support for Xen dom0 guests running under x86-64
     hosts (Daniel Kiper)"

* 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/xen/efi: Initialize only the EFI struct members used by Xen
  efi: Process the MEMATTR table only if EFI_MEMMAP is enabled
  efi/arm: Enable DMI/SMBIOS
  x86/efi: Extend CONFIG_EFI_PGT_DUMP support to x86_32 and kexec as well
  efi/efi_test: Use memdup_user() helper
  efi/capsule: Add support for Quark security header
  efi/capsule-loader: Use page addresses rather than struct page pointers
  efi/capsule-loader: Redirect calls to efi_capsule_setup_info() via weak alias
  efi/capsule: Remove NULL test on kmap()
  efi/capsule-loader: Use a cached copy of the capsule header
  efi/capsule: Adjust return type of efi_capsule_setup_info()
  efi/capsule: Clean up pr_err/_info() messages
  efi/capsule: Remove pr_debug() on ENOMEM or EFAULT
  efi/capsule: Fix return code on failing kmap/vmap
parents 330e9e46 6c64447e
...@@ -2062,6 +2062,23 @@ config EFI ...@@ -2062,6 +2062,23 @@ config EFI
is only useful for kernels that may run on systems that have is only useful for kernels that may run on systems that have
UEFI firmware. UEFI firmware.
config DMI
bool "Enable support for SMBIOS (DMI) tables"
depends on EFI
default y
help
This enables SMBIOS/DMI feature for systems.
This option is only useful on systems that have UEFI firmware.
However, even with this option, the resultant kernel should
continue to boot on existing non-UEFI platforms.
NOTE: This does *NOT* enable or encourage the use of DMI quirks,
i.e., the the practice of identifying the platform via DMI to
decide whether certain workarounds for buggy hardware and/or
firmware need to be enabled. This would require the DMI subsystem
to be enabled much earlier than we do on ARM, which is non-trivial.
endmenu endmenu
menu "CPU Power Management" menu "CPU Power Management"
......
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_DMI_H
#define __ASM_DMI_H
#include <linux/io.h>
#include <linux/slab.h>
#define dmi_early_remap(x, l) memremap(x, l, MEMREMAP_WB)
#define dmi_early_unmap(x, l) memunmap(x)
#define dmi_remap(x, l) memremap(x, l, MEMREMAP_WB)
#define dmi_unmap(x) memunmap(x)
#define dmi_alloc(l) kzalloc(l, GFP_KERNEL)
#endif
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
* *
*/ */
#include <linux/dmi.h>
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -117,20 +116,6 @@ int __init efi_set_mapping_permissions(struct mm_struct *mm, ...@@ -117,20 +116,6 @@ int __init efi_set_mapping_permissions(struct mm_struct *mm,
set_permissions, md); set_permissions, md);
} }
static int __init arm64_dmi_init(void)
{
/*
* On arm64, DMI depends on UEFI, and dmi_scan_machine() needs to
* be called early because dmi_id_init(), which is an arch_initcall
* itself, depends on dmi_scan_machine() having been called already.
*/
dmi_scan_machine();
if (dmi_available)
dmi_set_dump_stack_arch_desc();
return 0;
}
core_initcall(arm64_dmi_init);
/* /*
* UpdateCapsule() depends on the system being shutdown via * UpdateCapsule() depends on the system being shutdown via
* ResetSystem(). * ResetSystem().
......
...@@ -1014,7 +1014,6 @@ static void __init __efi_enter_virtual_mode(void) ...@@ -1014,7 +1014,6 @@ static void __init __efi_enter_virtual_mode(void)
* necessary relocation fixups for the new virtual addresses. * necessary relocation fixups for the new virtual addresses.
*/ */
efi_runtime_update_mappings(); efi_runtime_update_mappings();
efi_dump_pagetable();
/* clean DUMMY object */ /* clean DUMMY object */
efi_delete_dummy_variable(); efi_delete_dummy_variable();
...@@ -1029,6 +1028,8 @@ void __init efi_enter_virtual_mode(void) ...@@ -1029,6 +1028,8 @@ void __init efi_enter_virtual_mode(void)
kexec_enter_virtual_mode(); kexec_enter_virtual_mode();
else else
__efi_enter_virtual_mode(); __efi_enter_virtual_mode();
efi_dump_pagetable();
} }
/* /*
......
...@@ -44,7 +44,14 @@ int __init efi_alloc_page_tables(void) ...@@ -44,7 +44,14 @@ int __init efi_alloc_page_tables(void)
} }
void efi_sync_low_kernel_mappings(void) {} void efi_sync_low_kernel_mappings(void) {}
void __init efi_dump_pagetable(void) {}
void __init efi_dump_pagetable(void)
{
#ifdef CONFIG_EFI_PGT_DUMP
ptdump_walk_pgd_level(NULL, swapper_pg_dir);
#endif
}
int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
{ {
return 0; return 0;
......
...@@ -589,7 +589,10 @@ void __init efi_runtime_update_mappings(void) ...@@ -589,7 +589,10 @@ void __init efi_runtime_update_mappings(void)
void __init efi_dump_pagetable(void) void __init efi_dump_pagetable(void)
{ {
#ifdef CONFIG_EFI_PGT_DUMP #ifdef CONFIG_EFI_PGT_DUMP
ptdump_walk_pgd_level(NULL, efi_pgd); if (efi_enabled(EFI_OLD_MEMMAP))
ptdump_walk_pgd_level(NULL, swapper_pg_dir);
else
ptdump_walk_pgd_level(NULL, efi_pgd);
#endif #endif
} }
......
...@@ -15,12 +15,66 @@ ...@@ -15,12 +15,66 @@
#include <asm/e820/api.h> #include <asm/e820/api.h>
#include <asm/efi.h> #include <asm/efi.h>
#include <asm/uv/uv.h> #include <asm/uv/uv.h>
#include <asm/cpu_device_id.h>
#define EFI_MIN_RESERVE 5120 #define EFI_MIN_RESERVE 5120
#define EFI_DUMMY_GUID \ #define EFI_DUMMY_GUID \
EFI_GUID(0x4424ac57, 0xbe4b, 0x47dd, 0x9e, 0x97, 0xed, 0x50, 0xf0, 0x9f, 0x92, 0xa9) EFI_GUID(0x4424ac57, 0xbe4b, 0x47dd, 0x9e, 0x97, 0xed, 0x50, 0xf0, 0x9f, 0x92, 0xa9)
#define QUARK_CSH_SIGNATURE 0x5f435348 /* _CSH */
#define QUARK_SECURITY_HEADER_SIZE 0x400
/*
* Header prepended to the standard EFI capsule on Quark systems the are based
* on Intel firmware BSP.
* @csh_signature: Unique identifier to sanity check signed module
* presence ("_CSH").
* @version: Current version of CSH used. Should be one for Quark A0.
* @modulesize: Size of the entire module including the module header
* and payload.
* @security_version_number_index: Index of SVN to use for validation of signed
* module.
* @security_version_number: Used to prevent against roll back of modules.
* @rsvd_module_id: Currently unused for Clanton (Quark).
* @rsvd_module_vendor: Vendor Identifier. For Intel products value is
* 0x00008086.
* @rsvd_date: BCD representation of build date as yyyymmdd, where
* yyyy=4 digit year, mm=1-12, dd=1-31.
* @headersize: Total length of the header including including any
* padding optionally added by the signing tool.
* @hash_algo: What Hash is used in the module signing.
* @cryp_algo: What Crypto is used in the module signing.
* @keysize: Total length of the key data including including any
* padding optionally added by the signing tool.
* @signaturesize: Total length of the signature including including any
* padding optionally added by the signing tool.
* @rsvd_next_header: 32-bit pointer to the next Secure Boot Module in the
* chain, if there is a next header.
* @rsvd: Reserved, padding structure to required size.
*
* See also QuartSecurityHeader_t in
* Quark_EDKII_v1.2.1.1/QuarkPlatformPkg/Include/QuarkBootRom.h
* from https://downloadcenter.intel.com/download/23197/Intel-Quark-SoC-X1000-Board-Support-Package-BSP
*/
struct quark_security_header {
u32 csh_signature;
u32 version;
u32 modulesize;
u32 security_version_number_index;
u32 security_version_number;
u32 rsvd_module_id;
u32 rsvd_module_vendor;
u32 rsvd_date;
u32 headersize;
u32 hash_algo;
u32 cryp_algo;
u32 keysize;
u32 signaturesize;
u32 rsvd_next_header;
u32 rsvd[2];
};
static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 }; static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 };
static bool efi_no_storage_paranoia; static bool efi_no_storage_paranoia;
...@@ -504,3 +558,86 @@ bool efi_poweroff_required(void) ...@@ -504,3 +558,86 @@ bool efi_poweroff_required(void)
{ {
return acpi_gbl_reduced_hardware || acpi_no_s5; return acpi_gbl_reduced_hardware || acpi_no_s5;
} }
#ifdef CONFIG_EFI_CAPSULE_QUIRK_QUARK_CSH
static int qrk_capsule_setup_info(struct capsule_info *cap_info, void **pkbuff,
size_t hdr_bytes)
{
struct quark_security_header *csh = *pkbuff;
/* Only process data block that is larger than the security header */
if (hdr_bytes < sizeof(struct quark_security_header))
return 0;
if (csh->csh_signature != QUARK_CSH_SIGNATURE ||
csh->headersize != QUARK_SECURITY_HEADER_SIZE)
return 1;
/* Only process data block if EFI header is included */
if (hdr_bytes < QUARK_SECURITY_HEADER_SIZE +
sizeof(efi_capsule_header_t))
return 0;
pr_debug("Quark security header detected\n");
if (csh->rsvd_next_header != 0) {
pr_err("multiple Quark security headers not supported\n");
return -EINVAL;
}
*pkbuff += csh->headersize;
cap_info->total_size = csh->headersize;
/*
* Update the first page pointer to skip over the CSH header.
*/
cap_info->pages[0] += csh->headersize;
return 1;
}
#define ICPU(family, model, quirk_handler) \
{ X86_VENDOR_INTEL, family, model, X86_FEATURE_ANY, \
(unsigned long)&quirk_handler }
static const struct x86_cpu_id efi_capsule_quirk_ids[] = {
ICPU(5, 9, qrk_capsule_setup_info), /* Intel Quark X1000 */
{ }
};
int efi_capsule_setup_info(struct capsule_info *cap_info, void *kbuff,
size_t hdr_bytes)
{
int (*quirk_handler)(struct capsule_info *, void **, size_t);
const struct x86_cpu_id *id;
int ret;
if (hdr_bytes < sizeof(efi_capsule_header_t))
return 0;
cap_info->total_size = 0;
id = x86_match_cpu(efi_capsule_quirk_ids);
if (id) {
/*
* The quirk handler is supposed to return
* - a value > 0 if the setup should continue, after advancing
* kbuff as needed
* - 0 if not enough hdr_bytes are available yet
* - a negative error code otherwise
*/
quirk_handler = (typeof(quirk_handler))id->driver_data;
ret = quirk_handler(cap_info, &kbuff, hdr_bytes);
if (ret <= 0)
return ret;
}
memcpy(&cap_info->header, kbuff, sizeof(cap_info->header));
cap_info->total_size += cap_info->header.imagesize;
return __efi_capsule_setup_info(cap_info);
}
#endif
...@@ -54,38 +54,6 @@ static efi_system_table_t efi_systab_xen __initdata = { ...@@ -54,38 +54,6 @@ static efi_system_table_t efi_systab_xen __initdata = {
.tables = EFI_INVALID_TABLE_ADDR /* Initialized later. */ .tables = EFI_INVALID_TABLE_ADDR /* Initialized later. */
}; };
static const struct efi efi_xen __initconst = {
.systab = NULL, /* Initialized later. */
.runtime_version = 0, /* Initialized later. */
.mps = EFI_INVALID_TABLE_ADDR,
.acpi = EFI_INVALID_TABLE_ADDR,
.acpi20 = EFI_INVALID_TABLE_ADDR,
.smbios = EFI_INVALID_TABLE_ADDR,
.smbios3 = EFI_INVALID_TABLE_ADDR,
.sal_systab = EFI_INVALID_TABLE_ADDR,
.boot_info = EFI_INVALID_TABLE_ADDR,
.hcdp = EFI_INVALID_TABLE_ADDR,
.uga = EFI_INVALID_TABLE_ADDR,
.uv_systab = EFI_INVALID_TABLE_ADDR,
.fw_vendor = EFI_INVALID_TABLE_ADDR,
.runtime = EFI_INVALID_TABLE_ADDR,
.config_table = EFI_INVALID_TABLE_ADDR,
.get_time = xen_efi_get_time,
.set_time = xen_efi_set_time,
.get_wakeup_time = xen_efi_get_wakeup_time,
.set_wakeup_time = xen_efi_set_wakeup_time,
.get_variable = xen_efi_get_variable,
.get_next_variable = xen_efi_get_next_variable,
.set_variable = xen_efi_set_variable,
.query_variable_info = xen_efi_query_variable_info,
.update_capsule = xen_efi_update_capsule,
.query_capsule_caps = xen_efi_query_capsule_caps,
.get_next_high_mono_count = xen_efi_get_next_high_mono_count,
.reset_system = xen_efi_reset_system,
.set_virtual_address_map = NULL, /* Not used under Xen. */
.flags = 0 /* Initialized later. */
};
static efi_system_table_t __init *xen_efi_probe(void) static efi_system_table_t __init *xen_efi_probe(void)
{ {
struct xen_platform_op op = { struct xen_platform_op op = {
...@@ -102,7 +70,18 @@ static efi_system_table_t __init *xen_efi_probe(void) ...@@ -102,7 +70,18 @@ static efi_system_table_t __init *xen_efi_probe(void)
/* Here we know that Xen runs on EFI platform. */ /* Here we know that Xen runs on EFI platform. */
efi = efi_xen; efi.get_time = xen_efi_get_time;
efi.set_time = xen_efi_set_time;
efi.get_wakeup_time = xen_efi_get_wakeup_time;
efi.set_wakeup_time = xen_efi_set_wakeup_time;
efi.get_variable = xen_efi_get_variable;
efi.get_next_variable = xen_efi_get_next_variable;
efi.set_variable = xen_efi_set_variable;
efi.query_variable_info = xen_efi_query_variable_info;
efi.update_capsule = xen_efi_update_capsule;
efi.query_capsule_caps = xen_efi_query_capsule_caps;
efi.get_next_high_mono_count = xen_efi_get_next_high_mono_count;
efi.reset_system = xen_efi_reset_system;
efi_systab_xen.tables = info->cfg.addr; efi_systab_xen.tables = info->cfg.addr;
efi_systab_xen.nr_tables = info->cfg.nent; efi_systab_xen.nr_tables = info->cfg.nent;
......
...@@ -112,6 +112,15 @@ config EFI_CAPSULE_LOADER ...@@ -112,6 +112,15 @@ config EFI_CAPSULE_LOADER
Most users should say N. Most users should say N.
config EFI_CAPSULE_QUIRK_QUARK_CSH
boolean "Add support for Quark capsules with non-standard headers"
depends on X86 && !64BIT
select EFI_CAPSULE_LOADER
default y
help
Add support for processing Quark X1000 EFI capsules, whose header
layout deviates from the layout mandated by the UEFI specification.
config EFI_TEST config EFI_TEST
tristate "EFI Runtime Service Tests Support" tristate "EFI Runtime Service Tests Support"
depends on EFI depends on EFI
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* *
*/ */
#include <linux/dmi.h>
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/memblock.h> #include <linux/memblock.h>
...@@ -166,3 +167,18 @@ void efi_virtmap_unload(void) ...@@ -166,3 +167,18 @@ void efi_virtmap_unload(void)
efi_set_pgd(current->active_mm); efi_set_pgd(current->active_mm);
preempt_enable(); preempt_enable();
} }
static int __init arm_dmi_init(void)
{
/*
* On arm64/ARM, DMI depends on UEFI, and dmi_scan_machine() needs to
* be called early because dmi_id_init(), which is an arch_initcall
* itself, depends on dmi_scan_machine() having been called already.
*/
dmi_scan_machine();
if (dmi_available)
dmi_set_dump_stack_arch_desc();
return 0;
}
core_initcall(arm_dmi_init);
...@@ -20,15 +20,9 @@ ...@@ -20,15 +20,9 @@
#define NO_FURTHER_WRITE_ACTION -1 #define NO_FURTHER_WRITE_ACTION -1
struct capsule_info { #ifndef phys_to_page
bool header_obtained; #define phys_to_page(x) pfn_to_page((x) >> PAGE_SHIFT)
int reset_type; #endif
long index;
size_t count;
size_t total_size;
struct page **pages;
size_t page_bytes_remain;
};
/** /**
* efi_free_all_buff_pages - free all previous allocated buffer pages * efi_free_all_buff_pages - free all previous allocated buffer pages
...@@ -41,64 +35,69 @@ struct capsule_info { ...@@ -41,64 +35,69 @@ struct capsule_info {
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;
} }
/** int __efi_capsule_setup_info(struct capsule_info *cap_info)
* efi_capsule_setup_info - obtain the efi capsule header in the binary and
* setup capsule_info structure
* @cap_info: pointer to current instance of capsule_info structure
* @kbuff: a mapped first page buffer pointer
* @hdr_bytes: the total received number of bytes for efi header
**/
static ssize_t efi_capsule_setup_info(struct capsule_info *cap_info,
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;
/* Only process data block that is larger than efi header size */ pages_needed = ALIGN(cap_info->total_size, PAGE_SIZE) / PAGE_SIZE;
if (hdr_bytes < sizeof(efi_capsule_header_t))
return 0;
/* Reset back to the correct offset of header */
cap_hdr = kbuff - cap_info->count;
pages_needed = ALIGN(cap_hdr->imagesize, PAGE_SIZE) >> PAGE_SHIFT;
if (pages_needed == 0) { if (pages_needed == 0) {
pr_err("%s: pages count invalid\n", __func__); pr_err("invalid capsule size");
return -EINVAL; return -EINVAL;
} }
/* 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("%s: efi_capsule_supported() failed\n", pr_err("capsule not supported\n");
__func__);
return ret; return ret;
} }
cap_info->total_size = cap_hdr->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);
if (!temp_page) { if (!temp_page)
pr_debug("%s: krealloc() failed\n", __func__);
return -ENOMEM; return -ENOMEM;
}
cap_info->pages = temp_page; cap_info->pages = temp_page;
cap_info->header_obtained = true;
return 0; return 0;
} }
/**
* efi_capsule_setup_info - obtain the efi capsule header in the binary and
* setup capsule_info structure
* @cap_info: pointer to current instance of capsule_info structure
* @kbuff: a mapped first page buffer pointer
* @hdr_bytes: the total received number of bytes for efi header
*
* Platforms with non-standard capsule update mechanisms can override
* this __weak function so they can perform any required capsule
* image munging. See quark_quirk_function() for an example.
**/
int __weak efi_capsule_setup_info(struct capsule_info *cap_info, void *kbuff,
size_t hdr_bytes)
{
/* Only process data block that is larger than efi header size */
if (hdr_bytes < sizeof(efi_capsule_header_t))
return 0;
memcpy(&cap_info->header, kbuff, sizeof(cap_info->header));
cap_info->total_size = cap_info->header.imagesize;
return __efi_capsule_setup_info(cap_info);
}
/** /**
* efi_capsule_submit_update - invoke the efi_capsule_update API once binary * efi_capsule_submit_update - invoke the efi_capsule_update API once binary
* upload done * upload done
...@@ -107,26 +106,17 @@ static ssize_t efi_capsule_setup_info(struct capsule_info *cap_info, ...@@ -107,26 +106,17 @@ static ssize_t 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,
VM_MAP, PAGE_KERNEL);
if (!cap_hdr_temp) {
pr_debug("%s: vmap() failed\n", __func__);
return -EFAULT;
}
ret = efi_capsule_update(cap_hdr_temp, cap_info->pages); ret = efi_capsule_update(&cap_info->header, cap_info->pages);
vunmap(cap_hdr_temp);
if (ret) { if (ret) {
pr_err("%s: efi_capsule_update() failed\n", __func__); pr_err("capsule update failed\n");
return ret; return ret;
} }
/* Indicate capsule binary uploading is done */ /* Indicate capsule binary uploading is done */
cap_info->index = NO_FURTHER_WRITE_ACTION; cap_info->index = NO_FURTHER_WRITE_ACTION;
pr_info("%s: Successfully upload capsule file with reboot type '%s'\n", pr_info("Successfully upload capsule file with reboot type '%s'\n",
__func__, !cap_info->reset_type ? "RESET_COLD" : !cap_info->reset_type ? "RESET_COLD" :
cap_info->reset_type == 1 ? "RESET_WARM" : cap_info->reset_type == 1 ? "RESET_WARM" :
"RESET_SHUTDOWN"); "RESET_SHUTDOWN");
return 0; return 0;
...@@ -171,37 +161,30 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff, ...@@ -171,37 +161,30 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
if (!cap_info->page_bytes_remain) { if (!cap_info->page_bytes_remain) {
page = alloc_page(GFP_KERNEL); page = alloc_page(GFP_KERNEL);
if (!page) { if (!page) {
pr_debug("%s: alloc_page() failed\n", __func__);
ret = -ENOMEM; ret = -ENOMEM;
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);
if (!kbuff) {
pr_debug("%s: kmap() failed\n", __func__);
ret = -EFAULT;
goto failed;
}
kbuff += PAGE_SIZE - cap_info->page_bytes_remain; kbuff += PAGE_SIZE - cap_info->page_bytes_remain;
/* Copy capsule binary data from user space to kernel space buffer */ /* Copy capsule binary data from user space to kernel space buffer */
write_byte = min_t(size_t, count, cap_info->page_bytes_remain); write_byte = min_t(size_t, count, cap_info->page_bytes_remain);
if (copy_from_user(kbuff, buff, write_byte)) { if (copy_from_user(kbuff, buff, write_byte)) {
pr_debug("%s: copy_from_user() failed\n", __func__);
ret = -EFAULT; ret = -EFAULT;
goto fail_unmap; goto fail_unmap;
} }
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,
cap_info->count + write_byte); cap_info->count + write_byte);
if (ret) if (ret)
goto fail_unmap; goto fail_unmap;
...@@ -211,11 +194,10 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff, ...@@ -211,11 +194,10 @@ 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("%s: upload size exceeded header defined size\n", pr_err("capsule upload size exceeded header defined size\n");
__func__);
ret = -EINVAL; ret = -EINVAL;
goto failed; goto failed;
} }
...@@ -249,7 +231,7 @@ static int efi_capsule_flush(struct file *file, fl_owner_t id) ...@@ -249,7 +231,7 @@ static int efi_capsule_flush(struct file *file, fl_owner_t id)
struct capsule_info *cap_info = file->private_data; struct capsule_info *cap_info = file->private_data;
if (cap_info->index > 0) { if (cap_info->index > 0) {
pr_err("%s: capsule upload not complete\n", __func__); pr_err("capsule upload not complete\n");
efi_free_all_buff_pages(cap_info); efi_free_all_buff_pages(cap_info);
ret = -ECANCELED; ret = -ECANCELED;
} }
...@@ -328,8 +310,7 @@ static int __init efi_capsule_loader_init(void) ...@@ -328,8 +310,7 @@ static int __init efi_capsule_loader_init(void)
ret = misc_register(&efi_capsule_misc); ret = misc_register(&efi_capsule_misc);
if (ret) if (ret)
pr_err("%s: Failed to register misc char file note\n", pr_err("Unable to register capsule loader device\n");
__func__);
return ret; return ret;
} }
......
...@@ -214,7 +214,7 @@ efi_capsule_update_locked(efi_capsule_header_t *capsule, ...@@ -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;
...@@ -247,16 +247,13 @@ int efi_capsule_update(efi_capsule_header_t *capsule, struct page **pages) ...@@ -247,16 +247,13 @@ int efi_capsule_update(efi_capsule_header_t *capsule, struct page **pages)
efi_capsule_block_desc_t *sglist; efi_capsule_block_desc_t *sglist;
sglist = kmap(sg_pages[i]); sglist = kmap(sg_pages[i]);
if (!sglist) {
rv = -ENOMEM;
goto out;
}
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--;
......
...@@ -528,7 +528,8 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz, ...@@ -528,7 +528,8 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
} }
} }
efi_memattr_init(); if (efi_enabled(EFI_MEMMAP))
efi_memattr_init();
/* Parse the EFI Properties table if it exists */ /* Parse the EFI Properties table if it exists */
if (efi.properties_table != EFI_INVALID_TABLE_ADDR) { if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
......
...@@ -71,18 +71,13 @@ copy_ucs2_from_user_len(efi_char16_t **dst, efi_char16_t __user *src, ...@@ -71,18 +71,13 @@ copy_ucs2_from_user_len(efi_char16_t **dst, efi_char16_t __user *src,
if (!access_ok(VERIFY_READ, src, 1)) if (!access_ok(VERIFY_READ, src, 1))
return -EFAULT; return -EFAULT;
buf = kmalloc(len, GFP_KERNEL); buf = memdup_user(src, len);
if (!buf) { if (IS_ERR(buf)) {
*dst = NULL; *dst = NULL;
return -ENOMEM; return PTR_ERR(buf);
} }
*dst = buf; *dst = buf;
if (copy_from_user(*dst, src, len)) {
kfree(buf);
return -EFAULT;
}
return 0; return 0;
} }
......
...@@ -137,6 +137,18 @@ struct efi_boot_memmap { ...@@ -137,6 +137,18 @@ struct efi_boot_memmap {
#define EFI_CAPSULE_POPULATE_SYSTEM_TABLE 0x00020000 #define EFI_CAPSULE_POPULATE_SYSTEM_TABLE 0x00020000
#define EFI_CAPSULE_INITIATE_RESET 0x00040000 #define EFI_CAPSULE_INITIATE_RESET 0x00040000
struct capsule_info {
efi_capsule_header_t header;
int reset_type;
long index;
size_t count;
size_t total_size;
phys_addr_t *pages;
size_t page_bytes_remain;
};
int __efi_capsule_setup_info(struct capsule_info *cap_info);
/* /*
* Allocation types for calls to boottime->allocate_pages. * Allocation types for calls to boottime->allocate_pages.
*/ */
...@@ -1403,7 +1415,7 @@ extern int efi_capsule_supported(efi_guid_t guid, u32 flags, ...@@ -1403,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 *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment