aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStewart Smith <stewart@linux.vnet.ibm.com>2015-09-21 11:19:23 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-09-22 16:28:49 +1000
commit084f1deb99f10b210ac2751b60b65f35ffca2a22 (patch)
treedf9fffd34dd113307e369a2492e5c816046cbd44
parent1e147dcdd6c0456ca0ab1f079898f2e90f90bdd1 (diff)
downloadskiboot-084f1deb99f10b210ac2751b60b65f35ffca2a22.zip
skiboot-084f1deb99f10b210ac2751b60b65f35ffca2a22.tar.gz
skiboot-084f1deb99f10b210ac2751b60b65f35ffca2a22.tar.bz2
Ensure reserved memory ranges are exposed correctly to host (fix corrupted SLW image)
Memory regions in skiboot have an interesting life cycle. First, we get a bunch from the initial device tree or hdat specifying some existing reserved ranges (as well as adding some of our own if they're missing) but we also get ranges for the entirety of RAM. The idea is that we can do node local allocations for per node resources (which we do) and then, just prior to booting linux, we copy the reserved memory regions to expose to linux along with a set of reserver regions to cover the node local allocations. The problem was that mem_range_is_reserved() was wanting subtle different semantics for memory region type than region_is_reserved() provided. That is, we were overriding the meaning of REGION_SKIBOOT_HEAP to mean both "this is reserved by skiboot" *and* "this is a memory region that covers all of memory and will be shrunk to cover just the memory we have allocated for it just before we boot the payload (linux)". So what would happen is we would ask "hey, is the memory holding the SLW image reserved?" and we'd get the answer of "yes" but referring to the memory region that covers the entirety of memory in a NUMA node, *not* meaning our intent of "this will be reserved when we start linux". To fix this, introduce a new memory region type REGION_MEMORY. This has the semantics of a memory region that covers a block of memory that we can allocate from (using local_alloc) and that the part that was allocated will be passed to linux as reserved, but that the entire range will not be reserved. So our new semantics are: - region_is_reservable() is true if the region *MAY* be reserved (i.e. is the regions that cover the whole of memory OR is explicitly reserved) - region_is_reserved() is true if the region *WILL* be reserved (i.e. is explicitly reserved) This way we check that the SLW image is explicitly reserved and if it isn't, we reserve it. Fixes: 58033e44 Acked-by: Jeremy Kerr <jk@ozlabs.org> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--core/mem_region.c36
-rw-r--r--core/test/run-mem_region_init.c2
-rw-r--r--core/test/run-mem_region_release_unused.c2
-rw-r--r--include/mem_region.h3
4 files changed, 29 insertions, 14 deletions
diff --git a/core/mem_region.c b/core/mem_region.c
index 17fe268..f8d9a11 100644
--- a/core/mem_region.c
+++ b/core/mem_region.c
@@ -133,7 +133,8 @@ static struct alloc_hdr *next_hdr(const struct mem_region *region,
static void init_allocatable_region(struct mem_region *region)
{
struct free_hdr *f = region_start(region);
- assert(region->type == REGION_SKIBOOT_HEAP);
+ assert(region->type == REGION_SKIBOOT_HEAP ||
+ region->type == REGION_MEMORY);
f->hdr.num_longs = region->len / sizeof(long);
f->hdr.free = true;
f->hdr.prev_free = false;
@@ -256,11 +257,16 @@ static void bad_header(const struct mem_region *region,
abort();
}
-static bool region_is_reserved(struct mem_region *region)
+static bool region_is_reservable(struct mem_region *region)
{
return region->type != REGION_OS;
}
+static bool region_is_reserved(struct mem_region *region)
+{
+ return region->type != REGION_OS && region->type != REGION_MEMORY;
+}
+
void mem_dump_allocs(void)
{
struct mem_region *region;
@@ -269,7 +275,8 @@ void mem_dump_allocs(void)
/* Second pass: populate property data */
printf("Memory regions:\n");
list_for_each(&regions, region, list) {
- if (region->type != REGION_SKIBOOT_HEAP)
+ if (!(region->type == REGION_SKIBOOT_HEAP ||
+ region->type == REGION_MEMORY))
continue;
printf(" 0x%012llx..%012llx : %s\n",
(long long)region->start,
@@ -299,7 +306,8 @@ int64_t mem_dump_free(void)
printf("Free space in HEAP memory regions:\n");
list_for_each(&regions, region, list) {
- if (region->type != REGION_SKIBOOT_HEAP)
+ if (!(region->type == REGION_SKIBOOT_HEAP ||
+ region->type == REGION_MEMORY))
continue;
region_free = 0;
@@ -335,7 +343,8 @@ static void *__mem_alloc(struct mem_region *region, size_t size, size_t align,
assert(is_rodata(location));
/* Unallocatable region? */
- if (region->type != REGION_SKIBOOT_HEAP)
+ if (!(region->type == REGION_SKIBOOT_HEAP ||
+ region->type == REGION_MEMORY))
return NULL;
/* First allocation? */
@@ -535,8 +544,9 @@ bool mem_check(const struct mem_region *region)
}
/* Not ours to play with, or empty? Don't do anything. */
- if (region->type != REGION_SKIBOOT_HEAP ||
- region->free_list.n.next == NULL)
+ if (!(region->type == REGION_MEMORY ||
+ region->type == REGION_SKIBOOT_HEAP) ||
+ region->free_list.n.next == NULL)
return true;
/* Walk linearly. */
@@ -738,7 +748,8 @@ restart:
const struct dt_property *prop;
const __be32 *ids;
- if (region->type != REGION_SKIBOOT_HEAP)
+ if (!(region->type == REGION_SKIBOOT_HEAP ||
+ region->type == REGION_MEMORY))
continue;
/* Don't allocate from normal heap. */
@@ -950,7 +961,7 @@ void mem_region_init(void)
strcat(rname, i->name);
start = dt_get_address(i, 0, &len);
lock(&mem_region_lock);
- region = new_region(rname, start, len, i, REGION_SKIBOOT_HEAP);
+ region = new_region(rname, start, len, i, REGION_MEMORY);
if (!region) {
prerror("MEM: Could not add mem region %s!\n", i->name);
abort();
@@ -1023,7 +1034,8 @@ void mem_region_release_unused(void)
uint64_t used_len;
/* If it's not allocatable, ignore it. */
- if (r->type != REGION_SKIBOOT_HEAP)
+ if (!(r->type == REGION_SKIBOOT_HEAP ||
+ r->type == REGION_MEMORY))
continue;
used_len = allocated_length(r);
@@ -1123,7 +1135,7 @@ void mem_region_add_dt_reserved(void)
/* First pass: calculate length of property data */
list_for_each(&regions, region, list) {
- if (!region_is_reserved(region))
+ if (!region_is_reservable(region))
continue;
names_len += strlen(region->name) + 1;
ranges_len += 2 * sizeof(uint64_t);
@@ -1135,7 +1147,7 @@ void mem_region_add_dt_reserved(void)
printf("Reserved regions:\n");
/* Second pass: populate property data */
list_for_each(&regions, region, list) {
- if (!region_is_reserved(region))
+ if (!region_is_reservable(region))
continue;
len = strlen(region->name) + 1;
memcpy(name, region->name, len);
diff --git a/core/test/run-mem_region_init.c b/core/test/run-mem_region_init.c
index 7ab23d2..d780ae5 100644
--- a/core/test/run-mem_region_init.c
+++ b/core/test/run-mem_region_init.c
@@ -164,7 +164,7 @@ int main(void)
r == &skiboot_os_reserve)
builtins++;
else
- assert(r->type == REGION_SKIBOOT_HEAP);
+ assert(r->type == REGION_MEMORY);
assert(mem_check(r));
}
assert(builtins == 5);
diff --git a/core/test/run-mem_region_release_unused.c b/core/test/run-mem_region_release_unused.c
index 980f4c4..fca5278 100644
--- a/core/test/run-mem_region_release_unused.c
+++ b/core/test/run-mem_region_release_unused.c
@@ -159,7 +159,7 @@ int main(void)
if (r == &skiboot_cpu_stacks)
continue;
if (r == other) {
- assert(r->type == REGION_SKIBOOT_HEAP);
+ assert(r->type == REGION_MEMORY);
assert(r->len < 1024 * 1024);
} else {
assert(r->type == REGION_OS);
diff --git a/include/mem_region.h b/include/mem_region.h
index 913dbb6..c34858e 100644
--- a/include/mem_region.h
+++ b/include/mem_region.h
@@ -25,6 +25,9 @@ enum mem_region_type {
/* ranges allocatable by mem_alloc: this will be most of memory */
REGION_SKIBOOT_HEAP,
+ /* ranges allocatable by mem_alloc but shrunk (e.g. whole memory) */
+ REGION_MEMORY,
+
/* ranges used explicitly for skiboot, but not allocatable. eg .text */
REGION_SKIBOOT_FIRMWARE,