201 lines
6.9 KiB
Python
201 lines
6.9 KiB
Python
|
#!/usr/bin/python
|
||
|
# Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||
|
#
|
||
|
# Redistribution and use in source and binary forms, with or without
|
||
|
# modification, are permitted provided that the following conditions are
|
||
|
# met:
|
||
|
# * Redistributions of source code must retain the above copyright
|
||
|
# notice, this list of conditions and the following disclaimer.
|
||
|
# * Redistributions in binary form must reproduce the above
|
||
|
# copyright notice, this list of conditions and the following
|
||
|
# disclaimer in the documentation and/or other materials provided
|
||
|
# with the distribution.
|
||
|
# * Neither the name of The Linux Foundation nor the names of its
|
||
|
# contributors may be used to endorse or promote products derived
|
||
|
# from this software without specific prior written permission.
|
||
|
|
||
|
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||
|
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||
|
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||
|
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||
|
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||
|
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||
|
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
|
||
|
import struct
|
||
|
import sys
|
||
|
import os
|
||
|
|
||
|
"""A utility to generate ipq8064 uber SBL..
|
||
|
|
||
|
The very first blob (aka 'uber SBL') read out of NOR SPI flash by the IPQ8064
|
||
|
maskrom is supposed to be a concatenation of up to three binaries: one to run
|
||
|
on the RPM, another one to run on the AP, and the third one - the actual
|
||
|
coreboot bootblock.
|
||
|
|
||
|
The uber SBL starts with the combined header descriptor of 80 bytes, with the
|
||
|
first two 4 byte words set to certain values, and the total size of the
|
||
|
payload saved at offsets 28 and 32.
|
||
|
|
||
|
To generate the uber SBL this utility expects two or three input file names in
|
||
|
the command line, the first file including the described header, and the
|
||
|
following one(s) - in QCA MBN format. This allows to create the uber SBL in
|
||
|
one or two invocations.
|
||
|
|
||
|
The input files are concatenated together aligned at 256 byte boundary offset
|
||
|
from the combined header. See Usage() below for more details.
|
||
|
|
||
|
The resulting uber SBL file is prepended by the same combined header adjusted
|
||
|
to reflect the new total file size.
|
||
|
"""
|
||
|
|
||
|
DEFAULT_OUTPUT_FILE_NAME = 'sbl-ro.mbn'
|
||
|
|
||
|
class NorSbl:
|
||
|
"""Object representing the uber SBL."""
|
||
|
|
||
|
NOR_SBL1_HEADER = '<II72s'
|
||
|
NOR_SBL1_HEADER_SZ = struct.calcsize(NOR_SBL1_HEADER)
|
||
|
ALIGNMENT = 256 # Make sure this == UBER_SBL_PAD_SIZE
|
||
|
NOR_CODE_WORD = 0x844bdcd1
|
||
|
MAGIC_NUM = 0x73d71034
|
||
|
|
||
|
def __init__(self, sbl1, verbose):
|
||
|
"""Initialize the object and verify the first file in the sequence.
|
||
|
|
||
|
Args:
|
||
|
sbl1: string, the name of the first out of the three input blobs,
|
||
|
must be prepended by the combined header.
|
||
|
verbose: boolean, if True - print debug information on the console.
|
||
|
"""
|
||
|
self.verbose = verbose
|
||
|
self.mbn_file_names = []
|
||
|
if self.verbose:
|
||
|
print 'Reading ' + sbl1
|
||
|
|
||
|
try:
|
||
|
self.sbl1 = open(sbl1, 'rb').read()
|
||
|
except IOError as e:
|
||
|
print 'I/O error({0}): {1}'.format(e.errno, e.strerror)
|
||
|
raise
|
||
|
|
||
|
(codeword, magic, _) = struct.unpack_from(
|
||
|
self.NOR_SBL1_HEADER, self.sbl1)
|
||
|
|
||
|
if codeword != self.NOR_CODE_WORD:
|
||
|
print '\n\nError: Unexpected Codeword!'
|
||
|
print 'Codeword : ' + ('0x%x' % self.NOR_CODE_WORD) + \
|
||
|
' != ' + ('0x%x' % codeword)
|
||
|
sys.exit(-1)
|
||
|
|
||
|
if magic != self.MAGIC_NUM:
|
||
|
print '\n\nError: Unexpected Magic!'
|
||
|
print 'Magic : ' + ('0x%x' % self.MAGIC_NUM) + \
|
||
|
' != ' + ('0x%x' % magic)
|
||
|
sys.exit(-1)
|
||
|
|
||
|
def Append(self, src):
|
||
|
"""Add a file to the list of files to be concatenated"""
|
||
|
self.mbn_file_names.append(src)
|
||
|
|
||
|
def PadOutput(self, outfile, size):
|
||
|
"""Pad output file to the required alignment.
|
||
|
|
||
|
Adds 0xff to the passed in file to get its size to the ALIGNMENT
|
||
|
boundary.
|
||
|
|
||
|
Args:
|
||
|
outfile: file handle of the file to be padded
|
||
|
size: int, current size of the file
|
||
|
|
||
|
Returns number of bytes in the added padding.
|
||
|
"""
|
||
|
|
||
|
# Is padding needed?
|
||
|
overflow = size % self.ALIGNMENT
|
||
|
if overflow:
|
||
|
pad_size = self.ALIGNMENT - overflow
|
||
|
pad = '\377' * pad_size
|
||
|
outfile.write(pad)
|
||
|
if self.verbose:
|
||
|
print 'Added %d byte padding' % pad_size
|
||
|
return pad_size
|
||
|
return 0
|
||
|
|
||
|
def Create(self, out_file_name):
|
||
|
"""Create the uber SBL.
|
||
|
|
||
|
Concatenate input files with the appropriate padding and update the
|
||
|
combined header to reflect the new blob size.
|
||
|
|
||
|
Args:
|
||
|
out_file_name: string, name of the file to save the generated uber
|
||
|
SBL in.
|
||
|
"""
|
||
|
outfile = open(out_file_name, 'wb')
|
||
|
total_size = len(self.sbl1) - self.NOR_SBL1_HEADER_SZ
|
||
|
outfile.write(self.sbl1)
|
||
|
|
||
|
for mbn_file_name in self.mbn_file_names:
|
||
|
total_size += self.PadOutput(outfile, total_size)
|
||
|
mbn_file_data = open(mbn_file_name, 'r').read()
|
||
|
outfile.write(mbn_file_data)
|
||
|
if self.verbose:
|
||
|
print 'Added %s (%d bytes)' % (mbn_file_name,
|
||
|
len(mbn_file_data))
|
||
|
total_size += len(mbn_file_data)
|
||
|
|
||
|
outfile.seek(28)
|
||
|
outfile.write(struct.pack('<I', total_size))
|
||
|
outfile.write(struct.pack('<I', total_size))
|
||
|
|
||
|
|
||
|
def Usage(v):
|
||
|
print '%s: [-v] [-h] [-o Output MBN] sbl1 sbl2 [bootblock]' % (
|
||
|
os.path.basename(sys.argv[0]))
|
||
|
print
|
||
|
print 'Concatenates up to three mbn files: two SBLs and a coreboot bootblock'
|
||
|
print ' -h This message'
|
||
|
print ' -v verbose'
|
||
|
print ' -o Output file name, (default: %s)\n' % DEFAULT_OUTPUT_FILE_NAME
|
||
|
sys.exit(v)
|
||
|
|
||
|
def main():
|
||
|
verbose = 0
|
||
|
mbn_output = DEFAULT_OUTPUT_FILE_NAME
|
||
|
i = 0
|
||
|
|
||
|
while i < (len(sys.argv) - 1):
|
||
|
i += 1
|
||
|
if (sys.argv[i] == '-h'):
|
||
|
Usage(0) # doesn't return
|
||
|
|
||
|
if (sys.argv[i] == '-o'):
|
||
|
mbn_output = sys.argv[i + 1]
|
||
|
i += 1
|
||
|
continue
|
||
|
|
||
|
if (sys.argv[i] == '-v'):
|
||
|
verbose = 1
|
||
|
continue
|
||
|
|
||
|
break
|
||
|
|
||
|
argv = sys.argv[i:]
|
||
|
if len(argv) < 2 or len(argv) > 3:
|
||
|
Usage(-1)
|
||
|
|
||
|
nsbl = NorSbl(argv[0], verbose)
|
||
|
|
||
|
for mbnf in argv[1:]:
|
||
|
nsbl.Append(mbnf)
|
||
|
|
||
|
nsbl.Create(mbn_output)
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|