T Michael Turney | 540b8ec | 2020-01-24 08:42:47 -0800 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Vadim Bendebury | 5aaa828 | 2014-11-30 13:05:38 -0800 | [diff] [blame] | 2 | # Copyright (c) 2014, The Linux Foundation. All rights reserved. |
| 3 | # |
| 4 | # Redistribution and use in source and binary forms, with or without |
| 5 | # modification, are permitted provided that the following conditions are |
| 6 | # met: |
| 7 | # * Redistributions of source code must retain the above copyright |
| 8 | # notice, this list of conditions and the following disclaimer. |
| 9 | # * Redistributions in binary form must reproduce the above |
| 10 | # copyright notice, this list of conditions and the following |
| 11 | # disclaimer in the documentation and/or other materials provided |
| 12 | # with the distribution. |
| 13 | # * Neither the name of The Linux Foundation nor the names of its |
| 14 | # contributors may be used to endorse or promote products derived |
| 15 | # from this software without specific prior written permission. |
| 16 | |
| 17 | # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| 18 | # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| 20 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| 21 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 22 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 23 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| 24 | # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| 25 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| 26 | # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| 27 | # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | |
| 29 | import struct |
| 30 | import sys |
| 31 | import os |
| 32 | |
| 33 | """A utility to generate ipq8064 uber SBL.. |
| 34 | |
| 35 | The very first blob (aka 'uber SBL') read out of NOR SPI flash by the IPQ8064 |
| 36 | maskrom is supposed to be a concatenation of up to three binaries: one to run |
| 37 | on the RPM, another one to run on the AP, and the third one - the actual |
| 38 | coreboot bootblock. |
| 39 | |
| 40 | The uber SBL starts with the combined header descriptor of 80 bytes, with the |
| 41 | first two 4 byte words set to certain values, and the total size of the |
| 42 | payload saved at offsets 28 and 32. |
| 43 | |
| 44 | To generate the uber SBL this utility expects two or three input file names in |
| 45 | the command line, the first file including the described header, and the |
| 46 | following one(s) - in QCA MBN format. This allows to create the uber SBL in |
| 47 | one or two invocations. |
| 48 | |
| 49 | The input files are concatenated together aligned at 256 byte boundary offset |
| 50 | from the combined header. See Usage() below for more details. |
| 51 | |
| 52 | The resulting uber SBL file is prepended by the same combined header adjusted |
| 53 | to reflect the new total file size. |
| 54 | """ |
| 55 | |
| 56 | DEFAULT_OUTPUT_FILE_NAME = 'sbl-ro.mbn' |
| 57 | |
| 58 | class NorSbl: |
| 59 | """Object representing the uber SBL.""" |
| 60 | |
| 61 | NOR_SBL1_HEADER = '<II72s' |
| 62 | NOR_SBL1_HEADER_SZ = struct.calcsize(NOR_SBL1_HEADER) |
| 63 | ALIGNMENT = 256 # Make sure this == UBER_SBL_PAD_SIZE |
| 64 | NOR_CODE_WORD = 0x844bdcd1 |
| 65 | MAGIC_NUM = 0x73d71034 |
| 66 | |
| 67 | def __init__(self, sbl1, verbose): |
| 68 | """Initialize the object and verify the first file in the sequence. |
| 69 | |
| 70 | Args: |
| 71 | sbl1: string, the name of the first out of the three input blobs, |
| 72 | must be prepended by the combined header. |
| 73 | verbose: boolean, if True - print debug information on the console. |
| 74 | """ |
| 75 | self.verbose = verbose |
| 76 | self.mbn_file_names = [] |
| 77 | if self.verbose: |
T Michael Turney | 540b8ec | 2020-01-24 08:42:47 -0800 | [diff] [blame] | 78 | print('Reading ' + sbl1) |
Vadim Bendebury | 5aaa828 | 2014-11-30 13:05:38 -0800 | [diff] [blame] | 79 | |
| 80 | try: |
| 81 | self.sbl1 = open(sbl1, 'rb').read() |
| 82 | except IOError as e: |
T Michael Turney | 540b8ec | 2020-01-24 08:42:47 -0800 | [diff] [blame] | 83 | print('I/O error({0}): {1}'.format(e.errno, e.strerror)) |
Vadim Bendebury | 5aaa828 | 2014-11-30 13:05:38 -0800 | [diff] [blame] | 84 | raise |
| 85 | |
| 86 | (codeword, magic, _) = struct.unpack_from( |
| 87 | self.NOR_SBL1_HEADER, self.sbl1) |
| 88 | |
| 89 | if codeword != self.NOR_CODE_WORD: |
T Michael Turney | 540b8ec | 2020-01-24 08:42:47 -0800 | [diff] [blame] | 90 | print('\n\nError: Unexpected Codeword!') |
| 91 | print('Codeword : ' + ('0x%x' % self.NOR_CODE_WORD) + \ |
| 92 | ' != ' + ('0x%x' % codeword)) |
Vadim Bendebury | 5aaa828 | 2014-11-30 13:05:38 -0800 | [diff] [blame] | 93 | sys.exit(-1) |
| 94 | |
| 95 | if magic != self.MAGIC_NUM: |
T Michael Turney | 540b8ec | 2020-01-24 08:42:47 -0800 | [diff] [blame] | 96 | print('\n\nError: Unexpected Magic!') |
| 97 | print('Magic : ' + ('0x%x' % self.MAGIC_NUM) + \ |
| 98 | ' != ' + ('0x%x' % magic)) |
Vadim Bendebury | 5aaa828 | 2014-11-30 13:05:38 -0800 | [diff] [blame] | 99 | sys.exit(-1) |
| 100 | |
| 101 | def Append(self, src): |
| 102 | """Add a file to the list of files to be concatenated""" |
| 103 | self.mbn_file_names.append(src) |
| 104 | |
| 105 | def PadOutput(self, outfile, size): |
| 106 | """Pad output file to the required alignment. |
| 107 | |
| 108 | Adds 0xff to the passed in file to get its size to the ALIGNMENT |
| 109 | boundary. |
| 110 | |
| 111 | Args: |
| 112 | outfile: file handle of the file to be padded |
| 113 | size: int, current size of the file |
| 114 | |
| 115 | Returns number of bytes in the added padding. |
| 116 | """ |
| 117 | |
| 118 | # Is padding needed? |
| 119 | overflow = size % self.ALIGNMENT |
| 120 | if overflow: |
| 121 | pad_size = self.ALIGNMENT - overflow |
T Michael Turney | 540b8ec | 2020-01-24 08:42:47 -0800 | [diff] [blame] | 122 | pad = b'\377' * pad_size |
Vadim Bendebury | 5aaa828 | 2014-11-30 13:05:38 -0800 | [diff] [blame] | 123 | outfile.write(pad) |
| 124 | if self.verbose: |
T Michael Turney | 540b8ec | 2020-01-24 08:42:47 -0800 | [diff] [blame] | 125 | print('Added %d byte padding' % pad_size) |
Vadim Bendebury | 5aaa828 | 2014-11-30 13:05:38 -0800 | [diff] [blame] | 126 | return pad_size |
| 127 | return 0 |
| 128 | |
| 129 | def Create(self, out_file_name): |
| 130 | """Create the uber SBL. |
| 131 | |
| 132 | Concatenate input files with the appropriate padding and update the |
| 133 | combined header to reflect the new blob size. |
| 134 | |
| 135 | Args: |
| 136 | out_file_name: string, name of the file to save the generated uber |
| 137 | SBL in. |
| 138 | """ |
| 139 | outfile = open(out_file_name, 'wb') |
| 140 | total_size = len(self.sbl1) - self.NOR_SBL1_HEADER_SZ |
| 141 | outfile.write(self.sbl1) |
| 142 | |
| 143 | for mbn_file_name in self.mbn_file_names: |
| 144 | total_size += self.PadOutput(outfile, total_size) |
T Michael Turney | 540b8ec | 2020-01-24 08:42:47 -0800 | [diff] [blame] | 145 | mbn_file_data = open(mbn_file_name, 'rb').read() |
Vadim Bendebury | 5aaa828 | 2014-11-30 13:05:38 -0800 | [diff] [blame] | 146 | outfile.write(mbn_file_data) |
| 147 | if self.verbose: |
T Michael Turney | 540b8ec | 2020-01-24 08:42:47 -0800 | [diff] [blame] | 148 | print('Added %s (%d bytes)' % (mbn_file_name, |
| 149 | len(mbn_file_data))) |
Vadim Bendebury | 5aaa828 | 2014-11-30 13:05:38 -0800 | [diff] [blame] | 150 | total_size += len(mbn_file_data) |
| 151 | |
| 152 | outfile.seek(28) |
| 153 | outfile.write(struct.pack('<I', total_size)) |
| 154 | outfile.write(struct.pack('<I', total_size)) |
| 155 | |
| 156 | |
| 157 | def Usage(v): |
T Michael Turney | 540b8ec | 2020-01-24 08:42:47 -0800 | [diff] [blame] | 158 | print('%s: [-v] [-h] [-o Output MBN] sbl1 sbl2 [bootblock]' % ( |
| 159 | os.path.basename(sys.argv[0]))) |
| 160 | print() |
| 161 | print('Concatenates up to three mbn files: two SBLs and a coreboot bootblock') |
| 162 | print(' -h This message') |
| 163 | print(' -v verbose') |
| 164 | print(' -o Output file name, (default: %s)\n' % DEFAULT_OUTPUT_FILE_NAME) |
Vadim Bendebury | 5aaa828 | 2014-11-30 13:05:38 -0800 | [diff] [blame] | 165 | sys.exit(v) |
| 166 | |
| 167 | def main(): |
| 168 | verbose = 0 |
| 169 | mbn_output = DEFAULT_OUTPUT_FILE_NAME |
| 170 | i = 0 |
| 171 | |
| 172 | while i < (len(sys.argv) - 1): |
| 173 | i += 1 |
| 174 | if (sys.argv[i] == '-h'): |
| 175 | Usage(0) # doesn't return |
| 176 | |
| 177 | if (sys.argv[i] == '-o'): |
| 178 | mbn_output = sys.argv[i + 1] |
| 179 | i += 1 |
| 180 | continue |
| 181 | |
| 182 | if (sys.argv[i] == '-v'): |
| 183 | verbose = 1 |
| 184 | continue |
| 185 | |
| 186 | break |
| 187 | |
| 188 | argv = sys.argv[i:] |
| 189 | if len(argv) < 2 or len(argv) > 3: |
| 190 | Usage(-1) |
| 191 | |
| 192 | nsbl = NorSbl(argv[0], verbose) |
| 193 | |
| 194 | for mbnf in argv[1:]: |
| 195 | nsbl.Append(mbnf) |
| 196 | |
| 197 | nsbl.Create(mbn_output) |
| 198 | |
| 199 | if __name__ == '__main__': |
| 200 | main() |