2019-02-02 12:41:15 +03:00
// SPDX-License-Identifier: GPL-2.0
2016-04-25 23:06:59 +03:00
/*
* EFI capsule support .
*
* Copyright 2013 Intel Corporation ; author Matt Fleming
*/
# define pr_fmt(fmt) "efi: " fmt
# include <linux/slab.h>
# include <linux/mutex.h>
# include <linux/highmem.h>
# include <linux/efi.h>
# include <linux/vmalloc.h>
# include <asm/io.h>
typedef struct {
u64 length ;
u64 data ;
} efi_capsule_block_desc_t ;
static bool capsule_pending ;
2016-05-07 00:39:27 +03:00
static bool stop_capsules ;
2016-04-25 23:06:59 +03:00
static int efi_reset_type = - 1 ;
/*
* capsule_mutex serialises access to both capsule_pending and
2016-05-07 00:39:27 +03:00
* efi_reset_type and stop_capsules .
2016-04-25 23:06:59 +03:00
*/
static DEFINE_MUTEX ( capsule_mutex ) ;
/**
* efi_capsule_pending - has a capsule been passed to the firmware ?
* @ reset_type : store the type of EFI reset if capsule is pending
*
* To ensure that the registered capsule is processed correctly by the
* firmware we need to perform a specific type of reset . If a capsule is
* pending return the reset type in @ reset_type .
*
* This function will race with callers of efi_capsule_update ( ) , for
* example , calling this function while somebody else is in
* efi_capsule_update ( ) but hasn ' t reached efi_capsue_update_locked ( )
* will miss the updates to capsule_pending and efi_reset_type after
* efi_capsule_update_locked ( ) completes .
*
* A non - racy use is from platform reboot code because we use
* system_state to ensure no capsules can be sent to the firmware once
* we ' re at SYSTEM_RESTART . See efi_capsule_update_locked ( ) .
*/
bool efi_capsule_pending ( int * reset_type )
{
if ( ! capsule_pending )
2016-05-07 00:39:27 +03:00
return false ;
2016-04-25 23:06:59 +03:00
if ( reset_type )
* reset_type = efi_reset_type ;
2016-05-07 00:39:27 +03:00
return true ;
2016-04-25 23:06:59 +03:00
}
/*
* Whitelist of EFI capsule flags that we support .
*
* We do not handle EFI_CAPSULE_INITIATE_RESET because that would
* require us to prepare the kernel for reboot . Refuse to load any
* capsules with that flag and any other flags that we do not know how
* to handle .
*/
# define EFI_CAPSULE_SUPPORTED_FLAG_MASK \
( EFI_CAPSULE_PERSIST_ACROSS_RESET | EFI_CAPSULE_POPULATE_SYSTEM_TABLE )
/**
* efi_capsule_supported - does the firmware support the capsule ?
* @ guid : vendor guid of capsule
* @ flags : capsule flags
* @ size : size of capsule data
* @ reset : the reset type required for this capsule
*
* Check whether a capsule with @ flags is supported by the firmware
* and that @ size doesn ' t exceed the maximum size for a capsule .
*
* No attempt is made to check @ reset against the reset type required
* by any pending capsules because of the races involved .
*/
int efi_capsule_supported ( efi_guid_t guid , u32 flags , size_t size , int * reset )
{
2016-05-07 00:39:29 +03:00
efi_capsule_header_t capsule ;
efi_capsule_header_t * cap_list [ ] = { & capsule } ;
2016-04-25 23:06:59 +03:00
efi_status_t status ;
u64 max_size ;
if ( flags & ~ EFI_CAPSULE_SUPPORTED_FLAG_MASK )
return - EINVAL ;
2016-05-07 00:39:29 +03:00
capsule . headersize = capsule . imagesize = sizeof ( capsule ) ;
memcpy ( & capsule . guid , & guid , sizeof ( efi_guid_t ) ) ;
capsule . flags = flags ;
2016-04-25 23:06:59 +03:00
2016-05-07 00:39:29 +03:00
status = efi . query_capsule_caps ( cap_list , 1 , & max_size , reset ) ;
if ( status ! = EFI_SUCCESS )
return efi_status_to_err ( status ) ;
2016-04-25 23:06:59 +03:00
if ( size > max_size )
2016-05-07 00:39:29 +03:00
return - ENOSPC ;
return 0 ;
2016-04-25 23:06:59 +03:00
}
EXPORT_SYMBOL_GPL ( efi_capsule_supported ) ;
/*
* Every scatter gather list ( block descriptor ) page must end with a
* continuation pointer . The last continuation pointer of the last
* page must be zero to mark the end of the chain .
*/
# define SGLIST_PER_PAGE ((PAGE_SIZE / sizeof(efi_capsule_block_desc_t)) - 1)
/*
* How many scatter gather list ( block descriptor ) pages do we need
* to map @ count pages ?
*/
static inline unsigned int sg_pages_num ( unsigned int count )
{
return DIV_ROUND_UP ( count , SGLIST_PER_PAGE ) ;
}
/**
* efi_capsule_update_locked - pass a single capsule to the firmware
* @ capsule : capsule to send to the firmware
* @ sg_pages : array of scatter gather ( block descriptor ) pages
* @ reset : the reset type required for @ capsule
*
* Since this function must be called under capsule_mutex check
* whether efi_reset_type will conflict with @ reset , and atomically
* set it and capsule_pending if a capsule was successfully sent to
* the firmware .
*
* We also check to see if the system is about to restart , and if so ,
* abort . This avoids races between efi_capsule_update ( ) and
* efi_capsule_pending ( ) .
*/
static int
efi_capsule_update_locked ( efi_capsule_header_t * capsule ,
struct page * * sg_pages , int reset )
{
efi_physical_addr_t sglist_phys ;
efi_status_t status ;
lockdep_assert_held ( & capsule_mutex ) ;
/*
* If someone has already registered a capsule that requires a
* different reset type , we ' re out of luck and must abort .
*/
if ( efi_reset_type > = 0 & & efi_reset_type ! = reset ) {
pr_err ( " Conflicting capsule reset type %d (%d). \n " ,
reset , efi_reset_type ) ;
return - EINVAL ;
}
/*
* If the system is getting ready to restart it may have
* called efi_capsule_pending ( ) to make decisions ( such as
* whether to force an EFI reboot ) , and we ' re racing against
* that call . Abort in that case .
*/
2016-05-07 00:39:27 +03:00
if ( unlikely ( stop_capsules ) ) {
2016-04-25 23:06:59 +03:00
pr_warn ( " Capsule update raced with reboot, aborting. \n " ) ;
return - EINVAL ;
}
sglist_phys = page_to_phys ( sg_pages [ 0 ] ) ;
status = efi . update_capsule ( & capsule , 1 , sglist_phys ) ;
if ( status = = EFI_SUCCESS ) {
capsule_pending = true ;
efi_reset_type = reset ;
}
return efi_status_to_err ( status ) ;
}
/**
* efi_capsule_update - send a capsule to the firmware
* @ capsule : capsule to send to firmware
* @ pages : an array of capsule data pages
*
* Build a scatter gather list with EFI capsule block descriptors to
* map the capsule described by @ capsule with its data in @ pages and
* send it to the firmware via the UpdateCapsule ( ) runtime service .
*
2016-08-11 13:42:00 +03:00
* @ capsule must be a virtual mapping of the complete capsule update in the
* kernel address space , as the capsule can be consumed immediately .
* A capsule_header_t that describes the entire contents of the capsule
2016-04-25 23:06:59 +03:00
* must be at the start of the first data page .
*
* Even though this function will validate that the firmware supports
* the capsule guid , users will likely want to check that
* efi_capsule_supported ( ) returns true before calling this function
* because it makes it easier to print helpful error messages .
*
* If the capsule is successfully submitted to the firmware , any
* subsequent calls to efi_capsule_pending ( ) will return true . @ pages
* must not be released or modified if this function returns
* successfully .
*
* Callers must be prepared for this function to fail , which can
* happen if we raced with system reboot or if there is already a
* pending capsule that has a reset type that conflicts with the one
* required by @ capsule . Do NOT use efi_capsule_pending ( ) to detect
* this conflict since that would be racy . Instead , submit the capsule
* to efi_capsule_update ( ) and check the return value .
*
* Return 0 on success , a converted EFI status code on failure .
*/
2017-06-02 16:52:03 +03:00
int efi_capsule_update ( efi_capsule_header_t * capsule , phys_addr_t * pages )
2016-04-25 23:06:59 +03:00
{
u32 imagesize = capsule - > imagesize ;
efi_guid_t guid = capsule - > guid ;
unsigned int count , sg_count ;
u32 flags = capsule - > flags ;
struct page * * sg_pages ;
int rv , reset_type ;
int i , j ;
rv = efi_capsule_supported ( guid , flags , imagesize , & reset_type ) ;
if ( rv )
return rv ;
count = DIV_ROUND_UP ( imagesize , PAGE_SIZE ) ;
sg_count = sg_pages_num ( count ) ;
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:03:40 +03:00
sg_pages = kcalloc ( sg_count , sizeof ( * sg_pages ) , GFP_KERNEL ) ;
2016-04-25 23:06:59 +03:00
if ( ! sg_pages )
return - ENOMEM ;
for ( i = 0 ; i < sg_count ; i + + ) {
sg_pages [ i ] = alloc_page ( GFP_KERNEL ) ;
if ( ! sg_pages [ i ] ) {
rv = - ENOMEM ;
goto out ;
}
}
for ( i = 0 ; i < sg_count ; i + + ) {
efi_capsule_block_desc_t * sglist ;
sglist = kmap ( sg_pages [ i ] ) ;
for ( j = 0 ; j < SGLIST_PER_PAGE & & count > 0 ; j + + ) {
2017-06-02 16:52:03 +03:00
u64 sz = min_t ( u64 , imagesize ,
PAGE_SIZE - ( u64 ) * pages % PAGE_SIZE ) ;
2016-04-25 23:06:59 +03:00
sglist [ j ] . length = sz ;
2017-06-02 16:52:03 +03:00
sglist [ j ] . data = * pages + + ;
2016-04-25 23:06:59 +03:00
imagesize - = sz ;
count - - ;
}
/* Continuation pointer */
sglist [ j ] . length = 0 ;
if ( i + 1 = = sg_count )
sglist [ j ] . data = 0 ;
else
sglist [ j ] . data = page_to_phys ( sg_pages [ i + 1 ] ) ;
kunmap ( sg_pages [ i ] ) ;
}
mutex_lock ( & capsule_mutex ) ;
rv = efi_capsule_update_locked ( capsule , sg_pages , reset_type ) ;
mutex_unlock ( & capsule_mutex ) ;
out :
for ( i = 0 ; rv & & i < sg_count ; i + + ) {
if ( sg_pages [ i ] )
__free_page ( sg_pages [ i ] ) ;
}
kfree ( sg_pages ) ;
return rv ;
}
EXPORT_SYMBOL_GPL ( efi_capsule_update ) ;
2016-05-07 00:39:27 +03:00
static int capsule_reboot_notify ( struct notifier_block * nb , unsigned long event , void * cmd )
{
mutex_lock ( & capsule_mutex ) ;
stop_capsules = true ;
mutex_unlock ( & capsule_mutex ) ;
return NOTIFY_DONE ;
}
static struct notifier_block capsule_reboot_nb = {
. notifier_call = capsule_reboot_notify ,
} ;
static int __init capsule_reboot_register ( void )
{
return register_reboot_notifier ( & capsule_reboot_nb ) ;
}
core_initcall ( capsule_reboot_register ) ;