Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * FDT related Helper functions used by the EFI stub on multiple
0004  * architectures. This should be #included by the EFI stub
0005  * implementation files.
0006  *
0007  * Copyright 2013 Linaro Limited; author Roy Franz
0008  */
0009 
0010 #include <linux/efi.h>
0011 #include <linux/libfdt.h>
0012 #include <asm/efi.h>
0013 
0014 #include "efistub.h"
0015 
0016 #define EFI_DT_ADDR_CELLS_DEFAULT 2
0017 #define EFI_DT_SIZE_CELLS_DEFAULT 2
0018 
0019 static void fdt_update_cell_size(void *fdt)
0020 {
0021     int offset;
0022 
0023     offset = fdt_path_offset(fdt, "/");
0024     /* Set the #address-cells and #size-cells values for an empty tree */
0025 
0026     fdt_setprop_u32(fdt, offset, "#address-cells", EFI_DT_ADDR_CELLS_DEFAULT);
0027     fdt_setprop_u32(fdt, offset, "#size-cells",    EFI_DT_SIZE_CELLS_DEFAULT);
0028 }
0029 
0030 static efi_status_t update_fdt(void *orig_fdt, unsigned long orig_fdt_size,
0031                    void *fdt, int new_fdt_size, char *cmdline_ptr,
0032                    u64 initrd_addr, u64 initrd_size)
0033 {
0034     int node, num_rsv;
0035     int status;
0036     u32 fdt_val32;
0037     u64 fdt_val64;
0038 
0039     /* Do some checks on provided FDT, if it exists: */
0040     if (orig_fdt) {
0041         if (fdt_check_header(orig_fdt)) {
0042             efi_err("Device Tree header not valid!\n");
0043             return EFI_LOAD_ERROR;
0044         }
0045         /*
0046          * We don't get the size of the FDT if we get if from a
0047          * configuration table:
0048          */
0049         if (orig_fdt_size && fdt_totalsize(orig_fdt) > orig_fdt_size) {
0050             efi_err("Truncated device tree! foo!\n");
0051             return EFI_LOAD_ERROR;
0052         }
0053     }
0054 
0055     if (orig_fdt) {
0056         status = fdt_open_into(orig_fdt, fdt, new_fdt_size);
0057     } else {
0058         status = fdt_create_empty_tree(fdt, new_fdt_size);
0059         if (status == 0) {
0060             /*
0061              * Any failure from the following function is
0062              * non-critical:
0063              */
0064             fdt_update_cell_size(fdt);
0065         }
0066     }
0067 
0068     if (status != 0)
0069         goto fdt_set_fail;
0070 
0071     /*
0072      * Delete all memory reserve map entries. When booting via UEFI,
0073      * kernel will use the UEFI memory map to find reserved regions.
0074      */
0075     num_rsv = fdt_num_mem_rsv(fdt);
0076     while (num_rsv-- > 0)
0077         fdt_del_mem_rsv(fdt, num_rsv);
0078 
0079     node = fdt_subnode_offset(fdt, 0, "chosen");
0080     if (node < 0) {
0081         node = fdt_add_subnode(fdt, 0, "chosen");
0082         if (node < 0) {
0083             /* 'node' is an error code when negative: */
0084             status = node;
0085             goto fdt_set_fail;
0086         }
0087     }
0088 
0089     if (cmdline_ptr != NULL && strlen(cmdline_ptr) > 0) {
0090         status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr,
0091                      strlen(cmdline_ptr) + 1);
0092         if (status)
0093             goto fdt_set_fail;
0094     }
0095 
0096     /* Set initrd address/end in device tree, if present */
0097     if (initrd_size != 0) {
0098         u64 initrd_image_end;
0099         u64 initrd_image_start = cpu_to_fdt64(initrd_addr);
0100 
0101         status = fdt_setprop_var(fdt, node, "linux,initrd-start", initrd_image_start);
0102         if (status)
0103             goto fdt_set_fail;
0104 
0105         initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size);
0106         status = fdt_setprop_var(fdt, node, "linux,initrd-end", initrd_image_end);
0107         if (status)
0108             goto fdt_set_fail;
0109     }
0110 
0111     /* Add FDT entries for EFI runtime services in chosen node. */
0112     node = fdt_subnode_offset(fdt, 0, "chosen");
0113     fdt_val64 = cpu_to_fdt64((u64)(unsigned long)efi_system_table);
0114 
0115     status = fdt_setprop_var(fdt, node, "linux,uefi-system-table", fdt_val64);
0116     if (status)
0117         goto fdt_set_fail;
0118 
0119     fdt_val64 = U64_MAX; /* placeholder */
0120 
0121     status = fdt_setprop_var(fdt, node, "linux,uefi-mmap-start", fdt_val64);
0122     if (status)
0123         goto fdt_set_fail;
0124 
0125     fdt_val32 = U32_MAX; /* placeholder */
0126 
0127     status = fdt_setprop_var(fdt, node, "linux,uefi-mmap-size", fdt_val32);
0128     if (status)
0129         goto fdt_set_fail;
0130 
0131     status = fdt_setprop_var(fdt, node, "linux,uefi-mmap-desc-size", fdt_val32);
0132     if (status)
0133         goto fdt_set_fail;
0134 
0135     status = fdt_setprop_var(fdt, node, "linux,uefi-mmap-desc-ver", fdt_val32);
0136     if (status)
0137         goto fdt_set_fail;
0138 
0139     if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && !efi_nokaslr) {
0140         efi_status_t efi_status;
0141 
0142         efi_status = efi_get_random_bytes(sizeof(fdt_val64),
0143                           (u8 *)&fdt_val64);
0144         if (efi_status == EFI_SUCCESS) {
0145             status = fdt_setprop_var(fdt, node, "kaslr-seed", fdt_val64);
0146             if (status)
0147                 goto fdt_set_fail;
0148         }
0149     }
0150 
0151     /* Shrink the FDT back to its minimum size: */
0152     fdt_pack(fdt);
0153 
0154     return EFI_SUCCESS;
0155 
0156 fdt_set_fail:
0157     if (status == -FDT_ERR_NOSPACE)
0158         return EFI_BUFFER_TOO_SMALL;
0159 
0160     return EFI_LOAD_ERROR;
0161 }
0162 
0163 static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map)
0164 {
0165     int node = fdt_path_offset(fdt, "/chosen");
0166     u64 fdt_val64;
0167     u32 fdt_val32;
0168     int err;
0169 
0170     if (node < 0)
0171         return EFI_LOAD_ERROR;
0172 
0173     fdt_val64 = cpu_to_fdt64((unsigned long)*map->map);
0174 
0175     err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-start", fdt_val64);
0176     if (err)
0177         return EFI_LOAD_ERROR;
0178 
0179     fdt_val32 = cpu_to_fdt32(*map->map_size);
0180 
0181     err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-size", fdt_val32);
0182     if (err)
0183         return EFI_LOAD_ERROR;
0184 
0185     fdt_val32 = cpu_to_fdt32(*map->desc_size);
0186 
0187     err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-desc-size", fdt_val32);
0188     if (err)
0189         return EFI_LOAD_ERROR;
0190 
0191     fdt_val32 = cpu_to_fdt32(*map->desc_ver);
0192 
0193     err = fdt_setprop_inplace_var(fdt, node, "linux,uefi-mmap-desc-ver", fdt_val32);
0194     if (err)
0195         return EFI_LOAD_ERROR;
0196 
0197     return EFI_SUCCESS;
0198 }
0199 
0200 struct exit_boot_struct {
0201     efi_memory_desc_t   *runtime_map;
0202     int         *runtime_entry_count;
0203     void            *new_fdt_addr;
0204 };
0205 
0206 static efi_status_t exit_boot_func(struct efi_boot_memmap *map,
0207                    void *priv)
0208 {
0209     struct exit_boot_struct *p = priv;
0210     /*
0211      * Update the memory map with virtual addresses. The function will also
0212      * populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME
0213      * entries so that we can pass it straight to SetVirtualAddressMap()
0214      */
0215     efi_get_virtmap(*map->map, *map->map_size, *map->desc_size,
0216             p->runtime_map, p->runtime_entry_count);
0217 
0218     return update_fdt_memmap(p->new_fdt_addr, map);
0219 }
0220 
0221 #ifndef MAX_FDT_SIZE
0222 # define MAX_FDT_SIZE SZ_2M
0223 #endif
0224 
0225 /*
0226  * Allocate memory for a new FDT, then add EFI, commandline, and
0227  * initrd related fields to the FDT.  This routine increases the
0228  * FDT allocation size until the allocated memory is large
0229  * enough.  EFI allocations are in EFI_PAGE_SIZE granules,
0230  * which are fixed at 4K bytes, so in most cases the first
0231  * allocation should succeed.
0232  * EFI boot services are exited at the end of this function.
0233  * There must be no allocations between the get_memory_map()
0234  * call and the exit_boot_services() call, so the exiting of
0235  * boot services is very tightly tied to the creation of the FDT
0236  * with the final memory map in it.
0237  */
0238 
0239 efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
0240                         unsigned long *new_fdt_addr,
0241                         u64 initrd_addr, u64 initrd_size,
0242                         char *cmdline_ptr,
0243                         unsigned long fdt_addr,
0244                         unsigned long fdt_size)
0245 {
0246     unsigned long map_size, desc_size, buff_size;
0247     u32 desc_ver;
0248     unsigned long mmap_key;
0249     efi_memory_desc_t *memory_map, *runtime_map;
0250     efi_status_t status;
0251     int runtime_entry_count;
0252     struct efi_boot_memmap map;
0253     struct exit_boot_struct priv;
0254 
0255     map.map     = &runtime_map;
0256     map.map_size    = &map_size;
0257     map.desc_size   = &desc_size;
0258     map.desc_ver    = &desc_ver;
0259     map.key_ptr = &mmap_key;
0260     map.buff_size   = &buff_size;
0261 
0262     /*
0263      * Get a copy of the current memory map that we will use to prepare
0264      * the input for SetVirtualAddressMap(). We don't have to worry about
0265      * subsequent allocations adding entries, since they could not affect
0266      * the number of EFI_MEMORY_RUNTIME regions.
0267      */
0268     status = efi_get_memory_map(&map);
0269     if (status != EFI_SUCCESS) {
0270         efi_err("Unable to retrieve UEFI memory map.\n");
0271         return status;
0272     }
0273 
0274     efi_info("Exiting boot services...\n");
0275 
0276     map.map = &memory_map;
0277     status = efi_allocate_pages(MAX_FDT_SIZE, new_fdt_addr, ULONG_MAX);
0278     if (status != EFI_SUCCESS) {
0279         efi_err("Unable to allocate memory for new device tree.\n");
0280         goto fail;
0281     }
0282 
0283     /*
0284      * Now that we have done our final memory allocation (and free)
0285      * we can get the memory map key needed for exit_boot_services().
0286      */
0287     status = efi_get_memory_map(&map);
0288     if (status != EFI_SUCCESS)
0289         goto fail_free_new_fdt;
0290 
0291     status = update_fdt((void *)fdt_addr, fdt_size,
0292                 (void *)*new_fdt_addr, MAX_FDT_SIZE, cmdline_ptr,
0293                 initrd_addr, initrd_size);
0294 
0295     if (status != EFI_SUCCESS) {
0296         efi_err("Unable to construct new device tree.\n");
0297         goto fail_free_new_fdt;
0298     }
0299 
0300     runtime_entry_count     = 0;
0301     priv.runtime_map        = runtime_map;
0302     priv.runtime_entry_count    = &runtime_entry_count;
0303     priv.new_fdt_addr       = (void *)*new_fdt_addr;
0304 
0305     status = efi_exit_boot_services(handle, &map, &priv, exit_boot_func);
0306 
0307     if (status == EFI_SUCCESS) {
0308         efi_set_virtual_address_map_t *svam;
0309 
0310         if (efi_novamap)
0311             return EFI_SUCCESS;
0312 
0313         /* Install the new virtual address map */
0314         svam = efi_system_table->runtime->set_virtual_address_map;
0315         status = svam(runtime_entry_count * desc_size, desc_size,
0316                   desc_ver, runtime_map);
0317 
0318         /*
0319          * We are beyond the point of no return here, so if the call to
0320          * SetVirtualAddressMap() failed, we need to signal that to the
0321          * incoming kernel but proceed normally otherwise.
0322          */
0323         if (status != EFI_SUCCESS) {
0324             int l;
0325 
0326             /*
0327              * Set the virtual address field of all
0328              * EFI_MEMORY_RUNTIME entries to 0. This will signal
0329              * the incoming kernel that no virtual translation has
0330              * been installed.
0331              */
0332             for (l = 0; l < map_size; l += desc_size) {
0333                 efi_memory_desc_t *p = (void *)memory_map + l;
0334 
0335                 if (p->attribute & EFI_MEMORY_RUNTIME)
0336                     p->virt_addr = 0;
0337             }
0338         }
0339         return EFI_SUCCESS;
0340     }
0341 
0342     efi_err("Exit boot services failed.\n");
0343 
0344 fail_free_new_fdt:
0345     efi_free(MAX_FDT_SIZE, *new_fdt_addr);
0346 
0347 fail:
0348     efi_system_table->boottime->free_pool(runtime_map);
0349 
0350     return EFI_LOAD_ERROR;
0351 }
0352 
0353 void *get_fdt(unsigned long *fdt_size)
0354 {
0355     void *fdt;
0356 
0357     fdt = get_efi_config_table(DEVICE_TREE_GUID);
0358 
0359     if (!fdt)
0360         return NULL;
0361 
0362     if (fdt_check_header(fdt) != 0) {
0363         efi_err("Invalid header detected on UEFI supplied FDT, ignoring ...\n");
0364         return NULL;
0365     }
0366     *fdt_size = fdt_totalsize(fdt);
0367     return fdt;
0368 }