mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
Merge branch 'efi-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull EFI fixes from Ingo Molnar: "This contains a Xen fix, an arm64 fix and a race condition / robustization set of fixes related to ExitBootServices() usage and boundary conditions" * 'efi-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/efi: Use efi_exit_boot_services() efi/libstub: Use efi_exit_boot_services() in FDT efi/libstub: Introduce ExitBootServices helper efi/libstub: Allocate headspace in efi_get_memory_map() efi: Fix handling error value in fdt_find_uefi_params efi: Make for_each_efi_memory_desc_in_map() cope with running on Xen
This commit is contained in:
commit
7c2c114416
6 changed files with 283 additions and 120 deletions
|
|
@ -657,9 +657,12 @@ static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
|
|||
}
|
||||
|
||||
if (subnode) {
|
||||
node = of_get_flat_dt_subnode_by_name(node, subnode);
|
||||
if (node < 0)
|
||||
int err = of_get_flat_dt_subnode_by_name(node, subnode);
|
||||
|
||||
if (err < 0)
|
||||
return 0;
|
||||
|
||||
node = err;
|
||||
}
|
||||
|
||||
return __find_uefi_params(node, info, dt_params[i].params);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE;
|
|||
#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE
|
||||
#endif
|
||||
|
||||
#define EFI_MMAP_NR_SLACK_SLOTS 8
|
||||
|
||||
struct file_info {
|
||||
efi_file_handle_t *handle;
|
||||
u64 size;
|
||||
|
|
@ -63,49 +65,62 @@ void efi_printk(efi_system_table_t *sys_table_arg, char *str)
|
|||
}
|
||||
}
|
||||
|
||||
static inline bool mmap_has_headroom(unsigned long buff_size,
|
||||
unsigned long map_size,
|
||||
unsigned long desc_size)
|
||||
{
|
||||
unsigned long slack = buff_size - map_size;
|
||||
|
||||
return slack / desc_size >= EFI_MMAP_NR_SLACK_SLOTS;
|
||||
}
|
||||
|
||||
efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
|
||||
efi_memory_desc_t **map,
|
||||
unsigned long *map_size,
|
||||
unsigned long *desc_size,
|
||||
u32 *desc_ver,
|
||||
unsigned long *key_ptr)
|
||||
struct efi_boot_memmap *map)
|
||||
{
|
||||
efi_memory_desc_t *m = NULL;
|
||||
efi_status_t status;
|
||||
unsigned long key;
|
||||
u32 desc_version;
|
||||
|
||||
*map_size = sizeof(*m) * 32;
|
||||
*map->desc_size = sizeof(*m);
|
||||
*map->map_size = *map->desc_size * 32;
|
||||
*map->buff_size = *map->map_size;
|
||||
again:
|
||||
/*
|
||||
* Add an additional efi_memory_desc_t because we're doing an
|
||||
* allocation which may be in a new descriptor region.
|
||||
*/
|
||||
*map_size += sizeof(*m);
|
||||
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
|
||||
*map_size, (void **)&m);
|
||||
*map->map_size, (void **)&m);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
*desc_size = 0;
|
||||
*map->desc_size = 0;
|
||||
key = 0;
|
||||
status = efi_call_early(get_memory_map, map_size, m,
|
||||
&key, desc_size, &desc_version);
|
||||
if (status == EFI_BUFFER_TOO_SMALL) {
|
||||
status = efi_call_early(get_memory_map, map->map_size, m,
|
||||
&key, map->desc_size, &desc_version);
|
||||
if (status == EFI_BUFFER_TOO_SMALL ||
|
||||
!mmap_has_headroom(*map->buff_size, *map->map_size,
|
||||
*map->desc_size)) {
|
||||
efi_call_early(free_pool, m);
|
||||
/*
|
||||
* Make sure there is some entries of headroom so that the
|
||||
* buffer can be reused for a new map after allocations are
|
||||
* no longer permitted. Its unlikely that the map will grow to
|
||||
* exceed this headroom once we are ready to trigger
|
||||
* ExitBootServices()
|
||||
*/
|
||||
*map->map_size += *map->desc_size * EFI_MMAP_NR_SLACK_SLOTS;
|
||||
*map->buff_size = *map->map_size;
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
efi_call_early(free_pool, m);
|
||||
|
||||
if (key_ptr && status == EFI_SUCCESS)
|
||||
*key_ptr = key;
|
||||
if (desc_ver && status == EFI_SUCCESS)
|
||||
*desc_ver = desc_version;
|
||||
if (map->key_ptr && status == EFI_SUCCESS)
|
||||
*map->key_ptr = key;
|
||||
if (map->desc_ver && status == EFI_SUCCESS)
|
||||
*map->desc_ver = desc_version;
|
||||
|
||||
fail:
|
||||
*map = m;
|
||||
*map->map = m;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -113,13 +128,20 @@ fail:
|
|||
unsigned long get_dram_base(efi_system_table_t *sys_table_arg)
|
||||
{
|
||||
efi_status_t status;
|
||||
unsigned long map_size;
|
||||
unsigned long map_size, buff_size;
|
||||
unsigned long membase = EFI_ERROR;
|
||||
struct efi_memory_map map;
|
||||
efi_memory_desc_t *md;
|
||||
struct efi_boot_memmap boot_map;
|
||||
|
||||
status = efi_get_memory_map(sys_table_arg, (efi_memory_desc_t **)&map.map,
|
||||
&map_size, &map.desc_size, NULL, NULL);
|
||||
boot_map.map = (efi_memory_desc_t **)&map.map;
|
||||
boot_map.map_size = &map_size;
|
||||
boot_map.desc_size = &map.desc_size;
|
||||
boot_map.desc_ver = NULL;
|
||||
boot_map.key_ptr = NULL;
|
||||
boot_map.buff_size = &buff_size;
|
||||
|
||||
status = efi_get_memory_map(sys_table_arg, &boot_map);
|
||||
if (status != EFI_SUCCESS)
|
||||
return membase;
|
||||
|
||||
|
|
@ -144,15 +166,22 @@ efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg,
|
|||
unsigned long size, unsigned long align,
|
||||
unsigned long *addr, unsigned long max)
|
||||
{
|
||||
unsigned long map_size, desc_size;
|
||||
unsigned long map_size, desc_size, buff_size;
|
||||
efi_memory_desc_t *map;
|
||||
efi_status_t status;
|
||||
unsigned long nr_pages;
|
||||
u64 max_addr = 0;
|
||||
int i;
|
||||
struct efi_boot_memmap boot_map;
|
||||
|
||||
status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size,
|
||||
NULL, NULL);
|
||||
boot_map.map = ↦
|
||||
boot_map.map_size = &map_size;
|
||||
boot_map.desc_size = &desc_size;
|
||||
boot_map.desc_ver = NULL;
|
||||
boot_map.key_ptr = NULL;
|
||||
boot_map.buff_size = &buff_size;
|
||||
|
||||
status = efi_get_memory_map(sys_table_arg, &boot_map);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
|
|
@ -230,14 +259,21 @@ efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
|
|||
unsigned long size, unsigned long align,
|
||||
unsigned long *addr)
|
||||
{
|
||||
unsigned long map_size, desc_size;
|
||||
unsigned long map_size, desc_size, buff_size;
|
||||
efi_memory_desc_t *map;
|
||||
efi_status_t status;
|
||||
unsigned long nr_pages;
|
||||
int i;
|
||||
struct efi_boot_memmap boot_map;
|
||||
|
||||
status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size,
|
||||
NULL, NULL);
|
||||
boot_map.map = ↦
|
||||
boot_map.map_size = &map_size;
|
||||
boot_map.desc_size = &desc_size;
|
||||
boot_map.desc_ver = NULL;
|
||||
boot_map.key_ptr = NULL;
|
||||
boot_map.buff_size = &buff_size;
|
||||
|
||||
status = efi_get_memory_map(sys_table_arg, &boot_map);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
|
|
@ -704,3 +740,76 @@ char *efi_convert_cmdline(efi_system_table_t *sys_table_arg,
|
|||
*cmd_line_len = options_bytes;
|
||||
return (char *)cmdline_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle calling ExitBootServices according to the requirements set out by the
|
||||
* spec. Obtains the current memory map, and returns that info after calling
|
||||
* ExitBootServices. The client must specify a function to perform any
|
||||
* processing of the memory map data prior to ExitBootServices. A client
|
||||
* specific structure may be passed to the function via priv. The client
|
||||
* function may be called multiple times.
|
||||
*/
|
||||
efi_status_t efi_exit_boot_services(efi_system_table_t *sys_table_arg,
|
||||
void *handle,
|
||||
struct efi_boot_memmap *map,
|
||||
void *priv,
|
||||
efi_exit_boot_map_processing priv_func)
|
||||
{
|
||||
efi_status_t status;
|
||||
|
||||
status = efi_get_memory_map(sys_table_arg, map);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
status = priv_func(sys_table_arg, map, priv);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto free_map;
|
||||
|
||||
status = efi_call_early(exit_boot_services, handle, *map->key_ptr);
|
||||
|
||||
if (status == EFI_INVALID_PARAMETER) {
|
||||
/*
|
||||
* The memory map changed between efi_get_memory_map() and
|
||||
* exit_boot_services(). Per the UEFI Spec v2.6, Section 6.4:
|
||||
* EFI_BOOT_SERVICES.ExitBootServices we need to get the
|
||||
* updated map, and try again. The spec implies one retry
|
||||
* should be sufficent, which is confirmed against the EDK2
|
||||
* implementation. Per the spec, we can only invoke
|
||||
* get_memory_map() and exit_boot_services() - we cannot alloc
|
||||
* so efi_get_memory_map() cannot be used, and we must reuse
|
||||
* the buffer. For all practical purposes, the headroom in the
|
||||
* buffer should account for any changes in the map so the call
|
||||
* to get_memory_map() is expected to succeed here.
|
||||
*/
|
||||
*map->map_size = *map->buff_size;
|
||||
status = efi_call_early(get_memory_map,
|
||||
map->map_size,
|
||||
*map->map,
|
||||
map->key_ptr,
|
||||
map->desc_size,
|
||||
map->desc_ver);
|
||||
|
||||
/* exit_boot_services() was called, thus cannot free */
|
||||
if (status != EFI_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
status = priv_func(sys_table_arg, map, priv);
|
||||
/* exit_boot_services() was called, thus cannot free */
|
||||
if (status != EFI_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
status = efi_call_early(exit_boot_services, handle, *map->key_ptr);
|
||||
}
|
||||
|
||||
/* exit_boot_services() was called, thus cannot free */
|
||||
if (status != EFI_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
||||
free_map:
|
||||
efi_call_early(free_pool, *map->map);
|
||||
fail:
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,6 +152,27 @@ fdt_set_fail:
|
|||
#define EFI_FDT_ALIGN EFI_PAGE_SIZE
|
||||
#endif
|
||||
|
||||
struct exit_boot_struct {
|
||||
efi_memory_desc_t *runtime_map;
|
||||
int *runtime_entry_count;
|
||||
};
|
||||
|
||||
static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
|
||||
struct efi_boot_memmap *map,
|
||||
void *priv)
|
||||
{
|
||||
struct exit_boot_struct *p = priv;
|
||||
/*
|
||||
* Update the memory map with virtual addresses. The function will also
|
||||
* populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME
|
||||
* entries so that we can pass it straight to SetVirtualAddressMap()
|
||||
*/
|
||||
efi_get_virtmap(*map->map, *map->map_size, *map->desc_size,
|
||||
p->runtime_map, p->runtime_entry_count);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate memory for a new FDT, then add EFI, commandline, and
|
||||
* initrd related fields to the FDT. This routine increases the
|
||||
|
|
@ -175,13 +196,22 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
|
|||
unsigned long fdt_addr,
|
||||
unsigned long fdt_size)
|
||||
{
|
||||
unsigned long map_size, desc_size;
|
||||
unsigned long map_size, desc_size, buff_size;
|
||||
u32 desc_ver;
|
||||
unsigned long mmap_key;
|
||||
efi_memory_desc_t *memory_map, *runtime_map;
|
||||
unsigned long new_fdt_size;
|
||||
efi_status_t status;
|
||||
int runtime_entry_count = 0;
|
||||
struct efi_boot_memmap map;
|
||||
struct exit_boot_struct priv;
|
||||
|
||||
map.map = &runtime_map;
|
||||
map.map_size = &map_size;
|
||||
map.desc_size = &desc_size;
|
||||
map.desc_ver = &desc_ver;
|
||||
map.key_ptr = &mmap_key;
|
||||
map.buff_size = &buff_size;
|
||||
|
||||
/*
|
||||
* Get a copy of the current memory map that we will use to prepare
|
||||
|
|
@ -189,8 +219,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
|
|||
* subsequent allocations adding entries, since they could not affect
|
||||
* the number of EFI_MEMORY_RUNTIME regions.
|
||||
*/
|
||||
status = efi_get_memory_map(sys_table, &runtime_map, &map_size,
|
||||
&desc_size, &desc_ver, &mmap_key);
|
||||
status = efi_get_memory_map(sys_table, &map);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err(sys_table, "Unable to retrieve UEFI memory map.\n");
|
||||
return status;
|
||||
|
|
@ -199,6 +228,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
|
|||
pr_efi(sys_table,
|
||||
"Exiting boot services and installing virtual address map...\n");
|
||||
|
||||
map.map = &memory_map;
|
||||
/*
|
||||
* Estimate size of new FDT, and allocate memory for it. We
|
||||
* will allocate a bigger buffer if this ends up being too
|
||||
|
|
@ -218,8 +248,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
|
|||
* we can get the memory map key needed for
|
||||
* exit_boot_services().
|
||||
*/
|
||||
status = efi_get_memory_map(sys_table, &memory_map, &map_size,
|
||||
&desc_size, &desc_ver, &mmap_key);
|
||||
status = efi_get_memory_map(sys_table, &map);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto fail_free_new_fdt;
|
||||
|
||||
|
|
@ -250,16 +279,11 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the memory map with virtual addresses. The function will also
|
||||
* populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME
|
||||
* entries so that we can pass it straight into SetVirtualAddressMap()
|
||||
*/
|
||||
efi_get_virtmap(memory_map, map_size, desc_size, runtime_map,
|
||||
&runtime_entry_count);
|
||||
|
||||
/* Now we are ready to exit_boot_services.*/
|
||||
status = sys_table->boottime->exit_boot_services(handle, mmap_key);
|
||||
sys_table->boottime->free_pool(memory_map);
|
||||
priv.runtime_map = runtime_map;
|
||||
priv.runtime_entry_count = &runtime_entry_count;
|
||||
status = efi_exit_boot_services(sys_table, handle, &map, &priv,
|
||||
exit_boot_func);
|
||||
|
||||
if (status == EFI_SUCCESS) {
|
||||
efi_set_virtual_address_map_t *svam;
|
||||
|
|
|
|||
|
|
@ -73,12 +73,20 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg,
|
|||
unsigned long random_seed)
|
||||
{
|
||||
unsigned long map_size, desc_size, total_slots = 0, target_slot;
|
||||
unsigned long buff_size;
|
||||
efi_status_t status;
|
||||
efi_memory_desc_t *memory_map;
|
||||
int map_offset;
|
||||
struct efi_boot_memmap map;
|
||||
|
||||
status = efi_get_memory_map(sys_table_arg, &memory_map, &map_size,
|
||||
&desc_size, NULL, NULL);
|
||||
map.map = &memory_map;
|
||||
map.map_size = &map_size;
|
||||
map.desc_size = &desc_size;
|
||||
map.desc_ver = NULL;
|
||||
map.key_ptr = NULL;
|
||||
map.buff_size = &buff_size;
|
||||
|
||||
status = efi_get_memory_map(sys_table_arg, &map);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue