1 // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 /*
3 * Simple memory allocator
4 *
5 * Copyright 2013-2018 IBM Corp.
6 */
7
8 #include <inttypes.h>
9 #include <skiboot.h>
10 #include <mem-map.h>
11 #include <libfdt_env.h>
12 #include <lock.h>
13 #include <device.h>
14 #include <cpu.h>
15 #include <chip.h>
16 #include <affinity.h>
17 #include <types.h>
18 #include <mem_region.h>
19 #include <mem_region-malloc.h>
20
21 /* Memory poisoning on free (if POISON_MEM_REGION set to 1) */
22 #ifdef DEBUG
23 #define POISON_MEM_REGION 1
24 #else
25 #define POISON_MEM_REGION 0
26 #endif
27 #define POISON_MEM_REGION_WITH 0x99
28 #define POISON_MEM_REGION_LIMIT 1*1024*1024*1024
29
30 /* Locking: The mem_region_lock protects the regions list from concurrent
31 * updates. Additions to, or removals from, the region list must be done
32 * with this lock held. This is typically done when we're establishing
33 * the memory & reserved regions.
34 *
35 * Each region has a lock (region->free_list_lock) to protect the free list
36 * from concurrent modification. This lock is used when we're allocating
37 * memory out of a specific region.
38 *
39 * If both locks are needed (eg, __local_alloc, where we need to find a region,
40 * then allocate from it), the mem_region_lock must be acquired before (and
41 * released after) the per-region lock.
42 */
43 struct lock mem_region_lock = LOCK_UNLOCKED;
44
45 static struct list_head regions = LIST_HEAD_INIT(regions);
46 static struct list_head early_reserves = LIST_HEAD_INIT(early_reserves);
47
48 static bool mem_region_init_done = false;
49 static bool mem_regions_finalised = false;
50
51 unsigned long top_of_ram = SKIBOOT_BASE + SKIBOOT_SIZE;
52
53 static struct mem_region skiboot_os_reserve = {
54 .name = "ibm,os-reserve",
55 .start = 0,
56 .len = SKIBOOT_BASE,
57 .type = REGION_OS,
58 };
59
60 struct mem_region skiboot_heap = {
61 .name = "ibm,firmware-heap",
62 .start = HEAP_BASE,
63 .len = HEAP_SIZE,
64 .type = REGION_SKIBOOT_HEAP,
65 };
66
67 static struct mem_region skiboot_code_and_text = {
68 .name = "ibm,firmware-code",
69 .start = SKIBOOT_BASE,
70 .len = HEAP_BASE - SKIBOOT_BASE,
71 .type = REGION_SKIBOOT_FIRMWARE,
72 };
73
74 static struct mem_region skiboot_after_heap = {
75 .name = "ibm,firmware-data",
76 .start = HEAP_BASE + HEAP_SIZE,
77 .len = SKIBOOT_BASE + SKIBOOT_SIZE - (HEAP_BASE + HEAP_SIZE),
78 .type = REGION_SKIBOOT_FIRMWARE,
79 };
80
81 static struct mem_region skiboot_cpu_stacks = {
82 .name = "ibm,firmware-stacks",
83 .start = CPU_STACKS_BASE,
84 .len = 0, /* TBA */
85 .type = REGION_SKIBOOT_FIRMWARE,
86 };
87
88 static struct mem_region skiboot_mambo_kernel = {
89 .name = "ibm,firmware-mambo-kernel",
90 .start = (unsigned long)KERNEL_LOAD_BASE,
91 .len = KERNEL_LOAD_SIZE,
92 .type = REGION_SKIBOOT_FIRMWARE,
93 };
94
95 static struct mem_region skiboot_mambo_initramfs = {
96 .name = "ibm,firmware-mambo-initramfs",
97 .start = (unsigned long)INITRAMFS_LOAD_BASE,
98 .len = INITRAMFS_LOAD_SIZE,
99 .type = REGION_SKIBOOT_FIRMWARE,
100 };
101
102
103 struct alloc_hdr {
104 bool free : 1;
105 bool prev_free : 1;
106 bool printed : 1;
107 unsigned long num_longs : BITS_PER_LONG-3; /* Including header. */
108 const char *location;
109 };
110
111 struct free_hdr {
112 struct alloc_hdr hdr;
113 struct list_node list;
114 /* ... unsigned long tailer; */
115 };
116
117 #define ALLOC_HDR_LONGS (sizeof(struct alloc_hdr) / sizeof(long))
118 #define ALLOC_MIN_LONGS (sizeof(struct free_hdr) / sizeof(long) + 1)
119
120 /* Avoid ugly casts. */
region_start(const struct mem_region * region)121 static void *region_start(const struct mem_region *region)
122 {
123 return (void *)(unsigned long)region->start;
124 }
125
126 /* Each free block has a tailer, so we can walk backwards. */
tailer(struct free_hdr * f)127 static unsigned long *tailer(struct free_hdr *f)
128 {
129 return (unsigned long *)f + f->hdr.num_longs - 1;
130 }
131
132 /* This walks forward to the next hdr (or NULL if at the end). */
next_hdr(const struct mem_region * region,const struct alloc_hdr * hdr)133 static struct alloc_hdr *next_hdr(const struct mem_region *region,
134 const struct alloc_hdr *hdr)
135 {
136 void *next;
137
138 next = ((unsigned long *)hdr + hdr->num_longs);
139 if (next >= region_start(region) + region->len)
140 next = NULL;
141 return next;
142 }
143
144 #if POISON_MEM_REGION == 1
mem_poison(struct free_hdr * f)145 static void mem_poison(struct free_hdr *f)
146 {
147 size_t poison_size = (void*)tailer(f) - (void*)(f+1);
148
149 /* We only poison up to a limit, as otherwise boot is
150 * kinda slow */
151 if (poison_size > POISON_MEM_REGION_LIMIT)
152 poison_size = POISON_MEM_REGION_LIMIT;
153
154 memset(f+1, POISON_MEM_REGION_WITH, poison_size);
155 }
156 #endif
157
158 /* Creates free block covering entire region. */
init_allocatable_region(struct mem_region * region)159 static void init_allocatable_region(struct mem_region *region)
160 {
161 struct free_hdr *f = region_start(region);
162 assert(region->type == REGION_SKIBOOT_HEAP ||
163 region->type == REGION_MEMORY);
164 f->hdr.num_longs = region->len / sizeof(long);
165 f->hdr.free = true;
166 f->hdr.prev_free = false;
167 *tailer(f) = f->hdr.num_longs;
168 list_head_init(®ion->free_list);
169 list_add(®ion->free_list, &f->list);
170 #if POISON_MEM_REGION == 1
171 mem_poison(f);
172 #endif
173 }
174
make_free(struct mem_region * region,struct free_hdr * f,const char * location,bool skip_poison)175 static void make_free(struct mem_region *region, struct free_hdr *f,
176 const char *location, bool skip_poison)
177 {
178 struct alloc_hdr *next;
179
180 #if POISON_MEM_REGION == 1
181 if (!skip_poison)
182 mem_poison(f);
183 #else
184 (void)skip_poison;
185 #endif
186
187 if (f->hdr.prev_free) {
188 struct free_hdr *prev;
189 unsigned long *prev_tailer = (unsigned long *)f - 1;
190
191 assert(*prev_tailer);
192 prev = (void *)((unsigned long *)f - *prev_tailer);
193 assert(prev->hdr.free);
194 assert(!prev->hdr.prev_free);
195
196 /* Expand to cover the one we just freed. */
197 prev->hdr.num_longs += f->hdr.num_longs;
198 f = prev;
199 } else {
200 f->hdr.free = true;
201 f->hdr.location = location;
202 list_add(®ion->free_list, &f->list);
203 }
204
205 /* Fix up tailer. */
206 *tailer(f) = f->hdr.num_longs;
207
208 /* If next is free, coalesce it */
209 next = next_hdr(region, &f->hdr);
210 if (next) {
211 next->prev_free = true;
212 if (next->free) {
213 struct free_hdr *next_free = (void *)next;
214 list_del_from(®ion->free_list, &next_free->list);
215 /* Maximum of one level of recursion */
216 make_free(region, next_free, location, true);
217 }
218 }
219 }
220
221 /* Can we fit this many longs with this alignment in this free block? */
fits(struct free_hdr * f,size_t longs,size_t align,size_t * offset)222 static bool fits(struct free_hdr *f, size_t longs, size_t align, size_t *offset)
223 {
224 *offset = 0;
225
226 while (f->hdr.num_longs >= *offset + longs) {
227 size_t addr;
228
229 addr = (unsigned long)f
230 + (*offset + ALLOC_HDR_LONGS) * sizeof(long);
231 if ((addr & (align - 1)) == 0)
232 return true;
233
234 /* Don't make tiny chunks! */
235 if (*offset == 0)
236 *offset = ALLOC_MIN_LONGS;
237 else
238 (*offset)++;
239 }
240 return false;
241 }
242
discard_excess(struct mem_region * region,struct alloc_hdr * hdr,size_t alloc_longs,const char * location,bool skip_poison)243 static void discard_excess(struct mem_region *region,
244 struct alloc_hdr *hdr, size_t alloc_longs,
245 const char *location, bool skip_poison)
246 {
247 /* Do we have excess? */
248 if (hdr->num_longs > alloc_longs + ALLOC_MIN_LONGS) {
249 struct free_hdr *post;
250
251 /* Set up post block. */
252 post = (void *)hdr + alloc_longs * sizeof(long);
253 post->hdr.num_longs = hdr->num_longs - alloc_longs;
254 post->hdr.prev_free = false;
255
256 /* Trim our block. */
257 hdr->num_longs = alloc_longs;
258
259 /* This coalesces as required. */
260 make_free(region, post, location, skip_poison);
261 }
262 }
263
hdr_location(const struct alloc_hdr * hdr)264 static const char *hdr_location(const struct alloc_hdr *hdr)
265 {
266 /* Corrupt: step carefully! */
267 if (is_rodata(hdr->location))
268 return hdr->location;
269 return "*CORRUPT*";
270 }
271
bad_header(const struct mem_region * region,const struct alloc_hdr * hdr,const char * during,const char * location)272 static void bad_header(const struct mem_region *region,
273 const struct alloc_hdr *hdr,
274 const char *during,
275 const char *location)
276 {
277 /* Corrupt: step carefully! */
278 if (is_rodata(hdr->location))
279 prerror("%p (in %s) %s at %s, previously %s\n",
280 hdr-1, region->name, during, location, hdr->location);
281 else
282 prerror("%p (in %s) %s at %s, previously %p\n",
283 hdr-1, region->name, during, location, hdr->location);
284 abort();
285 }
286
region_is_reservable(struct mem_region * region)287 static bool region_is_reservable(struct mem_region *region)
288 {
289 return region->type != REGION_OS;
290 }
291
region_is_reserved(struct mem_region * region)292 static bool region_is_reserved(struct mem_region *region)
293 {
294 return region->type != REGION_OS && region->type != REGION_MEMORY;
295 }
296
mem_dump_allocs(void)297 void mem_dump_allocs(void)
298 {
299 struct mem_region *region;
300 struct alloc_hdr *h, *i;
301
302 /* Second pass: populate property data */
303 prlog(PR_INFO, "Memory regions:\n");
304 list_for_each(®ions, region, list) {
305 if (!(region->type == REGION_SKIBOOT_HEAP ||
306 region->type == REGION_MEMORY))
307 continue;
308 prlog(PR_INFO, " 0x%012llx..%012llx : %s\n",
309 (long long)region->start,
310 (long long)(region->start + region->len - 1),
311 region->name);
312 if (region->free_list.n.next == NULL) {
313 prlog(PR_INFO, " no allocs\n");
314 continue;
315 }
316
317 /*
318 * XXX: When dumping the allocation list we coalase allocations
319 * with the same location and size into a single line. This is
320 * quadratic, but it makes the dump human-readable and the raw
321 * dump sometimes causes the log buffer to wrap.
322 */
323 for (h = region_start(region); h; h = next_hdr(region, h))
324 h->printed = false;
325
326 for (h = region_start(region); h; h = next_hdr(region, h)) {
327 unsigned long bytes;
328 int count = 0;
329
330 if (h->free)
331 continue;
332 if (h->printed)
333 continue;
334
335 for (i = h; i; i = next_hdr(region, i)) {
336 if (i->free)
337 continue;
338 if (i->num_longs != h->num_longs)
339 continue;
340 if (strcmp(i->location, h->location))
341 continue;
342
343 i->printed = true;
344 count++;
345 }
346
347 bytes = h->num_longs * sizeof(long);
348 prlog(PR_NOTICE, " % 8d allocs of 0x%.8lx bytes at %s (total 0x%lx)\n",
349 count, bytes, hdr_location(h), bytes * count);
350 }
351 }
352 }
353
mem_dump_free(void)354 int64_t mem_dump_free(void)
355 {
356 struct mem_region *region;
357 struct alloc_hdr *hdr;
358 int64_t total_free;
359 int64_t region_free;
360
361 total_free = 0;
362
363 prlog(PR_INFO, "Free space in HEAP memory regions:\n");
364 list_for_each(®ions, region, list) {
365 if (!(region->type == REGION_SKIBOOT_HEAP ||
366 region->type == REGION_MEMORY))
367 continue;
368 region_free = 0;
369
370 if (region->free_list.n.next == NULL) {
371 continue;
372 }
373 for (hdr = region_start(region); hdr; hdr = next_hdr(region, hdr)) {
374 if (!hdr->free)
375 continue;
376
377 region_free+= hdr->num_longs * sizeof(long);
378 }
379 prlog(PR_INFO, "Region %s free: %"PRIx64"\n",
380 region->name, region_free);
381 total_free += region_free;
382 }
383
384 prlog(PR_INFO, "Total free: %"PRIu64"\n", total_free);
385
386 return total_free;
387 }
388
__mem_alloc(struct mem_region * region,size_t size,size_t align,const char * location)389 static void *__mem_alloc(struct mem_region *region, size_t size, size_t align,
390 const char *location)
391 {
392 size_t alloc_longs, offset;
393 struct free_hdr *f;
394 struct alloc_hdr *next;
395
396 /* Align must be power of 2. */
397 assert(!((align - 1) & align));
398
399 /* This should be a constant. */
400 assert(is_rodata(location));
401
402 /* Unallocatable region? */
403 if (!(region->type == REGION_SKIBOOT_HEAP ||
404 region->type == REGION_MEMORY))
405 return NULL;
406
407 /* First allocation? */
408 if (region->free_list.n.next == NULL)
409 init_allocatable_region(region);
410
411 /* Don't do screwy sizes. */
412 if (size > region->len)
413 return NULL;
414
415 /* Don't do tiny alignments, we deal in long increments. */
416 if (align < sizeof(long))
417 align = sizeof(long);
418
419 /* Convert size to number of longs, too. */
420 alloc_longs = (size + sizeof(long)-1) / sizeof(long) + ALLOC_HDR_LONGS;
421
422 /* Can't be too small for when we free it, either. */
423 if (alloc_longs < ALLOC_MIN_LONGS)
424 alloc_longs = ALLOC_MIN_LONGS;
425
426 /* Walk free list. */
427 list_for_each(®ion->free_list, f, list) {
428 /* We may have to skip some to meet alignment. */
429 if (fits(f, alloc_longs, align, &offset))
430 goto found;
431 }
432
433 return NULL;
434
435 found:
436 assert(f->hdr.free);
437 assert(!f->hdr.prev_free);
438
439 /* This block is no longer free. */
440 list_del_from(®ion->free_list, &f->list);
441 f->hdr.free = false;
442 f->hdr.location = location;
443
444 next = next_hdr(region, &f->hdr);
445 if (next) {
446 assert(next->prev_free);
447 next->prev_free = false;
448 }
449
450 if (offset != 0) {
451 struct free_hdr *pre = f;
452
453 f = (void *)f + offset * sizeof(long);
454 assert(f >= pre + 1);
455
456 /* Set up new header. */
457 f->hdr.num_longs = pre->hdr.num_longs - offset;
458 /* f->hdr.prev_free will be set by make_free below. */
459 f->hdr.free = false;
460 f->hdr.location = location;
461
462 /* Fix up old header. */
463 pre->hdr.num_longs = offset;
464 pre->hdr.prev_free = false;
465
466 /* This coalesces as required. */
467 make_free(region, pre, location, true);
468 }
469
470 /* We might be too long; put the rest back. */
471 discard_excess(region, &f->hdr, alloc_longs, location, true);
472
473 /* Clear tailer for debugging */
474 *tailer(f) = 0;
475
476 /* Their pointer is immediately after header. */
477 return &f->hdr + 1;
478 }
479
mem_alloc(struct mem_region * region,size_t size,size_t align,const char * location)480 void *mem_alloc(struct mem_region *region, size_t size, size_t align,
481 const char *location)
482 {
483 static bool dumped = false;
484 void *r;
485
486 assert(lock_held_by_me(®ion->free_list_lock));
487
488 r = __mem_alloc(region, size, align, location);
489 if (r)
490 return r;
491
492 prerror("mem_alloc(0x%lx, 0x%lx, \"%s\", %s) failed !\n",
493 size, align, location, region->name);
494 if (!dumped) {
495 mem_dump_allocs();
496 dumped = true;
497 }
498
499 return NULL;
500 }
501
mem_free(struct mem_region * region,void * mem,const char * location)502 void mem_free(struct mem_region *region, void *mem, const char *location)
503 {
504 struct alloc_hdr *hdr;
505
506 /* This should be a constant. */
507 assert(is_rodata(location));
508
509 assert(lock_held_by_me(®ion->free_list_lock));
510
511 /* Freeing NULL is always a noop. */
512 if (!mem)
513 return;
514
515 /* Your memory is in the region, right? */
516 assert(mem >= region_start(region) + sizeof(*hdr));
517 assert(mem < region_start(region) + region->len);
518
519 /* Grab header. */
520 hdr = mem - sizeof(*hdr);
521
522 if (hdr->free)
523 bad_header(region, hdr, "re-freed", location);
524
525 make_free(region, (struct free_hdr *)hdr, location, false);
526 }
527
mem_allocated_size(const void * ptr)528 size_t mem_allocated_size(const void *ptr)
529 {
530 const struct alloc_hdr *hdr = ptr - sizeof(*hdr);
531 return hdr->num_longs * sizeof(long) - sizeof(struct alloc_hdr);
532 }
533
mem_resize(struct mem_region * region,void * mem,size_t len,const char * location)534 bool mem_resize(struct mem_region *region, void *mem, size_t len,
535 const char *location)
536 {
537 struct alloc_hdr *hdr, *next;
538 struct free_hdr *f;
539
540 /* This should be a constant. */
541 assert(is_rodata(location));
542
543 assert(lock_held_by_me(®ion->free_list_lock));
544
545 /* Get header. */
546 hdr = mem - sizeof(*hdr);
547 if (hdr->free)
548 bad_header(region, hdr, "resize", location);
549
550 /* Round up size to multiple of longs. */
551 len = (sizeof(*hdr) + len + sizeof(long) - 1) / sizeof(long);
552
553 /* Can't be too small for when we free it, either. */
554 if (len < ALLOC_MIN_LONGS)
555 len = ALLOC_MIN_LONGS;
556
557 /* Shrinking is simple. */
558 if (len <= hdr->num_longs) {
559 hdr->location = location;
560 discard_excess(region, hdr, len, location, false);
561 return true;
562 }
563
564 /* Check if we can expand. */
565 next = next_hdr(region, hdr);
566 if (!next || !next->free || hdr->num_longs + next->num_longs < len)
567 return false;
568
569 /* OK, it's free and big enough, absorb it. */
570 f = (struct free_hdr *)next;
571 list_del_from(®ion->free_list, &f->list);
572 hdr->num_longs += next->num_longs;
573 hdr->location = location;
574
575 /* Update next prev_free */
576 next = next_hdr(region, &f->hdr);
577 if (next) {
578 assert(next->prev_free);
579 next->prev_free = false;
580 }
581
582 /* Clear tailer for debugging */
583 *tailer(f) = 0;
584
585 /* Now we might have *too* much. */
586 discard_excess(region, hdr, len, location, true);
587 return true;
588 }
589
mem_check(const struct mem_region * region)590 bool mem_check(const struct mem_region *region)
591 {
592 size_t frees = 0;
593 struct alloc_hdr *hdr, *prev_free = NULL;
594 struct free_hdr *f;
595
596 /* Check it's sanely aligned. */
597 if (region->start % sizeof(long)) {
598 prerror("Region '%s' not sanely aligned (%llx)\n",
599 region->name, (unsigned long long)region->start);
600 return false;
601 }
602 if ((long)region->len % sizeof(long)) {
603 prerror("Region '%s' not sane length (%llu)\n",
604 region->name, (unsigned long long)region->len);
605 return false;
606 }
607
608 /* Not ours to play with, or empty? Don't do anything. */
609 if (!(region->type == REGION_MEMORY ||
610 region->type == REGION_SKIBOOT_HEAP) ||
611 region->free_list.n.next == NULL)
612 return true;
613
614 /* Walk linearly. */
615 for (hdr = region_start(region); hdr; hdr = next_hdr(region, hdr)) {
616 if (hdr->num_longs < ALLOC_MIN_LONGS) {
617 prerror("Region '%s' %s %p (%s) size %zu\n",
618 region->name, hdr->free ? "free" : "alloc",
619 hdr, hdr_location(hdr),
620 hdr->num_longs * sizeof(long));
621 return false;
622 }
623 if ((unsigned long)hdr + hdr->num_longs * sizeof(long) >
624 region->start + region->len) {
625 prerror("Region '%s' %s %p (%s) oversize %zu\n",
626 region->name, hdr->free ? "free" : "alloc",
627 hdr, hdr_location(hdr),
628 hdr->num_longs * sizeof(long));
629 return false;
630 }
631 if (hdr->free) {
632 if (hdr->prev_free || prev_free) {
633 prerror("Region '%s' free %p (%s) has prev_free"
634 " %p (%s) %sset?\n",
635 region->name, hdr, hdr_location(hdr),
636 prev_free,
637 prev_free ? hdr_location(prev_free)
638 : "NULL",
639 hdr->prev_free ? "" : "un");
640 return false;
641 }
642 prev_free = hdr;
643 frees ^= (unsigned long)hdr - region->start;
644 } else {
645 if (hdr->prev_free != (bool)prev_free) {
646 prerror("Region '%s' alloc %p (%s) has"
647 " prev_free %p %sset?\n",
648 region->name, hdr, hdr_location(hdr),
649 prev_free, hdr->prev_free ? "" : "un");
650 return false;
651 }
652 prev_free = NULL;
653 }
654 }
655
656 /* Now walk free list. */
657 list_for_each(®ion->free_list, f, list)
658 frees ^= (unsigned long)f - region->start;
659
660 if (frees) {
661 prerror("Region '%s' free list and walk do not match!\n",
662 region->name);
663 return false;
664 }
665 return true;
666 }
667
mem_check_all(void)668 bool mem_check_all(void)
669 {
670 struct mem_region *r;
671
672 list_for_each(®ions, r, list) {
673 if (!mem_check(r))
674 return false;
675 }
676
677 return true;
678 }
679
new_region(const char * name,uint64_t start,uint64_t len,struct dt_node * node,enum mem_region_type type)680 static struct mem_region *new_region(const char *name,
681 uint64_t start, uint64_t len,
682 struct dt_node *node,
683 enum mem_region_type type)
684 {
685 struct mem_region *region;
686
687 region = malloc(sizeof(*region));
688 if (!region)
689 return NULL;
690
691 region->name = name;
692 region->start = start;
693 region->len = len;
694 region->node = node;
695 region->type = type;
696 region->free_list.n.next = NULL;
697 init_lock(®ion->free_list_lock);
698
699 return region;
700 }
701
702 /* We always split regions, so we only have to replace one. */
split_region(struct mem_region * head,uint64_t split_at,enum mem_region_type type)703 static struct mem_region *split_region(struct mem_region *head,
704 uint64_t split_at,
705 enum mem_region_type type)
706 {
707 struct mem_region *tail;
708 uint64_t end = head->start + head->len;
709
710 tail = new_region(head->name, split_at, end - split_at,
711 head->node, type);
712 /* Original region becomes head. */
713 if (tail)
714 head->len -= tail->len;
715
716 return tail;
717 }
718
intersects(const struct mem_region * region,uint64_t addr)719 static bool intersects(const struct mem_region *region, uint64_t addr)
720 {
721 return addr > region->start &&
722 addr < region->start + region->len;
723 }
724
maybe_split(struct mem_region * r,uint64_t split_at)725 static bool maybe_split(struct mem_region *r, uint64_t split_at)
726 {
727 struct mem_region *tail;
728
729 if (!intersects(r, split_at))
730 return true;
731
732 tail = split_region(r, split_at, r->type);
733 if (!tail)
734 return false;
735
736 /* Tail add is important: we may need to split again! */
737 list_add_after(®ions, &tail->list, &r->list);
738 return true;
739 }
740
overlaps(const struct mem_region * r1,const struct mem_region * r2)741 static bool overlaps(const struct mem_region *r1, const struct mem_region *r2)
742 {
743 return (r1->start + r1->len > r2->start
744 && r1->start < r2->start + r2->len);
745 }
746
contains(const struct mem_region * r1,const struct mem_region * r2)747 static bool contains(const struct mem_region *r1, const struct mem_region *r2)
748 {
749 u64 r1_end = r1->start + r1->len;
750 u64 r2_end = r2->start + r2->len;
751
752 return (r1->start <= r2->start && r2_end <= r1_end);
753 }
754
get_overlap(const struct mem_region * region)755 static struct mem_region *get_overlap(const struct mem_region *region)
756 {
757 struct mem_region *i;
758
759 list_for_each(®ions, i, list) {
760 if (overlaps(region, i))
761 return i;
762 }
763 return NULL;
764 }
765
add_region_to_regions(struct mem_region * region)766 static void add_region_to_regions(struct mem_region *region)
767 {
768 struct mem_region *r;
769
770 list_for_each(®ions, r, list) {
771 if (r->start < region->start)
772 continue;
773
774 list_add_before(®ions, ®ion->list, &r->list);
775 return;
776 }
777 list_add_tail(®ions, ®ion->list);
778 }
779
add_region(struct mem_region * region)780 static bool add_region(struct mem_region *region)
781 {
782 struct mem_region *r;
783
784 if (mem_regions_finalised) {
785 prerror("MEM: add_region(%s@0x%"PRIx64") called after finalise!\n",
786 region->name, region->start);
787 return false;
788 }
789
790 /* First split any regions which intersect. */
791 list_for_each(®ions, r, list) {
792 /*
793 * The new region should be fully contained by an existing one.
794 * If it's not then we have a problem where reservations
795 * partially overlap which is probably broken.
796 *
797 * NB: There *might* be situations where this is legitimate,
798 * but the region handling does not currently support this.
799 */
800 if (overlaps(r, region) && !contains(r, region)) {
801 prerror("MEM: Partial overlap detected between regions:\n");
802 prerror("MEM: %s [0x%"PRIx64"-0x%"PRIx64"] (new)\n",
803 region->name, region->start,
804 region->start + region->len);
805 prerror("MEM: %s [0x%"PRIx64"-0x%"PRIx64"]\n",
806 r->name, r->start, r->start + r->len);
807 return false;
808 }
809
810 if (!maybe_split(r, region->start) ||
811 !maybe_split(r, region->start + region->len))
812 return false;
813 }
814
815 /* Now we have only whole overlaps, if any. */
816 while ((r = get_overlap(region)) != NULL) {
817 assert(r->start == region->start);
818 assert(r->len == region->len);
819 list_del_from(®ions, &r->list);
820 free(r);
821 }
822
823 /* Finally, add in our own region. */
824 add_region_to_regions(region);
825 return true;
826 }
827
mem_reserve(enum mem_region_type type,const char * name,uint64_t start,uint64_t len)828 static void mem_reserve(enum mem_region_type type, const char *name,
829 uint64_t start, uint64_t len)
830 {
831 struct mem_region *region;
832 bool added = true;
833
834 lock(&mem_region_lock);
835 region = new_region(name, start, len, NULL, type);
836 assert(region);
837
838 if (!mem_region_init_done)
839 list_add(&early_reserves, ®ion->list);
840 else
841 added = add_region(region);
842
843 assert(added);
844 unlock(&mem_region_lock);
845 }
846
mem_reserve_fw(const char * name,uint64_t start,uint64_t len)847 void mem_reserve_fw(const char *name, uint64_t start, uint64_t len)
848 {
849 mem_reserve(REGION_FW_RESERVED, name, start, len);
850 }
851
mem_reserve_hwbuf(const char * name,uint64_t start,uint64_t len)852 void mem_reserve_hwbuf(const char *name, uint64_t start, uint64_t len)
853 {
854 mem_reserve(REGION_RESERVED, name, start, len);
855 }
856
matches_chip_id(const __be32 ids[],size_t num,u32 chip_id)857 static bool matches_chip_id(const __be32 ids[], size_t num, u32 chip_id)
858 {
859 size_t i;
860
861 for (i = 0; i < num; i++)
862 if (be32_to_cpu(ids[i]) == chip_id)
863 return true;
864
865 return false;
866 }
867
__local_alloc(unsigned int chip_id,size_t size,size_t align,const char * location)868 void *__local_alloc(unsigned int chip_id, size_t size, size_t align,
869 const char *location)
870 {
871 struct mem_region *region;
872 void *p = NULL;
873 bool use_local = true;
874
875 lock(&mem_region_lock);
876
877 restart:
878 list_for_each(®ions, region, list) {
879 const struct dt_property *prop;
880 const __be32 *ids;
881
882 if (!(region->type == REGION_SKIBOOT_HEAP ||
883 region->type == REGION_MEMORY))
884 continue;
885
886 /* Don't allocate from normal heap. */
887 if (region == &skiboot_heap)
888 continue;
889
890 /* First pass, only match node local regions */
891 if (use_local) {
892 if (!region->node)
893 continue;
894 prop = dt_find_property(region->node, "ibm,chip-id");
895 ids = (const __be32 *)prop->prop;
896 if (!matches_chip_id(ids, prop->len/sizeof(u32),
897 chip_id))
898 continue;
899 }
900
901 /* Second pass, match anything */
902 lock(®ion->free_list_lock);
903 p = mem_alloc(region, size, align, location);
904 unlock(®ion->free_list_lock);
905 if (p)
906 break;
907 }
908
909 /*
910 * If we can't allocate the memory block from the expected
911 * node, we bail to any one that can accommodate our request.
912 */
913 if (!p && use_local) {
914 use_local = false;
915 goto restart;
916 }
917
918 unlock(&mem_region_lock);
919
920 return p;
921 }
922
find_mem_region(const char * name)923 struct mem_region *find_mem_region(const char *name)
924 {
925 struct mem_region *region;
926
927 list_for_each(®ions, region, list) {
928 if (streq(region->name, name))
929 return region;
930 }
931 return NULL;
932 }
933
mem_range_is_reserved(uint64_t start,uint64_t size)934 bool mem_range_is_reserved(uint64_t start, uint64_t size)
935 {
936 uint64_t end = start + size;
937 struct mem_region *region;
938 struct list_head *search;
939
940 /* We may have the range covered by a number of regions, which could
941 * appear in any order. So, we look for a region that covers the
942 * start address, and bump start up to the end of that region.
943 *
944 * We repeat until we've either bumped past the end of the range,
945 * or we didn't find a matching region.
946 *
947 * This has a worst-case of O(n^2), but n is well bounded by the
948 * small number of reservations.
949 */
950
951 if (!mem_region_init_done)
952 search = &early_reserves;
953 else
954 search = ®ions;
955
956 for (;;) {
957 bool found = false;
958
959 list_for_each(search, region, list) {
960 if (!region_is_reserved(region))
961 continue;
962
963 /* does this region overlap the start address, and
964 * have a non-zero size? */
965 if (region->start <= start &&
966 region->start + region->len > start &&
967 region->len) {
968 start = region->start + region->len;
969 found = true;
970 }
971 }
972
973 /* 'end' is the first byte outside of the range */
974 if (start >= end)
975 return true;
976
977 if (!found)
978 break;
979 }
980
981 return false;
982 }
983
mem_region_parse_reserved_properties(void)984 static void mem_region_parse_reserved_properties(void)
985 {
986 const struct dt_property *names, *ranges;
987 struct mem_region *region;
988
989 prlog(PR_DEBUG, "MEM: parsing reserved memory from "
990 "reserved-names/-ranges properties\n");
991
992 names = dt_find_property(dt_root, "reserved-names");
993 ranges = dt_find_property(dt_root, "reserved-ranges");
994 if (names && ranges) {
995 const uint64_t *range;
996 int n, len;
997
998 range = (const void *)ranges->prop;
999
1000 for (n = 0; n < names->len; n += len, range += 2) {
1001 char *name;
1002
1003 len = strlen(names->prop + n) + 1;
1004 name = strdup(names->prop + n);
1005
1006 region = new_region(name,
1007 dt_get_number(range, 2),
1008 dt_get_number(range + 1, 2),
1009 NULL, REGION_FW_RESERVED);
1010 if (!add_region(region)) {
1011 prerror("Couldn't add mem_region %s\n", name);
1012 abort();
1013 }
1014 }
1015 } else if (names || ranges) {
1016 prerror("Invalid properties: reserved-names=%p "
1017 "with reserved-ranges=%p\n",
1018 names, ranges);
1019 abort();
1020 } else {
1021 return;
1022 }
1023 }
1024
mem_region_parse_reserved_nodes(const char * path)1025 static bool mem_region_parse_reserved_nodes(const char *path)
1026 {
1027 struct dt_node *parent, *node;
1028
1029 parent = dt_find_by_path(dt_root, path);
1030 if (!parent)
1031 return false;
1032
1033 prlog(PR_INFO, "MEM: parsing reserved memory from node %s\n", path);
1034
1035 dt_for_each_child(parent, node) {
1036 const struct dt_property *reg;
1037 struct mem_region *region;
1038 int type;
1039
1040 reg = dt_find_property(node, "reg");
1041 if (!reg) {
1042 char *nodepath = dt_get_path(node);
1043 prerror("node %s has no reg property, ignoring\n",
1044 nodepath);
1045 free(nodepath);
1046 continue;
1047 }
1048
1049 if (dt_has_node_property(node, "no-map", NULL))
1050 type = REGION_RESERVED;
1051 else
1052 type = REGION_FW_RESERVED;
1053
1054 region = new_region(strdup(node->name),
1055 dt_get_number(reg->prop, 2),
1056 dt_get_number(reg->prop + sizeof(u64), 2),
1057 node, type);
1058 if (!add_region(region)) {
1059 char *nodepath = dt_get_path(node);
1060 prerror("node %s failed to add_region()\n", nodepath);
1061 free(nodepath);
1062 }
1063 }
1064
1065 return true;
1066 }
1067
1068 /* Trawl through device tree, create memory regions from nodes. */
mem_region_init(void)1069 void mem_region_init(void)
1070 {
1071 struct mem_region *region, *next;
1072 struct dt_node *i;
1073 bool rc;
1074
1075 /*
1076 * Add associativity properties outside of the lock
1077 * to avoid recursive locking caused by allocations
1078 * done by add_chip_dev_associativity()
1079 */
1080 dt_for_each_node(dt_root, i) {
1081 if (!dt_has_node_property(i, "device_type", "memory") &&
1082 !dt_has_node_property(i, "compatible", "pmem-region"))
1083 continue;
1084
1085 /* Add associativity properties */
1086 add_chip_dev_associativity(i);
1087 }
1088
1089 /* Add each memory node. */
1090 dt_for_each_node(dt_root, i) {
1091 uint64_t start, len;
1092 char *rname;
1093 #define NODE_REGION_PREFIX "ibm,firmware-allocs-"
1094
1095 if (!dt_has_node_property(i, "device_type", "memory"))
1096 continue;
1097 rname = zalloc(strlen(i->name) + strlen(NODE_REGION_PREFIX) + 1);
1098 assert(rname);
1099 strcat(rname, NODE_REGION_PREFIX);
1100 strcat(rname, i->name);
1101 start = dt_get_address(i, 0, &len);
1102 lock(&mem_region_lock);
1103 region = new_region(rname, start, len, i, REGION_MEMORY);
1104 if (!region) {
1105 prerror("MEM: Could not add mem region %s!\n", i->name);
1106 abort();
1107 }
1108 add_region_to_regions(region);
1109 if ((start + len) > top_of_ram)
1110 top_of_ram = start + len;
1111 unlock(&mem_region_lock);
1112 }
1113
1114 /*
1115 * This is called after we know the maximum PIR of all CPUs,
1116 * so we can dynamically set the stack length.
1117 */
1118 skiboot_cpu_stacks.len = (cpu_max_pir + 1) * STACK_SIZE;
1119
1120 lock(&mem_region_lock);
1121
1122 /* Now carve out our own reserved areas. */
1123 if (!add_region(&skiboot_os_reserve) ||
1124 !add_region(&skiboot_code_and_text) ||
1125 !add_region(&skiboot_heap) ||
1126 !add_region(&skiboot_after_heap) ||
1127 !add_region(&skiboot_cpu_stacks)) {
1128 prerror("Out of memory adding skiboot reserved areas\n");
1129 abort();
1130 }
1131
1132 if (chip_quirk(QUIRK_MAMBO_CALLOUTS)) {
1133 if (!add_region(&skiboot_mambo_kernel) ||
1134 !add_region(&skiboot_mambo_initramfs)) {
1135 prerror("Out of memory adding mambo payload\n");
1136 abort();
1137 }
1138 }
1139
1140 /* Add reserved reanges from HDAT */
1141 list_for_each_safe(&early_reserves, region, next, list) {
1142 bool added;
1143
1144 list_del(®ion->list);
1145 added = add_region(region);
1146 assert(added);
1147 }
1148
1149 /* Add reserved ranges from the DT */
1150 rc = mem_region_parse_reserved_nodes("/reserved-memory");
1151 if (!rc)
1152 rc = mem_region_parse_reserved_nodes(
1153 "/ibm,hostboot/reserved-memory");
1154 if (!rc)
1155 mem_region_parse_reserved_properties();
1156
1157 mem_region_init_done = true;
1158 unlock(&mem_region_lock);
1159 }
1160
allocated_length(const struct mem_region * r)1161 static uint64_t allocated_length(const struct mem_region *r)
1162 {
1163 struct free_hdr *f, *last = NULL;
1164
1165 /* No allocations at all? */
1166 if (r->free_list.n.next == NULL)
1167 return 0;
1168
1169 /* Find last free block. */
1170 list_for_each(&r->free_list, f, list)
1171 if (f > last)
1172 last = f;
1173
1174 /* No free blocks? */
1175 if (!last)
1176 return r->len;
1177
1178 /* Last free block isn't at end? */
1179 if (next_hdr(r, &last->hdr))
1180 return r->len;
1181 return (unsigned long)last - r->start;
1182 }
1183
1184 /* Separate out allocated sections into their own region. */
mem_region_release_unused(void)1185 void mem_region_release_unused(void)
1186 {
1187 struct mem_region *r;
1188
1189 lock(&mem_region_lock);
1190 assert(!mem_regions_finalised);
1191
1192 prlog(PR_INFO, "Releasing unused memory:\n");
1193 list_for_each(®ions, r, list) {
1194 uint64_t used_len;
1195
1196 /* If it's not allocatable, ignore it. */
1197 if (!(r->type == REGION_SKIBOOT_HEAP ||
1198 r->type == REGION_MEMORY))
1199 continue;
1200
1201 used_len = allocated_length(r);
1202
1203 prlog(PR_INFO, " %s: %llu/%llu used\n",
1204 r->name, (long long)used_len, (long long)r->len);
1205
1206 /* We keep the skiboot heap. */
1207 if (r == &skiboot_heap)
1208 continue;
1209
1210 /* Nothing used? Whole thing is for Linux. */
1211 if (used_len == 0)
1212 r->type = REGION_OS;
1213 /* Partially used? Split region. */
1214 else if (used_len != r->len) {
1215 struct mem_region *for_linux;
1216 struct free_hdr *last = region_start(r) + used_len;
1217
1218 /* Remove the final free block. */
1219 list_del_from(&r->free_list, &last->list);
1220
1221 for_linux = split_region(r, r->start + used_len,
1222 REGION_OS);
1223 if (!for_linux) {
1224 prerror("OOM splitting mem node %s for linux\n",
1225 r->name);
1226 abort();
1227 }
1228 list_add(®ions, &for_linux->list);
1229 }
1230 }
1231 unlock(&mem_region_lock);
1232 }
1233
mem_clear_range(uint64_t s,uint64_t e)1234 static void mem_clear_range(uint64_t s, uint64_t e)
1235 {
1236 uint64_t res_start, res_end;
1237
1238 /* Skip exception vectors */
1239 if (s < EXCEPTION_VECTORS_END)
1240 s = EXCEPTION_VECTORS_END;
1241
1242 /* Skip kernel preload area */
1243 res_start = (uint64_t)KERNEL_LOAD_BASE;
1244 res_end = res_start + KERNEL_LOAD_SIZE;
1245
1246 if (s >= res_start && s < res_end)
1247 s = res_end;
1248 if (e > res_start && e <= res_end)
1249 e = res_start;
1250 if (e <= s)
1251 return;
1252 if (s < res_start && e > res_end) {
1253 mem_clear_range(s, res_start);
1254 mem_clear_range(res_end, e);
1255 return;
1256 }
1257
1258 /* Skip initramfs preload area */
1259 res_start = (uint64_t)INITRAMFS_LOAD_BASE;
1260 res_end = res_start + INITRAMFS_LOAD_SIZE;
1261
1262 if (s >= res_start && s < res_end)
1263 s = res_end;
1264 if (e > res_start && e <= res_end)
1265 e = res_start;
1266 if (e <= s)
1267 return;
1268 if (s < res_start && e > res_end) {
1269 mem_clear_range(s, res_start);
1270 mem_clear_range(res_end, e);
1271 return;
1272 }
1273
1274 prlog(PR_DEBUG, "Clearing region %llx-%llx\n",
1275 (long long)s, (long long)e);
1276 memset((void *)s, 0, e - s);
1277 }
1278
1279 struct mem_region_clear_job_args {
1280 char *job_name;
1281 uint64_t s,e;
1282 };
1283
mem_region_clear_job(void * data)1284 static void mem_region_clear_job(void *data)
1285 {
1286 struct mem_region_clear_job_args *arg = (struct mem_region_clear_job_args*)data;
1287 mem_clear_range(arg->s, arg->e);
1288 }
1289
1290 #define MEM_REGION_CLEAR_JOB_SIZE (16ULL*(1<<30))
1291
1292 static struct cpu_job **mem_clear_jobs;
1293 static struct mem_region_clear_job_args *mem_clear_job_args;
1294 static int mem_clear_njobs = 0;
1295
start_mem_region_clear_unused(void)1296 void start_mem_region_clear_unused(void)
1297 {
1298 struct mem_region *r;
1299 uint64_t s,l;
1300 uint64_t total = 0;
1301 uint32_t chip_id;
1302 char *path;
1303 int i;
1304 struct cpu_job **jobs;
1305 struct mem_region_clear_job_args *job_args;
1306
1307 lock(&mem_region_lock);
1308 assert(mem_regions_finalised);
1309
1310 mem_clear_njobs = 0;
1311
1312 list_for_each(®ions, r, list) {
1313 if (!(r->type == REGION_OS))
1314 continue;
1315 mem_clear_njobs++;
1316 /* One job per 16GB */
1317 mem_clear_njobs += r->len / MEM_REGION_CLEAR_JOB_SIZE;
1318 }
1319
1320 jobs = malloc(mem_clear_njobs * sizeof(struct cpu_job*));
1321 job_args = malloc(mem_clear_njobs * sizeof(struct mem_region_clear_job_args));
1322 mem_clear_jobs = jobs;
1323 mem_clear_job_args = job_args;
1324
1325 prlog(PR_NOTICE, "Clearing unused memory:\n");
1326 i = 0;
1327 list_for_each(®ions, r, list) {
1328 /* If it's not unused, ignore it. */
1329 if (!(r->type == REGION_OS))
1330 continue;
1331
1332 assert(r != &skiboot_heap);
1333
1334 s = r->start;
1335 l = r->len;
1336 while(l > MEM_REGION_CLEAR_JOB_SIZE) {
1337 job_args[i].s = s+l - MEM_REGION_CLEAR_JOB_SIZE;
1338 job_args[i].e = s+l;
1339 l-=MEM_REGION_CLEAR_JOB_SIZE;
1340 job_args[i].job_name = malloc(sizeof(char)*100);
1341 total+=MEM_REGION_CLEAR_JOB_SIZE;
1342 chip_id = __dt_get_chip_id(r->node);
1343 if (chip_id == -1)
1344 chip_id = 0;
1345 path = dt_get_path(r->node);
1346 snprintf(job_args[i].job_name, 100,
1347 "clear %s, %s 0x%"PRIx64" len: %"PRIx64" on %d",
1348 r->name, path,
1349 job_args[i].s,
1350 (job_args[i].e - job_args[i].s),
1351 chip_id);
1352 free(path);
1353 jobs[i] = cpu_queue_job_on_node(chip_id,
1354 job_args[i].job_name,
1355 mem_region_clear_job,
1356 &job_args[i]);
1357 if (!jobs[i])
1358 jobs[i] = cpu_queue_job(NULL,
1359 job_args[i].job_name,
1360 mem_region_clear_job,
1361 &job_args[i]);
1362 assert(jobs[i]);
1363 i++;
1364 }
1365 job_args[i].s = s;
1366 job_args[i].e = s+l;
1367 job_args[i].job_name = malloc(sizeof(char)*100);
1368 total+=l;
1369 chip_id = __dt_get_chip_id(r->node);
1370 if (chip_id == -1)
1371 chip_id = 0;
1372 path = dt_get_path(r->node);
1373 snprintf(job_args[i].job_name,100,
1374 "clear %s, %s 0x%"PRIx64" len: 0x%"PRIx64" on %d",
1375 r->name, path,
1376 job_args[i].s,
1377 (job_args[i].e - job_args[i].s),
1378 chip_id);
1379 free(path);
1380 jobs[i] = cpu_queue_job_on_node(chip_id,
1381 job_args[i].job_name,
1382 mem_region_clear_job,
1383 &job_args[i]);
1384 if (!jobs[i])
1385 jobs[i] = cpu_queue_job(NULL,
1386 job_args[i].job_name,
1387 mem_region_clear_job,
1388 &job_args[i]);
1389 assert(jobs[i]);
1390 i++;
1391 }
1392 unlock(&mem_region_lock);
1393 cpu_process_local_jobs();
1394 }
1395
wait_mem_region_clear_unused(void)1396 void wait_mem_region_clear_unused(void)
1397 {
1398 uint64_t l;
1399 uint64_t total = 0;
1400 int i;
1401
1402 for(i=0; i < mem_clear_njobs; i++) {
1403 total += (mem_clear_job_args[i].e - mem_clear_job_args[i].s);
1404 }
1405
1406 l = 0;
1407 for(i=0; i < mem_clear_njobs; i++) {
1408 cpu_wait_job(mem_clear_jobs[i], true);
1409 l += (mem_clear_job_args[i].e - mem_clear_job_args[i].s);
1410 printf("Clearing memory... %"PRIu64"/%"PRIu64"GB done\n",
1411 l>>30, total>>30);
1412 free(mem_clear_job_args[i].job_name);
1413 }
1414 free(mem_clear_jobs);
1415 free(mem_clear_job_args);
1416 }
1417
mem_region_add_dt_reserved_node(struct dt_node * parent,struct mem_region * region)1418 static void mem_region_add_dt_reserved_node(struct dt_node *parent,
1419 struct mem_region *region)
1420 {
1421 char *name, *p;
1422
1423 /* If a reserved region was established before skiboot, it may be
1424 * referenced by a device-tree node with extra data. In that case,
1425 * copy the node to /reserved-memory/, unless it's already there.
1426 *
1427 * We update region->node to the new copy here, as the prd code may
1428 * update regions' device-tree nodes, and we want those updates to
1429 * apply to the nodes in /reserved-memory/.
1430 */
1431 if (region->type == REGION_FW_RESERVED && region->node) {
1432 if (region->node->parent != parent)
1433 region->node = dt_copy(region->node, parent);
1434 return;
1435 }
1436
1437 name = strdup(region->name);
1438 assert(name);
1439
1440 /* remove any cell addresses in the region name; we have our own cell
1441 * addresses here */
1442 p = strchr(name, '@');
1443 if (p)
1444 *p = '\0';
1445
1446 region->node = dt_new_addr(parent, name, region->start);
1447 assert(region->node);
1448 dt_add_property_u64s(region->node, "reg", region->start, region->len);
1449
1450 /*
1451 * This memory is used by hardware and may need special handling. Ask
1452 * the host kernel not to map it by default.
1453 */
1454 if (region->type == REGION_RESERVED)
1455 dt_add_property(region->node, "no-map", NULL, 0);
1456
1457 free(name);
1458 }
1459
mem_region_add_dt_reserved(void)1460 void mem_region_add_dt_reserved(void)
1461 {
1462 int names_len, ranges_len, len;
1463 const struct dt_property *prop;
1464 struct mem_region *region;
1465 void *names, *ranges;
1466 struct dt_node *node;
1467 fdt64_t *range;
1468 char *name;
1469
1470 names_len = 0;
1471 ranges_len = 0;
1472
1473 /* Finalise the region list, so we know that the regions list won't be
1474 * altered after this point. The regions' free lists may change after
1475 * we drop the lock, but we don't access those. */
1476 lock(&mem_region_lock);
1477 mem_regions_finalised = true;
1478
1479 /* establish top-level reservation node */
1480 node = dt_find_by_path(dt_root, "reserved-memory");
1481 if (!node) {
1482 node = dt_new(dt_root, "reserved-memory");
1483 dt_add_property_cells(node, "#address-cells", 2);
1484 dt_add_property_cells(node, "#size-cells", 2);
1485 dt_add_property(node, "ranges", NULL, 0);
1486 }
1487
1488 prlog(PR_INFO, "Reserved regions:\n");
1489
1490 /* First pass, create /reserved-memory/ nodes for each reservation,
1491 * and calculate the length for the /reserved-names and
1492 * /reserved-ranges properties */
1493 list_for_each(®ions, region, list) {
1494 if (!region_is_reservable(region))
1495 continue;
1496
1497 prlog(PR_INFO, " 0x%012llx..%012llx : %s\n",
1498 (long long)region->start,
1499 (long long)(region->start + region->len - 1),
1500 region->name);
1501
1502 mem_region_add_dt_reserved_node(node, region);
1503
1504 /* calculate the size of the properties populated later */
1505 names_len += strlen(region->node->name) + 1;
1506 ranges_len += 2 * sizeof(uint64_t);
1507 }
1508
1509 name = names = malloc(names_len);
1510 range = ranges = malloc(ranges_len);
1511
1512 /* Second pass: populate the old-style reserved-names and
1513 * reserved-regions arrays based on the node data */
1514 list_for_each(®ions, region, list) {
1515 if (!region_is_reservable(region))
1516 continue;
1517
1518 len = strlen(region->node->name) + 1;
1519 memcpy(name, region->node->name, len);
1520 name += len;
1521
1522 range[0] = cpu_to_fdt64(region->start);
1523 range[1] = cpu_to_fdt64(region->len);
1524 range += 2;
1525 }
1526 unlock(&mem_region_lock);
1527
1528 prop = dt_find_property(dt_root, "reserved-names");
1529 if (prop)
1530 dt_del_property(dt_root, (struct dt_property *)prop);
1531
1532 prop = dt_find_property(dt_root, "reserved-ranges");
1533 if (prop)
1534 dt_del_property(dt_root, (struct dt_property *)prop);
1535
1536 dt_add_property(dt_root, "reserved-names", names, names_len);
1537 dt_add_property(dt_root, "reserved-ranges", ranges, ranges_len);
1538
1539 free(names);
1540 free(ranges);
1541 }
1542
mem_region_next(struct mem_region * region)1543 struct mem_region *mem_region_next(struct mem_region *region)
1544 {
1545 struct list_node *node;
1546
1547 assert(lock_held_by_me(&mem_region_lock));
1548
1549 node = region ? ®ion->list : ®ions.n;
1550
1551 if (node->next == ®ions.n)
1552 return NULL;
1553
1554 return list_entry(node->next, struct mem_region, list);
1555 }
1556