summaryrefslogtreecommitdiff
path: root/tools/binman/cbfs_util.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/binman/cbfs_util.py')
-rw-r--r--tools/binman/cbfs_util.py125
1 files changed, 72 insertions, 53 deletions
diff --git a/tools/binman/cbfs_util.py b/tools/binman/cbfs_util.py
index fc56b40b753..671cafa34c0 100644
--- a/tools/binman/cbfs_util.py
+++ b/tools/binman/cbfs_util.py
@@ -42,27 +42,24 @@ HEADER_VERSION2 = 0x31313132
FILE_HEADER_FORMAT = b'>8sIIII'
FILE_HEADER_LEN = 0x18
FILE_MAGIC = b'LARCHIVE'
-FILENAME_ALIGN = 16 # Filename lengths are aligned to this
+ATTRIBUTE_ALIGN = 4 # All attribute sizes must be divisible by this
-# A stage header containing information about 'stage' files
+# A stage-header attribute containing information about 'stage' files
# Yes this is correct: this header is in litte-endian format
-STAGE_FORMAT = '<IQQII'
-STAGE_LEN = 0x1c
+ATTR_STAGE_FORMAT = '>IIQII'
+ATTR_STAGE_LEN = 0x18
# An attribute describring the compression used in a file
ATTR_COMPRESSION_FORMAT = '>IIII'
ATTR_COMPRESSION_LEN = 0x10
# Attribute tags
-# Depending on how the header was initialised, it may be backed with 0x00 or
-# 0xff. Support both.
-FILE_ATTR_TAG_UNUSED = 0
-FILE_ATTR_TAG_UNUSED2 = 0xffffffff
FILE_ATTR_TAG_COMPRESSION = 0x42435a4c
FILE_ATTR_TAG_HASH = 0x68736148
FILE_ATTR_TAG_POSITION = 0x42435350 # PSCB
FILE_ATTR_TAG_ALIGNMENT = 0x42434c41 # ALCB
FILE_ATTR_TAG_PADDING = 0x47444150 # PDNG
+FILE_ATTR_TAG_STAGEHEADER = 0x53746748 # StgH
# This is 'the size of bootblock reserved in firmware image (cbfs.txt)'
# Not much more info is available, but we set it to 4, due to this comment in
@@ -100,7 +97,8 @@ ARCH_NAMES = {
# File types. Only supported ones are included here
TYPE_CBFSHEADER = 0x02 # Master header, HEADER_FORMAT
-TYPE_STAGE = 0x10 # Stage, holding an executable, see STAGE_FORMAT
+TYPE_LEGACY_STAGE = 0x10 # Stage, holding an executable
+TYPE_STAGE = 0x11 # New-type stage with ATTR_STAGE_FORMAT
TYPE_RAW = 0x50 # Raw file, possibly compressed
TYPE_EMPTY = 0xffffffff # Empty data
@@ -190,7 +188,7 @@ def _pack_string(instr):
String with required padding (at least one 0x00 byte) at the end
"""
val = tools.to_bytes(instr)
- pad_len = align_int(len(val) + 1, FILENAME_ALIGN)
+ pad_len = align_int(len(val) + 1, ATTRIBUTE_ALIGN)
return val + tools.get_bytes(0, pad_len - len(val))
@@ -304,7 +302,7 @@ class CbfsFile(object):
CbfsFile object containing the file information
"""
cfile = CbfsFile('', TYPE_EMPTY, b'', None)
- cfile.size = space_to_use - FILE_HEADER_LEN - FILENAME_ALIGN
+ cfile.size = space_to_use - FILE_HEADER_LEN - ATTRIBUTE_ALIGN
cfile.erase_byte = erase_byte
return cfile
@@ -331,9 +329,10 @@ class CbfsFile(object):
name = _pack_string(self.name)
hdr_len = len(name) + FILE_HEADER_LEN
if self.ftype == TYPE_STAGE:
- pass
+ hdr_len += ATTR_STAGE_LEN
elif self.ftype == TYPE_RAW:
- hdr_len += ATTR_COMPRESSION_LEN
+ if self.compress:
+ hdr_len += ATTR_COMPRESSION_LEN
elif self.ftype == TYPE_EMPTY:
pass
else:
@@ -359,9 +358,9 @@ class CbfsFile(object):
data = self.data
if self.ftype == TYPE_STAGE:
elf_data = elf.DecodeElf(data, self.base_address)
- content = struct.pack(STAGE_FORMAT, self.compress,
- elf_data.entry, elf_data.load,
- len(elf_data.data), elf_data.memsize)
+ attr = struct.pack(ATTR_STAGE_FORMAT, FILE_ATTR_TAG_STAGEHEADER,
+ ATTR_STAGE_LEN, elf_data.load,
+ elf_data.entry - elf_data.load, elf_data.memsize)
data = elf_data.data
elif self.ftype == TYPE_RAW:
orig_data = data
@@ -369,9 +368,11 @@ class CbfsFile(object):
data = self.comp_bintool.compress(orig_data)
self.memlen = len(orig_data)
self.data_len = len(data)
- attr = struct.pack(ATTR_COMPRESSION_FORMAT,
- FILE_ATTR_TAG_COMPRESSION, ATTR_COMPRESSION_LEN,
- self.compress, self.memlen)
+ if self.compress:
+ attr = struct.pack(ATTR_COMPRESSION_FORMAT,
+ FILE_ATTR_TAG_COMPRESSION,
+ ATTR_COMPRESSION_LEN, self.compress,
+ self.memlen)
elif self.ftype == TYPE_EMPTY:
data = tools.get_bytes(self.erase_byte, self.size)
else:
@@ -391,6 +392,8 @@ class CbfsFile(object):
raise ValueError("Internal error: CBFS file '%s': Requested offset %#x but current output position is %#x" %
(self.name, self.cbfs_offset, offset))
pad = tools.get_bytes(pad_byte, pad_len)
+ if attr_pos:
+ attr_pos += pad_len
hdr_len += pad_len
# This is the offset of the start of the file's data,
@@ -405,9 +408,9 @@ class CbfsFile(object):
if expected_len != actual_len: # pragma: no cover
# Test coverage of this is not available since this should never
# happen. It probably indicates that get_header_len() is broken.
- raise ValueError("Internal error: CBFS file '%s': Expected headers of %#x bytes, got %#d" %
+ raise ValueError("Internal error: CBFS file '%s': Expected headers of %#x bytes, got %#x" %
(self.name, expected_len, actual_len))
- return hdr + name + attr + pad + content + data, hdr_len
+ return hdr + name + pad + attr + content + data, hdr_len
class CbfsWriter(object):
@@ -453,6 +456,9 @@ class CbfsWriter(object):
self._arch = arch
self._bootblock_size = 0
self._erase_byte = 0xff
+
+ # Small padding to align a file uses 0
+ self._small_pad_byte = 0
self._align = ENTRY_ALIGN
self._add_fileheader = False
if self._arch == ARCHITECTURE_X86:
@@ -474,7 +480,7 @@ class CbfsWriter(object):
self._bootblock_size, self._align)
self._hdr_at_start = True
- def _skip_to(self, fd, offset):
+ def _skip_to(self, fd, offset, pad_byte):
"""Write out pad bytes until a given offset
Args:
@@ -484,16 +490,16 @@ class CbfsWriter(object):
if fd.tell() > offset:
raise ValueError('No space for data before offset %#x (current offset %#x)' %
(offset, fd.tell()))
- fd.write(tools.get_bytes(self._erase_byte, offset - fd.tell()))
+ fd.write(tools.get_bytes(pad_byte, offset - fd.tell()))
- def _pad_to(self, fd, offset):
+ def _pad_to(self, fd, offset, pad_byte):
"""Write out pad bytes and/or an empty file until a given offset
Args:
fd: File objext to write to
offset: Offset to write to
"""
- self._align_to(fd, self._align)
+ self._align_to(fd, self._align, pad_byte)
upto = fd.tell()
if upto > offset:
raise ValueError('No space for data before pad offset %#x (current offset %#x)' %
@@ -502,9 +508,9 @@ class CbfsWriter(object):
if todo:
cbf = CbfsFile.empty(todo, self._erase_byte)
fd.write(cbf.get_data_and_offset()[0])
- self._skip_to(fd, offset)
+ self._skip_to(fd, offset, pad_byte)
- def _align_to(self, fd, align):
+ def _align_to(self, fd, align, pad_byte):
"""Write out pad bytes until a given alignment is reached
This only aligns if the resulting output would not reach the end of the
@@ -518,7 +524,7 @@ class CbfsWriter(object):
"""
offset = align_int(fd.tell(), align)
if offset < self._size:
- self._skip_to(fd, offset)
+ self._skip_to(fd, offset, pad_byte)
def add_file_stage(self, name, data, cbfs_offset=None):
"""Add a new stage file to the CBFS
@@ -568,7 +574,7 @@ class CbfsWriter(object):
raise ValueError('No space for header at offset %#x (current offset %#x)' %
(self._header_offset, fd.tell()))
if not add_fileheader:
- self._pad_to(fd, self._header_offset)
+ self._pad_to(fd, self._header_offset, self._erase_byte)
hdr = struct.pack(HEADER_FORMAT, HEADER_MAGIC, HEADER_VERSION2,
self._size, self._bootblock_size, self._align,
self._contents_offset, self._arch, 0xffffffff)
@@ -580,7 +586,7 @@ class CbfsWriter(object):
fd.write(name)
self._header_offset = fd.tell()
fd.write(hdr)
- self._align_to(fd, self._align)
+ self._align_to(fd, self._align, self._erase_byte)
else:
fd.write(hdr)
@@ -597,24 +603,26 @@ class CbfsWriter(object):
# THe header can go at the start in some cases
if self._hdr_at_start:
self._write_header(fd, add_fileheader=self._add_fileheader)
- self._skip_to(fd, self._contents_offset)
+ self._skip_to(fd, self._contents_offset, self._erase_byte)
# Write out each file
for cbf in self._files.values():
# Place the file at its requested place, if any
offset = cbf.calc_start_offset()
if offset is not None:
- self._pad_to(fd, align_int_down(offset, self._align))
+ self._pad_to(fd, align_int_down(offset, self._align),
+ self._erase_byte)
pos = fd.tell()
- data, data_offset = cbf.get_data_and_offset(pos, self._erase_byte)
+ data, data_offset = cbf.get_data_and_offset(pos,
+ self._small_pad_byte)
fd.write(data)
- self._align_to(fd, self._align)
+ self._align_to(fd, self._align, self._erase_byte)
cbf.calced_cbfs_offset = pos + data_offset
if not self._hdr_at_start:
self._write_header(fd, add_fileheader=self._add_fileheader)
# Pad to the end and write a pointer to the CBFS master header
- self._pad_to(fd, self._base_address or self._size - 4)
+ self._pad_to(fd, self._base_address or self._size - 4, self._erase_byte)
rel_offset = self._header_offset - self._size
fd.write(struct.pack('<I', rel_offset & 0xffffffff))
@@ -734,26 +742,28 @@ class CbfsReader(object):
print('name', name)
# If there are attribute headers present, read those
- compress = self._read_attr(fd, file_pos, attr, offset)
- if compress is None:
+ attrs = self._read_attr(fd, file_pos, attr, offset)
+ if attrs is None:
return False
# Create the correct CbfsFile object depending on the type
cfile = None
cbfs_offset = file_pos + offset
fd.seek(cbfs_offset, io.SEEK_SET)
+ if DEBUG:
+ print(f'ftype {ftype:x}')
if ftype == TYPE_CBFSHEADER:
self._read_header(fd)
elif ftype == TYPE_STAGE:
- data = fd.read(STAGE_LEN)
cfile = CbfsFile.stage(self.stage_base_address, name, b'',
cbfs_offset)
- (cfile.compress, cfile.entry, cfile.load, cfile.data_len,
- cfile.memlen) = struct.unpack(STAGE_FORMAT, data)
- cfile.data = fd.read(cfile.data_len)
+ cfile.load, entry_offset, cfile.memlen = attrs
+ cfile.entry = cfile.load + entry_offset
+ cfile.data = fd.read(cfile.memlen)
+ cfile.data_len = cfile.memlen
elif ftype == TYPE_RAW:
data = fd.read(size)
- cfile = CbfsFile.raw(name, data, cbfs_offset, compress)
+ cfile = CbfsFile.raw(name, data, cbfs_offset, attrs)
cfile.decompress()
if DEBUG:
print('data', data)
@@ -777,8 +787,8 @@ class CbfsReader(object):
"""Read attributes from the file
CBFS files can have attributes which are things that cannot fit into the
- header. The only attributes currently supported are compression and the
- unused tag.
+ header. The only attributes currently supported are compression, stage
+ header and the unused tag
Args:
fd: File to read from
@@ -788,11 +798,16 @@ class CbfsReader(object):
attributes)
Returns:
- Compression to use for the file (COMPRESS_...)
+ Either:
+ Compression to use for the file (COMPRESS_...)
+ tuple containing stage info:
+ load address
+ entry offset
+ memory size
"""
- compress = COMPRESS_NONE
+ attrs = None
if not attr:
- return compress
+ return COMPRESS_NONE
attr_size = offset - attr
fd.seek(file_pos + attr, io.SEEK_SET)
while attr_size:
@@ -807,12 +822,15 @@ class CbfsReader(object):
# We don't currently use this information
atag, alen, compress, _decomp_size = struct.unpack(
ATTR_COMPRESSION_FORMAT, data)
- elif atag == FILE_ATTR_TAG_UNUSED2:
- break
+ attrs = compress
+ elif atag == FILE_ATTR_TAG_STAGEHEADER:
+ atag, alen, load, entry_offset, memsize = struct.unpack(
+ ATTR_STAGE_FORMAT, data)
+ attrs = (load, entry_offset, memsize)
else:
print('Unknown attribute tag %x' % atag)
attr_size -= len(data)
- return compress
+ return attrs
def _read_header(self, fd):
"""Read the master header
@@ -843,7 +861,8 @@ class CbfsReader(object):
def _read_string(cls, fd):
"""Read a string from a file
- This reads a string and aligns the data to the next alignment boundary
+ This reads a string and aligns the data to the next alignment boundary.
+ The string must be nul-terminated
Args:
fd: File to read from
@@ -854,8 +873,8 @@ class CbfsReader(object):
"""
val = b''
while True:
- data = fd.read(FILENAME_ALIGN)
- if len(data) < FILENAME_ALIGN:
+ data = fd.read(ATTRIBUTE_ALIGN)
+ if len(data) < ATTRIBUTE_ALIGN:
return None
pos = data.find(b'\0')
if pos == -1: