root/drivers/firmware/efi/fake_mem.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cmp_fake_mem
  2. efi_fake_memmap
  3. setup_fake_mem

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * fake_mem.c
   4  *
   5  * Copyright (C) 2015 FUJITSU LIMITED
   6  * Author: Taku Izumi <izumi.taku@jp.fujitsu.com>
   7  *
   8  * This code introduces new boot option named "efi_fake_mem"
   9  * By specifying this parameter, you can add arbitrary attribute to
  10  * specific memory range by updating original (firmware provided) EFI
  11  * memmap.
  12  */
  13 
  14 #include <linux/kernel.h>
  15 #include <linux/efi.h>
  16 #include <linux/init.h>
  17 #include <linux/memblock.h>
  18 #include <linux/types.h>
  19 #include <linux/sort.h>
  20 #include <asm/efi.h>
  21 
  22 #define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
  23 
  24 static struct efi_mem_range fake_mems[EFI_MAX_FAKEMEM];
  25 static int nr_fake_mem;
  26 
  27 static int __init cmp_fake_mem(const void *x1, const void *x2)
  28 {
  29         const struct efi_mem_range *m1 = x1;
  30         const struct efi_mem_range *m2 = x2;
  31 
  32         if (m1->range.start < m2->range.start)
  33                 return -1;
  34         if (m1->range.start > m2->range.start)
  35                 return 1;
  36         return 0;
  37 }
  38 
  39 void __init efi_fake_memmap(void)
  40 {
  41         int new_nr_map = efi.memmap.nr_map;
  42         efi_memory_desc_t *md;
  43         phys_addr_t new_memmap_phy;
  44         void *new_memmap;
  45         int i;
  46 
  47         if (!nr_fake_mem)
  48                 return;
  49 
  50         /* count up the number of EFI memory descriptor */
  51         for (i = 0; i < nr_fake_mem; i++) {
  52                 for_each_efi_memory_desc(md) {
  53                         struct range *r = &fake_mems[i].range;
  54 
  55                         new_nr_map += efi_memmap_split_count(md, r);
  56                 }
  57         }
  58 
  59         /* allocate memory for new EFI memmap */
  60         new_memmap_phy = efi_memmap_alloc(new_nr_map);
  61         if (!new_memmap_phy)
  62                 return;
  63 
  64         /* create new EFI memmap */
  65         new_memmap = early_memremap(new_memmap_phy,
  66                                     efi.memmap.desc_size * new_nr_map);
  67         if (!new_memmap) {
  68                 memblock_free(new_memmap_phy, efi.memmap.desc_size * new_nr_map);
  69                 return;
  70         }
  71 
  72         for (i = 0; i < nr_fake_mem; i++)
  73                 efi_memmap_insert(&efi.memmap, new_memmap, &fake_mems[i]);
  74 
  75         /* swap into new EFI memmap */
  76         early_memunmap(new_memmap, efi.memmap.desc_size * new_nr_map);
  77 
  78         efi_memmap_install(new_memmap_phy, new_nr_map);
  79 
  80         /* print new EFI memmap */
  81         efi_print_memmap();
  82 }
  83 
  84 static int __init setup_fake_mem(char *p)
  85 {
  86         u64 start = 0, mem_size = 0, attribute = 0;
  87         int i;
  88 
  89         if (!p)
  90                 return -EINVAL;
  91 
  92         while (*p != '\0') {
  93                 mem_size = memparse(p, &p);
  94                 if (*p == '@')
  95                         start = memparse(p+1, &p);
  96                 else
  97                         break;
  98 
  99                 if (*p == ':')
 100                         attribute = simple_strtoull(p+1, &p, 0);
 101                 else
 102                         break;
 103 
 104                 if (nr_fake_mem >= EFI_MAX_FAKEMEM)
 105                         break;
 106 
 107                 fake_mems[nr_fake_mem].range.start = start;
 108                 fake_mems[nr_fake_mem].range.end = start + mem_size - 1;
 109                 fake_mems[nr_fake_mem].attribute = attribute;
 110                 nr_fake_mem++;
 111 
 112                 if (*p == ',')
 113                         p++;
 114         }
 115 
 116         sort(fake_mems, nr_fake_mem, sizeof(struct efi_mem_range),
 117              cmp_fake_mem, NULL);
 118 
 119         for (i = 0; i < nr_fake_mem; i++)
 120                 pr_info("efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx]",
 121                         fake_mems[i].attribute, fake_mems[i].range.start,
 122                         fake_mems[i].range.end);
 123 
 124         return *p == '\0' ? 0 : -EINVAL;
 125 }
 126 
 127 early_param("efi_fake_mem", setup_fake_mem);

/* [<][>][^][v][top][bottom][index][help] */