coreboot-kgpe-d16/payloads/coreinfo/cbfs_module.c
Patrick Rudolph 7ee05eddf1 util/cbfstool: Support FIT payloads
In order to support booting a GNU/Linux payload on non x86, the FIT format
should be used, as it is the defacto standard on ARM.
Due to greater complexity of FIT it is not converted to simple ELF format.

Add support for autodecting FIT payloads and add them as new CBFS_TYPE 'fit'.
The payload is included as is, with no special header.
The code can determine the type at runtime using the CBFS_TYPE field.
Support for parsing FIT payloads in coreboot is added in a follow on
commit.
Compression of FIT payloads is not supported, as the FIT sections might be
compressed itself.

Starting at this point a CBFS payload/ can be either of type FIT or SELF.

Tested on Cavium SoC.

Change-Id: Ic5fc30cd5419eb76c4eb50cca3449caea60270de
Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Reviewed-on: https://review.coreboot.org/25860
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
2018-06-15 09:13:24 +00:00

266 lines
5.7 KiB
C

/*
* This file is part of the coreinfo project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "coreinfo.h"
#include "endian.h"
#if IS_ENABLED(CONFIG_MODULE_CBFS)
#define FILES_VISIBLE 19
#define HEADER_MAGIC 0x4F524243
#define HEADER_ADDR 0xfffffffc
#define LARCHIVE_MAGIC 0x455649484352414cLL /* "LARCHIVE" */
#define COMPONENT_DELETED 0x00
#define COMPONENT_BOOTBLOCK 0x01
#define COMPONENT_CBFSHEADER 0x02
#define COMPONENT_STAGE 0x10
#define COMPONENT_SELF 0x20
#define COMPONENT_FIT 0x21
#define COMPONENT_OPTIONROM 0x30
#define COMPONENT_RAW 0x50
#define COMPONENT_MICROCODE 0x53
#define COMPONENT_CMOS_LAYOUT 0x1aa
#define COMPONENT_NULL 0xffffffff
struct cbheader {
u32 magic;
u32 version;
u32 romsize;
u32 bootblocksize;
u32 align;
u32 offset;
u32 architecture;
u32 pad[1];
} __packed;
struct cbfile {
u64 magic;
u32 len;
u32 type;
u32 checksum;
u32 offset;
char filename[0];
} __packed;
static int filecount = 0, selected = 0, start_row = 0;
static char **filenames;
static struct cbheader *header = NULL;
static struct cbfile *getfile(struct cbfile *f)
{
while (1) {
if (f < (struct cbfile *)(0xffffffff - ntohl(header->romsize)))
return NULL;
if (f->magic == 0)
return NULL;
if (f->magic == LARCHIVE_MAGIC)
return f;
f = (void *)f + ntohl(header->align);
}
}
static struct cbfile *firstfile(void)
{
return getfile((void *)(0 - ntohl(header->romsize) +
ntohl(header->offset)));
}
static struct cbfile *nextfile(struct cbfile *f)
{
f = (void *)f + ALIGN(ntohl(f->len) + ntohl(f->offset),
ntohl(header->align));
return getfile(f);
}
static struct cbfile *findfile(const char *filename)
{
struct cbfile *f;
for (f = firstfile(); f; f = nextfile(f)) {
if (strcmp(filename, f->filename) == 0)
return f;
}
return NULL;
}
static int cbfs_module_init(void)
{
struct cbfile *f;
int index = 0;
header = *(void **)HEADER_ADDR;
if (header->magic != ntohl(HEADER_MAGIC)) {
header = NULL;
return 0;
}
for (f = firstfile(); f; f = nextfile(f))
filecount++;
filenames = malloc(filecount * sizeof(char *));
if (filenames == NULL)
return 0;
for (f = firstfile(); f; f = nextfile(f))
filenames[index++] = strdup((const char *)f->filename);
return 0;
}
static int cbfs_module_redraw(WINDOW * win)
{
struct cbfile *f;
int i, row, frow;
print_module_title(win, "CBFS Listing");
if (!header) {
mvwprintw(win, 11, 61 / 2, "Bad or missing CBFS header");
return 0;
}
/* Draw a line down the middle. */
for (i = 2; i < 21; i++)
mvwaddch(win, i, 30, ACS_VLINE);
/* Draw the names down the left side. */
for (frow = 0; frow < FILES_VISIBLE; frow++) {
row = 2 + frow;
i = start_row + frow;
if (i >= filecount)
break;
if (i == selected)
wattrset(win, COLOR_PAIR(3) | A_BOLD);
else
wattrset(win, COLOR_PAIR(2));
if (strlen(filenames[i]) == 0) {
if (findfile(filenames[i])->type == COMPONENT_NULL)
mvwprintw(win, row, 1, "<free space>");
else
mvwprintw(win, row, 1, "<unnamed>");
} else {
mvwprintw(win, row, 1, "%.25s", filenames[i]);
}
/* show scroll arrows */
if (frow == 0 && start_row > 0) {
wattrset(win, COLOR_PAIR(2));
mvwaddch(win, row, 28, ACS_UARROW);
}
if (frow == FILES_VISIBLE - 1 && i != filecount - 1) {
wattrset(win, COLOR_PAIR(2));
mvwaddch(win, row, 28, ACS_DARROW);
}
}
f = findfile(filenames[selected]);
if (!f) {
mvwprintw(win, 11, 32, "ERROR: CBFS component not found");
return 0;
}
wattrset(win, COLOR_PAIR(2));
/* Draw the file information */
row = 2;
/* mvwprintw(win, row++, 32, "Offset: 0x%x", f->offset); *//* FIXME */
mvwprintw(win, row, 32, "Type: ");
switch (ntohl(f->type)) {
case COMPONENT_BOOTBLOCK:
mvwprintw(win, row++, 38, "bootblock");
break;
case COMPONENT_CBFSHEADER:
mvwprintw(win, row++, 38, "CBFS header");
break;
case COMPONENT_STAGE:
mvwprintw(win, row++, 38, "stage");
break;
case COMPONENT_SELF:
mvwprintw(win, row++, 38, "simple ELF");
break;
case COMPONENT_FIT:
mvwprintw(win, row++, 38, "FIT");
break;
case COMPONENT_OPTIONROM:
mvwprintw(win, row++, 38, "optionrom");
break;
case COMPONENT_RAW:
mvwprintw(win, row++, 38, "raw");
break;
case COMPONENT_MICROCODE:
mvwprintw(win, row++, 38, "microcode");
break;
case COMPONENT_CMOS_LAYOUT:
mvwprintw(win, row++, 38, "cmos layout");
break;
case COMPONENT_NULL:
mvwprintw(win, row++, 38, "free");
break;
case COMPONENT_DELETED:
mvwprintw(win, row++, 38, "deleted");
break;
default:
mvwprintw(win, row++, 38, "Unknown (0x%x)", ntohl(f->type));
break;
}
mvwprintw(win, row++, 32, "Size: %d", ntohl(f->len));
mvwprintw(win, row++, 32, "Checksum: 0x%x", ntohl(f->checksum));
return 0;
}
static int cbfs_module_handle(int key)
{
int ret = 0;
if (filecount == 0)
return 0;
switch (key) {
case KEY_DOWN:
if (selected + 1 < filecount) {
selected++;
if (selected >= start_row + FILES_VISIBLE - 1)
start_row = selected - (FILES_VISIBLE - 1);
ret = 1;
}
break;
case KEY_UP:
if (selected > 0) {
selected--;
if (selected < start_row)
start_row = selected;
ret = 1;
}
break;
}
return ret;
}
struct coreinfo_module cbfs_module = {
.name = "CBFS",
.init = cbfs_module_init,
.redraw = cbfs_module_redraw,
.handle = cbfs_module_handle
};
#else
struct coreinfo_module cbfs_module = {
};
#endif