fake_mem.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * fake_mem.c
  4. *
  5. * Copyright (C) 2015 FUJITSU LIMITED
  6. * Author: Taku Izumi <[email protected]>
  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. #include <linux/kernel.h>
  14. #include <linux/efi.h>
  15. #include <linux/init.h>
  16. #include <linux/memblock.h>
  17. #include <linux/types.h>
  18. #include <linux/sort.h>
  19. #include "fake_mem.h"
  20. struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
  21. int nr_fake_mem;
  22. static int __init cmp_fake_mem(const void *x1, const void *x2)
  23. {
  24. const struct efi_mem_range *m1 = x1;
  25. const struct efi_mem_range *m2 = x2;
  26. if (m1->range.start < m2->range.start)
  27. return -1;
  28. if (m1->range.start > m2->range.start)
  29. return 1;
  30. return 0;
  31. }
  32. static void __init efi_fake_range(struct efi_mem_range *efi_range)
  33. {
  34. struct efi_memory_map_data data = { 0 };
  35. int new_nr_map = efi.memmap.nr_map;
  36. efi_memory_desc_t *md;
  37. void *new_memmap;
  38. /* count up the number of EFI memory descriptor */
  39. for_each_efi_memory_desc(md)
  40. new_nr_map += efi_memmap_split_count(md, &efi_range->range);
  41. /* allocate memory for new EFI memmap */
  42. if (efi_memmap_alloc(new_nr_map, &data) != 0)
  43. return;
  44. /* create new EFI memmap */
  45. new_memmap = early_memremap(data.phys_map, data.size);
  46. if (!new_memmap) {
  47. __efi_memmap_free(data.phys_map, data.size, data.flags);
  48. return;
  49. }
  50. efi_memmap_insert(&efi.memmap, new_memmap, efi_range);
  51. /* swap into new EFI memmap */
  52. early_memunmap(new_memmap, data.size);
  53. efi_memmap_install(&data);
  54. }
  55. void __init efi_fake_memmap(void)
  56. {
  57. int i;
  58. if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
  59. return;
  60. for (i = 0; i < nr_fake_mem; i++)
  61. efi_fake_range(&efi_fake_mems[i]);
  62. /* print new EFI memmap */
  63. efi_print_memmap();
  64. }
  65. static int __init setup_fake_mem(char *p)
  66. {
  67. u64 start = 0, mem_size = 0, attribute = 0;
  68. int i;
  69. if (!p)
  70. return -EINVAL;
  71. while (*p != '\0') {
  72. mem_size = memparse(p, &p);
  73. if (*p == '@')
  74. start = memparse(p+1, &p);
  75. else
  76. break;
  77. if (*p == ':')
  78. attribute = simple_strtoull(p+1, &p, 0);
  79. else
  80. break;
  81. if (nr_fake_mem >= EFI_MAX_FAKEMEM)
  82. break;
  83. efi_fake_mems[nr_fake_mem].range.start = start;
  84. efi_fake_mems[nr_fake_mem].range.end = start + mem_size - 1;
  85. efi_fake_mems[nr_fake_mem].attribute = attribute;
  86. nr_fake_mem++;
  87. if (*p == ',')
  88. p++;
  89. }
  90. sort(efi_fake_mems, nr_fake_mem, sizeof(struct efi_mem_range),
  91. cmp_fake_mem, NULL);
  92. for (i = 0; i < nr_fake_mem; i++)
  93. pr_info("efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx]",
  94. efi_fake_mems[i].attribute, efi_fake_mems[i].range.start,
  95. efi_fake_mems[i].range.end);
  96. return *p == '\0' ? 0 : -EINVAL;
  97. }
  98. early_param("efi_fake_mem", setup_fake_mem);