diff options
author | Michael Neuling <mikey@neuling.org> | 2015-02-12 12:57:53 +1100 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2015-02-17 09:20:52 +1100 |
commit | a8513d3f3e8db11d6efcd73dbbc384168688ddd0 (patch) | |
tree | d5aac9bcee05eb8a29c7955653616d09a9a1e71c /platforms/astbmc | |
parent | 4a4efc42a87da445333da85ce7f13db2f6095d03 (diff) | |
download | skiboot-a8513d3f3e8db11d6efcd73dbbc384168688ddd0.zip skiboot-a8513d3f3e8db11d6efcd73dbbc384168688ddd0.tar.gz skiboot-a8513d3f3e8db11d6efcd73dbbc384168688ddd0.tar.bz2 |
core: Add subid to load_resource()
This adds a subid to load_resource() so that sub-partitions can be accessed
inside a PNOR partition. These sub-partitions follow the format used by the
hostboot SBE image.
The subid will match on the EC field of the SBE table of contents. If it's
found, only that sub-partition is returned to the caller.
Current partitions (kernel and ramfs) don't support sub-partitions. If caller
tries to access a sub-partition within these, we fail the call.
Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'platforms/astbmc')
-rw-r--r-- | platforms/astbmc/astbmc.h | 4 | ||||
-rw-r--r-- | platforms/astbmc/pnor.c | 124 |
2 files changed, 121 insertions, 7 deletions
diff --git a/platforms/astbmc/astbmc.h b/platforms/astbmc/astbmc.h index 7e33f61..cff4757 100644 --- a/platforms/astbmc/astbmc.h +++ b/platforms/astbmc/astbmc.h @@ -24,6 +24,8 @@ extern int64_t astbmc_ipmi_power_down(uint64_t request); extern void astbmc_init(void); extern void astbmc_ext_irq(unsigned int chip_id); extern int pnor_init(void); -extern bool pnor_load_resource(enum resource_id id, void *buf, size_t *len); +extern int pnor_load_part(const char *name, void *addr, size_t *len); +extern bool pnor_load_resource(enum resource_id id, uint32_t subid, + void *buf, size_t *len); #endif /* __ASTBMC_H */ diff --git a/platforms/astbmc/pnor.c b/platforms/astbmc/pnor.c index 2cdb29b..c566877 100644 --- a/platforms/astbmc/pnor.c +++ b/platforms/astbmc/pnor.c @@ -84,15 +84,110 @@ int pnor_init(void) return rc; } -static const struct { - enum resource_id id; - char name[PART_NAME_MAX+1]; +static struct { + enum resource_id id; + uint32_t subid; + char name[PART_NAME_MAX+1]; } part_name_map[] = { - { RESOURCE_ID_KERNEL, "KERNEL" }, - { RESOURCE_ID_INITRAMFS, "ROOTFS" }, + { RESOURCE_ID_KERNEL, RESOURCE_SUBID_NONE, "KERNEL" }, + { RESOURCE_ID_INITRAMFS,RESOURCE_SUBID_NONE, "ROOTFS" }, }; -bool pnor_load_resource(enum resource_id id, void *buf, size_t *len) +/* This mimics the hostboot SBE format */ +#define PNOR_SUBPART_ALIGNMENT 0x1000 +#define PNOR_SUBPART_HEADER_SIZE PNOR_SUBPART_ALIGNMENT +struct pnor_hostboot_toc { + be32 ec; + be32 offset; /* From start of header. 4K aligned */ + be32 size; +}; +#define PNOR_HOSTBOOT_TOC_MAX_ENTRIES ((PNOR_SUBPART_HEADER_SIZE - 8)/sizeof(struct pnor_hostboot_toc)) +struct pnor_hostboot_header { + char eyecatcher[4]; + be32 version; + struct pnor_hostboot_toc toc[PNOR_HOSTBOOT_TOC_MAX_ENTRIES]; +}; + +static int pnor_find_subpartition(struct flash_chip *chip, + uint32_t subid, + uint32_t *start, + uint32_t *total_size) +{ + struct pnor_hostboot_header *header; + uint32_t i; + bool rc; + char eyecatcher[5]; + + header = malloc(PNOR_SUBPART_HEADER_SIZE); + if (!header) + return false; + + /* Get the TOC */ + rc = flash_read(chip, *start, header, PNOR_SUBPART_HEADER_SIZE); + if (rc) { + prerror("PLAT: pnor subpartition TOC read failed %i", rc); + goto end; + } + + /* Perform sanity */ + i = be32_to_cpu(header->version); + if (i != 1) { + prerror("PLAT: pnor subpartition TOC version unknown %i", i); + rc = OPAL_RESOURCE; + goto end; + } + /* NULL terminate eyecatcher */ + strncpy(eyecatcher, header->eyecatcher, 4); + eyecatcher[4] = 0; + printf("PLAT: pnor subpartition eyecatcher %s\n", eyecatcher); + + rc = OPAL_RESOURCE; + for (i = 0; i< PNOR_HOSTBOOT_TOC_MAX_ENTRIES; i++) { + uint32_t ec, offset, size; + + ec = be32_to_cpu(header->toc[i].ec); + offset = be32_to_cpu(header->toc[i].offset); + size = be32_to_cpu(header->toc[i].size); + /* Check for null terminating entry */ + if (!ec && !offset && !size) { + prerror("PLAT: pnor subpartition not found."); + goto end; + } + + if (ec != subid) + continue; + + /* Sanity check the offset and size */ + if (offset + size > *total_size) { + prerror("PLAT: pnor subpartition too big: %i", i); + goto end; + } + if (!size) { + prerror("PLAT: pnor subpartition zero size: %i", i); + goto end; + } + if (offset < PNOR_SUBPART_HEADER_SIZE) { + prerror("PLAT: pnor subpartition offset too small: %i", i); + goto end; + } + + /* All good, let's adjust the start and size */ + printf("PLAT: pnor found subpartition: %i size: %i offset %i\n", + i, size, offset); + *start += offset; + size = (size + (PNOR_SUBPART_ALIGNMENT - 1)) & ~(PNOR_SUBPART_ALIGNMENT - 1); + *total_size = size; + rc = 0; + goto end; + } + +end: + free(header); + return rc; +} + +bool pnor_load_resource(enum resource_id id, uint32_t subid, + void *buf, size_t *len) { int i, rc, part_num, part_size, part_start; const char *name; @@ -111,6 +206,16 @@ bool pnor_load_resource(enum resource_id id, void *buf, size_t *len) return false; } + /* + * If partition doesn't have a subindex but the caller specifies one, + * we fail. eg. kernel partition doesn't have a subindex + */ + if ((part_name_map[i].subid == RESOURCE_SUBID_NONE) && + (subid != RESOURCE_SUBID_NONE)) { + prerror("PLAT: Partition %s doesn't have subindex\n", name); + return false; + } + rc = ffs_lookup_part(pnor_ffs, name, &part_num); if (rc) { prerror("PLAT: No %s partition in PNOR\n", name); @@ -123,6 +228,13 @@ bool pnor_load_resource(enum resource_id id, void *buf, size_t *len) return false; } + /* Find the sub partition if required */ + if (subid != RESOURCE_SUBID_NONE) { + rc = pnor_find_subpartition(pnor_chip, subid, &part_start, + &part_size); + if (rc) + return false; + } if (part_size > *len) { prerror("PLAT: %s image too large (%d > %zd)\n", name, part_size, *len); |