blob: ac7102d35276a4553ae3e526eb9153d1450659fe [file] [log] [blame]
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301######################################################################
2# Copyright (c) 2017, The Linux Foundation. All rights reserved.
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05303#
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05304# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License version 2 and
6# only version 2 as published by the Free Software Foundation.
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05307#
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05308# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#####################################################################
13
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +053014"""
15Script to create a U-Boot flashable multi-image blob.
16
17This script creates a multi-image blob, from a bunch of images, and
18adds a U-Boot shell script to the blob, that can flash the images from
19within U-Boot. The procedure to use this script is listed below.
20
21 1. Create an images folder. Ex: my-pack
22
23 2. Copy all the images to be flashed into the folder.
24
25 3. Copy the partition MBN file into the folder. The file should be
26 named 'partition.mbn'. This is used to determine the offsets for
27 each of the named partitions.
28
29 4. Create a flash configuration file, specifying the images be
30 flashed, and the partition in which the images is to be
31 flashed. The flash configuration file can be specified using the
32 -f option, default is flash.conf.
33
34 5. Invoke 'pack' with the folder name as argument, pass flash
35 parameters as arguments if required. A single image file will
36 be created, out side the images folder, with .img suffix. Ex:
37 my-pack.img
38
39 6. Transfer the file into a valid SDRAM address and invoke the
40 following U-Boot command to flash the images. Replace 0x41000000,
41 with address location where the image has been loaded. The script
42 expects the variable 'imgaddr' to be set.
43
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +053044 u-boot> imgaddr=0x88000000 source $imgaddr:script
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +053045
46Host-side Pre-req
47
48 * Python >= 2.6
49 * ordereddict >= 1.1 (for Python 2.6)
50 * mkimage >= 2012.07
51 * dtc >= 1.2.0
52
53Target-side Pre-req
54
55The following U-Boot config macros should be enabled, for the
56generated flashing script to work.
57
58 * CONFIG_FIT -- FIT image format support
59 * CONFIG_SYS_HUSH_PARSER -- bash style scripting support
60 * CONFIG_SYS_NULLDEV -- redirecting command output support
61 * CONFIG_CMD_XIMG -- extracting sub-images support
62 * CONFIG_CMD_NAND -- NAND Flash commands support
63 * CONFIG_CMD_NAND_YAFFS -- NAND YAFFS2 write support
64 * CONFIG_CMD_SF -- SPI Flash commands support
65"""
66
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +053067from os.path import getsize
68from getopt import getopt
69from getopt import GetoptError
70from collections import namedtuple
71from string import Template
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +053072
73import os
74import sys
75import os.path
76import subprocess
77import struct
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +053078import hashlib
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +053079import xml.etree.ElementTree as ET
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +053080
81version = "1.1"
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +053082ARCH_NAME = ""
83SRC_DIR = ""
84MODE = ""
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +053085#
86# Python 2.6 and earlier did not have OrderedDict use the backport
87# from ordereddict package. If that is not available report error.
88#
89try:
90 from collections import OrderedDict
91except ImportError:
92 try:
93 from ordereddict import OrderedDict
94 except ImportError:
95 print "error: this script requires the 'ordereddict' class."
96 print "Try 'pip install --user ordereddict'"
97 print "Or 'easy_install --user ordereddict'"
98 sys.exit(1)
99
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530100def error(msg, ex=None):
101 """Print an error message and exit.
102
103 msg -- string, the message to print
104 ex -- exception, the associate exception, if any
105 """
106
107 sys.stderr.write("pack: %s" % msg)
108 if ex != None: sys.stderr.write(": %s" % str(ex))
109 sys.stderr.write("\n")
110 sys.exit(1)
111
112FlashInfo = namedtuple("FlashInfo", "type pagesize blocksize chipsize")
113ImageInfo = namedtuple("ProgInfo", "name filename type")
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530114PartInfo = namedtuple("PartInfo", "name offset length which_flash")
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530115
116def roundup(value, roundto):
117 """Return the next largest multiple of 'roundto'."""
118
119 return ((value + roundto - 1) // roundto) * roundto
120
121class GPT(object):
122 GPTheader = namedtuple("GPTheader", "signature revision header_size"
123 " crc32 current_lba backup_lba first_usable_lba"
124 " last_usable_lba disk_guid start_lba_part_entry"
125 " num_part_entry part_entry_size part_crc32")
126 GPT_SIGNATURE = 'EFI PART'
127 GPT_REVISION = '\x00\x00\x01\x00'
128 GPT_HEADER_SIZE = 0x5C
129 GPT_HEADER_FMT = "<8s4sLL4xQQQQ16sQLLL"
130
131 GPTtable = namedtuple("GPTtable", "part_type unique_guid first_lba"
132 " last_lba attribute_flag part_name")
133 GPT_TABLE_FMT = "<16s16sQQQ72s"
134
135 def __init__(self, filename, pagesize, blocksize, chipsize):
136 self.filename = filename
137 self.pagesize = pagesize
138 self.blocksize = blocksize
139 self.chipsize = chipsize
140 self.__partitions = OrderedDict()
141
142 def __validate_and_read_parts(self, part_fp):
143 """Validate the GPT and read the partition"""
144 part_fp.seek(self.blocksize, os.SEEK_SET)
145 gptheader_str = part_fp.read(struct.calcsize(GPT.GPT_HEADER_FMT))
146 gptheader = struct.unpack(GPT.GPT_HEADER_FMT, gptheader_str)
147 gptheader = GPT.GPTheader._make(gptheader)
148
149 if gptheader.signature != GPT.GPT_SIGNATURE:
150 error("Invalid signature")
151
152 if gptheader.revision != GPT.GPT_REVISION:
153 error("Unsupported GPT Revision")
154
155 if gptheader.header_size != GPT.GPT_HEADER_SIZE:
156 error("Invalid Header size")
157
158 # Adding GPT partition info. This has to be flashed first.
159 # GPT Header starts at LBA1 so (current_lba -1) will give the
160 # starting of primary GPT.
161 # blocksize will equal to gptheader.first_usuable_lba - current_lba + 1
162
163 name = "0:GPT"
164 block_start = gptheader.current_lba - 1
165 block_count = gptheader.first_usable_lba - gptheader.current_lba + 1
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530166 which_flash = 0
167 part_info = PartInfo(name, block_start, block_count, which_flash)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530168 self.__partitions[name] = part_info
169
170 part_fp.seek(2 * self.blocksize, os.SEEK_SET)
171
172 for i in range(gptheader.num_part_entry):
173 gpt_table_str = part_fp.read(struct.calcsize(GPT.GPT_TABLE_FMT))
174 gpt_table = struct.unpack(GPT.GPT_TABLE_FMT, gpt_table_str)
175 gpt_table = GPT.GPTtable._make(gpt_table)
176
177 block_start = gpt_table.first_lba
178 block_count = gpt_table.last_lba - gpt_table.first_lba + 1
179
180 part_name = gpt_table.part_name.strip(chr(0))
181 name = part_name.replace('\0','')
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530182 part_info = PartInfo(name, block_start, block_count, which_flash)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530183 self.__partitions[name] = part_info
184
185 # Adding the GPT Backup partition.
186 # GPT header backup_lba gives block number where the GPT backup header will be.
187 # GPT Backup header will start from offset of 32 blocks before
188 # the GPTheader.backup_lba. Backup GPT size is 33 blocks.
189 name = "0:GPTBACKUP"
190 block_start = gptheader.backup_lba - 32
191 block_count = 33
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530192 part_info = PartInfo(name, block_start, block_count, which_flash)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530193 self.__partitions[name] = part_info
194
195 def get_parts(self):
196 """Returns a list of partitions present in the GPT."""
197
198 try:
199 with open(self.filename, "r") as part_fp:
200 self.__validate_and_read_parts(part_fp)
201 except IOError, e:
202 error("error opening %s" % self.filename, e)
203
204 return self.__partitions
205
206class MIBIB(object):
207 Header = namedtuple("Header", "magic1 magic2 version age")
208 HEADER_FMT = "<LLLL"
209 HEADER_MAGIC1 = 0xFE569FAC
210 HEADER_MAGIC2 = 0xCD7F127A
211 HEADER_VERSION = 4
212
213 Table = namedtuple("Table", "magic1 magic2 version numparts")
214 TABLE_FMT = "<LLLL"
215 TABLE_MAGIC1 = 0x55EE73AA
216 TABLE_MAGIC2 = 0xE35EBDDB
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530217 TABLE_VERSION_IPQ806X = 3
218 TABLE_VERSION_OTHERS = 4
219
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530220
221 Entry = namedtuple("Entry", "name offset length"
222 " attr1 attr2 attr3 which_flash")
223 ENTRY_FMT = "<16sLLBBBB"
224
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530225 def __init__(self, filename, pagesize, blocksize, chipsize, nand_blocksize, nand_chipsize, root_part):
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530226 self.filename = filename
227 self.pagesize = pagesize
228 self.blocksize = blocksize
229 self.chipsize = chipsize
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530230 self.nand_blocksize = nand_blocksize
231 self.nand_chipsize = nand_chipsize
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530232 self.__partitions = OrderedDict()
233
234 def __validate(self, part_fp):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530235 """Validate the MIBIB by checking for magic bytes."""
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530236
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530237 mheader_str = part_fp.read(struct.calcsize(MIBIB.HEADER_FMT))
238 mheader = struct.unpack(MIBIB.HEADER_FMT, mheader_str)
239 mheader = MIBIB.Header._make(mheader)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530240
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530241 if (mheader.magic1 != MIBIB.HEADER_MAGIC1
242 or mheader.magic2 != MIBIB.HEADER_MAGIC2):
243 """ mheader.magic1 = MIBIB.HEADER_MAGIC1
244 mheader.magic2 = MIBIB.HEADER_MAGIC2 """
245 error("invalid partition table, magic byte not present")
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530246
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530247 if mheader.version != MIBIB.HEADER_VERSION:
248 error("unsupport mibib version")
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530249
250 def __read_parts(self, part_fp):
251 """Read the partitions from the MIBIB."""
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530252 global ARCH_NAME
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530253 part_fp.seek(self.pagesize, os.SEEK_SET)
254 mtable_str = part_fp.read(struct.calcsize(MIBIB.TABLE_FMT))
255 mtable = struct.unpack(MIBIB.TABLE_FMT, mtable_str)
256 mtable = MIBIB.Table._make(mtable)
257
258 if (mtable.magic1 != MIBIB.TABLE_MAGIC1
259 or mtable.magic2 != MIBIB.TABLE_MAGIC2):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530260 """ mtable.magic1 = MIBIB.TABLE_MAGIC1
261 mtable.magic2 = MIBIB.TABLE_MAGIC2 """
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530262 error("invalid sys part. table, magic byte not present")
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530263 if ARCH_NAME == "ipq806x":
264 if mtable.version != MIBIB.TABLE_VERSION_IPQ806X:
265 error("unsupported partition table version")
266 else:
267 if mtable.version != MIBIB.TABLE_VERSION_OTHERS:
268 error("unsupported partition table version")
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530269
270 for i in range(mtable.numparts):
271 mentry_str = part_fp.read(struct.calcsize(MIBIB.ENTRY_FMT))
272 mentry = struct.unpack(MIBIB.ENTRY_FMT, mentry_str)
273 mentry = MIBIB.Entry._make(mentry)
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530274 self.flash_flag = self.blocksize
275 self.chip_flag = self.chipsize
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530276
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530277 if mentry.which_flash != 0:
278 self.flash_flag = self.nand_blocksize
279 self.chip_flag = self.nand_chipsize
280
281 byte_offset = mentry.offset * self.flash_flag
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530282
283 if mentry.length == 0xFFFFFFFF:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530284 byte_length = self.chip_flag - byte_offset
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530285 else:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530286 byte_length = mentry.length * self.flash_flag
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530287
288 part_name = mentry.name.strip(chr(0))
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530289 part_info = PartInfo(part_name, byte_offset, byte_length, mentry.which_flash)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530290 self.__partitions[part_name] = part_info
291
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530292 def get_parts(self):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530293 """Returns a list of partitions present in the MIBIB. CE """
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530294
295 try:
296 with open(self.filename, "r") as part_fp:
297 self.__validate(part_fp)
298 self.__read_parts(part_fp)
299 except IOError, e:
300 error("error opening %s" % self.filename, e)
301
302 return self.__partitions
303
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530304class FlashScript(object):
305 """Base class for creating flash scripts."""
306
307 def __init__(self, flinfo):
308 self.pagesize = flinfo.pagesize
309 self.blocksize = flinfo.blocksize
310 self.script = []
311 self.parts = []
312 self.curr_stdout = "serial"
313 self.activity = None
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530314 self.flash_type = flinfo.type
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530315
316 self.script.append('if test "x$verbose" = "x"; then\n')
317 self.script.append("failedmsg='[failed]'\n")
318 self.script.append('else\n')
319 self.script.append("failedmsg='%s Failed'\n" % ("#" * 40))
320 self.script.append('fi\n')
321
322 def append(self, cmd, fatal=True):
323 """Add a command to the script.
324
325 Add additional code, to terminate on error. This can be
326 supressed by passing 'fatal' as False.
327 """
328
329 if fatal:
330 self.script.append(cmd
331 + ' || setenv stdout serial'
332 + ' && echo "$failedmsg"'
333 + ' && exit 1\n')
334 else:
335 self.script.append(cmd + "\n")
336
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530337 def dumps(self):
338 """Return the created script as a string."""
339 return "".join(self.script)
340
341 def redirect(self, dev):
342 """Generate code, to redirect command output to a device."""
343
344 if self.curr_stdout == dev:
345 return
346
347 self.append("setenv stdout %s" % dev, fatal=False)
348 self.curr_stdout = dev
349
350 def start_activity(self, activity):
351 """Generate code, to indicate start of an activity."""
352
353 self.script.append('if test "x$verbose" = "x"; then\n')
354 self.echo("'%-40.40s'" % activity, nl=False)
355 self.script.append('else\n')
356 self.echo("'%s %s Started'" % ("#" * 40, activity), verbose=True)
357 self.script.append('fi\n')
358 self.activity = activity
359
360 def finish_activity(self):
361 """Generate code, to indicate end of an activity."""
362
363 self.script.append('if test "x$verbose" = "x"; then\n')
364 self.echo("'[ done ]'")
365 self.redirect("serial")
366 self.script.append('else\n')
367 self.echo("'%s %s Done'" % ("#" * 40, self.activity), verbose=True)
368 self.script.append('fi\n')
369
370 def imxtract(self, part):
371 """Generate code, to extract image location, from a multi-image blob.
372
373 part -- string, name of the sub-image
374
375 Sets the $fileaddr environment variable, to point to the
376 location of the sub-image.
377 """
378
379 self.append("imxtract $imgaddr %s" % part)
380
381 def echo(self, msg, nl=True, verbose=False):
382 """Generate code, to print a message.
383
384 nl -- bool, indicates whether newline is to be printed
385 verbose -- bool, indicates whether printing in verbose mode
386 """
387
388 if not verbose:
389 self.redirect("serial")
390
391 if nl:
392 self.append("echo %s" % msg, fatal=False)
393 else:
394 self.append("echo %s%s" % (r"\\c", msg), fatal=False)
395
396 if not verbose:
397 self.redirect("nulldev")
398
399 def end(self):
400 """Generate code, to indicate successful completion of script."""
401
402 self.append("exit 0\n", fatal=False)
403
404 def start_if(self, var, value):
405 """Generate code, to check an environment variable.
406
407 var -- string, variable to check
408 value -- string, the value to compare with
409 """
410
411 self.append('if test "$%s" = "%s"; then\n' % (var, value),
412 fatal=False)
413
414 def end_if(self):
415 """Generate code, to end if statement."""
416
417 self.append('fi\n', fatal=False)
418
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530419class Flash_Script(FlashScript):
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530420 """Class for creating NAND flash scripts."""
421
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530422 def __init__(self, *args):
423 FlashScript.__init__(self, args[0])
424 if args[0].type == "nand":
425 self.ipq_nand = args[1]
426 elif args[0].type == "nor" or args[0].type == "norplusnand":
427 self.nand_pagesize = args[1]
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530428
429 def erase(self, offset, size):
430 """Generate code, to erase the specified partition."""
431
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530432 if self.flash_type != "emmc":
433 size = roundup(size, self.blocksize)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530434
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530435 if self.flash_type == "nand":
436 self.append("nand device 0 && nand erase 0x%08x 0x%08x" % (offset, size))
437 elif self.flash_type == "nor":
438 self.append("sf erase 0x%08x +0x%08x" % (offset, size))
439 elif self.flash_type == "emmc":
440 self.append("mmc erase 0x%08x %x" % (offset, size))
441
442 def nand_write(self, offset, part_size, img_size, spi_nand):
443 """Handle the NOR + NAND case
444 All binaries upto HLOS will go to NOR and Root FS will go to NAND
445 Assumed all nand page sizes are less than are equal to 8KB
446 """
447
448 if spi_nand == "true":
449 self.append("nand device 1 && nand erase 0x%08x 0x%08x" % (offset, part_size))
450 else:
451 self.append("nand device 0 && nand erase 0x%08x 0x%08x" % (offset, part_size))
452
453 if img_size > 0:
454 self.append("nand write $fileaddr 0x%08x 0x%08x" % (offset, img_size))
455
456 def write(self, offset, size):
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530457 """Generate code, to write to a partition."""
458
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530459 if self.flash_type == "nand":
460 if size > 0:
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530461 size = roundup(size, self.pagesize)
462 self.append("nand write $fileaddr 0x%08x 0x%08x" % (offset, size))
463
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530464 elif self.flash_type == "nor":
465 if size > 0:
466 self.append("sf write $fileaddr 0x%08x 0x%08x" % (offset, size))
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530467
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530468 elif self.flash_type == "emmc":
469 if size > 0:
470 size = roundup(size, self.blocksize)
471 blk_cnt = size / self.blocksize
472 self.append("mmc write $fileaddr 0x%08x %x" % (offset, blk_cnt))
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530473
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530474 def probe(self):
475 if self.flash_type == "nand":
476 pass
477 elif self.flash_type == "nor":
478 self.append("sf probe")
479 else:
480 pass
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +0530481
482 def switch_layout(self, layout):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530483 if self.flash_type == "nand":
484 self.append("ipq_nand %s" % layout)
485 else:
486 pass
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530487
488its_tmpl = Template("""
489/dts-v1/;
490
491/ {
492 description = "${desc}";
493 images {
494${images}
495 };
496};
497""")
498
499its_image_tmpl = Template("""
500 ${name} {
501 description = "${desc}";
502 data = /incbin/("./${fname}");
503 type = "${imtype}";
504 arch = "arm";
505 compression = "none";
506 hash@1 { algo = "crc32"; };
507 };
508""")
509
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530510def sha1(message):
511 """Returns SHA1 digest in hex format of the message."""
512
513 m = hashlib.sha1()
514 m.update(message)
515 return m.hexdigest()
516
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530517class Pack(object):
518 """Class to create a flashable, multi-image blob.
519
520 Combine multiple images present in a directory, and generate a
521 U-Boot script to flash the images.
522 """
523 # The maximum rootfs size is 64MB
524 norplusnand_rootfs_img_size = (64 * 1024 * 1024)
525
526 def __init__(self):
527 self.flinfo = None
528 self.images_dname = None
529 self.ipq_nand = None
530 self.partitions = {}
531
532 self.fconf_fname = None
533 self.scr_fname = None
534 self.its_fname = None
535 self.img_fname = None
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530536 self.emmc_page_size = 512
537 self.emmc_block_size = 512
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530538
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530539 def __get_machid(self, section):
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530540 """Get the machid for a section.
541
542 info -- ConfigParser object, containing image flashing info
543 section -- section to retreive the machid from
544 """
545 try:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530546 machid = int(section.find("./machid").text, 0)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530547 machid = "%x" % machid
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530548 except ValueError, e:
549 error("invalid value for machid, should be integer")
550
551 return machid
552
553 def __get_img_size(self, filename):
554 """Get the size of the image to be flashed
555
556 filaneme -- string, filename of the image to be flashed
557 """
558
559 if filename.lower() == "none":
560 return 0
561 try:
562 return getsize(os.path.join(self.images_dname, filename))
563 except OSError, e:
564 error("error getting image size '%s'" % filename, e)
565
566 def __get_part_info(self, partition):
567 """Return partition info for the specified partition.
568
569 partition -- string, partition name
570 """
571 try:
572 return self.partitions[partition]
573 except KeyError, e:
574 return None
575
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530576 def __gen_flash_script_cdt(self, entries, partition, flinfo, script):
577 global ARCH_NAME
578 for section in entries:
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530579
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530580 machid = int(section.find(".//machid").text, 0)
581 machid = "%x" % machid
582 board = section.find(".//board").text
583 spi_nand = section.find(".//spi_nand").text
584 if ARCH_NAME != "ipq806x":
585 try:
586 memory = section.find(".//memory").text
587 except AttributeError, e:
588 memory = "128M16"
589 filename = "cdt-" + board + "_" + memory + ".bin"
590 else:
591 filename = "cdt-" + board + ".bin"
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530592
593 img_size = self.__get_img_size(filename)
594 part_info = self.__get_part_info(partition)
595
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530596 section_label = partition.split(":")
597 if len(section_label) != 1:
598 section_conf = section_label[1]
599 else:
600 section_conf = section_label[0]
601
602 section_conf = section_conf.lower()
603
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530604 if self.flinfo.type == 'nand':
605 size = roundup(img_size, flinfo.pagesize)
606 tr = ' | tr \"\\000\" \"\\377\"'
607
608 if self.flinfo.type == 'emmc':
609 size = roundup(img_size, flinfo.blocksize)
610 tr = ''
611
612 if ((self.flinfo.type == 'nand' or self.flinfo.type == 'emmc') and (size != img_size)):
613 pad_size = size - img_size
614 filename_abs = os.path.join(self.images_dname, filename)
615 filename_abs_pad = filename_abs + ".padded"
616 cmd = 'cat %s > %s' % (filename_abs, filename_abs_pad)
617 ret = subprocess.call(cmd, shell=True)
618 if ret != 0:
619 error("failed to copy image")
620 cmd = 'dd if=/dev/zero count=1 bs=%s %s >> %s' % (pad_size, tr, filename_abs_pad)
621 cmd = '(' + cmd + ') 1>/dev/null 2>/dev/null'
622 ret = subprocess.call(cmd, shell=True)
623 if ret != 0:
624 error("failed to create padded image from script")
625
626 if self.flinfo.type != "emmc":
627 if part_info == None:
628 if self.flinfo.type == 'norplusnand':
629 if count > 2:
630 error("More than 2 NAND images for NOR+NAND is not allowed")
631 elif img_size > part_info.length:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530632 error("img size is larger than part. len in '%s'" % section_conf)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530633 else:
634 if part_info != None:
635 if (img_size > 0):
636 if img_size > (part_info.length * self.flinfo.blocksize):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530637 error("img size is larger than part. len in '%s'" % section_conf)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530638
639 if part_info == None and self.flinfo.type != 'norplusnand':
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530640 print "Flash type is norplusemmc"
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530641 continue
642
643 if machid:
644 script.start_if("machid", machid)
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530645 if ARCH_NAME != "ipq806x":
646 script.start_activity("Flashing ddr-%s_%s:" % ( board, memory ))
647 if img_size > 0:
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +0530648 filename_pad = filename + ".padded"
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530649 if ((self.flinfo.type == 'nand' or self.flinfo.type == 'emmc') and (size != img_size)):
650 script.imxtract("ddr-" + board + "_" + memory + "-" + sha1(filename_pad))
651 else:
652 script.imxtract("ddr-" + board + "_" + memory + "-" + sha1(filename))
653 """ script.imxtract("cdt-" + board + "_" + memory + ".bin-" + sha1(filename_pad))
654 else:
655 script.imxtract("cdt-" + board + "_" + memory + ".bin-" + sha1(filename)) """
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530656
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530657 else:
658 script.start_activity("Flashing ddr-%s:" % (board))
659 script.switch_layout("sbl")
660 if img_size > 0:
661 filename_pad = filename + ".padded"
662 if ((self.flinfo.type == 'nand' or self.flinfo.type == 'emmc') and (size != img_size)):
663 script.imxtract("ddr-" + board + "-" + sha1(filename_pad))
664 else:
665 script.imxtract("ddr-" + board + "-" + sha1(filename))
666 """ script.imxtract("cdt-" + board + ".bin-" + sha1(filename_pad))
667 else:
668 script.imxtract("cdt-" + board + ".bin-" + sha1(filename)) """
669
670 part_size = Pack.norplusnand_rootfs_img_size
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530671 if part_info == None:
672 if self.flinfo.type == 'norplusnand':
673 offset = count * Pack.norplusnand_rootfs_img_size
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530674 script.nand_write(offset, part_size, img_size, spi_nand)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530675 count = count + 1
676 else:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530677 if part_info.which_flash == 0:
678 offset = part_info.offset
679 script.erase(offset, part_info.length)
680 script.write(offset, img_size)
681 else:
682 offset = part_info.offset
683 script.nand_write(offset, part_info.length, img_size, spi_nand)
684
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530685 script.finish_activity()
686
687 if machid:
688 script.end_if()
689
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530690 def __gen_flash_script(self, script, flinfo, root):
691 """Generate the script to flash the images.
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530692
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530693 info -- ConfigParser object, containing image flashing info
694 script -- Script object, to append commands to
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530695 """
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530696 global MODE
697 global SRC_DIR
698 global ARCH_NAME
Aditya Kumar Patra Sb68f13e2017-03-08 14:07:23 +0530699
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530700 diff_files = ""
701 count = 0
Aditya Kumar Patra Sb68f13e2017-03-08 14:07:23 +0530702
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530703 if self.flash_type == "norplusemmc" and flinfo.type == "emmc":
704 srcDir_part = SRC_DIR + "/" + ARCH_NAME + "/flash_partition/" + flinfo.type + "-partition.xml"
705 else:
706 srcDir_part = SRC_DIR + "/" + ARCH_NAME + "/flash_partition/" + self.flash_type.lower() + "-partition.xml"
707
708 root_part = ET.parse(srcDir_part)
709 if self.flash_type != "emmc" and flinfo.type != "emmc":
710 parts = root_part.findall(".//partitions/partition")
711 elif self.flash_type != "emmc" and flinfo.type == "emmc":
712 parts = root_part.findall(".//physical_partition[@ref='norplusemmc']/partition")
713 else:
714 parts = root_part.findall(".//physical_partition[@ref='emmc']/partition")
715 if flinfo.type == "emmc":
716 parts_length = len(parts) + 2
717 else:
718 parts_length = len(parts)
719 entries = root.findall(".//data[@type='MACH_ID_BOARD_MAP']/entry")
720
721 first = False
722 section = None
723 part_index = 0
724
725 if flinfo.type == "emmc":
726 first = True
727
728 for index in range(parts_length):
729
730 if first:
731 if self.flash_type == "norplusemmc":
732 part_info = root.find(".//data[@type='NORPLUSEMMC_PARAMETER']")
733 else:
734 part_info = root.find(".//data[@type='EMMC_PARAMETER']")
735 part_fname = part_info.find(".//partition_mbn")
736 filename = part_fname.text
737 partition = "0:GPT"
738 first = False
739
740 elif index == (parts_length - 1) and flinfo.type == "emmc":
741 if self.flash_type == "norplusemmc":
742 part_info = root.find(".//data[@type='NORPLUSEMMC_PARAMETER']")
743 else:
744 part_info = root.find(".//data[@type='EMMC_PARAMETER']")
745 part_fname = part_info.find(".//partition_mbn_backup")
746 filename = part_fname.text
747 partition = "0:GPTBACKUP"
748
749 else:
750 section = parts[part_index]
751 part_index += 1
752 if flinfo.type != "emmc":
753 try:
754 filename = section[8].text
755 try:
756 if section[8].attrib['mode'] != MODE:
757 filename = section[9].text
758 else:
759 pass
760 except AttributeError, e:
761 pass
762 except KeyError, e:
763 pass
764 except IndexError, e:
765 if index == (parts_length - 1):
766 return
767 else:
768 continue
769 partition = section[0].text
770 else:
771 try:
772 diff_files = section.attrib['diff_files']
773 except KeyError, e:
774 try:
775 filename = section.attrib['filename']
776 partition = section.attrib['label']
777 if filename == "":
778 continue
779 except KeyError, e:
780 error("Error getting image info in section '%s'" % section.attrib['label'], e)
781
782 if diff_files == "true":
783 try:
784 filename = section.attrib['filename_' + MODE]
785 partition = section.attrib['label']
786 if filename == "":
787 continue
788 except KeyError, e:
789 error("Error getting image info in section '%s'" % section.attrib['label'], e)
790 diff_files = "" # Clear for next iteration
791
792 # Get machID
793 if partition != "0:CDT" and partition != "0:DDRCONFIG":
794 machid = None
795 else:
796 self.__gen_flash_script_cdt(entries, partition, flinfo, script)
Aditya Kumar Patra Sb68f13e2017-03-08 14:07:23 +0530797 continue
798
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530799 if ARCH_NAME == "ipq806x":
800 # Get Layout
801 try:
802 layout = section[9].text
803 except:
804 layout = None
805
806 if layout not in ("sbl", "linux", None):
807 error("invalid layout in '%s'" % section)
808
809 img_size = self.__get_img_size(filename)
810 part_info = self.__get_part_info(partition)
811
812 section_label = partition.split(":")
813 if len(section_label) != 1:
814 section_conf = section_label[1]
815 else:
816 section_conf = section_label[0]
817
818 section_conf = section_conf.lower()
819 spi_nand = False
820
821 if self.flinfo.type == 'nand':
822 size = roundup(img_size, flinfo.pagesize)
823 tr = ' | tr \"\\000\" \"\\377\"'
824
825 if self.flinfo.type == 'emmc':
826 size = roundup(img_size, flinfo.blocksize)
827 tr = ''
828
829 if ((self.flinfo.type == 'nand' or self.flinfo.type == 'emmc') and (size != img_size)):
830 pad_size = size - img_size
831 filename_abs = os.path.join(self.images_dname, filename)
832 filename_abs_pad = filename_abs + ".padded"
833 cmd = 'cat %s > %s' % (filename_abs, filename_abs_pad)
834 ret = subprocess.call(cmd, shell=True)
835 if ret != 0:
836 error("failed to copy image")
837 cmd = 'dd if=/dev/zero count=1 bs=%s %s >> %s' % (pad_size, tr, filename_abs_pad)
838 cmd = '(' + cmd + ') 1>/dev/null 2>/dev/null'
839 ret = subprocess.call(cmd, shell=True)
840 if ret != 0:
841 error("failed to create padded image from script")
842
843 if self.flinfo.type != "emmc":
844 if part_info == None:
845 if self.flinfo.type == 'norplusnand':
846 if count > 2:
847 error("More than 2 NAND images for NOR+NAND is not allowed")
848 elif img_size > part_info.length:
849 error("img size is larger than part. len in '%s'" % section_conf)
850 else:
851 if part_info != None:
852 if (img_size > 0):
853 if img_size > (part_info.length * self.flinfo.blocksize):
854 error("img size is larger than part. len in '%s'" % section_conf)
855
856 if part_info == None and self.flinfo.type != 'norplusnand':
857 print "Flash type is norplusemmc"
858 continue
859
860 if machid:
861 script.start_if("machid", machid)
862
863 if section_conf == "qsee":
864 section_conf = "tz"
865 elif section_conf == "appsbl":
866 section_conf = "u-boot"
867 elif section_conf == "rootfs" and flinfo.type != "nor" and self.flash_type != "norplusemmc":
868 section_conf = "ubi"
869
870 script.start_activity("Flashing %s:" % section_conf)
871
872 if ARCH_NAME == "ipq806x":
873 script.switch_layout(layout)
874 if img_size > 0:
875 filename_pad = filename + ".padded"
876 if ((self.flinfo.type == 'nand' or self.flinfo.type == 'emmc') and (size != img_size)):
877 script.imxtract(section_conf + "-" + sha1(filename_pad))
878 else:
879 script.imxtract(section_conf + "-" + sha1(filename))
880
881 part_size = Pack.norplusnand_rootfs_img_size
882 if part_info == None:
883 if self.flinfo.type == 'norplusnand':
884 offset = count * Pack.norplusnand_rootfs_img_size
885 img_size = Pack.norplusnand_rootfs_img_size
886 script.nand_write(offset, part_size, img_size, spi_nand)
887 count = count + 1
888 else:
889 if part_info.which_flash == 0:
890 offset = part_info.offset
891 script.erase(offset, part_info.length)
892 script.write(offset, img_size)
893 else:
894 offset = part_info.offset
895 script.nand_write(offset, part_info.length, img_size, spi_nand)
896
897 script.finish_activity()
898
899 if machid:
900 script.end_if()
901
902 def __gen_script_cdt(self, images, flinfo, root, section_conf, partition):
903 global ARCH_NAME
904
905 entries = root.findall(".//data[@type='MACH_ID_BOARD_MAP']/entry")
906
907 for section in entries:
908
909 board = section.find(".//board").text
910 if ARCH_NAME != "ipq806x":
911 try:
912 memory = section.find(".//memory").text
913 except AttributeError, e:
914 memory = "128M16"
915
916 filename = "cdt-" + board + "_" + memory + ".bin"
917 file_info = "ddr-" + board + "_" + memory
918 else:
919 filename = "cdt-" + board + ".bin"
920 file_info = "ddr-" + board
921
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +0530922 part_info = self.__get_part_info(partition)
923
Aditya Kumar Patra Sb68f13e2017-03-08 14:07:23 +0530924 if part_info == None and self.flinfo.type != 'norplusnand':
925 continue
926
927 if self.flinfo.type == 'nand':
928 img_size = self.__get_img_size(filename)
929 size = roundup(img_size, flinfo.pagesize)
930 if ( size != img_size ):
931 filename = filename + ".padded"
932 if self.flinfo.type == 'emmc':
933 img_size = self.__get_img_size(filename)
934 size = roundup(img_size, flinfo.blocksize)
935 if ( size != img_size ):
936 filename = filename + ".padded"
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530937 image_info = ImageInfo(file_info + "-" + sha1(filename),
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +0530938 filename, "firmware")
Aditya Kumar Patra Sb68f13e2017-03-08 14:07:23 +0530939 if filename.lower() != "none":
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530940 if image_info not in images:
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +0530941 images.append(image_info)
942
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530943 def __gen_script(self, script_fp, script, images, flinfo, root):
944 """Generate the script to flash the multi-image blob.
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +0530945
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530946 script_fp -- file object, to write script to
947 info_fp -- file object, to read flashing information from
948 script -- Script object, to append the commands to
949 images -- list of ImageInfo, appended to, based on images in config
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +0530950 """
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530951 global MODE
952 global SRC_DIR
953
954 diff_files = ""
955 self.__gen_flash_script(script, flinfo, root)
956 if (self.flash_type == "norplusemmc" and flinfo.type == "emmc") or (self.flash_type != "norplusemmc"):
957 if flinfo.type == "emmc":
958 script.start_activity("Flashing rootfs_data:")
959 part_info = self.partitions["rootfs_data"]
960 script.erase(part_info.offset, part_info.length)
961 script.finish_activity()
962 script.end()
963
964 if self.flash_type == "norplusemmc" and flinfo.type == "emmc":
965 srcDir_part = SRC_DIR + "/" + ARCH_NAME + "/flash_partition/" + flinfo.type + "-partition.xml"
966 else:
967 srcDir_part = SRC_DIR + "/" + ARCH_NAME + "/flash_partition/" + self.flash_type.lower() + "-partition.xml"
968 root_part = ET.parse(srcDir_part)
969 if self.flash_type != "emmc" and flinfo.type != "emmc":
970 parts = root_part.findall(".//partitions/partition")
971 elif self.flash_type != "emmc" and flinfo.type == "emmc":
972 parts = root_part.findall(".//physical_partition[@ref='norplusemmc']/partition")
973 else:
974 parts = root_part.findall(".//physical_partition[@ref='emmc']/partition")
975 if flinfo.type == "emmc":
976 parts_length = len(parts) + 2
977 else:
978 parts_length = len(parts)
979
980 first = False
981 section = None
982 part_index = 0
983
984 if flinfo.type == "emmc":
985 first = True
986
987 for index in range(parts_length):
988
989 if first:
990 if self.flash_type == "norplusemmc":
991 part_info = root.find(".//data[@type='NORPLUSEMMC_PARAMETER']")
992 else:
993 part_info = root.find(".//data[@type='EMMC_PARAMETER']")
994 part_fname = part_info.find(".//partition_mbn")
995 filename = part_fname.text
996 partition = "0:GPT"
997 first = False
998
999 elif index == (parts_length - 1) and flinfo.type == "emmc":
1000 if self.flash_type == "norplusemmc":
1001 part_info = root.find(".//data[@type='NORPLUSEMMC_PARAMETER']")
1002 else:
1003 part_info = root.find(".//data[@type='EMMC_PARAMETER']")
1004 part_fname = part_info.find(".//partition_mbn_backup")
1005 filename = part_fname.text
1006 partition = "0:GPTBACKUP"
1007
1008 else:
1009 section = parts[part_index]
1010 part_index += 1
1011 if flinfo.type != "emmc":
1012 try:
1013 filename = section[8].text
1014 try:
1015 if section[8].attrib['mode'] != MODE:
1016 filename = section[9].text
1017 except AttributeError, e:
1018 pass
1019 except KeyError, e:
1020 pass
1021 except IndexError, e:
1022 if index == (parts_length - 1):
1023 return
1024 else:
1025 continue
1026 partition = section[0].text
1027 else:
1028
1029 try:
1030 diff_files = section.attrib['diff_files']
1031 except KeyError, e:
1032 try:
1033 filename = section.attrib['filename']
1034 partition = section.attrib['label']
1035 if filename == "":
1036 continue
1037 except KeyError, e:
1038 error("Error getting image info in section '%s'" % section.attrib['label'], e)
1039
1040 if diff_files == "true":
1041 try:
1042 filename = section.attrib['filename_' + MODE]
1043 partition = section.attrib['label']
1044 if filename == "":
1045 continue
1046
1047 except KeyError, e:
1048 error("Error getting image info in section '%s'" % section.attrib['label'], e)
1049 diff_files = "" # Clear for next iteration
1050
1051 part_info = self.__get_part_info(partition)
1052
1053 section_label = partition.split(":")
1054 if len(section_label) != 1:
1055 section_conf = section_label[1]
1056 else:
1057 section_conf = section_label[0]
1058
1059 section_conf = section_conf.lower()
1060
1061 if section_conf == "cdt" or section_conf == "ddrconfig":
1062 self.__gen_script_cdt(images, flinfo, root, section_conf, partition)
1063 continue
1064
1065 if part_info == None and self.flinfo.type != 'norplusnand':
1066 continue
1067
1068 if self.flinfo.type == 'nand':
1069 img_size = self.__get_img_size(filename)
1070 size = roundup(img_size, flinfo.pagesize)
1071 if ( size != img_size ):
1072 filename = filename + ".padded"
1073 if self.flinfo.type == 'emmc':
1074 img_size = self.__get_img_size(filename)
1075 size = roundup(img_size, flinfo.blocksize)
1076 if ( size != img_size ):
1077 filename = filename + ".padded"
1078 if section_conf == "qsee":
1079 section_conf = "tz"
1080 elif section_conf == "appsbl":
1081 section_conf = "u-boot"
1082 elif section_conf == "rootfs" and flinfo.type != "nor" and self.flash_type != "norplusemmc":
1083 section_conf = "ubi"
1084 image_info = ImageInfo(section_conf + "-" + sha1(filename),
1085 filename, "firmware")
1086 if filename.lower() != "none":
1087 if image_info not in images:
1088 images.append(image_info)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301089
1090 def __mkimage(self, images):
1091 """Create the multi-image blob.
1092
1093 images -- list of ImageInfo, containing images to be part of the blob
1094 """
1095 try:
1096 its_fp = open(self.its_fname, "wb")
1097 except IOError, e:
1098 error("error opening its file '%s'" % self.its_fname, e)
1099
1100 desc = "Flashing %s %x %x"
1101 desc = desc % (self.flinfo.type, self.flinfo.pagesize,
1102 self.flinfo.blocksize)
1103
1104 image_data = []
1105 for (section, fname, imtype) in images:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301106 fname = fname.replace("\\", "\\\\")
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301107 subs = dict(name=section, desc=fname, fname=fname, imtype=imtype)
1108 image_data.append(its_image_tmpl.substitute(subs))
1109
1110 image_data = "".join(image_data)
1111 its_data = its_tmpl.substitute(desc=desc, images=image_data)
1112
1113 its_fp.write(its_data)
1114 its_fp.close()
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301115
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301116 try:
1117 cmd = ["mkimage", "-f", self.its_fname, self.img_fname]
1118 ret = subprocess.call(cmd)
1119 if ret != 0:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301120 print ret
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301121 error("failed to create u-boot image from script")
1122 except OSError, e:
1123 error("error executing mkimage", e)
1124
1125 def __create_fnames(self):
1126 """Populate the filenames."""
1127
1128 self.scr_fname = os.path.join(self.images_dname, "flash.scr")
1129 self.its_fname = os.path.join(self.images_dname, "flash.its")
1130
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301131 def __gen_board_script(self, flinfo, part_fname, images, root):
1132 global SRC_DIR
1133 global ARCH_NAME
1134
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301135 """Generate the flashing script for one board.
1136
1137 board_section -- string, board section in board config file
1138 machid -- string, board machine ID in hex format
1139 flinfo -- FlashInfo object, contains board specific flash params
1140 part_fname -- string, partition file specific to the board
1141 fconf_fname -- string, flash config file specific to the board
1142 images -- list of ImageInfo, append images used by the board here
1143 """
1144 script_fp = open(self.scr_fname, "a")
1145
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301146 if flinfo.type != "emmc":
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301147 flash_param = root.find(".//data[@type='NAND_PARAMETER']")
1148 pagesize = int(flash_param.find(".//page_size").text)
1149 pages_per_block = int(flash_param.find(".//pages_per_block").text)
1150 blocksize = pages_per_block * pagesize
1151 blocks_per_chip = int(flash_param.find(".//total_block").text)
1152 chipsize = blocks_per_chip * blocksize
1153
1154 srcDir_part = SRC_DIR + "/" + ARCH_NAME + "/flash_partition/" + flinfo.type + "-partition.xml"
1155 root_part = ET.parse(srcDir_part)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301156 mibib = MIBIB(part_fname, flinfo.pagesize, flinfo.blocksize,
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301157 flinfo.chipsize, blocksize, chipsize, root_part)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301158 self.partitions = mibib.get_parts()
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301159 if flinfo.type == "nand":
1160 script = Flash_Script(flinfo, self.ipq_nand)
1161 elif flinfo.type == "nor":
1162 script = Flash_Script(flinfo, pagesize)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301163 else:
1164 gpt = GPT(part_fname, flinfo.pagesize, flinfo.blocksize, flinfo.chipsize)
1165 self.partitions = gpt.get_parts()
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301166 script = Flash_Script(flinfo)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301167
1168 self.flinfo = flinfo
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301169
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301170 script.probe()
1171 self.__gen_script(script_fp, script, images, flinfo, root)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301172
1173 try:
1174 script_fp.write(script.dumps())
1175 except IOError, e:
1176 error("error writing to script '%s'" % script_fp.name, e)
1177
1178 script_fp.close()
1179
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301180 def __process_board_flash_emmc(self, ftype, images, root):
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301181 """Extract board info from config and generate the flash script.
1182
1183 ftype -- string, flash type 'emmc'
1184 board_section -- string, board section in config file
1185 machid -- string, board machine ID in hex format
1186 images -- list of ImageInfo, append images used by the board here
1187 """
1188
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301189 try:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301190 part_info = root.find(".//data[@type='" + self.flash_type.upper() + "_PARAMETER']")
1191 part_fname = part_info.find(".//partition_mbn")
1192 part_fname = part_fname.text
1193 part_fname = os.path.join(self.images_dname, part_fname)
1194 if ftype == "norplusemmc":
1195 part_info = root.find(".//data[@type='NORPLUSEMMC_PARAMETER']")
1196 pagesize = int(part_info.find(".//page_size_flash").text)
1197 part_info = root.find(".//data[@type='EMMC_PARAMETER']")
1198 else:
1199 pagesize = self.emmc_page_size
1200 blocksize = self.emmc_block_size
1201 chipsize = int(part_info.find(".//total_block").text)
1202 if ftype.lower() == "norplusemmc":
1203 ftype = "emmc"
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301204
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301205 except ValueError, e:
1206 error("invalid flash info in section '%s'" % board_section.find('machid').text, e)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301207
1208 flinfo = FlashInfo(ftype, pagesize, blocksize, chipsize)
1209
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301210 self.__gen_board_script(flinfo, part_fname, images, root)
1211
1212 def __process_board_flash(self, ftype, images, root):
1213 global SRC_DIR
1214 global ARCH_NAME
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301215
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301216 try:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301217 part_info = root.find(".//data[@type='" + ftype.upper() + "_PARAMETER']")
1218 part_file = SRC_DIR + "/" + ARCH_NAME + "/flash_partition/" + ftype + "-partition.xml"
1219 part_xml = ET.parse(part_file)
1220 partition = part_xml.find(".//partitions/partition[2]")
1221 part_fname = partition[8].text
1222 part_fname = os.path.join(self.images_dname, part_fname)
1223 pagesize = int(part_info.find(".//page_size").text)
1224 pages_per_block = int(part_info.find(".//pages_per_block").text)
1225 blocks_per_chip = int(part_info.find(".//total_block").text)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301226
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301227 if ftype == "norplusnand" or ftype == "norplusemmc":
1228 ftype = "nor"
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301229
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301230 except ValueError, e:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301231 error("invalid flash info in section '%s'" % board_section.find('machid').text, e)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301232
1233 blocksize = pages_per_block * pagesize
1234 chipsize = blocks_per_chip * blocksize
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301235
1236 flinfo = FlashInfo(ftype, pagesize, blocksize, chipsize)
1237
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301238 self.__gen_board_script(flinfo, part_fname, images, root)
1239
1240 def __process_board(self, images, root):
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301241
1242 try:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301243 if self.flash_type in [ "nand", "nor", "norplusnand" ]:
1244 self.__process_board_flash(self.flash_type, images, root)
1245 elif self.flash_type == "emmc":
1246 self.__process_board_flash_emmc(self.flash_type, images, root)
1247 elif self.flash_type == "norplusemmc":
1248 self.__process_board_flash("norplusemmc", images, root)
1249 self.__process_board_flash_emmc("norplusemmc", images, root)
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301250 except ValueError, e:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301251 error("error getting board info in section '%s'" % board_section.find('machid').text, e)
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301252
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301253 def main_bconf(self, flash_type, images_dname, out_fname, root):
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301254 """Start the packing process, using board config.
1255
1256 flash_type -- string, indicates flash type, 'nand' or 'nor' or 'emmc' or 'norplusnand'
1257 images_dname -- string, name of images directory
1258 out_fname -- string, output file path
1259 """
1260 self.flash_type = flash_type
1261 self.images_dname = images_dname
1262 self.img_fname = out_fname
1263
1264 self.__create_fnames()
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301265 try:
1266 os.unlink(self.scr_fname)
1267 except OSError, e:
1268 pass
1269
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301270 images = []
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301271 self.__process_board(images, root)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301272 images.insert(0, ImageInfo("script", "flash.scr", "script"))
1273 self.__mkimage(images)
1274
1275class UsageError(Exception):
1276 """Indicates error in command arguments."""
1277 pass
1278
1279class ArgParser(object):
1280 """Class to parse command-line arguments."""
1281
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301282 DEFAULT_TYPE = "nor,nand,norplusnand,emmc,norplusemmc"
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301283
1284 def __init__(self):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301285 self.flash_type = None
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301286 self.images_dname = None
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301287 self.out_dname = None
1288 self.scr_fname = None
1289 self.its_fname = None
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301290
1291 def parse(self, argv):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301292 global MODE
1293 global SRC_DIR
1294 global ARCH_NAME
1295
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301296 """Start the parsing process, and populate members with parsed value.
1297
1298 argv -- list of string, the command line arguments
1299 """
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301300
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301301 cdir = os.path.abspath(os.path.dirname(""))
1302 if len(sys.argv) > 1:
1303 try:
1304 opts, args = getopt(sys.argv[1:], "", ["arch=", "fltype=", "srcPath=", "inImage=", "outImage="])
1305 except GetoptError, e:
1306 raise UsageError(e.msg)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301307
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301308 for option, value in opts:
1309 if option == "--arch":
1310 ARCH_NAME = value
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301311
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301312 elif option == "--fltype":
1313 self.flash_type = value
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301314
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301315 elif option == "--srcPath":
1316 SRC_DIR = os.path.abspath(value)
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301317
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301318 elif option == "--inImage":
1319 self.images_dname = os.path.join(cdir, value)
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301320
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301321 elif option == "--outImage":
1322 self.out_dname = os.path.join(cdir, value)
1323
1324#Verify Arguments passed by user
1325
1326# Verify arch type
1327 if ARCH_NAME not in ["ipq40xx", "ipq806x", "ipq807x", "ipq807x_64"]:
1328 raise UsageError("Invalid arch type '%s'" % arch)
1329
1330 if ARCH_NAME == "ipq807x":
1331 MODE = "32"
1332 elif ARCH_NAME == "ipq807x_64":
1333 MODE = "64"
1334 ARCH_NAME = "ipq807x"
1335
1336# Set flash type to default type (nand) if not given by user
1337 if self.flash_type == None:
1338 self.flash_type = ArgParser.DEFAULT_TYPE
1339 for flash_type in self.flash_type.split(","):
1340 if flash_type not in [ "nand", "nor", "emmc", "norplusnand", "norplusemmc" ]:
1341 raise UsageError("invalid flash type '%s'" % flash_type)
1342
1343# Verify src Path
1344 if SRC_DIR == "":
1345 raise UsageError("Source Path is not provided")
1346
1347#Verify input image path
1348 if self.images_dname == None:
1349 raise UsageError("input images' Path is not provided")
1350
1351#Verify Output image path
1352 if self.out_dname == None:
1353 raise UsageError("Output Path is not provided")
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301354
1355 def usage(self, msg):
1356 """Print error message and command usage information.
1357
1358 msg -- string, the error message
1359 """
1360 print "pack: %s" % msg
1361 print
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301362 print "Usage:"
1363 print "python pack_hk.py [options] [Value] ..."
1364 print
1365 print "options:"
1366 print " --arch \tARCH_TYPE [ipq40xx/ipq806x/ipq807x/ipq807x_64]"
1367 print
1368 print " --fltype \tFlash Type [nor/nand/emmc/norplusnand/norplusemmc]"
1369 print " \t\tMultiple flashtypes can be passed by a comma separated string"
1370 print " \t\tDefault is all. i.e If \"--fltype\" is not passed image for all the flash-type will be created.\n"
1371 print " --srcPath \tPath to the directory containg the meta scripts and configs"
1372 print
1373 print " --inImage \tPath to the direcory containg binaries and images needed for singleimage"
1374 print
1375 print " --outImage \tPath to the directory where single image will be generated"
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301376 print
1377 print "Pack Version: %s" % version
1378
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301379def main():
1380 """Main script entry point.
1381
1382 Created to avoid polluting the global namespace.
1383 """
1384 try:
1385 parser = ArgParser()
1386 parser.parse(sys.argv)
1387 except UsageError, e:
1388 parser.usage(e.args[0])
1389 sys.exit(1)
1390
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301391 pack = Pack()
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301392
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301393 if not os.path.exists(parser.out_dname):
1394 os.makedirs(parser.out_dname)
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301395
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301396 config = SRC_DIR + "/" + ARCH_NAME + "/config.xml"
1397 root = ET.parse(config)
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301398
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301399# Format the output image name from Arch, flash type and mode
1400 for flash_type in parser.flash_type.split(","):
1401 if MODE == "64":
1402 parser.out_fname = flash_type + "-" + ARCH_NAME + "_" + MODE + "-single.img"
1403 else:
1404 parser.out_fname = flash_type + "-" + ARCH_NAME + "-single.img"
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301405
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301406 parser.out_fname = os.path.join(parser.out_dname, parser.out_fname)
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301407
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301408 pack.main_bconf(flash_type, parser.images_dname,
1409 parser.out_fname, root)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301410
1411if __name__ == "__main__":
1412 main()