aboutsummaryrefslogtreecommitdiff
path: root/platforms/astbmc
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2015-02-12 12:57:53 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-02-17 09:20:52 +1100
commita8513d3f3e8db11d6efcd73dbbc384168688ddd0 (patch)
treed5aac9bcee05eb8a29c7955653616d09a9a1e71c /platforms/astbmc
parent4a4efc42a87da445333da85ce7f13db2f6095d03 (diff)
downloadskiboot-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.h4
-rw-r--r--platforms/astbmc/pnor.c124
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);