2019-02-02 17:41:15 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2014-01-09 09:54:19 +08:00
|
|
|
/*
|
|
|
|
* FDT related Helper functions used by the EFI stub on multiple
|
|
|
|
* architectures. This should be #included by the EFI stub
|
|
|
|
* implementation files.
|
|
|
|
*
|
|
|
|
* Copyright 2013 Linaro Limited; author Roy Franz
|
|
|
|
*/
|
|
|
|
|
2014-07-02 20:54:42 +08:00
|
|
|
#include <linux/efi.h>
|
|
|
|
#include <linux/libfdt.h>
|
|
|
|
#include <asm/efi.h>
|
|
|
|
|
2014-10-20 22:27:26 +08:00
|
|
|
#include "efistub.h"
|
|
|
|
|
2017-04-03 10:26:33 +08:00
|
|
|
#define EFI_DT_ADDR_CELLS_DEFAULT 2
|
|
|
|
#define EFI_DT_SIZE_CELLS_DEFAULT 2
|
|
|
|
|
2019-12-24 23:10:19 +08:00
|
|
|
static void fdt_update_cell_size(void *fdt)
|
2017-04-03 10:26:33 +08:00
|
|
|
{
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
offset = fdt_path_offset(fdt, "/");
|
|
|
|
/* Set the #address-cells and #size-cells values for an empty tree */
|
|
|
|
|
2019-02-02 17:41:14 +08:00
|
|
|
fdt_setprop_u32(fdt, offset, "#address-cells", EFI_DT_ADDR_CELLS_DEFAULT);
|
|
|
|
fdt_setprop_u32(fdt, offset, "#size-cells", EFI_DT_SIZE_CELLS_DEFAULT);
|
2017-04-03 10:26:33 +08:00
|
|
|
}
|
|
|
|
|
2019-12-24 23:10:19 +08:00
|
|
|
static efi_status_t update_fdt(void *orig_fdt, unsigned long orig_fdt_size,
|
2016-12-24 21:59:23 +08:00
|
|
|
void *fdt, int new_fdt_size, char *cmdline_ptr,
|
|
|
|
u64 initrd_addr, u64 initrd_size)
|
2014-01-09 09:54:19 +08:00
|
|
|
{
|
2016-04-09 06:50:23 +08:00
|
|
|
int node, num_rsv;
|
2014-01-09 09:54:19 +08:00
|
|
|
int status;
|
|
|
|
u32 fdt_val32;
|
|
|
|
u64 fdt_val64;
|
|
|
|
|
2019-02-02 17:41:14 +08:00
|
|
|
/* Do some checks on provided FDT, if it exists: */
|
2014-01-09 09:54:19 +08:00
|
|
|
if (orig_fdt) {
|
|
|
|
if (fdt_check_header(orig_fdt)) {
|
2020-05-01 02:28:35 +08:00
|
|
|
efi_err("Device Tree header not valid!\n");
|
2014-01-09 09:54:19 +08:00
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We don't get the size of the FDT if we get if from a
|
2019-02-02 17:41:14 +08:00
|
|
|
* configuration table:
|
2014-01-09 09:54:19 +08:00
|
|
|
*/
|
|
|
|
if (orig_fdt_size && fdt_totalsize(orig_fdt) > orig_fdt_size) {
|
2020-05-01 02:28:35 +08:00
|
|
|
efi_err("Truncated device tree! foo!\n");
|
2014-01-09 09:54:19 +08:00
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-03 10:26:33 +08:00
|
|
|
if (orig_fdt) {
|
2014-01-09 09:54:19 +08:00
|
|
|
status = fdt_open_into(orig_fdt, fdt, new_fdt_size);
|
2017-04-03 10:26:33 +08:00
|
|
|
} else {
|
2014-01-09 09:54:19 +08:00
|
|
|
status = fdt_create_empty_tree(fdt, new_fdt_size);
|
2017-04-03 10:26:33 +08:00
|
|
|
if (status == 0) {
|
|
|
|
/*
|
2019-02-02 17:41:14 +08:00
|
|
|
* Any failure from the following function is
|
|
|
|
* non-critical:
|
2017-04-03 10:26:33 +08:00
|
|
|
*/
|
2019-12-24 23:10:19 +08:00
|
|
|
fdt_update_cell_size(fdt);
|
2017-04-03 10:26:33 +08:00
|
|
|
}
|
|
|
|
}
|
2014-01-09 09:54:19 +08:00
|
|
|
|
|
|
|
if (status != 0)
|
|
|
|
goto fdt_set_fail;
|
|
|
|
|
2014-09-09 01:01:08 +08:00
|
|
|
/*
|
|
|
|
* Delete all memory reserve map entries. When booting via UEFI,
|
|
|
|
* kernel will use the UEFI memory map to find reserved regions.
|
|
|
|
*/
|
|
|
|
num_rsv = fdt_num_mem_rsv(fdt);
|
|
|
|
while (num_rsv-- > 0)
|
|
|
|
fdt_del_mem_rsv(fdt, num_rsv);
|
|
|
|
|
2014-01-09 09:54:19 +08:00
|
|
|
node = fdt_subnode_offset(fdt, 0, "chosen");
|
|
|
|
if (node < 0) {
|
|
|
|
node = fdt_add_subnode(fdt, 0, "chosen");
|
|
|
|
if (node < 0) {
|
2019-02-02 17:41:14 +08:00
|
|
|
/* 'node' is an error code when negative: */
|
|
|
|
status = node;
|
2014-01-09 09:54:19 +08:00
|
|
|
goto fdt_set_fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-02 17:41:14 +08:00
|
|
|
if (cmdline_ptr != NULL && strlen(cmdline_ptr) > 0) {
|
2014-01-09 09:54:19 +08:00
|
|
|
status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr,
|
|
|
|
strlen(cmdline_ptr) + 1);
|
|
|
|
if (status)
|
|
|
|
goto fdt_set_fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set initrd address/end in device tree, if present */
|
|
|
|
if (initrd_size != 0) {
|
|
|
|
u64 initrd_image_end;
|
|
|
|
u64 initrd_image_start = cpu_to_fdt64(initrd_addr);
|
|
|
|
|
2019-02-02 17:41:14 +08:00
|
|
|
status = fdt_setprop_var(fdt, node, "linux,initrd-start", initrd_image_start);
|
2014-01-09 09:54:19 +08:00
|
|
|
if (status)
|
|
|
|
goto fdt_set_fail;
|
2019-02-02 17:41:14 +08:00
|
|
|
|
2014-01-09 09:54:19 +08:00
|
|
|
initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size);
|
2019-02-02 17:41:14 +08:00
|
|
|
status = fdt_setprop_var(fdt, node, "linux,initrd-end", initrd_image_end);
|
2014-01-09 09:54:19 +08:00
|
|
|
if (status)
|
|
|
|
goto fdt_set_fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add FDT entries for EFI runtime services in chosen node. */
|
|
|
|
node = fdt_subnode_offset(fdt, 0, "chosen");
|
2020-04-17 00:38:06 +08:00
|
|
|
fdt_val64 = cpu_to_fdt64((u64)(unsigned long)efi_system_table);
|
2019-02-02 17:41:14 +08:00
|
|
|
|
|
|
|
status = fdt_setprop_var(fdt, node, "linux,uefi-system-table", fdt_val64);
|
2014-01-09 09:54:19 +08:00
|
|
|
if (status)
|
|
|
|
goto fdt_set_fail;
|
|
|
|
|
2016-12-24 21:59:23 +08:00
|
|
|
fdt_val64 = U64_MAX; /* placeholder */
|
2019-02-02 17:41:14 +08:00
|
|
|
|
|
|
|
status = fdt_setprop_var(fdt, node, "linux,uefi-mmap-start", fdt_val64);
|
2014-01-09 09:54:19 +08:00
|
|
|
if (status)
|
|
|
|
goto fdt_set_fail;
|
|
|
|
|
2016-12-24 21:59:23 +08:00
|
|
|
fdt_val32 = U32_MAX; /* placeholder */
|
2019-02-02 17:41:14 +08:00
|
|
|
|
|
|
|
status = fdt_setprop_var(fdt, node, "linux,uefi-mmap-size", fdt_val32);
|
2014-01-09 09:54:19 +08:00
|
|
|
if (status)
|
|
|
|
goto fdt_set_fail;
|
|
|
|
|
2019-02-02 17:41:14 +08:00
|
|
|
status = fdt_setprop_var(fdt, node, "linux,uefi-mmap-desc-size", fdt_val32);
|
2014-01-09 09:54:19 +08:00
|
|
|
if (status)
|
|
|
|
goto fdt_set_fail;
|
|
|
|
|
2019-02-02 17:41:14 +08:00
|
|
|
status = fdt_setprop_var(fdt, node, "linux,uefi-mmap-desc-ver", fdt_val32);
|
2014-01-09 09:54:19 +08:00
|
|
|
if (status)
|
|
|
|
goto fdt_set_fail;
|
|
|
|
|
2016-01-26 21:48:29 +08:00
|
|
|
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
|
|
|
|
efi_status_t efi_status;
|
|
|
|
|
2019-12-24 23:10:19 +08:00
|
|
|
efi_status = efi_get_random_bytes(sizeof(fdt_val64),
|
2016-01-26 21:48:29 +08:00
|
|
|
(u8 *)&fdt_val64);
|
|
|
|
if (efi_status == EFI_SUCCESS) {
|
2019-02-02 17:41:14 +08:00
|
|
|
status = fdt_setprop_var(fdt, node, "kaslr-seed", fdt_val64);
|
2016-01-26 21:48:29 +08:00
|
|
|
if (status)
|
|
|
|
goto fdt_set_fail;
|
|
|
|
} else if (efi_status != EFI_NOT_FOUND) {
|
|
|
|
return efi_status;
|
|
|
|
}
|
|
|
|
}
|
2018-11-15 01:55:42 +08:00
|
|
|
|
2019-02-02 17:41:14 +08:00
|
|
|
/* Shrink the FDT back to its minimum size: */
|
2018-11-15 01:55:42 +08:00
|
|
|
fdt_pack(fdt);
|
|
|
|
|
2014-01-09 09:54:19 +08:00
|
|
|
return EFI_SUCCESS;
|
|
|
|
|
|
|
|
fdt_set_fail:
|
|
|
|
if (status == -FDT_ERR_NOSPACE)
|
|
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
|
|
|
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
}
|
|
|
|
|
2016-12-24 21:59:23 +08:00
|
|
|
static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map)
|
|
|
|
{
|
|
|
|
int node = fdt_path_offset(fdt, "/chosen");
|
|
|
|
u64 fdt_val64;
|
|
|
|
u32 fdt_val32;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (node < 0)
|
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
|
|
|
|
fdt_val64 = cpu_to_fdt64((unsigned long)*map->map);
|
2019-02-02 17:41:14 +08:00
|
|
|
|
|
|
|
err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-start", fdt_val64);
|
2016-12-24 21:59:23 +08:00
|
|
|
if (err)
|
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
|
|
|
|
fdt_val32 = cpu_to_fdt32(*map->map_size);
|
2019-02-02 17:41:14 +08:00
|
|
|
|
|
|
|
err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-size", fdt_val32);
|
2016-12-24 21:59:23 +08:00
|
|
|
if (err)
|
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
|
|
|
|
fdt_val32 = cpu_to_fdt32(*map->desc_size);
|
2019-02-02 17:41:14 +08:00
|
|
|
|
|
|
|
err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-desc-size", fdt_val32);
|
2016-12-24 21:59:23 +08:00
|
|
|
if (err)
|
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
|
|
|
|
fdt_val32 = cpu_to_fdt32(*map->desc_ver);
|
2019-02-02 17:41:14 +08:00
|
|
|
|
|
|
|
err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-desc-ver", fdt_val32);
|
2016-12-24 21:59:23 +08:00
|
|
|
if (err)
|
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2016-08-30 04:38:53 +08:00
|
|
|
struct exit_boot_struct {
|
2019-02-02 17:41:14 +08:00
|
|
|
efi_memory_desc_t *runtime_map;
|
|
|
|
int *runtime_entry_count;
|
|
|
|
void *new_fdt_addr;
|
2016-08-30 04:38:53 +08:00
|
|
|
};
|
|
|
|
|
2019-12-24 23:10:19 +08:00
|
|
|
static efi_status_t exit_boot_func(struct efi_boot_memmap *map,
|
2016-08-30 04:38:53 +08:00
|
|
|
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);
|
|
|
|
|
2017-02-02 01:45:02 +08:00
|
|
|
return update_fdt_memmap(p->new_fdt_addr, map);
|
2016-08-30 04:38:53 +08:00
|
|
|
}
|
|
|
|
|
2017-04-05 00:02:39 +08:00
|
|
|
#ifndef MAX_FDT_SIZE
|
2019-02-02 17:41:14 +08:00
|
|
|
# define MAX_FDT_SIZE SZ_2M
|
2017-04-05 00:02:39 +08:00
|
|
|
#endif
|
|
|
|
|
2014-01-09 09:54:19 +08:00
|
|
|
/*
|
|
|
|
* Allocate memory for a new FDT, then add EFI, commandline, and
|
|
|
|
* initrd related fields to the FDT. This routine increases the
|
|
|
|
* FDT allocation size until the allocated memory is large
|
|
|
|
* enough. EFI allocations are in EFI_PAGE_SIZE granules,
|
|
|
|
* which are fixed at 4K bytes, so in most cases the first
|
|
|
|
* allocation should succeed.
|
|
|
|
* EFI boot services are exited at the end of this function.
|
|
|
|
* There must be no allocations between the get_memory_map()
|
|
|
|
* call and the exit_boot_services() call, so the exiting of
|
|
|
|
* boot services is very tightly tied to the creation of the FDT
|
|
|
|
* with the final memory map in it.
|
|
|
|
*/
|
|
|
|
|
2019-12-24 23:10:19 +08:00
|
|
|
efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
|
2014-01-09 09:54:19 +08:00
|
|
|
unsigned long *new_fdt_addr,
|
|
|
|
unsigned long max_addr,
|
|
|
|
u64 initrd_addr, u64 initrd_size,
|
|
|
|
char *cmdline_ptr,
|
|
|
|
unsigned long fdt_addr,
|
|
|
|
unsigned long fdt_size)
|
|
|
|
{
|
2016-08-30 04:38:51 +08:00
|
|
|
unsigned long map_size, desc_size, buff_size;
|
2014-01-09 09:54:19 +08:00
|
|
|
u32 desc_ver;
|
|
|
|
unsigned long mmap_key;
|
2014-10-20 22:27:26 +08:00
|
|
|
efi_memory_desc_t *memory_map, *runtime_map;
|
2014-01-09 09:54:19 +08:00
|
|
|
efi_status_t status;
|
2019-02-02 17:41:14 +08:00
|
|
|
int runtime_entry_count;
|
2016-08-30 04:38:51 +08:00
|
|
|
struct efi_boot_memmap map;
|
2016-08-30 04:38:53 +08:00
|
|
|
struct exit_boot_struct priv;
|
2016-08-30 04:38:51 +08:00
|
|
|
|
2019-02-02 17:41:14 +08:00
|
|
|
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;
|
2014-10-20 22:27:26 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get a copy of the current memory map that we will use to prepare
|
|
|
|
* the input for SetVirtualAddressMap(). We don't have to worry about
|
|
|
|
* subsequent allocations adding entries, since they could not affect
|
|
|
|
* the number of EFI_MEMORY_RUNTIME regions.
|
|
|
|
*/
|
2019-12-24 23:10:19 +08:00
|
|
|
status = efi_get_memory_map(&map);
|
2014-10-20 22:27:26 +08:00
|
|
|
if (status != EFI_SUCCESS) {
|
2020-05-01 02:28:35 +08:00
|
|
|
efi_err("Unable to retrieve UEFI memory map.\n");
|
2014-10-20 22:27:26 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2020-05-01 02:28:35 +08:00
|
|
|
efi_info("Exiting boot services and installing virtual address map...\n");
|
2014-01-09 09:54:19 +08:00
|
|
|
|
2016-08-30 04:38:51 +08:00
|
|
|
map.map = &memory_map;
|
2020-02-11 00:02:35 +08:00
|
|
|
status = efi_allocate_pages(MAX_FDT_SIZE, new_fdt_addr, max_addr);
|
2017-04-05 00:02:39 +08:00
|
|
|
if (status != EFI_SUCCESS) {
|
2020-05-01 02:28:35 +08:00
|
|
|
efi_err("Unable to allocate memory for new device tree.\n");
|
2017-04-05 00:02:39 +08:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2014-01-09 09:54:19 +08:00
|
|
|
/*
|
2017-04-05 00:02:39 +08:00
|
|
|
* Now that we have done our final memory allocation (and free)
|
|
|
|
* we can get the memory map key needed for exit_boot_services().
|
2014-01-09 09:54:19 +08:00
|
|
|
*/
|
2019-12-24 23:10:19 +08:00
|
|
|
status = efi_get_memory_map(&map);
|
2017-04-05 00:02:39 +08:00
|
|
|
if (status != EFI_SUCCESS)
|
|
|
|
goto fail_free_new_fdt;
|
2014-01-09 09:54:19 +08:00
|
|
|
|
2019-12-24 23:10:19 +08:00
|
|
|
status = update_fdt((void *)fdt_addr, fdt_size,
|
2017-04-05 00:02:39 +08:00
|
|
|
(void *)*new_fdt_addr, MAX_FDT_SIZE, cmdline_ptr,
|
|
|
|
initrd_addr, initrd_size);
|
2014-01-09 09:54:19 +08:00
|
|
|
|
2017-04-05 00:02:39 +08:00
|
|
|
if (status != EFI_SUCCESS) {
|
2020-05-01 02:28:35 +08:00
|
|
|
efi_err("Unable to construct new device tree.\n");
|
2017-04-05 00:02:39 +08:00
|
|
|
goto fail_free_new_fdt;
|
2014-01-09 09:54:19 +08:00
|
|
|
}
|
|
|
|
|
2019-02-02 17:41:14 +08:00
|
|
|
runtime_entry_count = 0;
|
|
|
|
priv.runtime_map = runtime_map;
|
|
|
|
priv.runtime_entry_count = &runtime_entry_count;
|
|
|
|
priv.new_fdt_addr = (void *)*new_fdt_addr;
|
|
|
|
|
2019-12-24 23:10:19 +08:00
|
|
|
status = efi_exit_boot_services(handle, &map, &priv, exit_boot_func);
|
2014-01-09 09:54:19 +08:00
|
|
|
|
2014-10-20 22:27:26 +08:00
|
|
|
if (status == EFI_SUCCESS) {
|
|
|
|
efi_set_virtual_address_map_t *svam;
|
2014-01-09 09:54:19 +08:00
|
|
|
|
2020-04-17 00:45:24 +08:00
|
|
|
if (efi_novamap)
|
efi/arm/arm64: Allow SetVirtualAddressMap() to be omitted
The UEFI spec revision 2.7 errata A section 8.4 has the following to
say about the virtual memory runtime services:
"This section contains function definitions for the virtual memory
support that may be optionally used by an operating system at runtime.
If an operating system chooses to make EFI runtime service calls in a
virtual addressing mode instead of the flat physical mode, then the
operating system must use the services in this section to switch the
EFI runtime services from flat physical addressing to virtual
addressing."
So it is pretty clear that calling SetVirtualAddressMap() is entirely
optional, and so there is no point in doing so unless it achieves
anything useful for us.
This is not the case for 64-bit ARM. The identity mapping used by the
firmware is arbitrarily converted into another permutation of userland
addresses (i.e., bits [63:48] cleared), and the runtime code could easily
deal with the original layout in exactly the same way as it deals with
the converted layout. However, due to constraints related to page size
differences if the OS is not running with 4k pages, and related to
systems that may expose the individual sections of PE/COFF runtime
modules as different memory regions, creating the virtual layout is a
bit fiddly, and requires us to sort the memory map and reason about
adjacent regions with identical memory types etc etc.
So the obvious fix is to stop calling SetVirtualAddressMap() altogether
on arm64 systems. However, to avoid surprises, which are notoriously
hard to diagnose when it comes to OS<->firmware interactions, let's
start by making it an opt-out feature, and implement support for the
'efi=novamap' kernel command line parameter on ARM and arm64 systems.
( Note that 32-bit ARM generally does require SetVirtualAddressMap() to be
used, given that the physical memory map and the kernel virtual address
map are not guaranteed to be non-overlapping like on arm64. However,
having support for efi=novamap,noruntime on 32-bit ARM, combined with
the recently proposed support for earlycon=efifb, is likely to be useful
to diagnose boot issues on such systems if they have no accessible serial
port. )
Tested-by: Jeffrey Hugo <jhugo@codeaurora.org>
Tested-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Tested-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Alexander Graf <agraf@suse.de>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Peter Jones <pjones@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/20190202094119.13230-8-ard.biesheuvel@linaro.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-02-02 17:41:16 +08:00
|
|
|
return EFI_SUCCESS;
|
|
|
|
|
2014-10-20 22:27:26 +08:00
|
|
|
/* Install the new virtual address map */
|
2020-04-17 00:38:06 +08:00
|
|
|
svam = efi_system_table->runtime->set_virtual_address_map;
|
2014-10-20 22:27:26 +08:00
|
|
|
status = svam(runtime_entry_count * desc_size, desc_size,
|
|
|
|
desc_ver, runtime_map);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We are beyond the point of no return here, so if the call to
|
|
|
|
* SetVirtualAddressMap() failed, we need to signal that to the
|
|
|
|
* incoming kernel but proceed normally otherwise.
|
|
|
|
*/
|
|
|
|
if (status != EFI_SUCCESS) {
|
|
|
|
int l;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the virtual address field of all
|
|
|
|
* EFI_MEMORY_RUNTIME entries to 0. This will signal
|
|
|
|
* 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;
|
|
|
|
|
|
|
|
if (p->attribute & EFI_MEMORY_RUNTIME)
|
|
|
|
p->virt_addr = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
2014-01-09 09:54:19 +08:00
|
|
|
|
2020-05-01 02:28:35 +08:00
|
|
|
efi_err("Exit boot services failed.\n");
|
2014-01-09 09:54:19 +08:00
|
|
|
|
|
|
|
fail_free_new_fdt:
|
2019-12-24 23:10:19 +08:00
|
|
|
efi_free(MAX_FDT_SIZE, *new_fdt_addr);
|
2014-01-09 09:54:19 +08:00
|
|
|
|
|
|
|
fail:
|
2020-04-17 00:38:06 +08:00
|
|
|
efi_system_table->boottime->free_pool(runtime_map);
|
2019-02-02 17:41:14 +08:00
|
|
|
|
2014-01-09 09:54:19 +08:00
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
}
|
|
|
|
|
2019-12-24 23:10:19 +08:00
|
|
|
void *get_fdt(unsigned long *fdt_size)
|
2014-01-09 09:54:19 +08:00
|
|
|
{
|
2019-06-08 04:51:46 +08:00
|
|
|
void *fdt;
|
2014-01-09 09:54:19 +08:00
|
|
|
|
2019-12-24 23:10:19 +08:00
|
|
|
fdt = get_efi_config_table(DEVICE_TREE_GUID);
|
2014-01-09 09:54:19 +08:00
|
|
|
|
2019-06-08 04:51:46 +08:00
|
|
|
if (!fdt)
|
|
|
|
return NULL;
|
2018-11-30 01:12:22 +08:00
|
|
|
|
2019-06-08 04:51:46 +08:00
|
|
|
if (fdt_check_header(fdt) != 0) {
|
2020-05-01 02:28:35 +08:00
|
|
|
efi_err("Invalid header detected on UEFI supplied FDT, ignoring ...\n");
|
2019-06-08 04:51:46 +08:00
|
|
|
return NULL;
|
2018-11-30 01:12:21 +08:00
|
|
|
}
|
2019-06-08 04:51:46 +08:00
|
|
|
*fdt_size = fdt_totalsize(fdt);
|
|
|
|
return fdt;
|
2014-01-09 09:54:19 +08:00
|
|
|
}
|