diff options
-rw-r--r-- | core/flash-subpartition.c | 86 | ||||
-rw-r--r-- | core/flash.c | 2 | ||||
-rw-r--r-- | core/test/run-flash-subpartition.c | 6 | ||||
-rw-r--r-- | include/skiboot.h | 3 |
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 */ |