fdt_check_mem_start.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/kernel.h>
  3. #include <linux/libfdt.h>
  4. #include <linux/sizes.h>
  5. #include "misc.h"
  6. static const void *get_prop(const void *fdt, const char *node_path,
  7. const char *property, int minlen)
  8. {
  9. const void *prop;
  10. int offset, len;
  11. offset = fdt_path_offset(fdt, node_path);
  12. if (offset < 0)
  13. return NULL;
  14. prop = fdt_getprop(fdt, offset, property, &len);
  15. if (!prop || len < minlen)
  16. return NULL;
  17. return prop;
  18. }
  19. static uint32_t get_cells(const void *fdt, const char *name)
  20. {
  21. const fdt32_t *prop = get_prop(fdt, "/", name, sizeof(fdt32_t));
  22. if (!prop) {
  23. /* default */
  24. return 1;
  25. }
  26. return fdt32_ld(prop);
  27. }
  28. static uint64_t get_val(const fdt32_t *cells, uint32_t ncells)
  29. {
  30. uint64_t r;
  31. r = fdt32_ld(cells);
  32. if (ncells > 1)
  33. r = (r << 32) | fdt32_ld(cells + 1);
  34. return r;
  35. }
  36. /*
  37. * Check the start of physical memory
  38. *
  39. * Traditionally, the start address of physical memory is obtained by masking
  40. * the program counter. However, this does require that this address is a
  41. * multiple of 128 MiB, precluding booting Linux on platforms where this
  42. * requirement is not fulfilled.
  43. * Hence validate the calculated address against the memory information in the
  44. * DTB, and, if out-of-range, replace it by the real start address.
  45. * To preserve backwards compatibility (systems reserving a block of memory
  46. * at the start of physical memory, kdump, ...), the traditional method is
  47. * used if it yields a valid address, unless the "linux,usable-memory-range"
  48. * property is present.
  49. *
  50. * Return value: start address of physical memory to use
  51. */
  52. uint32_t fdt_check_mem_start(uint32_t mem_start, const void *fdt)
  53. {
  54. uint32_t addr_cells, size_cells, usable_base, base;
  55. uint32_t fdt_mem_start = 0xffffffff;
  56. const fdt32_t *usable, *reg, *endp;
  57. uint64_t size, usable_end, end;
  58. const char *type;
  59. int offset, len;
  60. if (!fdt)
  61. return mem_start;
  62. if (fdt_magic(fdt) != FDT_MAGIC)
  63. return mem_start;
  64. /* There may be multiple cells on LPAE platforms */
  65. addr_cells = get_cells(fdt, "#address-cells");
  66. size_cells = get_cells(fdt, "#size-cells");
  67. if (addr_cells > 2 || size_cells > 2)
  68. return mem_start;
  69. /*
  70. * Usable memory in case of a crash dump kernel
  71. * This property describes a limitation: memory within this range is
  72. * only valid when also described through another mechanism
  73. */
  74. usable = get_prop(fdt, "/chosen", "linux,usable-memory-range",
  75. (addr_cells + size_cells) * sizeof(fdt32_t));
  76. if (usable) {
  77. size = get_val(usable + addr_cells, size_cells);
  78. if (!size)
  79. return mem_start;
  80. if (addr_cells > 1 && fdt32_ld(usable)) {
  81. /* Outside 32-bit address space */
  82. return mem_start;
  83. }
  84. usable_base = fdt32_ld(usable + addr_cells - 1);
  85. usable_end = usable_base + size;
  86. }
  87. /* Walk all memory nodes and regions */
  88. for (offset = fdt_next_node(fdt, -1, NULL); offset >= 0;
  89. offset = fdt_next_node(fdt, offset, NULL)) {
  90. type = fdt_getprop(fdt, offset, "device_type", NULL);
  91. if (!type || strcmp(type, "memory"))
  92. continue;
  93. reg = fdt_getprop(fdt, offset, "linux,usable-memory", &len);
  94. if (!reg)
  95. reg = fdt_getprop(fdt, offset, "reg", &len);
  96. if (!reg)
  97. continue;
  98. for (endp = reg + (len / sizeof(fdt32_t));
  99. endp - reg >= addr_cells + size_cells;
  100. reg += addr_cells + size_cells) {
  101. size = get_val(reg + addr_cells, size_cells);
  102. if (!size)
  103. continue;
  104. if (addr_cells > 1 && fdt32_ld(reg)) {
  105. /* Outside 32-bit address space, skipping */
  106. continue;
  107. }
  108. base = fdt32_ld(reg + addr_cells - 1);
  109. end = base + size;
  110. if (usable) {
  111. /*
  112. * Clip to usable range, which takes precedence
  113. * over mem_start
  114. */
  115. if (base < usable_base)
  116. base = usable_base;
  117. if (end > usable_end)
  118. end = usable_end;
  119. if (end <= base)
  120. continue;
  121. } else if (mem_start >= base && mem_start < end) {
  122. /* Calculated address is valid, use it */
  123. return mem_start;
  124. }
  125. if (base < fdt_mem_start)
  126. fdt_mem_start = base;
  127. }
  128. }
  129. if (fdt_mem_start == 0xffffffff) {
  130. /* No usable memory found, falling back to default */
  131. return mem_start;
  132. }
  133. /*
  134. * The calculated address is not usable, or was overridden by the
  135. * "linux,usable-memory-range" property.
  136. * Use the lowest usable physical memory address from the DTB instead,
  137. * and make sure this is a multiple of 2 MiB for phys/virt patching.
  138. */
  139. return round_up(fdt_mem_start, SZ_2M);
  140. }