fake_mem.c (2833B)
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 "fake_mem.h" 21 22struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM]; 23int nr_fake_mem; 24 25static int __init cmp_fake_mem(const void *x1, const void *x2) 26{ 27 const struct efi_mem_range *m1 = x1; 28 const struct efi_mem_range *m2 = x2; 29 30 if (m1->range.start < m2->range.start) 31 return -1; 32 if (m1->range.start > m2->range.start) 33 return 1; 34 return 0; 35} 36 37static void __init efi_fake_range(struct efi_mem_range *efi_range) 38{ 39 struct efi_memory_map_data data = { 0 }; 40 int new_nr_map = efi.memmap.nr_map; 41 efi_memory_desc_t *md; 42 void *new_memmap; 43 44 /* count up the number of EFI memory descriptor */ 45 for_each_efi_memory_desc(md) 46 new_nr_map += efi_memmap_split_count(md, &efi_range->range); 47 48 /* allocate memory for new EFI memmap */ 49 if (efi_memmap_alloc(new_nr_map, &data) != 0) 50 return; 51 52 /* create new EFI memmap */ 53 new_memmap = early_memremap(data.phys_map, data.size); 54 if (!new_memmap) { 55 __efi_memmap_free(data.phys_map, data.size, data.flags); 56 return; 57 } 58 59 efi_memmap_insert(&efi.memmap, new_memmap, efi_range); 60 61 /* swap into new EFI memmap */ 62 early_memunmap(new_memmap, data.size); 63 64 efi_memmap_install(&data); 65} 66 67void __init efi_fake_memmap(void) 68{ 69 int i; 70 71 if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem) 72 return; 73 74 for (i = 0; i < nr_fake_mem; i++) 75 efi_fake_range(&efi_fake_mems[i]); 76 77 /* print new EFI memmap */ 78 efi_print_memmap(); 79} 80 81static int __init setup_fake_mem(char *p) 82{ 83 u64 start = 0, mem_size = 0, attribute = 0; 84 int i; 85 86 if (!p) 87 return -EINVAL; 88 89 while (*p != '\0') { 90 mem_size = memparse(p, &p); 91 if (*p == '@') 92 start = memparse(p+1, &p); 93 else 94 break; 95 96 if (*p == ':') 97 attribute = simple_strtoull(p+1, &p, 0); 98 else 99 break; 100 101 if (nr_fake_mem >= EFI_MAX_FAKEMEM) 102 break; 103 104 efi_fake_mems[nr_fake_mem].range.start = start; 105 efi_fake_mems[nr_fake_mem].range.end = start + mem_size - 1; 106 efi_fake_mems[nr_fake_mem].attribute = attribute; 107 nr_fake_mem++; 108 109 if (*p == ',') 110 p++; 111 } 112 113 sort(efi_fake_mems, nr_fake_mem, sizeof(struct efi_mem_range), 114 cmp_fake_mem, NULL); 115 116 for (i = 0; i < nr_fake_mem; i++) 117 pr_info("efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx]", 118 efi_fake_mems[i].attribute, efi_fake_mems[i].range.start, 119 efi_fake_mems[i].range.end); 120 121 return *p == '\0' ? 0 : -EINVAL; 122} 123 124early_param("efi_fake_mem", setup_fake_mem);