Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 
0003 #include <linux/kernel.h>
0004 #include <linux/libfdt.h>
0005 #include <linux/sizes.h>
0006 
0007 static const void *get_prop(const void *fdt, const char *node_path,
0008                 const char *property, int minlen)
0009 {
0010     const void *prop;
0011     int offset, len;
0012 
0013     offset = fdt_path_offset(fdt, node_path);
0014     if (offset < 0)
0015         return NULL;
0016 
0017     prop = fdt_getprop(fdt, offset, property, &len);
0018     if (!prop || len < minlen)
0019         return NULL;
0020 
0021     return prop;
0022 }
0023 
0024 static uint32_t get_cells(const void *fdt, const char *name)
0025 {
0026     const fdt32_t *prop = get_prop(fdt, "/", name, sizeof(fdt32_t));
0027 
0028     if (!prop) {
0029         /* default */
0030         return 1;
0031     }
0032 
0033     return fdt32_ld(prop);
0034 }
0035 
0036 static uint64_t get_val(const fdt32_t *cells, uint32_t ncells)
0037 {
0038     uint64_t r;
0039 
0040     r = fdt32_ld(cells);
0041     if (ncells > 1)
0042         r = (r << 32) | fdt32_ld(cells + 1);
0043 
0044     return r;
0045 }
0046 
0047 /*
0048  * Check the start of physical memory
0049  *
0050  * Traditionally, the start address of physical memory is obtained by masking
0051  * the program counter.  However, this does require that this address is a
0052  * multiple of 128 MiB, precluding booting Linux on platforms where this
0053  * requirement is not fulfilled.
0054  * Hence validate the calculated address against the memory information in the
0055  * DTB, and, if out-of-range, replace it by the real start address.
0056  * To preserve backwards compatibility (systems reserving a block of memory
0057  * at the start of physical memory, kdump, ...), the traditional method is
0058  * used if it yields a valid address, unless the "linux,usable-memory-range"
0059  * property is present.
0060  *
0061  * Return value: start address of physical memory to use
0062  */
0063 uint32_t fdt_check_mem_start(uint32_t mem_start, const void *fdt)
0064 {
0065     uint32_t addr_cells, size_cells, usable_base, base;
0066     uint32_t fdt_mem_start = 0xffffffff;
0067     const fdt32_t *usable, *reg, *endp;
0068     uint64_t size, usable_end, end;
0069     const char *type;
0070     int offset, len;
0071 
0072     if (!fdt)
0073         return mem_start;
0074 
0075     if (fdt_magic(fdt) != FDT_MAGIC)
0076         return mem_start;
0077 
0078     /* There may be multiple cells on LPAE platforms */
0079     addr_cells = get_cells(fdt, "#address-cells");
0080     size_cells = get_cells(fdt, "#size-cells");
0081     if (addr_cells > 2 || size_cells > 2)
0082         return mem_start;
0083 
0084     /*
0085      * Usable memory in case of a crash dump kernel
0086      * This property describes a limitation: memory within this range is
0087      * only valid when also described through another mechanism
0088      */
0089     usable = get_prop(fdt, "/chosen", "linux,usable-memory-range",
0090               (addr_cells + size_cells) * sizeof(fdt32_t));
0091     if (usable) {
0092         size = get_val(usable + addr_cells, size_cells);
0093         if (!size)
0094             return mem_start;
0095 
0096         if (addr_cells > 1 && fdt32_ld(usable)) {
0097             /* Outside 32-bit address space */
0098             return mem_start;
0099         }
0100 
0101         usable_base = fdt32_ld(usable + addr_cells - 1);
0102         usable_end = usable_base + size;
0103     }
0104 
0105     /* Walk all memory nodes and regions */
0106     for (offset = fdt_next_node(fdt, -1, NULL); offset >= 0;
0107          offset = fdt_next_node(fdt, offset, NULL)) {
0108         type = fdt_getprop(fdt, offset, "device_type", NULL);
0109         if (!type || strcmp(type, "memory"))
0110             continue;
0111 
0112         reg = fdt_getprop(fdt, offset, "linux,usable-memory", &len);
0113         if (!reg)
0114             reg = fdt_getprop(fdt, offset, "reg", &len);
0115         if (!reg)
0116             continue;
0117 
0118         for (endp = reg + (len / sizeof(fdt32_t));
0119              endp - reg >= addr_cells + size_cells;
0120              reg += addr_cells + size_cells) {
0121             size = get_val(reg + addr_cells, size_cells);
0122             if (!size)
0123                 continue;
0124 
0125             if (addr_cells > 1 && fdt32_ld(reg)) {
0126                 /* Outside 32-bit address space, skipping */
0127                 continue;
0128             }
0129 
0130             base = fdt32_ld(reg + addr_cells - 1);
0131             end = base + size;
0132             if (usable) {
0133                 /*
0134                  * Clip to usable range, which takes precedence
0135                  * over mem_start
0136                  */
0137                 if (base < usable_base)
0138                     base = usable_base;
0139 
0140                 if (end > usable_end)
0141                     end = usable_end;
0142 
0143                 if (end <= base)
0144                     continue;
0145             } else if (mem_start >= base && mem_start < end) {
0146                 /* Calculated address is valid, use it */
0147                 return mem_start;
0148             }
0149 
0150             if (base < fdt_mem_start)
0151                 fdt_mem_start = base;
0152         }
0153     }
0154 
0155     if (fdt_mem_start == 0xffffffff) {
0156         /* No usable memory found, falling back to default */
0157         return mem_start;
0158     }
0159 
0160     /*
0161      * The calculated address is not usable, or was overridden by the
0162      * "linux,usable-memory-range" property.
0163      * Use the lowest usable physical memory address from the DTB instead,
0164      * and make sure this is a multiple of 2 MiB for phys/virt patching.
0165      */
0166     return round_up(fdt_mem_start, SZ_2M);
0167 }