*/
static bool check_image_region(u64 base, u64 size)
{
- unsigned long map_size, desc_size, buff_size;
- efi_memory_desc_t *memory_map;
- struct efi_boot_memmap map;
+ struct efi_boot_memmap *map;
efi_status_t status;
bool ret = false;
int map_offset;
- 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(&map);
if (status != EFI_SUCCESS)
return false;
- for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
- efi_memory_desc_t *md = (void *)memory_map + map_offset;
+ for (map_offset = 0; map_offset < map->map_size; map_offset += map->desc_size) {
+ efi_memory_desc_t *md = (void *)map->map + map_offset;
u64 end = md->phys_addr + md->num_pages * EFI_PAGE_SIZE;
/*
}
}
- efi_bs_call(free_pool, memory_map);
+ efi_bs_call(free_pool, map);
return ret;
}
/**
* efi_exit_boot_services() - Exit boot services
* @handle: handle of the exiting image
- * @map: pointer to receive the memory map
* @priv: argument to be passed to @priv_func
* @priv_func: function to process the memory map before exiting boot services
*
*
* Return: status code
*/
-efi_status_t efi_exit_boot_services(void *handle,
- struct efi_boot_memmap *map,
- void *priv,
+efi_status_t efi_exit_boot_services(void *handle, void *priv,
efi_exit_boot_map_processing priv_func)
{
+ struct efi_boot_memmap *map;
efi_status_t status;
- status = efi_get_memory_map(map);
+ status = efi_get_memory_map(&map);
if (status != EFI_SUCCESS)
goto fail;
if (efi_disable_pci_dma)
efi_pci_disable_bridge_busmaster();
- status = efi_bs_call(exit_boot_services, handle, *map->key_ptr);
+ status = efi_bs_call(exit_boot_services, handle, map->map_key);
if (status == EFI_INVALID_PARAMETER) {
/*
* 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;
+ map->map_size = map->buff_size;
status = efi_bs_call(get_memory_map,
- map->map_size,
- *map->map,
- map->key_ptr,
- map->desc_size,
- map->desc_ver);
+ &map->map_size,
+ &map->map,
+ &map->map_key,
+ &map->desc_size,
+ &map->desc_ver);
/* exit_boot_services() was called, thus cannot free */
if (status != EFI_SUCCESS)
if (status != EFI_SUCCESS)
goto fail;
- status = efi_bs_call(exit_boot_services, handle, *map->key_ptr);
+ status = efi_bs_call(exit_boot_services, handle, map->map_key);
}
/* exit_boot_services() was called, thus cannot free */
return EFI_SUCCESS;
free_map:
- efi_bs_call(free_pool, *map->map);
+ efi_bs_call(free_pool, map);
fail:
return status;
}
*/
#define EFI_MMAP_NR_SLACK_SLOTS 8
-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;
-};
-
typedef struct efi_generic_dev_path efi_device_path_protocol_t;
typedef void *efi_event_t;
struct efi_boot_memmap *map,
void *priv);
-efi_status_t efi_exit_boot_services(void *handle,
- struct efi_boot_memmap *map,
- void *priv,
+efi_status_t efi_exit_boot_services(void *handle, void *priv,
efi_exit_boot_map_processing priv_func);
efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len);
-efi_status_t efi_get_memory_map(struct efi_boot_memmap *map);
+efi_status_t efi_get_memory_map(struct efi_boot_memmap **map);
efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
unsigned long max);
if (node < 0)
return EFI_LOAD_ERROR;
- fdt_val64 = cpu_to_fdt64((unsigned long)*map->map);
+ fdt_val64 = cpu_to_fdt64((unsigned long)map->map);
err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-start", fdt_val64);
if (err)
return EFI_LOAD_ERROR;
- fdt_val32 = cpu_to_fdt32(*map->map_size);
+ fdt_val32 = cpu_to_fdt32(map->map_size);
err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-size", fdt_val32);
if (err)
return EFI_LOAD_ERROR;
- fdt_val32 = cpu_to_fdt32(*map->desc_size);
+ fdt_val32 = cpu_to_fdt32(map->desc_size);
err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-desc-size", fdt_val32);
if (err)
return EFI_LOAD_ERROR;
- fdt_val32 = cpu_to_fdt32(*map->desc_ver);
+ fdt_val32 = cpu_to_fdt32(map->desc_ver);
err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-desc-ver", fdt_val32);
if (err)
}
struct exit_boot_struct {
+ struct efi_boot_memmap *boot_memmap;
efi_memory_desc_t *runtime_map;
int runtime_entry_count;
void *new_fdt_addr;
};
-static efi_status_t exit_boot_func(struct efi_boot_memmap *map,
- void *priv)
+static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv)
{
struct exit_boot_struct *p = priv;
+
+ p->boot_memmap = map;
+
/*
* 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,
+ efi_get_virtmap(map->map, map->map_size, map->desc_size,
p->runtime_map, &p->runtime_entry_count);
return update_fdt_memmap(p->new_fdt_addr, map);
unsigned long fdt_addr,
unsigned long fdt_size)
{
- unsigned long map_size, desc_size, buff_size;
+ unsigned long desc_size;
u32 desc_ver;
- unsigned long mmap_key;
- efi_memory_desc_t *memory_map;
efi_status_t status;
- struct efi_boot_memmap map;
struct exit_boot_struct priv;
- 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;
-
if (!efi_novamap) {
status = efi_alloc_virtmap(&priv.runtime_map, &desc_size,
&desc_ver);
efi_info("Exiting boot services...\n");
- map.map = &memory_map;
status = efi_allocate_pages(MAX_FDT_SIZE, new_fdt_addr, ULONG_MAX);
if (status != EFI_SUCCESS) {
efi_err("Unable to allocate memory for new device tree.\n");
priv.new_fdt_addr = (void *)*new_fdt_addr;
- status = efi_exit_boot_services(handle, &map, &priv, exit_boot_func);
+ status = efi_exit_boot_services(handle, &priv, exit_boot_func);
if (status == EFI_SUCCESS) {
efi_set_virtual_address_map_t *svam;
* incoming kernel but proceed normally otherwise.
*/
if (status != EFI_SUCCESS) {
+ efi_memory_desc_t *p;
int l;
/*
* the incoming kernel that no virtual translation has
* been installed.
*/
- for (l = 0; l < map_size; l += desc_size) {
- efi_memory_desc_t *p = (void *)memory_map + l;
+ for (l = 0; l < priv.boot_memmap->map_size;
+ l += priv.boot_memmap->desc_size) {
+ p = (void *)priv.boot_memmap->map + l;
if (p->attribute & EFI_MEMORY_RUNTIME)
p->virt_addr = 0;
#include "efistub.h"
-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_get_memory_map() - get memory map
- * @map: on return pointer to memory map
+ * @map: pointer to memory map pointer to which to assign the
+ * newly allocated memory map
*
* Retrieve the UEFI memory map. The allocated memory leaves room for
* up to EFI_MMAP_NR_SLACK_SLOTS additional memory map entries.
*
* Return: status code
*/
-efi_status_t efi_get_memory_map(struct efi_boot_memmap *map)
+efi_status_t efi_get_memory_map(struct efi_boot_memmap **map)
{
- efi_memory_desc_t *m = NULL;
+ struct efi_boot_memmap *m, tmp;
efi_status_t status;
- unsigned long key;
- u32 desc_version;
+ unsigned long size;
- *map->desc_size = sizeof(*m);
- *map->map_size = *map->desc_size * 32;
- *map->buff_size = *map->map_size;
-again:
- status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
- *map->map_size, (void **)&m);
+ tmp.map_size = 0;
+ status = efi_bs_call(get_memory_map, &tmp.map_size, NULL, &tmp.map_key,
+ &tmp.desc_size, &tmp.desc_ver);
+ if (status != EFI_BUFFER_TOO_SMALL)
+ return EFI_LOAD_ERROR;
+
+ size = tmp.map_size + tmp.desc_size * EFI_MMAP_NR_SLACK_SLOTS;
+ status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(*m) + size,
+ (void **)&m);
if (status != EFI_SUCCESS)
- goto fail;
+ return status;
- *map->desc_size = 0;
- key = 0;
- status = efi_bs_call(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_bs_call(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;
- }
+ m->buff_size = m->map_size = size;
+ status = efi_bs_call(get_memory_map, &m->map_size, m->map, &m->map_key,
+ &m->desc_size, &m->desc_ver);
+ if (status != EFI_SUCCESS)
+ goto free_map;
- if (status == EFI_SUCCESS) {
- if (map->key_ptr)
- *map->key_ptr = key;
- if (map->desc_ver)
- *map->desc_ver = desc_version;
- } else {
- efi_bs_call(free_pool, m);
- }
+ *map = m;
+ return EFI_SUCCESS;
-fail:
- *map->map = m;
+free_map:
+ efi_bs_call(free_pool, m);
return status;
}
unsigned long *addr,
unsigned long random_seed)
{
- unsigned long map_size, desc_size, total_slots = 0, target_slot;
+ unsigned long total_slots = 0, target_slot;
unsigned long total_mirrored_slots = 0;
- unsigned long buff_size;
+ struct efi_boot_memmap *map;
efi_status_t status;
- efi_memory_desc_t *memory_map;
int map_offset;
- struct efi_boot_memmap map;
-
- 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(&map);
if (status != EFI_SUCCESS)
size = round_up(size, EFI_ALLOC_ALIGN);
/* count the suitable slots in each memory map entry */
- for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
- efi_memory_desc_t *md = (void *)memory_map + map_offset;
+ for (map_offset = 0; map_offset < map->map_size; map_offset += map->desc_size) {
+ efi_memory_desc_t *md = (void *)map->map + map_offset;
unsigned long slots;
slots = get_entry_num_slots(md, size, ilog2(align));
* to calculate the randomly chosen address, and allocate it directly
* using EFI_ALLOCATE_ADDRESS.
*/
- for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
- efi_memory_desc_t *md = (void *)memory_map + map_offset;
+ for (map_offset = 0; map_offset < map->map_size; map_offset += map->desc_size) {
+ efi_memory_desc_t *md = (void *)map->map + map_offset;
efi_physical_addr_t target;
unsigned long pages;
break;
}
- efi_bs_call(free_pool, memory_map);
+ efi_bs_call(free_pool, map);
return status;
}
efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
unsigned long *addr, unsigned long min)
{
- unsigned long map_size, desc_size, buff_size;
- efi_memory_desc_t *map;
+ struct efi_boot_memmap *map;
efi_status_t status;
unsigned long nr_pages;
int i;
- struct efi_boot_memmap boot_map;
- 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(&boot_map);
+ status = efi_get_memory_map(&map);
if (status != EFI_SUCCESS)
goto fail;
size = round_up(size, EFI_ALLOC_ALIGN);
nr_pages = size / EFI_PAGE_SIZE;
- for (i = 0; i < map_size / desc_size; i++) {
+ for (i = 0; i < map->map_size / map->desc_size; i++) {
efi_memory_desc_t *desc;
- unsigned long m = (unsigned long)map;
+ unsigned long m = (unsigned long)map->map;
u64 start, end;
- desc = efi_early_memdesc_ptr(m, desc_size, i);
+ desc = efi_early_memdesc_ptr(m, map->desc_size, i);
if (desc->type != EFI_CONVENTIONAL_MEMORY)
continue;
}
}
- if (i == map_size / desc_size)
+ if (i == map->map_size / map->desc_size)
status = EFI_NOT_FOUND;
efi_bs_call(free_pool, map);
efi_set_u64_split((unsigned long)efi_system_table,
&p->efi->efi_systab, &p->efi->efi_systab_hi);
- p->efi->efi_memdesc_size = *map->desc_size;
- p->efi->efi_memdesc_version = *map->desc_ver;
- efi_set_u64_split((unsigned long)*map->map,
+ p->efi->efi_memdesc_size = map->desc_size;
+ p->efi->efi_memdesc_version = map->desc_ver;
+ efi_set_u64_split((unsigned long)map->map,
&p->efi->efi_memmap, &p->efi->efi_memmap_hi);
- p->efi->efi_memmap_size = *map->map_size;
+ p->efi->efi_memmap_size = map->map_size;
return EFI_SUCCESS;
}
static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)
{
- unsigned long map_sz, key, desc_size, buff_size;
- efi_memory_desc_t *mem_map;
struct setup_data *e820ext = NULL;
__u32 e820ext_size = 0;
efi_status_t status;
- __u32 desc_version;
- struct efi_boot_memmap map;
struct exit_boot_struct priv;
- map.map = &mem_map;
- map.map_size = &map_sz;
- map.desc_size = &desc_size;
- map.desc_ver = &desc_version;
- map.key_ptr = &key;
- map.buff_size = &buff_size;
priv.boot_params = boot_params;
priv.efi = &boot_params->efi_info;
return status;
/* Might as well exit boot services now */
- status = efi_exit_boot_services(handle, &map, &priv, exit_boot_func);
+ status = efi_exit_boot_services(handle, &priv, exit_boot_func);
if (status != EFI_SUCCESS)
return status;
efi_system_table_32_t mixed_mode;
} efi_system_table_t;
+struct efi_boot_memmap {
+ unsigned long map_size;
+ unsigned long desc_size;
+ u32 desc_ver;
+ unsigned long map_key;
+ unsigned long buff_size;
+ efi_memory_desc_t map[];
+};
+
/*
* Architecture independent structure for describing a memory map for the
* benefit of efi_memmap_init_early(), and for passing context between