4 * Copyright (C) 2015 FUJITSU LIMITED
5 * Author: Taku Izumi <izumi.taku@jp.fujitsu.com>
7 * This code introduces new boot option named "efi_fake_mem"
8 * By specifying this parameter, you can add arbitrary attribute to
9 * specific memory range by updating original (firmware provided) EFI
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms and conditions of the GNU General Public License,
14 * version 2, as published by the Free Software Foundation.
16 * This program is distributed in the hope it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
21 * You should have received a copy of the GNU General Public License along with
22 * this program; if not, see <http://www.gnu.org/licenses/>.
24 * The full GNU General Public License is included in this distribution in
25 * the file called "COPYING".
28 #include <linux/kernel.h>
29 #include <linux/efi.h>
30 #include <linux/init.h>
31 #include <linux/memblock.h>
32 #include <linux/types.h>
33 #include <linux/sort.h>
36 #define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
38 static struct efi_mem_range fake_mems
[EFI_MAX_FAKEMEM
];
39 static int nr_fake_mem
;
41 static int __init
cmp_fake_mem(const void *x1
, const void *x2
)
43 const struct efi_mem_range
*m1
= x1
;
44 const struct efi_mem_range
*m2
= x2
;
46 if (m1
->range
.start
< m2
->range
.start
)
48 if (m1
->range
.start
> m2
->range
.start
)
53 void __init
efi_fake_memmap(void)
55 int new_nr_map
= efi
.memmap
.nr_map
;
56 efi_memory_desc_t
*md
;
57 phys_addr_t new_memmap_phy
;
64 /* count up the number of EFI memory descriptor */
65 for (i
= 0; i
< nr_fake_mem
; i
++) {
66 for_each_efi_memory_desc(md
) {
67 struct range
*r
= &fake_mems
[i
].range
;
69 new_nr_map
+= efi_memmap_split_count(md
, r
);
73 /* allocate memory for new EFI memmap */
74 new_memmap_phy
= efi_memmap_alloc(new_nr_map
);
78 /* create new EFI memmap */
79 new_memmap
= early_memremap(new_memmap_phy
,
80 efi
.memmap
.desc_size
* new_nr_map
);
82 memblock_free(new_memmap_phy
, efi
.memmap
.desc_size
* new_nr_map
);
86 for (i
= 0; i
< nr_fake_mem
; i
++)
87 efi_memmap_insert(&efi
.memmap
, new_memmap
, &fake_mems
[i
]);
89 /* swap into new EFI memmap */
90 early_memunmap(new_memmap
, efi
.memmap
.desc_size
* new_nr_map
);
92 efi_memmap_install(new_memmap_phy
, new_nr_map
);
94 /* print new EFI memmap */
98 static int __init
setup_fake_mem(char *p
)
100 u64 start
= 0, mem_size
= 0, attribute
= 0;
107 mem_size
= memparse(p
, &p
);
109 start
= memparse(p
+1, &p
);
114 attribute
= simple_strtoull(p
+1, &p
, 0);
118 if (nr_fake_mem
>= EFI_MAX_FAKEMEM
)
121 fake_mems
[nr_fake_mem
].range
.start
= start
;
122 fake_mems
[nr_fake_mem
].range
.end
= start
+ mem_size
- 1;
123 fake_mems
[nr_fake_mem
].attribute
= attribute
;
130 sort(fake_mems
, nr_fake_mem
, sizeof(struct efi_mem_range
),
133 for (i
= 0; i
< nr_fake_mem
; i
++)
134 pr_info("efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx]",
135 fake_mems
[i
].attribute
, fake_mems
[i
].range
.start
,
136 fake_mems
[i
].range
.end
);
138 return *p
== '\0' ? 0 : -EINVAL
;
141 early_param("efi_fake_mem", setup_fake_mem
);