diff options
-rw-r--r-- | core/init.c | 5 | ||||
-rw-r--r-- | core/platform.c | 4 | ||||
-rw-r--r-- | hw/fsp/fsp.c | 39 | ||||
-rw-r--r-- | include/fsp.h | 3 | ||||
-rw-r--r-- | include/platform.h | 6 | ||||
-rw-r--r-- | platforms/astbmc/astbmc.h | 4 | ||||
-rw-r--r-- | platforms/astbmc/pnor.c | 124 |
7 files changed, 158 insertions, 27 deletions
diff --git a/core/init.c b/core/init.c index c18b71c..f76d6c3 100644 --- a/core/init.c +++ b/core/init.c @@ -293,7 +293,8 @@ static bool load_kernel(void) /* Try to load an external kernel payload through the platform hooks */ ksize = KERNEL_LOAD_SIZE; - if (!load_resource(RESOURCE_ID_KERNEL, KERNEL_LOAD_BASE, + if (!load_resource(RESOURCE_ID_KERNEL, RESOURCE_SUBID_NONE, + KERNEL_LOAD_BASE, &ksize)) { printf("INIT: platform kernel load failed\n"); ksize = 0; @@ -334,7 +335,7 @@ static void load_initramfs(void) bool loaded; size = INITRAMFS_LOAD_SIZE; - loaded = load_resource(RESOURCE_ID_INITRAMFS, + loaded = load_resource(RESOURCE_ID_INITRAMFS, RESOURCE_SUBID_NONE, INITRAMFS_LOAD_BASE, &size); if (!loaded || !size) diff --git a/core/platform.c b/core/platform.c index 4232294..877251e 100644 --- a/core/platform.c +++ b/core/platform.c @@ -77,12 +77,12 @@ void probe_platform(void) printf("PLAT: Detected %s platform\n", platform.name); } -bool load_resource(enum resource_id id, +bool load_resource(enum resource_id id, uint32_t subid, void *buf, size_t *len) { if (!platform.load_resource) return false; - return platform.load_resource(id, buf, len); + return platform.load_resource(id, subid, buf, len); } diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c index fdc4ffb..da68eef 100644 --- a/hw/fsp/fsp.c +++ b/hw/fsp/fsp.c @@ -2245,22 +2245,33 @@ int fsp_fetch_data_queue(uint8_t flags, uint16_t id, uint32_t sub_id, return OPAL_SUCCESS; } -bool fsp_load_resource(enum resource_id id, void *buf, size_t *size) +static struct { + enum resource_id id; + uint32_t idx; + uint32_t lid_no; +} fsp_lid_map[] = { + { RESOURCE_ID_KERNEL, RESOURCE_SUBID_NONE, KERNEL_LID_OPAL }, + { RESOURCE_ID_INITRAMFS,RESOURCE_SUBID_NONE, INITRAMFS_LID_OPAL }, +}; + +bool fsp_load_resource(enum resource_id id, uint32_t idx, + void *buf, size_t *size) { - uint32_t lid_no, lid; + uint32_t lid_no = 0, lid; size_t tmp_size; - int rc; + int rc, i; - switch (id) { - case RESOURCE_ID_KERNEL: - lid_no = KERNEL_LID_OPAL; - break; - case RESOURCE_ID_INITRAMFS: - lid_no = INITRAMFS_LID_OPAL; - break; - default: - return false; + for (i = 0; i < ARRAY_SIZE(fsp_lid_map); i++) { + if (id != fsp_lid_map[i].id) + continue; + + if (fsp_lid_map[i].idx == idx) { + lid_no = fsp_lid_map[i].lid_no; + break; + } } + if (lid_no == 0) + return false; retry: tmp_size = *size; @@ -2285,8 +2296,10 @@ retry: prerror("Failed to load LID\n"); return false; } - + if (*size < tmp_size) + return false; *size = tmp_size; + return true; } diff --git a/include/fsp.h b/include/fsp.h index 9ef7d9f..b65ef98 100644 --- a/include/fsp.h +++ b/include/fsp.h @@ -709,7 +709,8 @@ extern int fsp_fetch_data(uint8_t flags, uint16_t id, uint32_t sub_id, extern int fsp_fetch_data_queue(uint8_t flags, uint16_t id, uint32_t sub_id, uint32_t offset, void *buffer, size_t *length, void (*comp)(struct fsp_msg *msg)) __warn_unused_result; -extern bool fsp_load_resource(enum resource_id id, void *buf, size_t *size); +extern bool fsp_load_resource(enum resource_id id, uint32_t subid, + void *buf, size_t *size); /* FSP console stuff */ extern void fsp_console_preinit(void); diff --git a/include/platform.h b/include/platform.h index ec5cbc6..690772e 100644 --- a/include/platform.h +++ b/include/platform.h @@ -26,6 +26,8 @@ enum resource_id { RESOURCE_ID_KERNEL, RESOURCE_ID_INITRAMFS, }; +#define RESOURCE_SUBID_NONE 0 +#define RESOURCE_SUBID_SUPPORTED 1 /* * Each platform can provide a set of hooks @@ -129,7 +131,7 @@ struct platform { * Load an external resource (eg, kernel payload) into a preallocated * buffer. Returns true on success. */ - bool (*load_resource)(enum resource_id id, + bool (*load_resource)(enum resource_id id, uint32_t idx, void *buf, size_t *len); /* @@ -148,7 +150,7 @@ static const struct platform __used __section(".platforms") name ##_platform extern void probe_platform(void); -extern bool load_resource(enum resource_id id, +extern bool load_resource(enum resource_id id, uint32_t subid, void *buf, size_t *len); #endif /* __PLATFORM_H */ 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); |