libpayload/libcbfs: add a function to return all the payload headers
For choosing payloads we need to be able to read out all the payload headers. cbfs_payload_headers() delivers names and all the info available about any payloads. BUG=None TEST=builds, tested on Nyan, works fine. BRANCH=None Change-Id: If98437819d53cc01d175234fc7429d6aa3383c2c Signed-off-by: Ronald G. Minnich <rminnich@google.com> Reviewed-on: https://chromium-review.googlesource.com/180352 Commit-Queue: Ronald Minnich <rminnich@chromium.org> Tested-by: Ronald Minnich <rminnich@chromium.org> Reviewed-by: Puneet Kumar <puneetster@chromium.org>
This commit is contained in:
parent
ab5be7178b
commit
8476c04022
2 changed files with 127 additions and 2 deletions
|
|
@ -150,8 +150,10 @@ struct cbfs_stage {
|
|||
uint32_t memlen; /** total length of object in memory */
|
||||
} __attribute__((packed));
|
||||
|
||||
/** this is the sub-header for payload components. Payloads
|
||||
are loaded by coreboot at the end of the boot process */
|
||||
/** this is the sub-header for payload components. Payloads are
|
||||
* loaded by coreboot or other payloads at the end of the boot
|
||||
* process
|
||||
*/
|
||||
|
||||
struct cbfs_payload_segment {
|
||||
uint32_t type;
|
||||
|
|
@ -166,6 +168,19 @@ struct cbfs_payload {
|
|||
struct cbfs_payload_segment segments;
|
||||
};
|
||||
|
||||
/* for returning payload info to (e.g.) bayou.
|
||||
* Return the file header, payload header, and name.
|
||||
* It must be done this way because we can't
|
||||
* assume file headers and names are contiguous.
|
||||
* Walking the headers can be expensive, so we get all
|
||||
* the information we can.
|
||||
*/
|
||||
struct cbfs_payload_info {
|
||||
struct cbfs_file file;
|
||||
struct cbfs_payload payload;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#define PAYLOAD_SEGMENT_CODE 0x45444F43
|
||||
#define PAYLOAD_SEGMENT_DATA 0x41544144
|
||||
#define PAYLOAD_SEGMENT_BSS 0x20535342
|
||||
|
|
@ -214,6 +229,14 @@ struct cbfs_media {
|
|||
/* returns pointer to a file entry inside CBFS or NULL */
|
||||
struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name);
|
||||
|
||||
/* Fills the pointer info with an array of payload file info structs.
|
||||
* Reads at most maxentries items.
|
||||
* Returns number we found.
|
||||
*/
|
||||
int cbfs_payload_headers(struct cbfs_media *media,
|
||||
struct cbfs_payload_info *info,
|
||||
int maxentries);
|
||||
|
||||
/* returns pointer to file content inside CBFS after if type is correct */
|
||||
void *cbfs_get_file_content(struct cbfs_media *media, const char *name,
|
||||
int type);
|
||||
|
|
|
|||
102
src/lib/cbfs.c
102
src/lib/cbfs.c
|
|
@ -226,6 +226,108 @@ int cbfs_execute_stage(struct cbfs_media *media, const char *name)
|
|||
return run_address((void *)(uintptr_t)ntohll(stage->entry));
|
||||
}
|
||||
|
||||
/* Get all the payload headers.
|
||||
* One might be tempted to implement cbfs operations as
|
||||
* - get all headers into memory
|
||||
* - scan the headers we got for a [payload, stage, file name]
|
||||
*
|
||||
* But: FLASH IO can be a very expensive operation on some systems.
|
||||
* For that reason, we keep this operation separate from anything else.
|
||||
* In other words, it is not intended to be a building block; in fact
|
||||
* the only current use is for the payload choose (Bayou) which does need
|
||||
* to scan all payloads. In future, we might decide we want to return all
|
||||
* the headers, but realistically we only need this for payloads right now
|
||||
* and it makes the bayou code less complex to just return payloads.
|
||||
* Return a count of the payloads found, up to maxentries payloads.
|
||||
*/
|
||||
int cbfs_payload_headers(struct cbfs_media *media,
|
||||
struct cbfs_payload_info *info,
|
||||
int maxentries)
|
||||
{
|
||||
int cur;
|
||||
const char *file_name;
|
||||
uint32_t offset, align, romsize, name_len;
|
||||
const struct cbfs_header *header;
|
||||
struct cbfs_file file;
|
||||
struct cbfs_media default_media;
|
||||
|
||||
cur = 0;
|
||||
|
||||
if (media == CBFS_DEFAULT_MEDIA) {
|
||||
media = &default_media;
|
||||
if (init_default_cbfs_media(media) != 0) {
|
||||
ERROR("Failed to initialize default media.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (CBFS_HEADER_INVALID_ADDRESS == (header = cbfs_get_header(media)))
|
||||
return 0;
|
||||
|
||||
// Logical offset (for source media) of first file.
|
||||
offset = ntohl(header->offset);
|
||||
align = ntohl(header->align);
|
||||
romsize = ntohl(header->romsize);
|
||||
|
||||
// TODO Add a "size" in CBFS header for a platform independent way to
|
||||
// determine the end of CBFS data.
|
||||
|
||||
DEBUG("CBFS location: 0x%x~0x%x, align: %d\n", offset, romsize, align);
|
||||
|
||||
media->open(media);
|
||||
while (cur < maxentries && offset < romsize &&
|
||||
media->read(media, &file, offset, sizeof(file))
|
||||
== sizeof(file)) {
|
||||
DEBUG("cur %d offset %08x\n", cur, offset);
|
||||
if (memcmp(CBFS_FILE_MAGIC, file.magic,
|
||||
sizeof(file.magic))) {
|
||||
uint32_t new_align = align;
|
||||
if (offset % align)
|
||||
new_align += align - (offset % align);
|
||||
ERROR("ERROR: No file header found at 0x%xx - "
|
||||
"try next aligned address: 0x%x.\n", offset,
|
||||
offset + new_align);
|
||||
offset += new_align;
|
||||
continue;
|
||||
}
|
||||
|
||||
// load file name (arbitrary length).
|
||||
// Do it here so we can debug if we want. It's not expensive.
|
||||
name_len = ntohl(file.offset) - sizeof(file);
|
||||
file_name = (const char*)media->map(
|
||||
media, offset + sizeof(file), name_len);
|
||||
if (file_name == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
|
||||
DEBUG("ERROR: Failed to get filename: 0x%x.\n", offset);
|
||||
continue;
|
||||
}
|
||||
DEBUG("Check :%s: type %x\n", file_name, ntohl(file.type));
|
||||
if (ntohl(file.type) == CBFS_TYPE_PAYLOAD){
|
||||
DEBUG(" - add entry 0x%x file name (%d bytes)...\n",
|
||||
offset, name_len);
|
||||
|
||||
info[cur].file = file;
|
||||
info[cur].name = file_name;
|
||||
/* we need the metadata too. */
|
||||
if (media->read(media, &info[cur].payload, offset,
|
||||
sizeof(info[cur].payload)) !=
|
||||
sizeof(info[cur].payload)){
|
||||
ERROR("ERROR: Failed to get payload"
|
||||
"info for %s@0x%x.\n",
|
||||
file_name, offset);
|
||||
continue;
|
||||
}
|
||||
cur++;
|
||||
}
|
||||
// Move to next file.
|
||||
offset += ntohl(file.len) + ntohl(file.offset);
|
||||
DEBUG("offset moves to %08x\n", offset);
|
||||
if (offset % align)
|
||||
offset += align - (offset % align);
|
||||
}
|
||||
media->close(media);
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
#if !CONFIG_ALT_CBFS_LOAD_PAYLOAD && !defined(__BOOT_BLOCK__)
|
||||
void *cbfs_load_payload(struct cbfs_media *media, const char *name)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue