aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/init.c5
-rw-r--r--core/platform.c4
-rw-r--r--hw/fsp/fsp.c39
-rw-r--r--include/fsp.h3
-rw-r--r--include/platform.h6
-rw-r--r--platforms/astbmc/astbmc.h4
-rw-r--r--platforms/astbmc/pnor.c124
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);