2 * early_res, could be used to replace bootmem
4 #include <linux/kernel.h>
5 #include <linux/types.h>
6 #include <linux/init.h>
7 #include <linux/bootmem.h>
9 #include <linux/early_res.h>
10 #include <linux/slab.h>
11 #include <linux/kmemleak.h>
14 * Early reserved memory areas.
17 * need to make sure this one is bigger enough before
18 * find_fw_memmap_area could be used
20 #define MAX_EARLY_RES_X 32
27 static struct early_res early_res_x
[MAX_EARLY_RES_X
] __initdata
;
29 static int max_early_res __initdata
= MAX_EARLY_RES_X
;
30 static struct early_res
*early_res __initdata
= &early_res_x
[0];
31 static int early_res_count __initdata
;
33 static int __init
find_overlapped_early(u64 start
, u64 end
)
38 for (i
= 0; i
< max_early_res
&& early_res
[i
].end
; i
++) {
40 if (end
> r
->start
&& start
< r
->end
)
48 * Drop the i-th range from the early reservation map,
49 * by copying any higher ranges down one over it, and
50 * clearing what had been the last slot.
52 static void __init
drop_range(int i
)
56 for (j
= i
+ 1; j
< max_early_res
&& early_res
[j
].end
; j
++)
59 memmove(&early_res
[i
], &early_res
[i
+ 1],
60 (j
- 1 - i
) * sizeof(struct early_res
));
62 early_res
[j
- 1].end
= 0;
66 static void __init
drop_range_partial(int i
, u64 start
, u64 end
)
68 u64 common_start
, common_end
;
69 u64 old_start
, old_end
;
71 old_start
= early_res
[i
].start
;
72 old_end
= early_res
[i
].end
;
73 common_start
= max(old_start
, start
);
74 common_end
= min(old_end
, end
);
77 if (common_start
>= common_end
)
80 if (old_start
< common_start
) {
81 /* make head segment */
82 early_res
[i
].end
= common_start
;
83 if (old_end
> common_end
) {
87 * Save a local copy of the name, since the
88 * early_res array could get resized inside
89 * reserve_early_without_check() ->
90 * __check_and_double_early_res(), which would
91 * make the current name pointer invalid.
93 strncpy(name
, early_res
[i
].name
,
94 sizeof(early_res
[i
].name
) - 1);
95 /* add another for left over on tail */
96 reserve_early_without_check(common_end
, old_end
, name
);
100 if (old_end
> common_end
) {
101 /* reuse the entry for tail left */
102 early_res
[i
].start
= common_end
;
111 * Split any existing ranges that:
112 * 1) are marked 'overlap_ok', and
113 * 2) overlap with the stated range [start, end)
114 * into whatever portion (if any) of the existing range is entirely
115 * below or entirely above the stated range. Drop the portion
116 * of the existing range that overlaps with the stated range,
117 * which will allow the caller of this routine to then add that
118 * stated range without conflicting with any existing range.
120 static void __init
drop_overlaps_that_are_ok(u64 start
, u64 end
)
124 u64 lower_start
, lower_end
;
125 u64 upper_start
, upper_end
;
128 for (i
= 0; i
< max_early_res
&& early_res
[i
].end
; i
++) {
131 /* Continue past non-overlapping ranges */
132 if (end
<= r
->start
|| start
>= r
->end
)
136 * Leave non-ok overlaps as is; let caller
137 * panic "Overlapping early reservations"
138 * when it hits this overlap.
144 * We have an ok overlap. We will drop it from the early
145 * reservation map, and add back in any non-overlapping
146 * portions (lower or upper) as separate, overlap_ok,
147 * non-overlapping ranges.
150 /* 1. Note any non-overlapping (lower or upper) ranges. */
151 strncpy(name
, r
->name
, sizeof(name
) - 1);
153 lower_start
= lower_end
= 0;
154 upper_start
= upper_end
= 0;
155 if (r
->start
< start
) {
156 lower_start
= r
->start
;
164 /* 2. Drop the original ok overlapping range */
167 i
--; /* resume for-loop on copied down entry */
169 /* 3. Add back in any non-overlapping ranges. */
171 reserve_early_overlap_ok(lower_start
, lower_end
, name
);
173 reserve_early_overlap_ok(upper_start
, upper_end
, name
);
177 static void __init
__reserve_early(u64 start
, u64 end
, char *name
,
183 i
= find_overlapped_early(start
, end
);
184 if (i
>= max_early_res
)
185 panic("Too many early reservations");
188 panic("Overlapping early reservations "
189 "%llx-%llx %s to %llx-%llx %s\n",
190 start
, end
- 1, name
? name
: "", r
->start
,
191 r
->end
- 1, r
->name
);
194 r
->overlap_ok
= overlap_ok
;
196 strncpy(r
->name
, name
, sizeof(r
->name
) - 1);
201 * A few early reservtations come here.
203 * The 'overlap_ok' in the name of this routine does -not- mean it
204 * is ok for these reservations to overlap an earlier reservation.
205 * Rather it means that it is ok for subsequent reservations to
208 * Use this entry point to reserve early ranges when you are doing
209 * so out of "Paranoia", reserving perhaps more memory than you need,
210 * just in case, and don't mind a subsequent overlapping reservation
211 * that is known to be needed.
213 * The drop_overlaps_that_are_ok() call here isn't really needed.
214 * It would be needed if we had two colliding 'overlap_ok'
215 * reservations, so that the second such would not panic on the
216 * overlap with the first. We don't have any such as of this
217 * writing, but might as well tolerate such if it happens in
220 void __init
reserve_early_overlap_ok(u64 start
, u64 end
, char *name
)
222 drop_overlaps_that_are_ok(start
, end
);
223 __reserve_early(start
, end
, name
, 1);
226 static void __init
__check_and_double_early_res(u64 ex_start
, u64 ex_end
)
228 u64 start
, end
, size
, mem
;
229 struct early_res
*new;
231 /* do we have enough slots left ? */
232 if ((max_early_res
- early_res_count
) > max(max_early_res
/8, 2))
237 size
= sizeof(struct early_res
) * max_early_res
* 2;
238 if (early_res
== early_res_x
)
241 start
= early_res
[0].end
;
243 if (start
+ size
< end
)
244 mem
= find_fw_memmap_area(start
, end
, size
,
245 sizeof(struct early_res
));
248 end
= get_max_mapped();
249 if (start
+ size
< end
)
250 mem
= find_fw_memmap_area(start
, end
, size
,
251 sizeof(struct early_res
));
254 panic("can not find more space for early_res array");
257 /* save the first one for own */
259 new[0].end
= mem
+ size
;
260 new[0].overlap_ok
= 0;
261 /* copy old to new */
262 if (early_res
== early_res_x
) {
263 memcpy(&new[1], &early_res
[0],
264 sizeof(struct early_res
) * max_early_res
);
265 memset(&new[max_early_res
+1], 0,
266 sizeof(struct early_res
) * (max_early_res
- 1));
269 memcpy(&new[1], &early_res
[1],
270 sizeof(struct early_res
) * (max_early_res
- 1));
271 memset(&new[max_early_res
], 0,
272 sizeof(struct early_res
) * max_early_res
);
274 memset(&early_res
[0], 0, sizeof(struct early_res
) * max_early_res
);
277 printk(KERN_DEBUG
"early_res array is doubled to %d at [%llx - %llx]\n",
278 max_early_res
, mem
, mem
+ size
- 1);
282 * Most early reservations come here.
284 * We first have drop_overlaps_that_are_ok() drop any pre-existing
285 * 'overlap_ok' ranges, so that we can then reserve this memory
286 * range without risk of panic'ing on an overlapping overlap_ok
289 void __init
reserve_early(u64 start
, u64 end
, char *name
)
294 __check_and_double_early_res(start
, end
);
296 drop_overlaps_that_are_ok(start
, end
);
297 __reserve_early(start
, end
, name
, 0);
300 void __init
reserve_early_without_check(u64 start
, u64 end
, char *name
)
307 __check_and_double_early_res(start
, end
);
309 r
= &early_res
[early_res_count
];
315 strncpy(r
->name
, name
, sizeof(r
->name
) - 1);
319 void __init
free_early(u64 start
, u64 end
)
324 kmemleak_free_part(__va(start
), end
- start
);
326 i
= find_overlapped_early(start
, end
);
328 if (i
>= max_early_res
|| r
->end
!= end
|| r
->start
!= start
)
329 panic("free_early on not reserved area: %llx-%llx!",
335 void __init
free_early_partial(u64 start
, u64 end
)
340 kmemleak_free_part(__va(start
), end
- start
);
345 if (WARN_ONCE(start
> end
, " wrong range [%#llx, %#llx]\n", start
, end
))
349 i
= find_overlapped_early(start
, end
);
350 if (i
>= max_early_res
)
355 if (r
->end
>= end
&& r
->start
<= start
) {
356 drop_range_partial(i
, start
, end
);
360 drop_range_partial(i
, start
, end
);
364 #ifdef CONFIG_NO_BOOTMEM
365 static void __init
subtract_early_res(struct range
*range
, int az
)
368 u64 final_start
, final_end
;
372 for (i
= 0; i
< max_early_res
&& early_res
[i
].end
; i
++)
375 /* need to skip first one ?*/
376 if (early_res
!= early_res_x
)
379 #define DEBUG_PRINT_EARLY_RES 1
381 #if DEBUG_PRINT_EARLY_RES
382 printk(KERN_INFO
"Subtract (%d early reservations)\n", count
);
384 for (i
= idx
; i
< count
; i
++) {
385 struct early_res
*r
= &early_res
[i
];
386 #if DEBUG_PRINT_EARLY_RES
387 printk(KERN_INFO
" #%d [%010llx - %010llx] %15s\n", i
,
388 r
->start
, r
->end
, r
->name
);
390 final_start
= PFN_DOWN(r
->start
);
391 final_end
= PFN_UP(r
->end
);
392 if (final_start
>= final_end
)
394 subtract_range(range
, az
, final_start
, final_end
);
399 int __init
get_free_all_memory_range(struct range
**rangep
, int nodeid
)
409 for (i
= 0; i
< max_early_res
&& early_res
[i
].end
; i
++)
414 size
= sizeof(struct range
) * count
;
415 end
= get_max_mapped();
417 if (end
> (MAX_DMA32_PFN
<< PAGE_SHIFT
))
418 start
= MAX_DMA32_PFN
<< PAGE_SHIFT
;
420 mem
= find_fw_memmap_area(start
, end
, size
, sizeof(struct range
));
422 panic("can not find more space for range free");
425 /* use early_node_map[] and early_res to get range array at first */
426 memset(range
, 0, size
);
429 /* need to go over early_node_map to find out good range for node */
430 nr_range
= add_from_early_node_map(range
, count
, nr_range
, nodeid
);
432 subtract_range(range
, count
, max_low_pfn
, -1ULL);
434 subtract_early_res(range
, count
);
435 nr_range
= clean_sort_range(range
, count
);
437 /* need to clear it ? */
438 if (nodeid
== MAX_NUMNODES
) {
439 memset(&early_res
[0], 0,
440 sizeof(struct early_res
) * max_early_res
);
449 void __init
early_res_to_bootmem(u64 start
, u64 end
)
452 u64 final_start
, final_end
;
456 for (i
= 0; i
< max_early_res
&& early_res
[i
].end
; i
++)
459 /* need to skip first one ?*/
460 if (early_res
!= early_res_x
)
463 printk(KERN_INFO
"(%d/%d early reservations) ==> bootmem [%010llx - %010llx]\n",
464 count
- idx
, max_early_res
, start
, end
);
465 for (i
= idx
; i
< count
; i
++) {
466 struct early_res
*r
= &early_res
[i
];
467 printk(KERN_INFO
" #%d [%010llx - %010llx] %16s", i
,
468 r
->start
, r
->end
, r
->name
);
469 final_start
= max(start
, r
->start
);
470 final_end
= min(end
, r
->end
);
471 if (final_start
>= final_end
) {
472 printk(KERN_CONT
"\n");
475 printk(KERN_CONT
" ==> [%010llx - %010llx]\n",
476 final_start
, final_end
);
477 reserve_bootmem_generic(final_start
, final_end
- final_start
,
481 memset(&early_res
[0], 0, sizeof(struct early_res
) * max_early_res
);
488 /* Check for already reserved areas */
489 static inline int __init
bad_addr(u64
*addrp
, u64 size
, u64 align
)
496 i
= find_overlapped_early(addr
, addr
+ size
);
498 if (i
< max_early_res
&& r
->end
) {
499 *addrp
= addr
= round_up(r
->end
, align
);
506 /* Check for already reserved areas */
507 static inline int __init
bad_addr_size(u64
*addrp
, u64
*sizep
, u64 align
)
510 u64 addr
= *addrp
, last
;
515 for (i
= 0; i
< max_early_res
&& early_res
[i
].end
; i
++) {
516 struct early_res
*r
= &early_res
[i
];
517 if (last
> r
->start
&& addr
< r
->start
) {
518 size
= r
->start
- addr
;
522 if (last
> r
->end
&& addr
< r
->end
) {
523 addr
= round_up(r
->end
, align
);
528 if (last
<= r
->end
&& addr
>= r
->start
) {
541 * Find a free area with specified alignment in a specific range.
542 * only with the area.between start to end is active range from early_node_map
543 * so they are good as RAM
545 u64 __init
find_early_area(u64 ei_start
, u64 ei_last
, u64 start
, u64 end
,
550 addr
= round_up(ei_start
, align
);
552 addr
= round_up(start
, align
);
555 while (bad_addr(&addr
, size
, align
) && addr
+size
<= ei_last
)
569 u64 __init
find_early_area_size(u64 ei_start
, u64 ei_last
, u64 start
,
570 u64
*sizep
, u64 align
)
574 addr
= round_up(ei_start
, align
);
576 addr
= round_up(start
, align
);
579 *sizep
= ei_last
- addr
;
580 while (bad_addr_size(&addr
, sizep
, align
) && addr
+ *sizep
<= ei_last
)
582 last
= addr
+ *sizep
;