mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-20 03:24:03 +08:00
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
This commit is contained in:
commit
162b246eb4
@ -2062,6 +2062,23 @@ config EFI
|
||||
is only useful for kernels that may run on systems that have
|
||||
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
|
||||
|
||||
menu "CPU Power Management"
|
||||
|
19
arch/arm/include/asm/dmi.h
Normal file
19
arch/arm/include/asm/dmi.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
@ -117,20 +116,6 @@ int __init efi_set_mapping_permissions(struct mm_struct *mm,
|
||||
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
|
||||
* ResetSystem().
|
||||
|
@ -1014,7 +1014,6 @@ static void __init __efi_enter_virtual_mode(void)
|
||||
* necessary relocation fixups for the new virtual addresses.
|
||||
*/
|
||||
efi_runtime_update_mappings();
|
||||
efi_dump_pagetable();
|
||||
|
||||
/* clean DUMMY object */
|
||||
efi_delete_dummy_variable();
|
||||
@ -1029,6 +1028,8 @@ void __init efi_enter_virtual_mode(void)
|
||||
kexec_enter_virtual_mode();
|
||||
else
|
||||
__efi_enter_virtual_mode();
|
||||
|
||||
efi_dump_pagetable();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -44,7 +44,14 @@ int __init efi_alloc_page_tables(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)
|
||||
{
|
||||
return 0;
|
||||
|
@ -589,7 +589,10 @@ void __init efi_runtime_update_mappings(void)
|
||||
void __init efi_dump_pagetable(void)
|
||||
{
|
||||
#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
|
||||
}
|
||||
|
||||
|
@ -15,12 +15,66 @@
|
||||
#include <asm/e820/api.h>
|
||||
#include <asm/efi.h>
|
||||
#include <asm/uv/uv.h>
|
||||
#include <asm/cpu_device_id.h>
|
||||
|
||||
#define EFI_MIN_RESERVE 5120
|
||||
|
||||
#define EFI_DUMMY_GUID \
|
||||
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 bool efi_no_storage_paranoia;
|
||||
@ -504,3 +558,86 @@ bool efi_poweroff_required(void)
|
||||
{
|
||||
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 = {
|
||||
.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)
|
||||
{
|
||||
struct xen_platform_op op = {
|
||||
@ -102,7 +70,18 @@ static efi_system_table_t __init *xen_efi_probe(void)
|
||||
|
||||
/* 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.nr_tables = info->cfg.nent;
|
||||
|
@ -112,6 +112,15 @@ config EFI_CAPSULE_LOADER
|
||||
|
||||
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
|
||||
tristate "EFI Runtime Service Tests Support"
|
||||
depends on EFI
|
||||
|
@ -11,6 +11,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/memblock.h>
|
||||
@ -166,3 +167,18 @@ void efi_virtmap_unload(void)
|
||||
efi_set_pgd(current->active_mm);
|
||||
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 @@
|
||||
|
||||
#define NO_FURTHER_WRITE_ACTION -1
|
||||
|
||||
struct capsule_info {
|
||||
bool header_obtained;
|
||||
int reset_type;
|
||||
long index;
|
||||
size_t count;
|
||||
size_t total_size;
|
||||
struct page **pages;
|
||||
size_t page_bytes_remain;
|
||||
};
|
||||
#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
|
||||
@ -41,62 +35,67 @@ struct capsule_info {
|
||||
static void efi_free_all_buff_pages(struct capsule_info *cap_info)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
int __efi_capsule_setup_info(struct capsule_info *cap_info)
|
||||
{
|
||||
size_t pages_needed;
|
||||
int ret;
|
||||
void *temp_page;
|
||||
|
||||
pages_needed = ALIGN(cap_info->total_size, PAGE_SIZE) / PAGE_SIZE;
|
||||
|
||||
if (pages_needed == 0) {
|
||||
pr_err("invalid capsule size");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if the capsule binary supported */
|
||||
ret = efi_capsule_supported(cap_info->header.guid,
|
||||
cap_info->header.flags,
|
||||
cap_info->header.imagesize,
|
||||
&cap_info->reset_type);
|
||||
if (ret) {
|
||||
pr_err("capsule not supported\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
temp_page = krealloc(cap_info->pages,
|
||||
pages_needed * sizeof(void *),
|
||||
GFP_KERNEL | __GFP_ZERO);
|
||||
if (!temp_page)
|
||||
return -ENOMEM;
|
||||
|
||||
cap_info->pages = temp_page;
|
||||
|
||||
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.
|
||||
**/
|
||||
static ssize_t efi_capsule_setup_info(struct capsule_info *cap_info,
|
||||
void *kbuff, size_t hdr_bytes)
|
||||
int __weak 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;
|
||||
int ret;
|
||||
void *temp_page;
|
||||
|
||||
/* Only process data block that is larger than efi header 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;
|
||||
memcpy(&cap_info->header, kbuff, sizeof(cap_info->header));
|
||||
cap_info->total_size = cap_info->header.imagesize;
|
||||
|
||||
if (pages_needed == 0) {
|
||||
pr_err("%s: pages count invalid\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if the capsule binary supported */
|
||||
ret = efi_capsule_supported(cap_hdr->guid, cap_hdr->flags,
|
||||
cap_hdr->imagesize,
|
||||
&cap_info->reset_type);
|
||||
if (ret) {
|
||||
pr_err("%s: efi_capsule_supported() failed\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cap_info->total_size = cap_hdr->imagesize;
|
||||
temp_page = krealloc(cap_info->pages,
|
||||
pages_needed * sizeof(void *),
|
||||
GFP_KERNEL | __GFP_ZERO);
|
||||
if (!temp_page) {
|
||||
pr_debug("%s: krealloc() failed\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cap_info->pages = temp_page;
|
||||
cap_info->header_obtained = true;
|
||||
|
||||
return 0;
|
||||
return __efi_capsule_setup_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)
|
||||
{
|
||||
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);
|
||||
vunmap(cap_hdr_temp);
|
||||
ret = efi_capsule_update(&cap_info->header, cap_info->pages);
|
||||
if (ret) {
|
||||
pr_err("%s: efi_capsule_update() failed\n", __func__);
|
||||
pr_err("capsule update failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Indicate capsule binary uploading is done */
|
||||
cap_info->index = NO_FURTHER_WRITE_ACTION;
|
||||
pr_info("%s: Successfully upload capsule file with reboot type '%s'\n",
|
||||
__func__, !cap_info->reset_type ? "RESET_COLD" :
|
||||
pr_info("Successfully upload capsule file with reboot type '%s'\n",
|
||||
!cap_info->reset_type ? "RESET_COLD" :
|
||||
cap_info->reset_type == 1 ? "RESET_WARM" :
|
||||
"RESET_SHUTDOWN");
|
||||
return 0;
|
||||
@ -171,37 +161,30 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
|
||||
if (!cap_info->page_bytes_remain) {
|
||||
page = alloc_page(GFP_KERNEL);
|
||||
if (!page) {
|
||||
pr_debug("%s: alloc_page() failed\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
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;
|
||||
} else {
|
||||
page = phys_to_page(cap_info->pages[cap_info->index - 1]);
|
||||
}
|
||||
|
||||
page = cap_info->pages[cap_info->index - 1];
|
||||
|
||||
kbuff = kmap(page);
|
||||
if (!kbuff) {
|
||||
pr_debug("%s: kmap() failed\n", __func__);
|
||||
ret = -EFAULT;
|
||||
goto failed;
|
||||
}
|
||||
kbuff += PAGE_SIZE - cap_info->page_bytes_remain;
|
||||
|
||||
/* Copy capsule binary data from user space to kernel space buffer */
|
||||
write_byte = min_t(size_t, count, cap_info->page_bytes_remain);
|
||||
if (copy_from_user(kbuff, buff, write_byte)) {
|
||||
pr_debug("%s: copy_from_user() failed\n", __func__);
|
||||
ret = -EFAULT;
|
||||
goto fail_unmap;
|
||||
}
|
||||
cap_info->page_bytes_remain -= write_byte;
|
||||
|
||||
/* Setup capsule binary info structure */
|
||||
if (!cap_info->header_obtained) {
|
||||
ret = efi_capsule_setup_info(cap_info, kbuff,
|
||||
if (cap_info->header.headersize == 0) {
|
||||
ret = efi_capsule_setup_info(cap_info, kbuff - cap_info->count,
|
||||
cap_info->count + write_byte);
|
||||
if (ret)
|
||||
goto fail_unmap;
|
||||
@ -211,11 +194,10 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
|
||||
kunmap(page);
|
||||
|
||||
/* 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) {
|
||||
if (cap_info->count > cap_info->total_size) {
|
||||
pr_err("%s: upload size exceeded header defined size\n",
|
||||
__func__);
|
||||
pr_err("capsule upload size exceeded header defined size\n");
|
||||
ret = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
@ -249,7 +231,7 @@ static int efi_capsule_flush(struct file *file, fl_owner_t id)
|
||||
struct capsule_info *cap_info = file->private_data;
|
||||
|
||||
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);
|
||||
ret = -ECANCELED;
|
||||
}
|
||||
@ -328,8 +310,7 @@ static int __init efi_capsule_loader_init(void)
|
||||
|
||||
ret = misc_register(&efi_capsule_misc);
|
||||
if (ret)
|
||||
pr_err("%s: Failed to register misc char file note\n",
|
||||
__func__);
|
||||
pr_err("Unable to register capsule loader device\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ efi_capsule_update_locked(efi_capsule_header_t *capsule,
|
||||
*
|
||||
* 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;
|
||||
efi_guid_t guid = capsule->guid;
|
||||
@ -247,16 +247,13 @@ int efi_capsule_update(efi_capsule_header_t *capsule, struct page **pages)
|
||||
efi_capsule_block_desc_t *sglist;
|
||||
|
||||
sglist = kmap(sg_pages[i]);
|
||||
if (!sglist) {
|
||||
rv = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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].data = page_to_phys(*pages++);
|
||||
sglist[j].data = *pages++;
|
||||
|
||||
imagesize -= sz;
|
||||
count--;
|
||||
|
@ -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 */
|
||||
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,
|
||||
if (!access_ok(VERIFY_READ, src, 1))
|
||||
return -EFAULT;
|
||||
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
buf = memdup_user(src, len);
|
||||
if (IS_ERR(buf)) {
|
||||
*dst = NULL;
|
||||
return -ENOMEM;
|
||||
return PTR_ERR(buf);
|
||||
}
|
||||
*dst = buf;
|
||||
|
||||
if (copy_from_user(*dst, src, len)) {
|
||||
kfree(buf);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -137,6 +137,18 @@ struct efi_boot_memmap {
|
||||
#define EFI_CAPSULE_POPULATE_SYSTEM_TABLE 0x00020000
|
||||
#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.
|
||||
*/
|
||||
@ -1403,7 +1415,7 @@ extern int efi_capsule_supported(efi_guid_t guid, u32 flags,
|
||||
size_t size, int *reset);
|
||||
|
||||
extern int efi_capsule_update(efi_capsule_header_t *capsule,
|
||||
struct page **pages);
|
||||
phys_addr_t *pages);
|
||||
|
||||
#ifdef CONFIG_EFI_RUNTIME_MAP
|
||||
int efi_runtime_map_init(struct kobject *);
|
||||
|
Loading…
Reference in New Issue
Block a user