Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Extensible Firmware Interface
0004  *
0005  * Copyright (C) 2020 Western Digital Corporation or its affiliates.
0006  *
0007  * Based on Extensible Firmware Interface Specification version 2.4
0008  * Adapted from drivers/firmware/efi/arm-runtime.c
0009  *
0010  */
0011 
0012 #include <linux/dmi.h>
0013 #include <linux/efi.h>
0014 #include <linux/io.h>
0015 #include <linux/memblock.h>
0016 #include <linux/mm_types.h>
0017 #include <linux/preempt.h>
0018 #include <linux/rbtree.h>
0019 #include <linux/rwsem.h>
0020 #include <linux/sched.h>
0021 #include <linux/slab.h>
0022 #include <linux/spinlock.h>
0023 #include <linux/pgtable.h>
0024 
0025 #include <asm/cacheflush.h>
0026 #include <asm/efi.h>
0027 #include <asm/mmu.h>
0028 #include <asm/pgalloc.h>
0029 
0030 static bool __init efi_virtmap_init(void)
0031 {
0032     efi_memory_desc_t *md;
0033 
0034     efi_mm.pgd = pgd_alloc(&efi_mm);
0035     mm_init_cpumask(&efi_mm);
0036     init_new_context(NULL, &efi_mm);
0037 
0038     for_each_efi_memory_desc(md) {
0039         phys_addr_t phys = md->phys_addr;
0040         int ret;
0041 
0042         if (!(md->attribute & EFI_MEMORY_RUNTIME))
0043             continue;
0044         if (md->virt_addr == 0)
0045             return false;
0046 
0047         ret = efi_create_mapping(&efi_mm, md);
0048         if (ret) {
0049             pr_warn("  EFI remap %pa: failed to create mapping (%d)\n",
0050                 &phys, ret);
0051             return false;
0052         }
0053     }
0054 
0055     if (efi_memattr_apply_permissions(&efi_mm, efi_set_mapping_permissions))
0056         return false;
0057 
0058     return true;
0059 }
0060 
0061 /*
0062  * Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
0063  * non-early mapping of the UEFI system table and virtual mappings for all
0064  * EFI_MEMORY_RUNTIME regions.
0065  */
0066 static int __init riscv_enable_runtime_services(void)
0067 {
0068     u64 mapsize;
0069 
0070     if (!efi_enabled(EFI_BOOT)) {
0071         pr_info("EFI services will not be available.\n");
0072         return 0;
0073     }
0074 
0075     efi_memmap_unmap();
0076 
0077     mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
0078 
0079     if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
0080         pr_err("Failed to remap EFI memory map\n");
0081         return 0;
0082     }
0083 
0084     if (efi_soft_reserve_enabled()) {
0085         efi_memory_desc_t *md;
0086 
0087         for_each_efi_memory_desc(md) {
0088             int md_size = md->num_pages << EFI_PAGE_SHIFT;
0089             struct resource *res;
0090 
0091             if (!(md->attribute & EFI_MEMORY_SP))
0092                 continue;
0093 
0094             res = kzalloc(sizeof(*res), GFP_KERNEL);
0095             if (WARN_ON(!res))
0096                 break;
0097 
0098             res->start  = md->phys_addr;
0099             res->end    = md->phys_addr + md_size - 1;
0100             res->name   = "Soft Reserved";
0101             res->flags  = IORESOURCE_MEM;
0102             res->desc   = IORES_DESC_SOFT_RESERVED;
0103 
0104             insert_resource(&iomem_resource, res);
0105         }
0106     }
0107 
0108     if (efi_runtime_disabled()) {
0109         pr_info("EFI runtime services will be disabled.\n");
0110         return 0;
0111     }
0112 
0113     if (efi_enabled(EFI_RUNTIME_SERVICES)) {
0114         pr_info("EFI runtime services access via paravirt.\n");
0115         return 0;
0116     }
0117 
0118     pr_info("Remapping and enabling EFI services.\n");
0119 
0120     if (!efi_virtmap_init()) {
0121         pr_err("UEFI virtual mapping missing or invalid -- runtime services will not be available\n");
0122         return -ENOMEM;
0123     }
0124 
0125     /* Set up runtime services function pointers */
0126     efi_native_runtime_setup();
0127     set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
0128 
0129     return 0;
0130 }
0131 early_initcall(riscv_enable_runtime_services);
0132 
0133 void efi_virtmap_load(void)
0134 {
0135     preempt_disable();
0136     switch_mm(current->active_mm, &efi_mm, NULL);
0137 }
0138 
0139 void efi_virtmap_unload(void)
0140 {
0141     switch_mm(&efi_mm, current->active_mm, NULL);
0142     preempt_enable();
0143 }