uboot/lib/efi_loader/efi_dt_fixup.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * EFI_DT_FIXUP_PROTOCOL
   4 *
   5 * Copyright (c) 2020 Heinrich Schuchardt
   6 */
   7
   8#include <common.h>
   9#include <efi_dt_fixup.h>
  10#include <efi_loader.h>
  11#include <efi_rng.h>
  12#include <fdtdec.h>
  13#include <mapmem.h>
  14
  15const efi_guid_t efi_guid_dt_fixup_protocol = EFI_DT_FIXUP_PROTOCOL_GUID;
  16
  17/**
  18 * efi_reserve_memory() - add reserved memory to memory map
  19 *
  20 * @addr:       start address of the reserved memory range
  21 * @size:       size of the reserved memory range
  22 * @nomap:      indicates that the memory range shall not be accessed by the
  23 *              UEFI payload
  24 */
  25static void efi_reserve_memory(u64 addr, u64 size, bool nomap)
  26{
  27        int type;
  28        efi_uintn_t ret;
  29
  30        /* Convert from sandbox address space. */
  31        addr = (uintptr_t)map_sysmem(addr, 0);
  32
  33        if (nomap)
  34                type = EFI_RESERVED_MEMORY_TYPE;
  35        else
  36                type = EFI_BOOT_SERVICES_DATA;
  37
  38        ret = efi_add_memory_map(addr, size, type);
  39        if (ret != EFI_SUCCESS)
  40                log_err("Reserved memory mapping failed addr %llx size %llx\n",
  41                        addr, size);
  42}
  43
  44/**
  45 * efi_try_purge_kaslr_seed() - Remove unused kaslr-seed
  46 *
  47 * Kernel's EFI STUB only relies on EFI_RNG_PROTOCOL for randomization
  48 * and completely ignores the kaslr-seed for its own randomness needs
  49 * (i.e the randomization of the physical placement of the kernel).
  50 * Weed it out from the DTB we hand over, which would mess up our DTB
  51 * TPM measurements as well.
  52 *
  53 * @fdt: Pointer to device tree
  54 */
  55void efi_try_purge_kaslr_seed(void *fdt)
  56{
  57        const efi_guid_t efi_guid_rng_protocol = EFI_RNG_PROTOCOL_GUID;
  58        struct efi_handler *handler;
  59        efi_status_t ret;
  60        int nodeoff = 0;
  61        int err = 0;
  62
  63        ret = efi_search_protocol(efi_root, &efi_guid_rng_protocol, &handler);
  64        if (ret != EFI_SUCCESS)
  65                return;
  66
  67        nodeoff = fdt_path_offset(fdt, "/chosen");
  68        if (nodeoff < 0)
  69                return;
  70
  71        err = fdt_delprop(fdt, nodeoff, "kaslr-seed");
  72        if (err < 0 && err != -FDT_ERR_NOTFOUND)
  73                log_err("Error deleting kaslr-seed\n");
  74}
  75
  76/**
  77 * efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
  78 *
  79 * The mem_rsv entries of the FDT are added to the memory map. Any failures are
  80 * ignored because this is not critical and we would rather continue to try to
  81 * boot.
  82 *
  83 * @fdt: Pointer to device tree
  84 */
  85void efi_carve_out_dt_rsv(void *fdt)
  86{
  87        int nr_rsv, i;
  88        u64 addr, size;
  89        int nodeoffset, subnode;
  90
  91        nr_rsv = fdt_num_mem_rsv(fdt);
  92
  93        /* Look for an existing entry and add it to the efi mem map. */
  94        for (i = 0; i < nr_rsv; i++) {
  95                if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0)
  96                        continue;
  97                efi_reserve_memory(addr, size, true);
  98        }
  99
 100        /* process reserved-memory */
 101        nodeoffset = fdt_subnode_offset(fdt, 0, "reserved-memory");
 102        if (nodeoffset >= 0) {
 103                subnode = fdt_first_subnode(fdt, nodeoffset);
 104                while (subnode >= 0) {
 105                        fdt_addr_t fdt_addr;
 106                        fdt_size_t fdt_size;
 107
 108                        /* check if this subnode has a reg property */
 109                        fdt_addr = fdtdec_get_addr_size_auto_parent(
 110                                                fdt, nodeoffset, subnode,
 111                                                "reg", 0, &fdt_size, false);
 112                        /*
 113                         * The /reserved-memory node may have children with
 114                         * a size instead of a reg property.
 115                         */
 116                        if (fdt_addr != FDT_ADDR_T_NONE &&
 117                            fdtdec_get_is_enabled(fdt, subnode)) {
 118                                bool nomap;
 119
 120                                nomap = !!fdt_getprop(fdt, subnode, "no-map",
 121                                                      NULL);
 122                                efi_reserve_memory(fdt_addr, fdt_size, nomap);
 123                        }
 124                        subnode = fdt_next_subnode(fdt, subnode);
 125                }
 126        }
 127}
 128
 129/**
 130 * efi_dt_fixup() - fix up device tree
 131 *
 132 * This function implements the Fixup() service of the
 133 * EFI Device Tree Fixup Protocol.
 134 *
 135 * @this:               instance of the protocol
 136 * @dtb:                device tree provided by caller
 137 * @buffer_size:        size of buffer for the device tree including free space
 138 * @flags:              bit field designating action to be performed
 139 * Return:              status code
 140 */
 141static efi_status_t __maybe_unused EFIAPI
 142efi_dt_fixup(struct efi_dt_fixup_protocol *this, void *dtb,
 143             efi_uintn_t *buffer_size, u32 flags)
 144{
 145        efi_status_t ret;
 146        size_t required_size;
 147        size_t total_size;
 148        bootm_headers_t img = { 0 };
 149
 150        EFI_ENTRY("%p, %p, %p, %d", this, dtb, buffer_size, flags);
 151
 152        if (this != &efi_dt_fixup_prot || !dtb || !buffer_size ||
 153            !flags || (flags & ~EFI_DT_ALL)) {
 154                ret = EFI_INVALID_PARAMETER;
 155                goto out;
 156        }
 157        if (fdt_check_header(dtb)) {
 158                ret = EFI_INVALID_PARAMETER;
 159                goto out;
 160        }
 161        if (flags & EFI_DT_APPLY_FIXUPS) {
 162                /* Check size */
 163                required_size = fdt_off_dt_strings(dtb) +
 164                                fdt_size_dt_strings(dtb) +
 165                                0x3000;
 166                total_size = fdt_totalsize(dtb);
 167                if (required_size < total_size)
 168                        required_size = total_size;
 169                if (required_size > *buffer_size) {
 170                        *buffer_size = required_size;
 171                        ret = EFI_BUFFER_TOO_SMALL;
 172                        goto out;
 173                }
 174
 175                fdt_set_totalsize(dtb, *buffer_size);
 176                if (image_setup_libfdt(&img, dtb, 0, NULL)) {
 177                        log_err("failed to process device tree\n");
 178                        ret = EFI_INVALID_PARAMETER;
 179                        goto out;
 180                }
 181        }
 182        if (flags & EFI_DT_RESERVE_MEMORY)
 183                efi_carve_out_dt_rsv(dtb);
 184
 185        if (flags & EFI_DT_INSTALL_TABLE) {
 186                ret = efi_install_configuration_table(&efi_guid_fdt, dtb);
 187                if (ret != EFI_SUCCESS) {
 188                        log_err("failed to install device tree\n");
 189                        goto out;
 190                }
 191        }
 192
 193        ret = EFI_SUCCESS;
 194out:
 195        return EFI_EXIT(ret);
 196}
 197
 198struct efi_dt_fixup_protocol efi_dt_fixup_prot = {
 199        .revision = EFI_DT_FIXUP_PROTOCOL_REVISION,
 200        .fixup = efi_dt_fixup
 201};
 202