0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/kernel.h>
0015 #include <linux/efi.h>
0016 #include <linux/init.h>
0017 #include <linux/memblock.h>
0018 #include <linux/types.h>
0019 #include <linux/sort.h>
0020 #include "fake_mem.h"
0021
0022 struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
0023 int nr_fake_mem;
0024
0025 static int __init cmp_fake_mem(const void *x1, const void *x2)
0026 {
0027 const struct efi_mem_range *m1 = x1;
0028 const struct efi_mem_range *m2 = x2;
0029
0030 if (m1->range.start < m2->range.start)
0031 return -1;
0032 if (m1->range.start > m2->range.start)
0033 return 1;
0034 return 0;
0035 }
0036
0037 static void __init efi_fake_range(struct efi_mem_range *efi_range)
0038 {
0039 struct efi_memory_map_data data = { 0 };
0040 int new_nr_map = efi.memmap.nr_map;
0041 efi_memory_desc_t *md;
0042 void *new_memmap;
0043
0044
0045 for_each_efi_memory_desc(md)
0046 new_nr_map += efi_memmap_split_count(md, &efi_range->range);
0047
0048
0049 if (efi_memmap_alloc(new_nr_map, &data) != 0)
0050 return;
0051
0052
0053 new_memmap = early_memremap(data.phys_map, data.size);
0054 if (!new_memmap) {
0055 __efi_memmap_free(data.phys_map, data.size, data.flags);
0056 return;
0057 }
0058
0059 efi_memmap_insert(&efi.memmap, new_memmap, efi_range);
0060
0061
0062 early_memunmap(new_memmap, data.size);
0063
0064 efi_memmap_install(&data);
0065 }
0066
0067 void __init efi_fake_memmap(void)
0068 {
0069 int i;
0070
0071 if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
0072 return;
0073
0074 for (i = 0; i < nr_fake_mem; i++)
0075 efi_fake_range(&efi_fake_mems[i]);
0076
0077
0078 efi_print_memmap();
0079 }
0080
0081 static int __init setup_fake_mem(char *p)
0082 {
0083 u64 start = 0, mem_size = 0, attribute = 0;
0084 int i;
0085
0086 if (!p)
0087 return -EINVAL;
0088
0089 while (*p != '\0') {
0090 mem_size = memparse(p, &p);
0091 if (*p == '@')
0092 start = memparse(p+1, &p);
0093 else
0094 break;
0095
0096 if (*p == ':')
0097 attribute = simple_strtoull(p+1, &p, 0);
0098 else
0099 break;
0100
0101 if (nr_fake_mem >= EFI_MAX_FAKEMEM)
0102 break;
0103
0104 efi_fake_mems[nr_fake_mem].range.start = start;
0105 efi_fake_mems[nr_fake_mem].range.end = start + mem_size - 1;
0106 efi_fake_mems[nr_fake_mem].attribute = attribute;
0107 nr_fake_mem++;
0108
0109 if (*p == ',')
0110 p++;
0111 }
0112
0113 sort(efi_fake_mems, nr_fake_mem, sizeof(struct efi_mem_range),
0114 cmp_fake_mem, NULL);
0115
0116 for (i = 0; i < nr_fake_mem; i++)
0117 pr_info("efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx]",
0118 efi_fake_mems[i].attribute, efi_fake_mems[i].range.start,
0119 efi_fake_mems[i].range.end);
0120
0121 return *p == '\0' ? 0 : -EINVAL;
0122 }
0123
0124 early_param("efi_fake_mem", setup_fake_mem);