CBFS: Automate ROM image layout and remove hardcoded offsets

Non-x86 boards currently need to hardcode the position of their CBFS
master header in a Kconfig. This is very brittle because it is usually
put in between the bootblock and the first CBFS entry, without any
checks to guarantee that it won't overlap either of those. It is not fun
to debug random failures that move and disappear with tiny alignment
changes because someone decided to write "ORBC1112" over some part of
your data section (in a way that is not visible in the symbolized .elf
binaries, only in the final image). This patch seeks to prevent those
issues and reduce the need for manual configuration by making the image
layout a completely automated part of cbfstool.

Since automated placement of the CBFS header means we can no longer
hardcode its position into coreboot, this patch takes the existing x86
solution of placing a pointer to the header at the very end of the
CBFS-managed section of the ROM and generalizes it to all architectures.
This is now even possible with the read-only/read-write split in
ChromeOS, since coreboot knows how large that section is from the
CBFS_SIZE Kconfig (which is by default equal to ROM_SIZE, but can be
changed on systems that place other data next to coreboot/CBFS in ROM).

Also adds a feature to cbfstool that makes the -B (bootblock file name)
argument on image creation optional, since we have recently found valid
use cases for CBFS images that are not the first boot medium of the
device (instead opened by an earlier bootloader that can already
interpret CBFS) and therefore don't really need a bootblock.

BRANCH=None
BUG=None
TEST=Built and booted on Veyron_Pinky, Nyan_Blaze and Falco.

Change-Id: Ib715bb8db258e602991b34f994750a2d3e2d5adf
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: e9879c0fbd57f105254c54bacb3e592acdcad35c
Original-Change-Id: Ifcc755326832755cfbccd6f0a12104cba28a20af
Original-Signed-off-by: Julius Werner <jwerner@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/229975
Reviewed-on: http://review.coreboot.org/9620
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
Julius Werner 2014-11-10 13:14:24 -08:00 committed by Patrick Georgi
parent f780c40f40
commit efcee767de
26 changed files with 153 additions and 320 deletions

View File

