aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/flash-subpartition.c86
-rw-r--r--core/flash.c2
-rw-r--r--core/test/run-flash-subpartition.c6
-rw-r--r--include/skiboot.h3
4 files changed, 60 insertions, 37 deletions
diff --git a/core/flash-subpartition.c b/core/flash-subpartition.c
index ba7f0a3..1e91c1b 100644
--- a/core/flash-subpartition.c
+++ b/core/flash-subpartition.c
@@ -31,16 +31,24 @@ struct flash_hostboot_header {
struct flash_hostboot_toc toc[FLASH_HOSTBOOT_TOC_MAX_ENTRIES];
};
-int flash_subpart_info(void *part_header, uint32_t part_size, uint32_t subid,
- uint32_t *offset, uint32_t *size)
+int flash_subpart_info(void *part_header, uint32_t header_len,
+ uint32_t part_size, uint32_t *part_actual,
+ uint32_t subid, uint32_t *offset, uint32_t *size)
{
struct flash_hostboot_header *header;
char eyecatcher[5];
- uint32_t i, ec;
+ uint32_t i, ec, o, s, toc;
+ bool subpart_found;
- if (!part_header || !offset || !size) {
- prlog(PR_ERR, "FLASH: invalid parameters: "
- "ph %p of %p sz %p\n", part_header, offset, size);
+ if (!part_header || ( !offset && !size && !part_actual)) {
+ prlog(PR_ERR, "FLASH: invalid parameters: ph %p of %p sz %p "
+ "tsz %p\n", part_header, offset, size, part_actual);
+ return OPAL_PARAMETER;
+ }
+
+ if (header_len < FLASH_SUBPART_HEADER_SIZE) {
+ prlog(PR_ERR, "FLASH: subpartition header too small 0x%x\n",
+ header_len);
return OPAL_PARAMETER;
}
@@ -50,53 +58,63 @@ int flash_subpart_info(void *part_header, uint32_t part_size, uint32_t subid,
i = be32_to_cpu(header->version);
if (i != 1) {
prerror("FLASH: flash subpartition TOC version unknown %i\n", i);
- goto end;
+ return OPAL_RESOURCE;
}
/* NULL terminate eyecatcher */
strncpy(eyecatcher, header->eyecatcher, 4);
eyecatcher[4] = '\0';
prlog(PR_DEBUG, "FLASH: flash subpartition eyecatcher %s\n",
- eyecatcher);
+ eyecatcher);
+ subpart_found = false;
+ *part_actual = 0;
+ toc = sizeof(header->eyecatcher) + sizeof(header->version);
for (i = 0; i < FLASH_HOSTBOOT_TOC_MAX_ENTRIES; i++) {
ec = be32_to_cpu(header->toc[i].ec);
- *offset = be32_to_cpu(header->toc[i].offset);
- *size = be32_to_cpu(header->toc[i].size);
+ o = be32_to_cpu(header->toc[i].offset);
+ s = be32_to_cpu(header->toc[i].size);
/* Check for null terminating entry */
- if (!ec && !*offset && !*size) {
- prerror("FLASH: flash subpartition not found.\n");
- goto end;
- }
-
- if (ec != subid)
- continue;
+ if (!ec && !o && !s)
+ break;
/* Sanity check the offset and size. */
- if (*offset + *size > part_size) {
+ if (o + s > part_size) {
prerror("FLASH: flash subpartition too big: %i\n", i);
- goto end;
+ return OPAL_RESOURCE;
}
- if (!*size) {
+ if (!s) {
prerror("FLASH: flash subpartition zero size: %i\n", i);
- goto end;
+ return OPAL_RESOURCE;
}
- if (*offset < FLASH_SUBPART_HEADER_SIZE) {
- prerror("FLASH: flash subpartition "
- "offset too small: %i\n", i);
- goto end;
+ if (o < FLASH_SUBPART_HEADER_SIZE) {
+ prerror("FLASH: flash subpartition offset too small: "
+ "%i\n", i);
+ return OPAL_RESOURCE;
}
+ /*
+ * Subpartitions content are different, but multiple toc entries
+ * may point to the same subpartition.
+ */
+ if (ALIGN_UP(o + s, FLASH_SUBPART_HEADER_SIZE) > *part_actual)
+ *part_actual = ALIGN_UP(o + s, FLASH_SUBPART_HEADER_SIZE);
- prlog(PR_DEBUG, "FLASH: flash found subpartition: "
- "%i size: %i offset %i\n",
- i, *size, *offset);
-
- return OPAL_SUCCESS;
+ if (ec == subid) {
+ if (offset)
+ *offset += o;
+ if (size)
+ *size = s;
+ if (!part_actual)
+ return OPAL_SUCCESS;
+ subpart_found = true;
+ }
+ toc += sizeof(struct flash_hostboot_toc);
+ }
+ if (!subpart_found && (offset || size)) {
+ prerror("FLASH: flash subpartition not found.\n");
+ return OPAL_RESOURCE;
}
-end:
- *size = 0;
- *offset = 0;
- return OPAL_RESOURCE;
+ return OPAL_SUCCESS;
}
diff --git a/core/flash.c b/core/flash.c
index 4b7f4b3..2299f45 100644
--- a/core/flash.c
+++ b/core/flash.c
@@ -459,7 +459,7 @@ static int flash_find_subpartition(struct blocklevel_device *bl, uint32_t subid,
goto end;
}
- rc = flash_subpart_info(header, partsize, subid, &offset, &size);
+ rc = flash_subpart_info(header, partsize, partsize, NULL, subid, &offset, &size);
if (rc)
goto end;
diff --git a/core/test/run-flash-subpartition.c b/core/test/run-flash-subpartition.c
index 169362e..419de88 100644
--- a/core/test/run-flash-subpartition.c
+++ b/core/test/run-flash-subpartition.c
@@ -35,20 +35,24 @@ char capp[4096] = {0x43, 0x41, 0x50, 0x50, 0x00, 0x00, 0x00, 0x01,
int main(void)
{
int rc;
+ uint32_t part_actual;
uint32_t offset;
uint32_t size;
uint32_t subids[] = { 0x100ea, 0x200ea, 0x200ef, 0x201ef, 0x100d3 };
for (int i = 0; i < sizeof(subids)/sizeof(uint32_t); i++) {
offset = 0;
- rc = flash_subpart_info(capp, 0x24000, subids[i],
+ rc = flash_subpart_info(capp, sizeof(capp), 0x24000,
+ &part_actual, subids[i],
&offset, &size);
printf("\nsubid %x\n", subids[i]);
+ printf("part_actual %u\n", part_actual);
printf("offset %u\n", offset);
printf("size %u\n", size);
assert (rc == 0);
assert (size == 36432);
assert (offset == 4096);
+ assert (part_actual == 40960);
}
return 0;
diff --git a/include/skiboot.h b/include/skiboot.h
index 30149a1..75c5207 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -227,7 +227,8 @@ extern bool flash_reserve(void);
extern void flash_release(void);
#define FLASH_SUBPART_ALIGNMENT 0x1000
#define FLASH_SUBPART_HEADER_SIZE FLASH_SUBPART_ALIGNMENT
-extern int flash_subpart_info(void *part_header, uint32_t part_size,
+extern int flash_subpart_info(void *part_header, uint32_t header_len,
+ uint32_t part_size, uint32_t *part_actual,
uint32_t subid, uint32_t *offset,
uint32_t *size);
/* NVRAM support */