~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/boot/compressed/fdt_check_mem_start.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php