@ -85,10 +85,9 @@
#define CBFS_HEADER_INVALID_ADDRESS ((void*)(0xffffffff)) #define CBFS_HEADER_INVALID_ADDRESS ((void*)(0xffffffff))
/** this is the master cbfs header - it needs to be located somewhere available /* this is the master cbfs header - it must be located somewhere available
to bootblock (to load romstage). Where it actually lives is up to coreboot. * to bootblock (to load romstage). The last 4 bytes in the image contain its
On x86, a pointer to this header will live at 0xFFFFFFFC. * relative offset from the end of the image (as a 32-bit signed integer). */
For other platforms, you need to define CONFIG_LP_CBFS_HEADER_ROM_OFFSET */
struct cbfs_header { struct cbfs_header {
uint32_t magic; uint32_t magic;

View File

@ -62,19 +62,6 @@
# endif # endif
#endif #endif
#if defined(CONFIG_LP_CBFS_HEADER_ROM_OFFSET) && (CONFIG_LP_CBFS_HEADER_ROM_OFFSET)
# define CBFS_HEADER_ROM_ADDRESS (CONFIG_LP_CBFS_HEADER_ROM_OFFSET)
#else
/* ugly hack: this assumes that "media" exists
in the scope where the macro is used. */
static uint32_t fetch_x86_header(struct cbfs_media *media)
{
uint32_t *header_ptr = media->map(media, 0xfffffffc, 4);
return *header_ptr;
}
# define CBFS_HEADER_ROM_ADDRESS fetch_x86_header(media)
#endif
#include "cbfs_core.c" #include "cbfs_core.c"
#ifndef __SMM__ #ifndef __SMM__

View File

@ -34,10 +34,6 @@
* CBFS_CORE_WITH_LZMA (must be #define) * CBFS_CORE_WITH_LZMA (must be #define)
* if defined, ulzma() must exist for decompression of data streams * if defined, ulzma() must exist for decompression of data streams
* *
* CBFS_HEADER_ROM_ADDRESS
* ROM address (offset) of CBFS header. Underlying CBFS media may interpret
* it in other way so we call this "address".
*
* ERROR(x...) * ERROR(x...)
* print an error message x (in printf format) * print an error message x (in printf format)
* *
@ -56,6 +52,7 @@
* on failure */ * on failure */
const struct cbfs_header *cbfs_get_header(struct cbfs_media *media) const struct cbfs_header *cbfs_get_header(struct cbfs_media *media)
{ {
int32_t rel_offset;
const struct cbfs_header *header; const struct cbfs_header *header;
struct cbfs_media default_media; struct cbfs_media default_media;
@ -66,22 +63,28 @@ const struct cbfs_header *cbfs_get_header(struct cbfs_media *media)
return CBFS_HEADER_INVALID_ADDRESS; return CBFS_HEADER_INVALID_ADDRESS;
} }
} }
media->open(media); media->open(media);
DEBUG("CBFS_HEADER_ROM_ADDRESS: 0x%x/0x%x\n", CBFS_HEADER_ROM_ADDRESS,
CONFIG_LP_ROM_SIZE); if (!media->read(media, &rel_offset, (size_t)(0 - sizeof(int32_t)),
header = media->map(media, CBFS_HEADER_ROM_ADDRESS, sizeof(*header)); sizeof(int32_t))) {
ERROR("Could not read CBFS master header offset!\n");
return CBFS_HEADER_INVALID_ADDRESS;
}
header = media->map(media, (size_t)rel_offset, sizeof(*header));
DEBUG("CBFS header at %#zx (-%#zx from end of image).\n",
(size_t)rel_offset, (size_t)-rel_offset);
media->close(media); media->close(media);
if (header == CBFS_MEDIA_INVALID_MAP_ADDRESS) { if (header == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
ERROR("Failed to load CBFS header from 0x%x\n", ERROR("Failed to load CBFS header from %#zx(-%#zx)\n",
CBFS_HEADER_ROM_ADDRESS); (size_t)rel_offset, (size_t)-rel_offset);
return CBFS_HEADER_INVALID_ADDRESS; return CBFS_HEADER_INVALID_ADDRESS;
} }
if (CBFS_HEADER_MAGIC != ntohl(header->magic)) { if (CBFS_HEADER_MAGIC != ntohl(header->magic)) {
ERROR("Could not find valid CBFS master header at %x: " ERROR("Could not find valid CBFS master header at %#zx(-%#zx): "
"%x vs %x.\n", CBFS_HEADER_ROM_ADDRESS, CBFS_HEADER_MAGIC, "magic %#.8x vs %#.8x.\n", (size_t)rel_offset,
(size_t)-rel_offset, CBFS_HEADER_MAGIC,
ntohl(header->magic)); ntohl(header->magic));
if (header->magic == 0xffffffff) { if (header->magic == 0xffffffff) {
ERROR("Maybe ROM is not mapped properly?\n"); ERROR("Maybe ROM is not mapped properly?\n");

View File

@ -31,9 +31,7 @@ subdirs-y += armv4/ armv7/
############################################################################### ###############################################################################
ifeq ($(CONFIG_ARCH_ROMSTAGE_ARM),y) ifeq ($(CONFIG_ARCH_ROMSTAGE_ARM),y)
CBFSTOOL_PRE1_OPTS = -m arm -b $(CONFIG_BOOTBLOCK_ROM_OFFSET) \ CBFSTOOL_PRE1_OPTS = -m arm -s $(CONFIG_CBFS_SIZE)
-H $(CONFIG_CBFS_HEADER_ROM_OFFSET) \
-o $(CONFIG_CBFS_ROM_OFFSET) -s $(CONFIG_CBFS_SIZE)
CBFSTOOL_PRE_OPTS = -b 0 CBFSTOOL_PRE_OPTS = -b 0
endif endif

View File

@ -34,9 +34,7 @@ subdirs-y += armv8/
################################################################################ ################################################################################
ifeq ($(CONFIG_ARCH_ROMSTAGE_ARM64),y) ifeq ($(CONFIG_ARCH_ROMSTAGE_ARM64),y)
CBFSTOOL_PRE1_OPTS = -m arm64 -b $(CONFIG_BOOTBLOCK_ROM_OFFSET) \ CBFSTOOL_PRE1_OPTS = -m arm64 -s $(CONFIG_CBFS_SIZE)
-H $(CONFIG_CBFS_HEADER_ROM_OFFSET) \
-o $(CONFIG_CBFS_ROM_OFFSET) -s $(CONFIG_CBFS_SIZE)
endif endif
ifeq ($(CONFIG_ARCH_ARM64),y) ifeq ($(CONFIG_ARCH_ARM64),y)

View File

@ -24,9 +24,7 @@
############################################################################### ###############################################################################
ifeq ($(CONFIG_ARCH_ROMSTAGE_MIPS),y) ifeq ($(CONFIG_ARCH_ROMSTAGE_MIPS),y)
CBFSTOOL_PRE1_OPTS = -m mips -b $(CONFIG_BOOTBLOCK_ROM_OFFSET) \ CBFSTOOL_PRE1_OPTS = -m mips -s $(CONFIG_CBFS_SIZE)
-H $(CONFIG_CBFS_HEADER_ROM_OFFSET) \
-o $(CONFIG_CBFS_ROM_OFFSET) -s $(CONFIG_CBFS_SIZE)
endif endif
############################################################################### ###############################################################################

View File

@ -72,7 +72,7 @@ $(objcbfs)/romstage.debug: $$(romstage-objs)
romstage-c-ccopts += $(riscv_flags) romstage-c-ccopts += $(riscv_flags)
romstage-S-ccopts += $(riscv_asm_flags) romstage-S-ccopts += $(riscv_asm_flags)
CBFSTOOL_PRE1_OPTS = -v -m riscv -b $(CONFIG_BOOTBLOCK_ROM_OFFSET) -H $(CONFIG_CBFS_HEADER_ROM_OFFSET) -o $(CONFIG_CBFS_ROM_OFFSET) -s $(CONFIG_CBFS_SIZE) CBFSTOOL_PRE1_OPTS = -v -m riscv -s $(CONFIG_CBFS_SIZE)
CBFSTOOL_PRE_OPTS = -v CBFSTOOL_PRE_OPTS = -v
endif endif

View File

@ -15,22 +15,6 @@ config CPU_SPECIFIC_OPTIONS
select BOOTBLOCK_CONSOLE select BOOTBLOCK_CONSOLE
select CPU_HAS_BOOTBLOCK_INIT select CPU_HAS_BOOTBLOCK_INIT
config BOOTBLOCK_ROM_OFFSET
hex
default 0x00
config CBFS_HEADER_ROM_OFFSET
hex
default 0x10
# This is the maximum size bootblock that the BROM will load. If the bootblock
# gets larger, this will generate a build failure, rather than a silent
# "coreboot won't run" failure.
# Normally, we would place romstage at 0x5fe0, but we place it a little lower to
# satisfy the 64 byte alignment.
config CBFS_ROM_OFFSET
default 0x5fc0
## TODO Change this to some better address not overlapping bootblock when ## TODO Change this to some better address not overlapping bootblock when
## cbfstool supports creating header in arbitrary location. ## cbfstool supports creating header in arbitrary location.
config CBFS_HEADER_ROM_OFFSET config CBFS_HEADER_ROM_OFFSET

View File

@ -25,8 +25,3 @@ config CPU_MIPS
select ARCH_VERSTAGE_MIPS select ARCH_VERSTAGE_MIPS
select ARCH_ROMSTAGE_MIPS select ARCH_ROMSTAGE_MIPS
select ARCH_RAMSTAGE_MIPS select ARCH_RAMSTAGE_MIPS
config BOOTBLOCK_ROM_OFFSET
hex
depends on CPU_MIPS
default 0x00

View File

@ -10,17 +10,3 @@ config CPU_TI_AM335X
select GENERIC_UDELAY select GENERIC_UDELAY
bool bool
default n default n
if CPU_TI_AM335X
config CBFS_ROM_OFFSET
# Calculated by BL1 + max bootblock size.
default 0x4c00
## TODO Change this to some better address not overlapping bootblock when
## cbfstool supports creating header in arbitrary location.
config CBFS_HEADER_ROM_OFFSET
hex "offset of master CBFS header in ROM"
default 0x40
endif

View File

@ -86,10 +86,9 @@
#define CBFS_HEADER_VERSION2 0x31313132 #define CBFS_HEADER_VERSION2 0x31313132
#define CBFS_HEADER_VERSION CBFS_HEADER_VERSION2 #define CBFS_HEADER_VERSION CBFS_HEADER_VERSION2
/** this is the master cbfs header - it need to be located somewhere available /* this is the master cbfs header - it must be located somewhere available
to bootblock (to load romstage). Where it actually lives is up to coreboot. * to bootblock (to load romstage). The last 4 bytes in the image contain its
On x86, a pointer to this header will live at 0xFFFFFFFC. * relative offset from the end of the image (as a 32-bit signed integer). */
For other platforms, you need to define CONFIG_CBFS_HEADER_ROM_OFFSET */
struct cbfs_header { struct cbfs_header {
uint32_t magic; uint32_t magic;

View File

@ -34,10 +34,6 @@
* CBFS_CORE_WITH_LZMA (must be #define) * CBFS_CORE_WITH_LZMA (must be #define)
* if defined, ulzma() must exist for decompression of data streams * if defined, ulzma() must exist for decompression of data streams
* *
* CBFS_HEADER_ROM_ADDRESS
* ROM address (offset) of CBFS header. Underlying CBFS media may interpret
* it in other way so we call this "address".
*
* ERROR(x...) * ERROR(x...)
* print an error message x (in printf format) * print an error message x (in printf format)
* *
@ -58,6 +54,7 @@
* on failure */ * on failure */
const struct cbfs_header *cbfs_get_header(struct cbfs_media *media) const struct cbfs_header *cbfs_get_header(struct cbfs_media *media)
{ {
size_t offset;
const struct cbfs_header *header; const struct cbfs_header *header;
struct cbfs_media default_media; struct cbfs_media default_media;
@ -68,22 +65,34 @@ const struct cbfs_header *cbfs_get_header(struct cbfs_media *media)
return CBFS_HEADER_INVALID_ADDRESS; return CBFS_HEADER_INVALID_ADDRESS;
} }
} }
media->open(media); media->open(media);
DEBUG("CBFS_HEADER_ROM_ADDRESS: 0x%x/0x%x\n", CBFS_HEADER_ROM_ADDRESS,
CONFIG_ROM_SIZE); /* TODO: allow negative offsets from the end of the CBFS image at media
header = media->map(media, CBFS_HEADER_ROM_ADDRESS, sizeof(*header)); * layer (like libpayload) so we can combine these two cases. */
if (IS_ENABLED(CONFIG_ARCH_X86)) {
offset = *(int32_t *)(uintptr_t)0xfffffffc;
header = media->map(media, offset, sizeof(*header));
} else {
int32_t rel_offset;
if (!media->read(media, &rel_offset, CONFIG_CBFS_SIZE -
sizeof(int32_t), sizeof(int32_t))) {
ERROR("Could not read CBFS master header offset!\n");
return CBFS_HEADER_INVALID_ADDRESS;
}
offset = CONFIG_CBFS_SIZE + rel_offset;
header = media->map(media, offset, sizeof(*header));
}
DEBUG("CBFS header offset: 0x%zx/0x%x\n", offset, CONFIG_ROM_SIZE);
media->close(media); media->close(media);
if (header == CBFS_MEDIA_INVALID_MAP_ADDRESS) { if (header == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
ERROR("Failed to load CBFS header from 0x%x\n", ERROR("Failed to load CBFS header from 0x%zx\n", offset);
CBFS_HEADER_ROM_ADDRESS);
return CBFS_HEADER_INVALID_ADDRESS; return CBFS_HEADER_INVALID_ADDRESS;
} }
if (CBFS_HEADER_MAGIC != ntohl(header->magic)) { if (CBFS_HEADER_MAGIC != ntohl(header->magic)) {
ERROR("Could not find valid CBFS master header at %x: " ERROR("Could not find valid CBFS master header at %#zx: "
"%x vs %x.\n", CBFS_HEADER_ROM_ADDRESS, CBFS_HEADER_MAGIC, "magic %#.8x vs %#.8x.\n", offset, CBFS_HEADER_MAGIC,
ntohl(header->magic)); ntohl(header->magic));
if (header->magic == 0xffffffff) { if (header->magic == 0xffffffff) {
ERROR("Maybe ROM is not mapped properly?\n"); ERROR("Maybe ROM is not mapped properly?\n");

View File

@ -42,11 +42,4 @@
# endif # endif
#endif #endif
#if defined(CONFIG_CBFS_HEADER_ROM_OFFSET) && (CONFIG_CBFS_HEADER_ROM_OFFSET)
# define CBFS_HEADER_ROM_ADDRESS (CONFIG_CBFS_HEADER_ROM_OFFSET)
#else
// Indirect address: only works on 32bit top-aligned systems.
# define CBFS_HEADER_ROM_ADDRESS (*(uint32_t *)0xfffffffc)
#endif
#endif /* __LIB_CBFS_CORE */ #endif /* __LIB_CBFS_CORE */

View File

@ -53,16 +53,4 @@ config DRAM_SIZE_MB
int int
default 1024 default 1024
config BOOTBLOCK_ROM_OFFSET
hex
default 0x0
config CBFS_HEADER_ROM_OFFSET
hex
default 0x0100000
config CBFS_ROM_OFFSET
hex
default 0x0110000
endif # BOARD_EMULATION_QEMU_ARMV7 endif # BOARD_EMULATION_QEMU_ARMV7

View File

@ -54,18 +54,6 @@ config DRAM_SIZE_MB
# 0x0011_0000: CBFS data # 0x0011_0000: CBFS data
# 0x0100_0000: reserved for ramstage # 0x0100_0000: reserved for ramstage
config BOOTBLOCK_ROM_OFFSET
hex
default 0x0
config CBFS_HEADER_ROM_OFFSET
hex
default 0x10000
config CBFS_ROM_OFFSET
hex
default 0x10040
config RAMTOP config RAMTOP
hex hex
default 0x1000000 default 0x1000000

View File

@ -35,13 +35,4 @@ config BOOTBLOCK_CPU_INIT
string string
default "soc/imgtec/pistachio/bootblock.c" default "soc/imgtec/pistachio/bootblock.c"
config CBFS_ROM_OFFSET
hex
default 0x8100
config CBFS_HEADER_ROM_OFFSET
# Effectively the maximum size of the bootblock
hex
default 0x8000
endif endif

View File

@ -37,16 +37,4 @@ config BOOTBLOCK_CPU_INIT
string string
default "soc/marvell/bg4cd/bootblock.c" default "soc/marvell/bg4cd/bootblock.c"
config BOOTBLOCK_ROM_OFFSET
hex
default 0x0
config CBFS_HEADER_ROM_OFFSET
hex
default 0x0008000
config CBFS_ROM_OFFSET
hex
default 0x0018000
endif endif

View File

@ -24,18 +24,6 @@ config BOOTBLOCK_CPU_INIT
bootblock must load microcode or copy data from ROM before bootblock must load microcode or copy data from ROM before
searching for the bootblock. searching for the bootblock.
config BOOTBLOCK_ROM_OFFSET
hex
default 0x0
config CBFS_HEADER_ROM_OFFSET
hex "offset of master CBFS header in ROM"
default 0x18000
config CBFS_ROM_OFFSET
hex "offset of CBFS data in ROM"
default 0x18080
config TEGRA124_MODEL_TD570D config TEGRA124_MODEL_TD570D
bool "TD570D" bool "TD570D"

View File

@ -42,22 +42,10 @@ config BOOTBLOCK_CPU_INIT
bootblock must load microcode or copy data from ROM before bootblock must load microcode or copy data from ROM before
searching for the bootblock. searching for the bootblock.
config BOOTBLOCK_ROM_OFFSET
hex
default 0x0
config MAX_CPUS config MAX_CPUS
int int
default 2 default 2
config CBFS_HEADER_ROM_OFFSET
hex "offset of master CBFS header in ROM"
default 0x40000
config CBFS_ROM_OFFSET
hex "offset of CBFS data in ROM"
default 0x40080
config MTS_DIRECTORY config MTS_DIRECTORY
string "Directory where MTS microcode files are located" string "Directory where MTS microcode files are located"
default "3rdparty/cpu/nvidia/tegra132/current/prod" default "3rdparty/cpu/nvidia/tegra132/current/prod"

View File

@ -21,18 +21,6 @@ config CBFS_SIZE
coreboot blob elsewhere in the system. Make sure this config option coreboot blob elsewhere in the system. Make sure this config option
is fine tuned in the board config file. is fine tuned in the board config file.
config BOOTBLOCK_ROM_OFFSET
hex
default 0x0
config CBFS_HEADER_ROM_OFFSET
hex "offset of master CBFS header in ROM"
default 0x1b4000
config CBFS_ROM_OFFSET
hex "offset of CBFS data in ROM"
default 0x1b4080
config MBN_ENCAPSULATION config MBN_ENCAPSULATION
depends on USE_BLOBS depends on USE_BLOBS
bool "bootblock encapsulation for ipq8064" bool "bootblock encapsulation for ipq8064"

View File

@ -37,22 +37,4 @@ config BOOTBLOCK_CPU_INIT
string string
default "soc/rockchip/rk3288/bootblock.c" default "soc/rockchip/rk3288/bootblock.c"
# ROM image layout.
#
# 0x00000 Combined bootblock and ID Block
# 0x08000 Master CBFS header.
# 0x18000 Free for CBFS data.
config BOOTBLOCK_ROM_OFFSET
hex
default 0x0
config CBFS_HEADER_ROM_OFFSET
hex
default 0x0010000
config CBFS_ROM_OFFSET
hex
default 0x0010100
endif endif

View File

@ -9,28 +9,3 @@ config CPU_SAMSUNG_EXYNOS5250
select HAVE_UART_SPECIAL select HAVE_UART_SPECIAL
bool bool
default n default n
if CPU_SAMSUNG_EXYNOS5250
# ROM image layout.
#
# 0x0000: vendor-provided BL1 (8k).
# 0x2000: bootblock
# 0x9FFC-0xA000: BL2 checksum
# 0xA000-0xA080: reserved for CBFS master header.
# 0xA080: Free for CBFS data.
config BOOTBLOCK_ROM_OFFSET
hex
default 0
config CBFS_HEADER_ROM_OFFSET
hex "offset of master CBFS header in ROM"
default 0x9F80
config CBFS_ROM_OFFSET
# Calculated by BOOTBLOCK_ROM_OFFSET + max bootblock size.
hex "offset of CBFS data in ROM"
default 0x0A080
endif

View File

@ -10,28 +10,3 @@ config CPU_SAMSUNG_EXYNOS5420
select RELOCATABLE_MODULES select RELOCATABLE_MODULES
bool bool
default n default n
if CPU_SAMSUNG_EXYNOS5420
# ROM image layout.
#
# 0x0000: vendor-provided BL1 (8k).
# 0x2000: variable length bootblock checksum header
# 0x2010: bootblock
# 0x9F80-0xA000: reserved for CBFS master header.
# 0xA000: Free for CBFS data.
config BOOTBLOCK_ROM_OFFSET
hex
default 0
config CBFS_HEADER_ROM_OFFSET
hex "offset of master CBFS header in ROM"
default 0x9F80
config CBFS_ROM_OFFSET
# Calculated by BOOTBLOCK_ROM_OFFSET + max bootblock size.
hex "offset of CBFS data in ROM"
default 0x0A000
endif

View File

@ -66,13 +66,6 @@ static const struct typedesc_t types_cbfs_compression[] = {
{0, NULL}, {0, NULL},
}; };
static uint32_t align_up(uint32_t value, uint32_t align)
{
if (value % align)
value += align - (value % align);
return value;
}
static const char *lookup_name_by_type(const struct typedesc_t *desc, uint32_t type, static const char *lookup_name_by_type(const struct typedesc_t *desc, uint32_t type,
const char *default_value) const char *default_value)
{ {
@ -180,6 +173,7 @@ int cbfs_image_create(struct cbfs_image *image,
{ {
struct cbfs_header header; struct cbfs_header header;
struct cbfs_file *entry; struct cbfs_file *entry;
int32_t *rel_offset;
uint32_t cbfs_len; uint32_t cbfs_len;
size_t entry_header_len; size_t entry_header_len;
void *header_loc; void *header_loc;
@ -207,9 +201,6 @@ int cbfs_image_create(struct cbfs_image *image,
"header=0x%x, entries_offset=0x%x\n", "header=0x%x, entries_offset=0x%x\n",
bootblock_offset, header_offset, entries_offset); bootblock_offset, header_offset, entries_offset);
if (align == 0)
align = 64; // default align size.
// Prepare bootblock // Prepare bootblock
if (bootblock_offset + bootblock->size > size) { if (bootblock_offset + bootblock->size > size) {
ERROR("Bootblock (0x%x+0x%zx) exceed ROM size (0x%zx)\n", ERROR("Bootblock (0x%x+0x%zx) exceed ROM size (0x%zx)\n",
@ -226,7 +217,7 @@ int cbfs_image_create(struct cbfs_image *image,
bootblock->size); bootblock->size);
// Prepare header // Prepare header
if (header_offset + sizeof(header) > size) { if (header_offset + sizeof(header) > size - sizeof(int32_t)) {
ERROR("Header (0x%x+0x%zx) exceed ROM size (0x%zx)\n", ERROR("Header (0x%x+0x%zx) exceed ROM size (0x%zx)\n",
header_offset, sizeof(header), size); header_offset, sizeof(header), size);
return -1; return -1;
@ -242,6 +233,14 @@ int cbfs_image_create(struct cbfs_image *image,
header_loc = (image->buffer.data + header_offset); header_loc = (image->buffer.data + header_offset);
cbfs_put_header(header_loc, image->header); cbfs_put_header(header_loc, image->header);
// The last 4 byte of the image contain the relative offset from the end
// of the image to the master header as a 32-bit signed integer. x86
// relies on this also being its (memory-mapped, top-aligned) absolute
// 32-bit address by virtue of how two's complement numbers work.
assert(size % sizeof(int32_t) == 0);
rel_offset = (int32_t *)(image->buffer.data + size - sizeof(int32_t));
*rel_offset = header_offset - size;
// Prepare entries // Prepare entries
if (align_up(entries_offset, align) != entries_offset) { if (align_up(entries_offset, align) != entries_offset) {
ERROR("Offset (0x%x) must be aligned to 0x%x.\n", ERROR("Offset (0x%x) must be aligned to 0x%x.\n",
@ -256,8 +255,8 @@ int cbfs_image_create(struct cbfs_image *image,
} }
entry = (struct cbfs_file *)(image->buffer.data + entries_offset); entry = (struct cbfs_file *)(image->buffer.data + entries_offset);
// To calculate available length, find // To calculate available length, find
// e = min(bootblock, header, size) where e > entries_offset. // e = min(bootblock, header, rel_offset) where e > entries_offset.
cbfs_len = size; cbfs_len = size - sizeof(int32_t);
if (bootblock_offset > entries_offset && bootblock_offset < cbfs_len) if (bootblock_offset > entries_offset && bootblock_offset < cbfs_len)
cbfs_len = bootblock_offset; cbfs_len = bootblock_offset;
if (header_offset > entries_offset && header_offset < cbfs_len) if (header_offset > entries_offset && header_offset < cbfs_len)
@ -772,17 +771,21 @@ struct cbfs_header *cbfs_find_header(char *data, size_t size)
{ {
size_t offset; size_t offset;
int found = 0; int found = 0;
uint32_t x86sig; int32_t rel_offset;
struct cbfs_header *header, *result = NULL; struct cbfs_header *header, *result = NULL;
// Try x86 style (check signature in bottom) header first. // Try finding relative offset of master header at end of file first.
x86sig = *(uint32_t *)(data + size - sizeof(uint32_t)); rel_offset = *(int32_t *)(data + size - sizeof(int32_t));
offset = (x86sig + (uint32_t)size); offset = size + rel_offset;
DEBUG("x86sig: 0x%x, offset: 0x%zx\n", x86sig, offset); DEBUG("relative offset: %#zx(-%#zx), offset: %#zx\n",
(size_t)rel_offset, (size_t)-rel_offset, offset);
if (offset >= size - sizeof(*header) || if (offset >= size - sizeof(*header) ||
ntohl(((struct cbfs_header *)(data + offset))->magic) != ntohl(((struct cbfs_header *)(data + offset))->magic) !=
CBFS_HEADER_MAGIC) CBFS_HEADER_MAGIC) {
// Some use cases append non-CBFS data to the end of the ROM.
DEBUG("relative offset seems wrong, scanning whole image...\n");
offset = 0; offset = 0;
}
for (; offset + sizeof(*header) < size; offset++) { for (; offset + sizeof(*header) < size; offset++) {
header = (struct cbfs_header *)(data + offset); header = (struct cbfs_header *)(data + offset);
@ -793,14 +796,15 @@ struct cbfs_header *cbfs_find_header(char *data, size_t size)
// Probably not a real CBFS header? // Probably not a real CBFS header?
continue; continue;
} }
found++; if (!found++)
result = header; result = header;
} }
if (found > 1) { if (found > 1)
ERROR("multiple (%d) CBFS headers found!\n", // Top-aligned images usually have a working relative offset
// field, so this is more likely to happen on bottom-aligned
// ones (where the first header is the "outermost" one)
WARN("Multiple (%d) CBFS headers found, using the first one.\n",
found); found);
result = NULL;
}
return result; return result;
} }

View File

@ -53,7 +53,8 @@ static struct param {
uint32_t size; uint32_t size;
uint32_t alignment; uint32_t alignment;
uint32_t pagesize; uint32_t pagesize;
uint32_t offset; uint32_t cbfsoffset;
uint32_t cbfsoffset_assigned;
uint32_t top_aligned; uint32_t top_aligned;
uint32_t arch; uint32_t arch;
int fit_empty_entries; int fit_empty_entries;
@ -339,40 +340,58 @@ static int cbfs_create(void)
return 1; return 1;
} }
if (!param.bootblock) {
ERROR("You need to specify -B/--bootblock.\n");
return 1;
}
if (param.arch == CBFS_ARCHITECTURE_UNKNOWN) { if (param.arch == CBFS_ARCHITECTURE_UNKNOWN) {
ERROR("You need to specify -m/--machine arch.\n"); ERROR("You need to specify -m/--machine arch.\n");
return 1; return 1;
} }
if (buffer_from_file(&bootblock, param.bootblock) != 0) { if (!param.bootblock) {
DEBUG("-B not given, creating image without bootblock.\n");
buffer_create(&bootblock, 0, "(dummy)");
} else if (buffer_from_file(&bootblock, param.bootblock)) {
return 1; return 1;
} }
// Setup default boot offset and header offset. if (!param.alignment)
param.alignment = 64; // default CBFS entry alignment
// Set default offsets. x86, as usual, needs to be a special snowflake.
if (!param.baseaddress_assigned) { if (!param.baseaddress_assigned) {
// put boot block before end of ROM. if (param.arch == CBFS_ARCHITECTURE_X86) {
param.baseaddress = param.size - bootblock.size; // Make sure there's at least enough room for rel_offset
DEBUG("bootblock in end of ROM.\n"); param.baseaddress = param.size - (
bootblock.size > sizeof(int32_t) ?
bootblock.size : sizeof(int32_t));
DEBUG("x86 -> bootblock lies at end of ROM (%#x).\n",
param.baseaddress);
} else {
param.baseaddress = 0;
DEBUG("bootblock starts at address 0x0.\n");
}
} }
if (!param.headeroffset_assigned) { if (!param.headeroffset_assigned) {
// Put header before bootblock, and make a reference in end of if (param.arch == CBFS_ARCHITECTURE_X86) {
// bootblock. param.headeroffset = param.baseaddress -
param.headeroffset = ( sizeof(struct cbfs_header);
param.baseaddress - DEBUG("x86 -> CBFS header before bootblock (%#x).\n",
sizeof(struct cbfs_header)); param.headeroffset);
if (bootblock.size >= sizeof(uint32_t)) { } else {
// TODO this only works for 32b top-aligned system now... param.headeroffset = align_up(param.baseaddress +
uint32_t ptr = param.headeroffset - param.size; bootblock.size, sizeof(uint32_t));
uint32_t *sig = (uint32_t *)(bootblock.data + DEBUG("CBFS header placed behind bootblock (%#x).\n",
bootblock.size - param.headeroffset);
sizeof(ptr)); }
*sig = ptr; }
DEBUG("CBFS header reference in end of bootblock.\n"); if (!param.cbfsoffset_assigned) {
if (param.arch == CBFS_ARCHITECTURE_X86) {
param.cbfsoffset = 0;
DEBUG("x86 -> CBFS entries start at address 0x0.\n");
} else {
param.cbfsoffset = align_up(param.headeroffset +
sizeof(struct cbfs_header),
param.alignment);
DEBUG("CBFS entries start beind master header (%#x).\n",
param.cbfsoffset);
} }
} }
@ -383,7 +402,7 @@ static int cbfs_create(void)
&bootblock, &bootblock,
param.baseaddress, param.baseaddress,
param.headeroffset, param.headeroffset,
param.offset) != 0) { param.cbfsoffset) != 0) {
ERROR("Failed to create %s.\n", param.cbfs_name); ERROR("Failed to create %s.\n", param.cbfs_name);
return 1; return 1;
} }
@ -533,28 +552,29 @@ static const struct command commands[] = {
}; };
static struct option long_options[] = { static struct option long_options[] = {
{"name", required_argument, 0, 'n' }, {"name", required_argument, 0, 'n' },
{"type", required_argument, 0, 't' }, {"type", required_argument, 0, 't' },
{"compression", required_argument, 0, 'c' }, {"compression", required_argument, 0, 'c' },
{"base-address", required_argument, 0, 'b' }, {"base-address", required_argument, 0, 'b' },
{"load-address", required_argument, 0, 'l' }, {"load-address", required_argument, 0, 'l' },
{"top-aligned", required_argument, 0, 'T' }, {"top-aligned", required_argument, 0, 'T' },
{"entry-point", required_argument, 0, 'e' }, {"entry-point", required_argument, 0, 'e' },
{"size", required_argument, 0, 's' }, {"size", required_argument, 0, 's' },
{"bootblock", required_argument, 0, 'B' }, {"bootblock", required_argument, 0, 'B' },
{"alignment", required_argument, 0, 'a' }, {"header-offset", required_argument, 0, 'H' },
{"page-size", required_argument, 0, 'P' }, {"alignment", required_argument, 0, 'a' },
{"offset", required_argument, 0, 'o' }, {"page-size", required_argument, 0, 'P' },
{"file", required_argument, 0, 'f' }, {"offset", required_argument, 0, 'o' },
{"int", required_argument, 0, 'i' }, {"file", required_argument, 0, 'f' },
{"machine", required_argument, 0, 'm' }, {"int", required_argument, 0, 'i' },
{"empty-fits", required_argument, 0, 'x' }, {"machine", required_argument, 0, 'm' },
{"initrd", required_argument, 0, 'I' }, {"empty-fits", required_argument, 0, 'x' },
{"cmdline", required_argument, 0, 'C' }, {"initrd", required_argument, 0, 'I' },
{"ignore-sec", required_argument, 0, 'S' }, {"cmdline", required_argument, 0, 'C' },
{"verbose", no_argument, 0, 'v' }, {"ignore-sec", required_argument, 0, 'S' },
{"help", no_argument, 0, 'h' }, {"verbose", no_argument, 0, 'v' },
{NULL, 0, 0, 0 } {"help", no_argument, 0, 'h' },
{NULL, 0, 0, 0 }
}; };
static void usage(char *name) static void usage(char *name)
@ -582,7 +602,8 @@ static void usage(char *name)
"Add a raw 64-bit integer value\n" "Add a raw 64-bit integer value\n"
" remove -n NAME " " remove -n NAME "
"Remove a component\n" "Remove a component\n"
" create -s size -B bootblock -m ARCH [-a align] [-o offset] " " create -s size -m ARCH [-B bootblock] [-b bootblock offset] \\\n"
" [-o CBFS offset] [-H header offset] [-a align] "
"Create a ROM file\n" "Create a ROM file\n"
" locate -f FILE -n NAME [-P page-size] [-a align] [-T] " " locate -f FILE -n NAME [-P page-size] [-a align] [-T] "
"Find a place for a file of that size\n" "Find a place for a file of that size\n"
@ -694,7 +715,8 @@ int main(int argc, char **argv)
param.pagesize = strtoul(optarg, NULL, 0); param.pagesize = strtoul(optarg, NULL, 0);
break; break;
case 'o': case 'o':
param.offset = strtoul(optarg, NULL, 0); param.cbfsoffset = strtoul(optarg, NULL, 0);
param.cbfsoffset_assigned = 1;
break; break;
case 'f': case 'f':
param.filename = optarg; param.filename = optarg;

View File

@ -47,6 +47,13 @@ extern int verbose;
#define unused __attribute__((unused)) #define unused __attribute__((unused))
static inline uint32_t align_up(uint32_t value, uint32_t align)
{
if (value % align)
value += align - (value % align);
return value;
}
/* Buffer and file I/O */ /* Buffer and file I/O */
struct buffer { struct buffer {
char *name; char *name;