LCOV - code coverage report
Current view: top level - drivers/firmware/efi - memattr.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 72 0.0 %
Date: 2022-03-28 13:20:08 Functions: 0 3 0.0 %
Branches: 0 52 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * Copyright (C) 2016 Linaro Ltd. <ard.biesheuvel@linaro.org>
       4                 :            :  */
       5                 :            : 
       6                 :            : #define pr_fmt(fmt)     "efi: memattr: " fmt
       7                 :            : 
       8                 :            : #include <linux/efi.h>
       9                 :            : #include <linux/init.h>
      10                 :            : #include <linux/io.h>
      11                 :            : #include <linux/memblock.h>
      12                 :            : 
      13                 :            : #include <asm/early_ioremap.h>
      14                 :            : 
      15                 :            : static int __initdata tbl_size;
      16                 :            : 
      17                 :            : /*
      18                 :            :  * Reserve the memory associated with the Memory Attributes configuration
      19                 :            :  * table, if it exists.
      20                 :            :  */
      21                 :          0 : int __init efi_memattr_init(void)
      22                 :            : {
      23                 :          0 :         efi_memory_attributes_table_t *tbl;
      24                 :            : 
      25         [ #  # ]:          0 :         if (efi.mem_attr_table == EFI_INVALID_TABLE_ADDR)
      26                 :            :                 return 0;
      27                 :            : 
      28                 :          0 :         tbl = early_memremap(efi.mem_attr_table, sizeof(*tbl));
      29         [ #  # ]:          0 :         if (!tbl) {
      30                 :          0 :                 pr_err("Failed to map EFI Memory Attributes table @ 0x%lx\n",
      31                 :            :                        efi.mem_attr_table);
      32                 :          0 :                 return -ENOMEM;
      33                 :            :         }
      34                 :            : 
      35         [ #  # ]:          0 :         if (tbl->version > 1) {
      36                 :          0 :                 pr_warn("Unexpected EFI Memory Attributes table version %d\n",
      37                 :            :                         tbl->version);
      38                 :          0 :                 goto unmap;
      39                 :            :         }
      40                 :            : 
      41                 :          0 :         tbl_size = sizeof(*tbl) + tbl->num_entries * tbl->desc_size;
      42                 :          0 :         memblock_reserve(efi.mem_attr_table, tbl_size);
      43                 :          0 :         set_bit(EFI_MEM_ATTR, &efi.flags);
      44                 :            : 
      45                 :          0 : unmap:
      46                 :          0 :         early_memunmap(tbl, sizeof(*tbl));
      47                 :          0 :         return 0;
      48                 :            : }
      49                 :            : 
      50                 :            : /*
      51                 :            :  * Returns a copy @out of the UEFI memory descriptor @in if it is covered
      52                 :            :  * entirely by a UEFI memory map entry with matching attributes. The virtual
      53                 :            :  * address of @out is set according to the matching entry that was found.
      54                 :            :  */
      55                 :          0 : static bool entry_is_valid(const efi_memory_desc_t *in, efi_memory_desc_t *out)
      56                 :            : {
      57                 :          0 :         u64 in_paddr = in->phys_addr;
      58                 :          0 :         u64 in_size = in->num_pages << EFI_PAGE_SHIFT;
      59                 :          0 :         efi_memory_desc_t *md;
      60                 :            : 
      61                 :          0 :         *out = *in;
      62                 :            : 
      63         [ #  # ]:          0 :         if (in->type != EFI_RUNTIME_SERVICES_CODE &&
      64                 :            :             in->type != EFI_RUNTIME_SERVICES_DATA) {
      65                 :          0 :                 pr_warn("Entry type should be RuntimeServiceCode/Data\n");
      66                 :          0 :                 return false;
      67                 :            :         }
      68                 :            : 
      69         [ #  # ]:          0 :         if (!(in->attribute & (EFI_MEMORY_RO | EFI_MEMORY_XP))) {
      70                 :          0 :                 pr_warn("Entry attributes invalid: RO and XP bits both cleared\n");
      71                 :          0 :                 return false;
      72                 :            :         }
      73                 :            : 
      74                 :          0 :         if (PAGE_SIZE > EFI_PAGE_SIZE &&
      75                 :            :             (!PAGE_ALIGNED(in->phys_addr) ||
      76                 :            :              !PAGE_ALIGNED(in->num_pages << EFI_PAGE_SHIFT))) {
      77                 :            :                 /*
      78                 :            :                  * Since arm64 may execute with page sizes of up to 64 KB, the
      79                 :            :                  * UEFI spec mandates that RuntimeServices memory regions must
      80                 :            :                  * be 64 KB aligned. We need to validate this here since we will
      81                 :            :                  * not be able to tighten permissions on such regions without
      82                 :            :                  * affecting adjacent regions.
      83                 :            :                  */
      84                 :            :                 pr_warn("Entry address region misaligned\n");
      85                 :            :                 return false;
      86                 :            :         }
      87                 :            : 
      88   [ #  #  #  # ]:          0 :         for_each_efi_memory_desc(md) {
      89                 :          0 :                 u64 md_paddr = md->phys_addr;
      90                 :          0 :                 u64 md_size = md->num_pages << EFI_PAGE_SHIFT;
      91                 :            : 
      92         [ #  # ]:          0 :                 if (!(md->attribute & EFI_MEMORY_RUNTIME))
      93                 :          0 :                         continue;
      94   [ #  #  #  # ]:          0 :                 if (md->virt_addr == 0 && md->phys_addr != 0) {
      95                 :            :                         /* no virtual mapping has been installed by the stub */
      96                 :            :                         break;
      97                 :            :                 }
      98                 :            : 
      99   [ #  #  #  # ]:          0 :                 if (md_paddr > in_paddr || (in_paddr - md_paddr) >= md_size)
     100                 :          0 :                         continue;
     101                 :            : 
     102                 :            :                 /*
     103                 :            :                  * This entry covers the start of @in, check whether
     104                 :            :                  * it covers the end as well.
     105                 :            :                  */
     106         [ #  # ]:          0 :                 if (md_paddr + md_size < in_paddr + in_size) {
     107                 :          0 :                         pr_warn("Entry covers multiple EFI memory map regions\n");
     108                 :          0 :                         return false;
     109                 :            :                 }
     110                 :            : 
     111         [ #  # ]:          0 :                 if (md->type != in->type) {
     112                 :          0 :                         pr_warn("Entry type deviates from EFI memory map region type\n");
     113                 :          0 :                         return false;
     114                 :            :                 }
     115                 :            : 
     116                 :          0 :                 out->virt_addr = in_paddr + (md->virt_addr - md_paddr);
     117                 :            : 
     118                 :          0 :                 return true;
     119                 :            :         }
     120                 :            : 
     121                 :          0 :         pr_warn("No matching entry found in the EFI memory map\n");
     122                 :          0 :         return false;
     123                 :            : }
     124                 :            : 
     125                 :            : /*
     126                 :            :  * To be called after the EFI page tables have been populated. If a memory
     127                 :            :  * attributes table is available, its contents will be used to update the
     128                 :            :  * mappings with tightened permissions as described by the table.
     129                 :            :  * This requires the UEFI memory map to have already been populated with
     130                 :            :  * virtual addresses.
     131                 :            :  */
     132                 :          0 : int __init efi_memattr_apply_permissions(struct mm_struct *mm,
     133                 :            :                                          efi_memattr_perm_setter fn)
     134                 :            : {
     135                 :          0 :         efi_memory_attributes_table_t *tbl;
     136                 :          0 :         int i, ret;
     137                 :            : 
     138         [ #  # ]:          0 :         if (tbl_size <= sizeof(*tbl))
     139                 :            :                 return 0;
     140                 :            : 
     141                 :            :         /*
     142                 :            :          * We need the EFI memory map to be setup so we can use it to
     143                 :            :          * lookup the virtual addresses of all entries in the  of EFI
     144                 :            :          * Memory Attributes table. If it isn't available, this
     145                 :            :          * function should not be called.
     146                 :            :          */
     147   [ #  #  #  # ]:          0 :         if (WARN_ON(!efi_enabled(EFI_MEMMAP)))
     148                 :            :                 return 0;
     149                 :            : 
     150                 :          0 :         tbl = memremap(efi.mem_attr_table, tbl_size, MEMREMAP_WB);
     151         [ #  # ]:          0 :         if (!tbl) {
     152                 :          0 :                 pr_err("Failed to map EFI Memory Attributes table @ 0x%lx\n",
     153                 :            :                        efi.mem_attr_table);
     154                 :          0 :                 return -ENOMEM;
     155                 :            :         }
     156                 :            : 
     157         [ #  # ]:          0 :         if (efi_enabled(EFI_DBG))
     158                 :          0 :                 pr_info("Processing EFI Memory Attributes table:\n");
     159                 :            : 
     160   [ #  #  #  # ]:          0 :         for (i = ret = 0; ret == 0 && i < tbl->num_entries; i++) {
     161                 :          0 :                 efi_memory_desc_t md;
     162                 :          0 :                 unsigned long size;
     163                 :          0 :                 bool valid;
     164                 :          0 :                 char buf[64];
     165                 :            : 
     166                 :          0 :                 valid = entry_is_valid((void *)tbl->entry + i * tbl->desc_size,
     167                 :            :                                        &md);
     168                 :          0 :                 size = md.num_pages << EFI_PAGE_SHIFT;
     169   [ #  #  #  # ]:          0 :                 if (efi_enabled(EFI_DBG) || !valid)
     170         [ #  # ]:          0 :                         pr_info("%s 0x%012llx-0x%012llx %s\n",
     171                 :            :                                 valid ? "" : "!", md.phys_addr,
     172                 :            :                                 md.phys_addr + size - 1,
     173                 :            :                                 efi_md_typeattr_format(buf, sizeof(buf), &md));
     174                 :            : 
     175         [ #  # ]:          0 :                 if (valid) {
     176                 :          0 :                         ret = fn(mm, &md);
     177         [ #  # ]:          0 :                         if (ret)
     178                 :          0 :                                 pr_err("Error updating mappings, skipping subsequent md's\n");
     179                 :            :                 }
     180                 :            :         }
     181                 :          0 :         memunmap(tbl);
     182                 :          0 :         return ret;
     183                 :            : }

Generated by: LCOV version 1.14