mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00: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 282 additions and 119 deletions
|
@ -1004,79 +1004,87 @@ static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct exit_boot_struct {
|
||||||
|
struct boot_params *boot_params;
|
||||||
|
struct efi_info *efi;
|
||||||
|
struct setup_data *e820ext;
|
||||||
|
__u32 e820ext_size;
|
||||||
|
bool is64;
|
||||||
|
};
|
||||||
|
|
||||||
|
static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
|
||||||
|
struct efi_boot_memmap *map,
|
||||||
|
void *priv)
|
||||||
|
{
|
||||||
|
static bool first = true;
|
||||||
|
const char *signature;
|
||||||
|
__u32 nr_desc;
|
||||||
|
efi_status_t status;
|
||||||
|
struct exit_boot_struct *p = priv;
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
nr_desc = *map->buff_size / *map->desc_size;
|
||||||
|
if (nr_desc > ARRAY_SIZE(p->boot_params->e820_map)) {
|
||||||
|
u32 nr_e820ext = nr_desc -
|
||||||
|
ARRAY_SIZE(p->boot_params->e820_map);
|
||||||
|
|
||||||
|
status = alloc_e820ext(nr_e820ext, &p->e820ext,
|
||||||
|
&p->e820ext_size);
|
||||||
|
if (status != EFI_SUCCESS)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
signature = p->is64 ? EFI64_LOADER_SIGNATURE : EFI32_LOADER_SIGNATURE;
|
||||||
|
memcpy(&p->efi->efi_loader_signature, signature, sizeof(__u32));
|
||||||
|
|
||||||
|
p->efi->efi_systab = (unsigned long)sys_table_arg;
|
||||||
|
p->efi->efi_memdesc_size = *map->desc_size;
|
||||||
|
p->efi->efi_memdesc_version = *map->desc_ver;
|
||||||
|
p->efi->efi_memmap = (unsigned long)*map->map;
|
||||||
|
p->efi->efi_memmap_size = *map->map_size;
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
p->efi->efi_systab_hi = (unsigned long)sys_table_arg >> 32;
|
||||||
|
p->efi->efi_memmap_hi = (unsigned long)*map->map >> 32;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static efi_status_t exit_boot(struct boot_params *boot_params,
|
static efi_status_t exit_boot(struct boot_params *boot_params,
|
||||||
void *handle, bool is64)
|
void *handle, bool is64)
|
||||||
{
|
{
|
||||||
struct efi_info *efi = &boot_params->efi_info;
|
unsigned long map_sz, key, desc_size, buff_size;
|
||||||
unsigned long map_sz, key, desc_size;
|
|
||||||
efi_memory_desc_t *mem_map;
|
efi_memory_desc_t *mem_map;
|
||||||
struct setup_data *e820ext;
|
struct setup_data *e820ext;
|
||||||
const char *signature;
|
|
||||||
__u32 e820ext_size;
|
__u32 e820ext_size;
|
||||||
__u32 nr_desc, prev_nr_desc;
|
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
__u32 desc_version;
|
__u32 desc_version;
|
||||||
bool called_exit = false;
|
struct efi_boot_memmap map;
|
||||||
u8 nr_entries;
|
struct exit_boot_struct priv;
|
||||||
int i;
|
|
||||||
|
|
||||||
nr_desc = 0;
|
map.map = &mem_map;
|
||||||
e820ext = NULL;
|
map.map_size = &map_sz;
|
||||||
e820ext_size = 0;
|
map.desc_size = &desc_size;
|
||||||
|
map.desc_ver = &desc_version;
|
||||||
get_map:
|
map.key_ptr = &key;
|
||||||
status = efi_get_memory_map(sys_table, &mem_map, &map_sz, &desc_size,
|
map.buff_size = &buff_size;
|
||||||
&desc_version, &key);
|
priv.boot_params = boot_params;
|
||||||
|
priv.efi = &boot_params->efi_info;
|
||||||
|
priv.e820ext = NULL;
|
||||||
|
priv.e820ext_size = 0;
|
||||||
|
priv.is64 = is64;
|
||||||
|
|
||||||
|
/* Might as well exit boot services now */
|
||||||
|
status = efi_exit_boot_services(sys_table, handle, &map, &priv,
|
||||||
|
exit_boot_func);
|
||||||
if (status != EFI_SUCCESS)
|
if (status != EFI_SUCCESS)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
prev_nr_desc = nr_desc;
|
e820ext = priv.e820ext;
|
||||||
nr_desc = map_sz / desc_size;
|
e820ext_size = priv.e820ext_size;
|
||||||
if (nr_desc > prev_nr_desc &&
|
|
||||||
nr_desc > ARRAY_SIZE(boot_params->e820_map)) {
|
|
||||||
u32 nr_e820ext = nr_desc - ARRAY_SIZE(boot_params->e820_map);
|
|
||||||
|
|
||||||
status = alloc_e820ext(nr_e820ext, &e820ext, &e820ext_size);
|
|
||||||
if (status != EFI_SUCCESS)
|
|
||||||
goto free_mem_map;
|
|
||||||
|
|
||||||
efi_call_early(free_pool, mem_map);
|
|
||||||
goto get_map; /* Allocated memory, get map again */
|
|
||||||
}
|
|
||||||
|
|
||||||
signature = is64 ? EFI64_LOADER_SIGNATURE : EFI32_LOADER_SIGNATURE;
|
|
||||||
memcpy(&efi->efi_loader_signature, signature, sizeof(__u32));
|
|
||||||
|
|
||||||
efi->efi_systab = (unsigned long)sys_table;
|
|
||||||
efi->efi_memdesc_size = desc_size;
|
|
||||||
efi->efi_memdesc_version = desc_version;
|
|
||||||
efi->efi_memmap = (unsigned long)mem_map;
|
|
||||||
efi->efi_memmap_size = map_sz;
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
|
||||||
efi->efi_systab_hi = (unsigned long)sys_table >> 32;
|
|
||||||
efi->efi_memmap_hi = (unsigned long)mem_map >> 32;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Might as well exit boot services now */
|
|
||||||
status = efi_call_early(exit_boot_services, handle, key);
|
|
||||||
if (status != EFI_SUCCESS) {
|
|
||||||
/*
|
|
||||||
* ExitBootServices() will fail if any of the event
|
|
||||||
* handlers change the memory map. In which case, we
|
|
||||||
* must be prepared to retry, but only once so that
|
|
||||||
* we're guaranteed to exit on repeated failures instead
|
|
||||||
* of spinning forever.
|
|
||||||
*/
|
|
||||||
if (called_exit)
|
|
||||||
goto free_mem_map;
|
|
||||||
|
|
||||||
called_exit = true;
|
|
||||||
efi_call_early(free_pool, mem_map);
|
|
||||||
goto get_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Historic? */
|
/* Historic? */
|
||||||
boot_params->alt_mem_k = 32 * 1024;
|
boot_params->alt_mem_k = 32 * 1024;
|
||||||
|
|
||||||
|
@ -1085,10 +1093,6 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
|
|
||||||
free_mem_map:
|
|
||||||
efi_call_early(free_pool, mem_map);
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -657,9 +657,12 @@ static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subnode) {
|
if (subnode) {
|
||||||
node = of_get_flat_dt_subnode_by_name(node, subnode);
|
int err = of_get_flat_dt_subnode_by_name(node, subnode);
|
||||||
if (node < 0)
|
|
||||||
|
if (err < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
node = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return __find_uefi_params(node, info, dt_params[i].params);
|
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
|
#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define EFI_MMAP_NR_SLACK_SLOTS 8
|
||||||
|
|
||||||
struct file_info {
|
struct file_info {
|
||||||
efi_file_handle_t *handle;
|
efi_file_handle_t *handle;
|
||||||
u64 size;
|
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_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
|
||||||
efi_memory_desc_t **map,
|
struct efi_boot_memmap *map)
|
||||||
unsigned long *map_size,
|
|
||||||
unsigned long *desc_size,
|
|
||||||
u32 *desc_ver,
|
|
||||||
unsigned long *key_ptr)
|
|
||||||
{
|
{
|
||||||
efi_memory_desc_t *m = NULL;
|
efi_memory_desc_t *m = NULL;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
unsigned long key;
|
unsigned long key;
|
||||||
u32 desc_version;
|
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:
|
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,
|
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
|
||||||
*map_size, (void **)&m);
|
*map->map_size, (void **)&m);
|
||||||
if (status != EFI_SUCCESS)
|
if (status != EFI_SUCCESS)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
*desc_size = 0;
|
*map->desc_size = 0;
|
||||||
key = 0;
|
key = 0;
|
||||||
status = efi_call_early(get_memory_map, map_size, m,
|
status = efi_call_early(get_memory_map, map->map_size, m,
|
||||||
&key, desc_size, &desc_version);
|
&key, map->desc_size, &desc_version);
|
||||||
if (status == EFI_BUFFER_TOO_SMALL) {
|
if (status == EFI_BUFFER_TOO_SMALL ||
|
||||||
|
!mmap_has_headroom(*map->buff_size, *map->map_size,
|
||||||
|
*map->desc_size)) {
|
||||||
efi_call_early(free_pool, m);
|
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;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status != EFI_SUCCESS)
|
if (status != EFI_SUCCESS)
|
||||||
efi_call_early(free_pool, m);
|
efi_call_early(free_pool, m);
|
||||||
|
|
||||||
if (key_ptr && status == EFI_SUCCESS)
|
if (map->key_ptr && status == EFI_SUCCESS)
|
||||||
*key_ptr = key;
|
*map->key_ptr = key;
|
||||||
if (desc_ver && status == EFI_SUCCESS)
|
if (map->desc_ver && status == EFI_SUCCESS)
|
||||||
*desc_ver = desc_version;
|
*map->desc_ver = desc_version;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
*map = m;
|
*map->map = m;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,13 +128,20 @@ efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
|
||||||
unsigned long get_dram_base(efi_system_table_t *sys_table_arg)
|
unsigned long get_dram_base(efi_system_table_t *sys_table_arg)
|
||||||
{
|
{
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
unsigned long map_size;
|
unsigned long map_size, buff_size;
|
||||||
unsigned long membase = EFI_ERROR;
|
unsigned long membase = EFI_ERROR;
|
||||||
struct efi_memory_map map;
|
struct efi_memory_map map;
|
||||||
efi_memory_desc_t *md;
|
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,
|
boot_map.map = (efi_memory_desc_t **)&map.map;
|
||||||
&map_size, &map.desc_size, NULL, NULL);
|
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)
|
if (status != EFI_SUCCESS)
|
||||||
return membase;
|
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 size, unsigned long align,
|
||||||
unsigned long *addr, unsigned long max)
|
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_memory_desc_t *map;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
unsigned long nr_pages;
|
unsigned long nr_pages;
|
||||||
u64 max_addr = 0;
|
u64 max_addr = 0;
|
||||||
int i;
|
int i;
|
||||||
|
struct efi_boot_memmap boot_map;
|
||||||
|
|
||||||
status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size,
|
boot_map.map = ↦
|
||||||
NULL, NULL);
|
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)
|
if (status != EFI_SUCCESS)
|
||||||
goto fail;
|
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 size, unsigned long align,
|
||||||
unsigned long *addr)
|
unsigned long *addr)
|
||||||
{
|
{
|
||||||
unsigned long map_size, desc_size;
|
unsigned long map_size, desc_size, buff_size;
|
||||||
efi_memory_desc_t *map;
|
efi_memory_desc_t *map;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
unsigned long nr_pages;
|
unsigned long nr_pages;
|
||||||
int i;
|
int i;
|
||||||
|
struct efi_boot_memmap boot_map;
|
||||||
|
|
||||||
status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size,
|
boot_map.map = ↦
|
||||||
NULL, NULL);
|
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)
|
if (status != EFI_SUCCESS)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -704,3 +740,76 @@ char *efi_convert_cmdline(efi_system_table_t *sys_table_arg,
|
||||||
*cmd_line_len = options_bytes;
|
*cmd_line_len = options_bytes;
|
||||||
return (char *)cmdline_addr;
|
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 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
|
||||||
#define EFI_FDT_ALIGN EFI_PAGE_SIZE
|
#define EFI_FDT_ALIGN EFI_PAGE_SIZE
|
||||||
#endif
|
#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
|
* Allocate memory for a new FDT, then add EFI, commandline, and
|
||||||
* initrd related fields to the FDT. This routine increases the
|
* 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_addr,
|
||||||
unsigned long fdt_size)
|
unsigned long fdt_size)
|
||||||
{
|
{
|
||||||
unsigned long map_size, desc_size;
|
unsigned long map_size, desc_size, buff_size;
|
||||||
u32 desc_ver;
|
u32 desc_ver;
|
||||||
unsigned long mmap_key;
|
unsigned long mmap_key;
|
||||||
efi_memory_desc_t *memory_map, *runtime_map;
|
efi_memory_desc_t *memory_map, *runtime_map;
|
||||||
unsigned long new_fdt_size;
|
unsigned long new_fdt_size;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
int runtime_entry_count = 0;
|
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
|
* 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
|
* subsequent allocations adding entries, since they could not affect
|
||||||
* the number of EFI_MEMORY_RUNTIME regions.
|
* the number of EFI_MEMORY_RUNTIME regions.
|
||||||
*/
|
*/
|
||||||
status = efi_get_memory_map(sys_table, &runtime_map, &map_size,
|
status = efi_get_memory_map(sys_table, &map);
|
||||||
&desc_size, &desc_ver, &mmap_key);
|
|
||||||
if (status != EFI_SUCCESS) {
|
if (status != EFI_SUCCESS) {
|
||||||
pr_efi_err(sys_table, "Unable to retrieve UEFI memory map.\n");
|
pr_efi_err(sys_table, "Unable to retrieve UEFI memory map.\n");
|
||||||
return status;
|
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,
|
pr_efi(sys_table,
|
||||||
"Exiting boot services and installing virtual address map...\n");
|
"Exiting boot services and installing virtual address map...\n");
|
||||||
|
|
||||||
|
map.map = &memory_map;
|
||||||
/*
|
/*
|
||||||
* Estimate size of new FDT, and allocate memory for it. We
|
* Estimate size of new FDT, and allocate memory for it. We
|
||||||
* will allocate a bigger buffer if this ends up being too
|
* 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
|
* we can get the memory map key needed for
|
||||||
* exit_boot_services().
|
* exit_boot_services().
|
||||||
*/
|
*/
|
||||||
status = efi_get_memory_map(sys_table, &memory_map, &map_size,
|
status = efi_get_memory_map(sys_table, &map);
|
||||||
&desc_size, &desc_ver, &mmap_key);
|
|
||||||
if (status != EFI_SUCCESS)
|
if (status != EFI_SUCCESS)
|
||||||
goto fail_free_new_fdt;
|
goto fail_free_new_fdt;
|
||||||
|
|
||||||
|
@ -250,16 +279,11 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
sys_table->boottime->free_pool(memory_map);
|
||||||
* Update the memory map with virtual addresses. The function will also
|
priv.runtime_map = runtime_map;
|
||||||
* populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME
|
priv.runtime_entry_count = &runtime_entry_count;
|
||||||
* entries so that we can pass it straight into SetVirtualAddressMap()
|
status = efi_exit_boot_services(sys_table, handle, &map, &priv,
|
||||||
*/
|
exit_boot_func);
|
||||||
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);
|
|
||||||
|
|
||||||
if (status == EFI_SUCCESS) {
|
if (status == EFI_SUCCESS) {
|
||||||
efi_set_virtual_address_map_t *svam;
|
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 random_seed)
|
||||||
{
|
{
|
||||||
unsigned long map_size, desc_size, total_slots = 0, target_slot;
|
unsigned long map_size, desc_size, total_slots = 0, target_slot;
|
||||||
|
unsigned long buff_size;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
efi_memory_desc_t *memory_map;
|
efi_memory_desc_t *memory_map;
|
||||||
int map_offset;
|
int map_offset;
|
||||||
|
struct efi_boot_memmap map;
|
||||||
|
|
||||||
status = efi_get_memory_map(sys_table_arg, &memory_map, &map_size,
|
map.map = &memory_map;
|
||||||
&desc_size, NULL, NULL);
|
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)
|
if (status != EFI_SUCCESS)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,15 @@ typedef struct {
|
||||||
u32 imagesize;
|
u32 imagesize;
|
||||||
} efi_capsule_header_t;
|
} efi_capsule_header_t;
|
||||||
|
|
||||||
|
struct efi_boot_memmap {
|
||||||
|
efi_memory_desc_t **map;
|
||||||
|
unsigned long *map_size;
|
||||||
|
unsigned long *desc_size;
|
||||||
|
u32 *desc_ver;
|
||||||
|
unsigned long *key_ptr;
|
||||||
|
unsigned long *buff_size;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EFI capsule flags
|
* EFI capsule flags
|
||||||
*/
|
*/
|
||||||
|
@ -946,7 +955,7 @@ extern int efi_memattr_apply_permissions(struct mm_struct *mm,
|
||||||
/* Iterate through an efi_memory_map */
|
/* Iterate through an efi_memory_map */
|
||||||
#define for_each_efi_memory_desc_in_map(m, md) \
|
#define for_each_efi_memory_desc_in_map(m, md) \
|
||||||
for ((md) = (m)->map; \
|
for ((md) = (m)->map; \
|
||||||
((void *)(md) + (m)->desc_size) <= (m)->map_end; \
|
(md) && ((void *)(md) + (m)->desc_size) <= (m)->map_end; \
|
||||||
(md) = (void *)(md) + (m)->desc_size)
|
(md) = (void *)(md) + (m)->desc_size)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1371,11 +1380,7 @@ char *efi_convert_cmdline(efi_system_table_t *sys_table_arg,
|
||||||
efi_loaded_image_t *image, int *cmd_line_len);
|
efi_loaded_image_t *image, int *cmd_line_len);
|
||||||
|
|
||||||
efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
|
efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
|
||||||
efi_memory_desc_t **map,
|
struct efi_boot_memmap *map);
|
||||||
unsigned long *map_size,
|
|
||||||
unsigned long *desc_size,
|
|
||||||
u32 *desc_ver,
|
|
||||||
unsigned long *key_ptr);
|
|
||||||
|
|
||||||
efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
|
efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
|
||||||
unsigned long size, unsigned long align,
|
unsigned long size, unsigned long align,
|
||||||
|
@ -1457,4 +1462,14 @@ extern void efi_call_virt_check_flags(unsigned long flags, const char *call);
|
||||||
arch_efi_call_virt_teardown(); \
|
arch_efi_call_virt_teardown(); \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
typedef efi_status_t (*efi_exit_boot_map_processing)(
|
||||||
|
efi_system_table_t *sys_table_arg,
|
||||||
|
struct efi_boot_memmap *map,
|
||||||
|
void *priv);
|
||||||
|
|
||||||
|
efi_status_t efi_exit_boot_services(efi_system_table_t *sys_table,
|
||||||
|
void *handle,
|
||||||
|
struct efi_boot_memmap *map,
|
||||||
|
void *priv,
|
||||||
|
efi_exit_boot_map_processing priv_func);
|
||||||
#endif /* _LINUX_EFI_H */
|
#endif /* _LINUX_EFI_H */
|
||||||
|
|
Loading…
Reference in a new issue