@@ -55,16 +55,17 @@ static uint64_t get_val(const fdt32_t *cells, uint32_t ncells)
5555 * DTB, and, if out-of-range, replace it by the real start address.
5656 * To preserve backwards compatibility (systems reserving a block of memory
5757 * at the start of physical memory, kdump, ...), the traditional method is
58- * always used if it yields a valid address.
58+ * used if it yields a valid address, unless the "linux,usable-memory-range"
59+ * property is present.
5960 *
6061 * Return value: start address of physical memory to use
6162 */
6263uint32_t fdt_check_mem_start (uint32_t mem_start , const void * fdt )
6364{
64- uint32_t addr_cells , size_cells , base ;
65+ uint32_t addr_cells , size_cells , usable_base , base ;
6566 uint32_t fdt_mem_start = 0xffffffff ;
66- const fdt32_t * reg , * endp ;
67- uint64_t size , end ;
67+ const fdt32_t * usable , * reg , * endp ;
68+ uint64_t size , usable_end , end ;
6869 const char * type ;
6970 int offset , len ;
7071
@@ -80,6 +81,27 @@ uint32_t fdt_check_mem_start(uint32_t mem_start, const void *fdt)
8081 if (addr_cells > 2 || size_cells > 2 )
8182 return mem_start ;
8283
84+ /*
85+ * Usable memory in case of a crash dump kernel
86+ * This property describes a limitation: memory within this range is
87+ * only valid when also described through another mechanism
88+ */
89+ usable = get_prop (fdt , "/chosen" , "linux,usable-memory-range" ,
90+ (addr_cells + size_cells ) * sizeof (fdt32_t ));
91+ if (usable ) {
92+ size = get_val (usable + addr_cells , size_cells );
93+ if (!size )
94+ return mem_start ;
95+
96+ if (addr_cells > 1 && fdt32_ld (usable )) {
97+ /* Outside 32-bit address space */
98+ return mem_start ;
99+ }
100+
101+ usable_base = fdt32_ld (usable + addr_cells - 1 );
102+ usable_end = usable_base + size ;
103+ }
104+
83105 /* Walk all memory nodes and regions */
84106 for (offset = fdt_next_node (fdt , -1 , NULL ); offset >= 0 ;
85107 offset = fdt_next_node (fdt , offset , NULL )) {
@@ -107,7 +129,20 @@ uint32_t fdt_check_mem_start(uint32_t mem_start, const void *fdt)
107129
108130 base = fdt32_ld (reg + addr_cells - 1 );
109131 end = base + size ;
110- if (mem_start >= base && mem_start < end ) {
132+ if (usable ) {
133+ /*
134+ * Clip to usable range, which takes precedence
135+ * over mem_start
136+ */
137+ if (base < usable_base )
138+ base = usable_base ;
139+
140+ if (end > usable_end )
141+ end = usable_end ;
142+
143+ if (end <= base )
144+ continue ;
145+ } else if (mem_start >= base && mem_start < end ) {
111146 /* Calculated address is valid, use it */
112147 return mem_start ;
113148 }
@@ -123,7 +158,8 @@ uint32_t fdt_check_mem_start(uint32_t mem_start, const void *fdt)
123158 }
124159
125160 /*
126- * The calculated address is not usable.
161+ * The calculated address is not usable, or was overridden by the
162+ * "linux,usable-memory-range" property.
127163 * Use the lowest usable physical memory address from the DTB instead,
128164 * and make sure this is a multiple of 2 MiB for phys/virt patching.
129165 */
0 commit comments