blob: ba304deb3b1c97bff77adf7178d155fd969822aa [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 = ""
Saravanan Jaganathan7d086402017-09-22 15:35:01 +053085image_type = "all"
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +053086#
87# Python 2.6 and earlier did not have OrderedDict use the backport
88# from ordereddict package. If that is not available report error.
89#
90try:
91 from collections import OrderedDict
92except ImportError:
93 try:
94 from ordereddict import OrderedDict
95 except ImportError:
96 print "error: this script requires the 'ordereddict' class."
97 print "Try 'pip install --user ordereddict'"
98 print "Or 'easy_install --user ordereddict'"
99 sys.exit(1)
100
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530101def error(msg, ex=None):
102 """Print an error message and exit.
103
104 msg -- string, the message to print
105 ex -- exception, the associate exception, if any
106 """
107
108 sys.stderr.write("pack: %s" % msg)
109 if ex != None: sys.stderr.write(": %s" % str(ex))
110 sys.stderr.write("\n")
111 sys.exit(1)
112
113FlashInfo = namedtuple("FlashInfo", "type pagesize blocksize chipsize")
114ImageInfo = namedtuple("ProgInfo", "name filename type")
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530115PartInfo = namedtuple("PartInfo", "name offset length which_flash")
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530116
117def roundup(value, roundto):
118 """Return the next largest multiple of 'roundto'."""
119
120 return ((value + roundto - 1) // roundto) * roundto
121
122class GPT(object):
123 GPTheader = namedtuple("GPTheader", "signature revision header_size"
124 " crc32 current_lba backup_lba first_usable_lba"
125 " last_usable_lba disk_guid start_lba_part_entry"
126 " num_part_entry part_entry_size part_crc32")
127 GPT_SIGNATURE = 'EFI PART'
128 GPT_REVISION = '\x00\x00\x01\x00'
129 GPT_HEADER_SIZE = 0x5C
130 GPT_HEADER_FMT = "<8s4sLL4xQQQQ16sQLLL"
131
132 GPTtable = namedtuple("GPTtable", "part_type unique_guid first_lba"
133 " last_lba attribute_flag part_name")
134 GPT_TABLE_FMT = "<16s16sQQQ72s"
135
136 def __init__(self, filename, pagesize, blocksize, chipsize):
137 self.filename = filename
138 self.pagesize = pagesize
139 self.blocksize = blocksize
140 self.chipsize = chipsize
141 self.__partitions = OrderedDict()
142
143 def __validate_and_read_parts(self, part_fp):
144 """Validate the GPT and read the partition"""
145 part_fp.seek(self.blocksize, os.SEEK_SET)
146 gptheader_str = part_fp.read(struct.calcsize(GPT.GPT_HEADER_FMT))
147 gptheader = struct.unpack(GPT.GPT_HEADER_FMT, gptheader_str)
148 gptheader = GPT.GPTheader._make(gptheader)
149
150 if gptheader.signature != GPT.GPT_SIGNATURE:
151 error("Invalid signature")
152
153 if gptheader.revision != GPT.GPT_REVISION:
154 error("Unsupported GPT Revision")
155
156 if gptheader.header_size != GPT.GPT_HEADER_SIZE:
157 error("Invalid Header size")
158
159 # Adding GPT partition info. This has to be flashed first.
160 # GPT Header starts at LBA1 so (current_lba -1) will give the
161 # starting of primary GPT.
162 # blocksize will equal to gptheader.first_usuable_lba - current_lba + 1
163
164 name = "0:GPT"
165 block_start = gptheader.current_lba - 1
166 block_count = gptheader.first_usable_lba - gptheader.current_lba + 1
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530167 which_flash = 0
168 part_info = PartInfo(name, block_start, block_count, which_flash)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530169 self.__partitions[name] = part_info
170
171 part_fp.seek(2 * self.blocksize, os.SEEK_SET)
172
173 for i in range(gptheader.num_part_entry):
174 gpt_table_str = part_fp.read(struct.calcsize(GPT.GPT_TABLE_FMT))
175 gpt_table = struct.unpack(GPT.GPT_TABLE_FMT, gpt_table_str)
176 gpt_table = GPT.GPTtable._make(gpt_table)
177
178 block_start = gpt_table.first_lba
179 block_count = gpt_table.last_lba - gpt_table.first_lba + 1
180
181 part_name = gpt_table.part_name.strip(chr(0))
182 name = part_name.replace('\0','')
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530183 part_info = PartInfo(name, block_start, block_count, which_flash)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530184 self.__partitions[name] = part_info
185
186 # Adding the GPT Backup partition.
187 # GPT header backup_lba gives block number where the GPT backup header will be.
188 # GPT Backup header will start from offset of 32 blocks before
189 # the GPTheader.backup_lba. Backup GPT size is 33 blocks.
190 name = "0:GPTBACKUP"
191 block_start = gptheader.backup_lba - 32
192 block_count = 33
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530193 part_info = PartInfo(name, block_start, block_count, which_flash)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530194 self.__partitions[name] = part_info
195
196 def get_parts(self):
197 """Returns a list of partitions present in the GPT."""
198
199 try:
200 with open(self.filename, "r") as part_fp:
201 self.__validate_and_read_parts(part_fp)
202 except IOError, e:
203 error("error opening %s" % self.filename, e)
204
205 return self.__partitions
206
207class MIBIB(object):
208 Header = namedtuple("Header", "magic1 magic2 version age")
209 HEADER_FMT = "<LLLL"
210 HEADER_MAGIC1 = 0xFE569FAC
211 HEADER_MAGIC2 = 0xCD7F127A
212 HEADER_VERSION = 4
213
214 Table = namedtuple("Table", "magic1 magic2 version numparts")
215 TABLE_FMT = "<LLLL"
216 TABLE_MAGIC1 = 0x55EE73AA
217 TABLE_MAGIC2 = 0xE35EBDDB
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530218 TABLE_VERSION_IPQ806X = 3
219 TABLE_VERSION_OTHERS = 4
220
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530221
222 Entry = namedtuple("Entry", "name offset length"
223 " attr1 attr2 attr3 which_flash")
224 ENTRY_FMT = "<16sLLBBBB"
225
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530226 def __init__(self, filename, pagesize, blocksize, chipsize, nand_blocksize, nand_chipsize, root_part):
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530227 self.filename = filename
228 self.pagesize = pagesize
229 self.blocksize = blocksize
230 self.chipsize = chipsize
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530231 self.nand_blocksize = nand_blocksize
232 self.nand_chipsize = nand_chipsize
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530233 self.__partitions = OrderedDict()
234
235 def __validate(self, part_fp):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530236 """Validate the MIBIB by checking for magic bytes."""
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530237
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530238 mheader_str = part_fp.read(struct.calcsize(MIBIB.HEADER_FMT))
239 mheader = struct.unpack(MIBIB.HEADER_FMT, mheader_str)
240 mheader = MIBIB.Header._make(mheader)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530241
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530242 if (mheader.magic1 != MIBIB.HEADER_MAGIC1
243 or mheader.magic2 != MIBIB.HEADER_MAGIC2):
244 """ mheader.magic1 = MIBIB.HEADER_MAGIC1
245 mheader.magic2 = MIBIB.HEADER_MAGIC2 """
246 error("invalid partition table, magic byte not present")
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530247
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530248 if mheader.version != MIBIB.HEADER_VERSION:
249 error("unsupport mibib version")
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530250
251 def __read_parts(self, part_fp):
252 """Read the partitions from the MIBIB."""
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530253 global ARCH_NAME
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530254 part_fp.seek(self.pagesize, os.SEEK_SET)
255 mtable_str = part_fp.read(struct.calcsize(MIBIB.TABLE_FMT))
256 mtable = struct.unpack(MIBIB.TABLE_FMT, mtable_str)
257 mtable = MIBIB.Table._make(mtable)
258
259 if (mtable.magic1 != MIBIB.TABLE_MAGIC1
260 or mtable.magic2 != MIBIB.TABLE_MAGIC2):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530261 """ mtable.magic1 = MIBIB.TABLE_MAGIC1
262 mtable.magic2 = MIBIB.TABLE_MAGIC2 """
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530263 error("invalid sys part. table, magic byte not present")
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530264 if ARCH_NAME == "ipq806x":
265 if mtable.version != MIBIB.TABLE_VERSION_IPQ806X:
266 error("unsupported partition table version")
267 else:
268 if mtable.version != MIBIB.TABLE_VERSION_OTHERS:
269 error("unsupported partition table version")
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530270
271 for i in range(mtable.numparts):
272 mentry_str = part_fp.read(struct.calcsize(MIBIB.ENTRY_FMT))
273 mentry = struct.unpack(MIBIB.ENTRY_FMT, mentry_str)
274 mentry = MIBIB.Entry._make(mentry)
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530275 self.flash_flag = self.blocksize
276 self.chip_flag = self.chipsize
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530277
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530278 if mentry.which_flash != 0:
279 self.flash_flag = self.nand_blocksize
280 self.chip_flag = self.nand_chipsize
281
282 byte_offset = mentry.offset * self.flash_flag
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530283
284 if mentry.length == 0xFFFFFFFF:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530285 byte_length = self.chip_flag - byte_offset
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530286 else:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530287 byte_length = mentry.length * self.flash_flag
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530288
289 part_name = mentry.name.strip(chr(0))
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530290 part_info = PartInfo(part_name, byte_offset, byte_length, mentry.which_flash)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530291 self.__partitions[part_name] = part_info
292
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530293 def get_parts(self):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530294 """Returns a list of partitions present in the MIBIB. CE """
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530295
296 try:
297 with open(self.filename, "r") as part_fp:
298 self.__validate(part_fp)
299 self.__read_parts(part_fp)
300 except IOError, e:
301 error("error opening %s" % self.filename, e)
302
303 return self.__partitions
304
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530305class FlashScript(object):
306 """Base class for creating flash scripts."""
307
308 def __init__(self, flinfo):
309 self.pagesize = flinfo.pagesize
310 self.blocksize = flinfo.blocksize
311 self.script = []
312 self.parts = []
313 self.curr_stdout = "serial"
314 self.activity = None
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530315 self.flash_type = flinfo.type
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530316
317 self.script.append('if test "x$verbose" = "x"; then\n')
318 self.script.append("failedmsg='[failed]'\n")
319 self.script.append('else\n')
320 self.script.append("failedmsg='%s Failed'\n" % ("#" * 40))
321 self.script.append('fi\n')
322
323 def append(self, cmd, fatal=True):
324 """Add a command to the script.
325
326 Add additional code, to terminate on error. This can be
327 supressed by passing 'fatal' as False.
328 """
329
330 if fatal:
Pavithra Palanisamy77ed38c2018-02-21 12:32:59 +0530331 """Check cmd strings to display reason for failure."""
332
333 if "imxtract" in cmd:
334 self.script.append("failreason='error: failed on image extraction'\n")
335 elif "erase" in cmd:
336 self.script.append("failreason='error: failed on partition erase'\n")
337 elif "write" in cmd:
338 self.script.append("failreason='error: failed on partition write'\n")
339 else:
340 pass
341
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530342 self.script.append(cmd
343 + ' || setenv stdout serial'
344 + ' && echo "$failedmsg"'
Pavithra Palanisamy77ed38c2018-02-21 12:32:59 +0530345 + ' && echo "$failreason"'
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530346 + ' && exit 1\n')
347 else:
348 self.script.append(cmd + "\n")
349
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530350 def dumps(self):
351 """Return the created script as a string."""
352 return "".join(self.script)
353
354 def redirect(self, dev):
355 """Generate code, to redirect command output to a device."""
356
357 if self.curr_stdout == dev:
358 return
359
360 self.append("setenv stdout %s" % dev, fatal=False)
361 self.curr_stdout = dev
362
363 def start_activity(self, activity):
364 """Generate code, to indicate start of an activity."""
365
366 self.script.append('if test "x$verbose" = "x"; then\n')
367 self.echo("'%-40.40s'" % activity, nl=False)
368 self.script.append('else\n')
369 self.echo("'%s %s Started'" % ("#" * 40, activity), verbose=True)
370 self.script.append('fi\n')
371 self.activity = activity
372
373 def finish_activity(self):
374 """Generate code, to indicate end of an activity."""
375
376 self.script.append('if test "x$verbose" = "x"; then\n')
377 self.echo("'[ done ]'")
378 self.redirect("serial")
379 self.script.append('else\n')
380 self.echo("'%s %s Done'" % ("#" * 40, self.activity), verbose=True)
381 self.script.append('fi\n')
382
383 def imxtract(self, part):
384 """Generate code, to extract image location, from a multi-image blob.
385
386 part -- string, name of the sub-image
387
388 Sets the $fileaddr environment variable, to point to the
389 location of the sub-image.
390 """
391
392 self.append("imxtract $imgaddr %s" % part)
393
394 def echo(self, msg, nl=True, verbose=False):
395 """Generate code, to print a message.
396
397 nl -- bool, indicates whether newline is to be printed
398 verbose -- bool, indicates whether printing in verbose mode
399 """
400
401 if not verbose:
402 self.redirect("serial")
403
404 if nl:
405 self.append("echo %s" % msg, fatal=False)
406 else:
407 self.append("echo %s%s" % (r"\\c", msg), fatal=False)
408
409 if not verbose:
410 self.redirect("nulldev")
411
412 def end(self):
413 """Generate code, to indicate successful completion of script."""
414
415 self.append("exit 0\n", fatal=False)
416
417 def start_if(self, var, value):
418 """Generate code, to check an environment variable.
419
420 var -- string, variable to check
421 value -- string, the value to compare with
422 """
423
424 self.append('if test "$%s" = "%s"; then\n' % (var, value),
425 fatal=False)
426
427 def end_if(self):
428 """Generate code, to end if statement."""
429
430 self.append('fi\n', fatal=False)
431
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530432class Flash_Script(FlashScript):
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530433 """Class for creating NAND flash scripts."""
434
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530435 def __init__(self, *args):
436 FlashScript.__init__(self, args[0])
437 if args[0].type == "nand":
438 self.ipq_nand = args[1]
439 elif args[0].type == "nor" or args[0].type == "norplusnand":
440 self.nand_pagesize = args[1]
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530441
442 def erase(self, offset, size):
443 """Generate code, to erase the specified partition."""
444
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530445 if self.flash_type != "emmc":
446 size = roundup(size, self.blocksize)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530447
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530448 if self.flash_type == "nand":
449 self.append("nand device 0 && nand erase 0x%08x 0x%08x" % (offset, size))
450 elif self.flash_type == "nor":
451 self.append("sf erase 0x%08x +0x%08x" % (offset, size))
452 elif self.flash_type == "emmc":
453 self.append("mmc erase 0x%08x %x" % (offset, size))
454
455 def nand_write(self, offset, part_size, img_size, spi_nand):
456 """Handle the NOR + NAND case
457 All binaries upto HLOS will go to NOR and Root FS will go to NAND
458 Assumed all nand page sizes are less than are equal to 8KB
459 """
460
461 if spi_nand == "true":
462 self.append("nand device 1 && nand erase 0x%08x 0x%08x" % (offset, part_size))
463 else:
464 self.append("nand device 0 && nand erase 0x%08x 0x%08x" % (offset, part_size))
465
466 if img_size > 0:
467 self.append("nand write $fileaddr 0x%08x 0x%08x" % (offset, img_size))
468
469 def write(self, offset, size):
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530470 """Generate code, to write to a partition."""
471
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530472 if self.flash_type == "nand":
473 if size > 0:
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530474 size = roundup(size, self.pagesize)
475 self.append("nand write $fileaddr 0x%08x 0x%08x" % (offset, size))
476
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530477 elif self.flash_type == "nor":
478 if size > 0:
479 self.append("sf write $fileaddr 0x%08x 0x%08x" % (offset, size))
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530480
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530481 elif self.flash_type == "emmc":
482 if size > 0:
483 size = roundup(size, self.blocksize)
484 blk_cnt = size / self.blocksize
485 self.append("mmc write $fileaddr 0x%08x %x" % (offset, blk_cnt))
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530486
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530487 def probe(self):
488 if self.flash_type == "nand":
489 pass
490 elif self.flash_type == "nor":
491 self.append("sf probe")
492 else:
493 pass
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +0530494
495 def switch_layout(self, layout):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530496 if self.flash_type == "nand":
497 self.append("ipq_nand %s" % layout)
498 else:
499 pass
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530500
501its_tmpl = Template("""
502/dts-v1/;
503
504/ {
505 description = "${desc}";
506 images {
507${images}
508 };
509};
510""")
511
512its_image_tmpl = Template("""
513 ${name} {
514 description = "${desc}";
515 data = /incbin/("./${fname}");
516 type = "${imtype}";
517 arch = "arm";
518 compression = "none";
519 hash@1 { algo = "crc32"; };
520 };
521""")
522
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530523def sha1(message):
524 """Returns SHA1 digest in hex format of the message."""
525
526 m = hashlib.sha1()
527 m.update(message)
528 return m.hexdigest()
529
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530530class Pack(object):
531 """Class to create a flashable, multi-image blob.
532
533 Combine multiple images present in a directory, and generate a
534 U-Boot script to flash the images.
535 """
536 # The maximum rootfs size is 64MB
537 norplusnand_rootfs_img_size = (64 * 1024 * 1024)
538
539 def __init__(self):
540 self.flinfo = None
541 self.images_dname = None
542 self.ipq_nand = None
543 self.partitions = {}
544
545 self.fconf_fname = None
546 self.scr_fname = None
547 self.its_fname = None
548 self.img_fname = None
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530549 self.emmc_page_size = 512
550 self.emmc_block_size = 512
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530551
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530552 def __get_machid(self, section):
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530553 """Get the machid for a section.
554
555 info -- ConfigParser object, containing image flashing info
556 section -- section to retreive the machid from
557 """
558 try:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530559 machid = int(section.find("./machid").text, 0)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530560 machid = "%x" % machid
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530561 except ValueError, e:
562 error("invalid value for machid, should be integer")
563
564 return machid
565
566 def __get_img_size(self, filename):
567 """Get the size of the image to be flashed
568
569 filaneme -- string, filename of the image to be flashed
570 """
571
572 if filename.lower() == "none":
573 return 0
574 try:
575 return getsize(os.path.join(self.images_dname, filename))
576 except OSError, e:
577 error("error getting image size '%s'" % filename, e)
578
579 def __get_part_info(self, partition):
580 """Return partition info for the specified partition.
581
582 partition -- string, partition name
583 """
584 try:
585 return self.partitions[partition]
586 except KeyError, e:
587 return None
588
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530589 def __gen_flash_script_cdt(self, entries, partition, flinfo, script):
590 global ARCH_NAME
591 for section in entries:
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530592
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530593 machid = int(section.find(".//machid").text, 0)
594 machid = "%x" % machid
595 board = section.find(".//board").text
596 spi_nand = section.find(".//spi_nand").text
597 if ARCH_NAME != "ipq806x":
598 try:
599 memory = section.find(".//memory").text
600 except AttributeError, e:
601 memory = "128M16"
602 filename = "cdt-" + board + "_" + memory + ".bin"
603 else:
604 filename = "cdt-" + board + ".bin"
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530605
606 img_size = self.__get_img_size(filename)
607 part_info = self.__get_part_info(partition)
608
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530609 section_label = partition.split(":")
610 if len(section_label) != 1:
611 section_conf = section_label[1]
612 else:
613 section_conf = section_label[0]
614
615 section_conf = section_conf.lower()
616
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530617 if self.flinfo.type == 'nand':
618 size = roundup(img_size, flinfo.pagesize)
619 tr = ' | tr \"\\000\" \"\\377\"'
620
621 if self.flinfo.type == 'emmc':
622 size = roundup(img_size, flinfo.blocksize)
623 tr = ''
624
625 if ((self.flinfo.type == 'nand' or self.flinfo.type == 'emmc') and (size != img_size)):
626 pad_size = size - img_size
627 filename_abs = os.path.join(self.images_dname, filename)
628 filename_abs_pad = filename_abs + ".padded"
629 cmd = 'cat %s > %s' % (filename_abs, filename_abs_pad)
630 ret = subprocess.call(cmd, shell=True)
631 if ret != 0:
632 error("failed to copy image")
633 cmd = 'dd if=/dev/zero count=1 bs=%s %s >> %s' % (pad_size, tr, filename_abs_pad)
634 cmd = '(' + cmd + ') 1>/dev/null 2>/dev/null'
635 ret = subprocess.call(cmd, shell=True)
636 if ret != 0:
637 error("failed to create padded image from script")
638
639 if self.flinfo.type != "emmc":
640 if part_info == None:
641 if self.flinfo.type == 'norplusnand':
642 if count > 2:
643 error("More than 2 NAND images for NOR+NAND is not allowed")
644 elif img_size > part_info.length:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530645 error("img size is larger than part. len in '%s'" % section_conf)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530646 else:
647 if part_info != None:
648 if (img_size > 0):
649 if img_size > (part_info.length * self.flinfo.blocksize):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530650 error("img size is larger than part. len in '%s'" % section_conf)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530651
652 if part_info == None and self.flinfo.type != 'norplusnand':
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530653 print "Flash type is norplusemmc"
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530654 continue
655
656 if machid:
657 script.start_if("machid", machid)
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530658 if ARCH_NAME != "ipq806x":
659 script.start_activity("Flashing ddr-%s_%s:" % ( board, memory ))
660 if img_size > 0:
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +0530661 filename_pad = filename + ".padded"
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530662 if ((self.flinfo.type == 'nand' or self.flinfo.type == 'emmc') and (size != img_size)):
663 script.imxtract("ddr-" + board + "_" + memory + "-" + sha1(filename_pad))
664 else:
665 script.imxtract("ddr-" + board + "_" + memory + "-" + sha1(filename))
666 """ script.imxtract("cdt-" + board + "_" + memory + ".bin-" + sha1(filename_pad))
667 else:
668 script.imxtract("cdt-" + board + "_" + memory + ".bin-" + sha1(filename)) """
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530669
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530670 else:
671 script.start_activity("Flashing ddr-%s:" % (board))
672 script.switch_layout("sbl")
673 if img_size > 0:
674 filename_pad = filename + ".padded"
675 if ((self.flinfo.type == 'nand' or self.flinfo.type == 'emmc') and (size != img_size)):
676 script.imxtract("ddr-" + board + "-" + sha1(filename_pad))
677 else:
678 script.imxtract("ddr-" + board + "-" + sha1(filename))
679 """ script.imxtract("cdt-" + board + ".bin-" + sha1(filename_pad))
680 else:
681 script.imxtract("cdt-" + board + ".bin-" + sha1(filename)) """
682
683 part_size = Pack.norplusnand_rootfs_img_size
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530684 if part_info == None:
685 if self.flinfo.type == 'norplusnand':
686 offset = count * Pack.norplusnand_rootfs_img_size
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530687 script.nand_write(offset, part_size, img_size, spi_nand)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530688 count = count + 1
689 else:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530690 if part_info.which_flash == 0:
691 offset = part_info.offset
692 script.erase(offset, part_info.length)
693 script.write(offset, img_size)
694 else:
695 offset = part_info.offset
696 script.nand_write(offset, part_info.length, img_size, spi_nand)
697
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530698 script.finish_activity()
699
700 if machid:
701 script.end_if()
702
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530703 def __gen_flash_script(self, script, flinfo, root):
704 """Generate the script to flash the images.
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530705
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530706 info -- ConfigParser object, containing image flashing info
707 script -- Script object, to append commands to
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +0530708 """
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530709 global MODE
710 global SRC_DIR
711 global ARCH_NAME
Aditya Kumar Patra Sb68f13e2017-03-08 14:07:23 +0530712
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530713 diff_files = ""
714 count = 0
Aditya Kumar Patra Sb68f13e2017-03-08 14:07:23 +0530715
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530716 if self.flash_type == "norplusemmc" and flinfo.type == "emmc":
717 srcDir_part = SRC_DIR + "/" + ARCH_NAME + "/flash_partition/" + flinfo.type + "-partition.xml"
718 else:
719 srcDir_part = SRC_DIR + "/" + ARCH_NAME + "/flash_partition/" + self.flash_type.lower() + "-partition.xml"
720
721 root_part = ET.parse(srcDir_part)
722 if self.flash_type != "emmc" and flinfo.type != "emmc":
723 parts = root_part.findall(".//partitions/partition")
724 elif self.flash_type != "emmc" and flinfo.type == "emmc":
725 parts = root_part.findall(".//physical_partition[@ref='norplusemmc']/partition")
726 else:
727 parts = root_part.findall(".//physical_partition[@ref='emmc']/partition")
728 if flinfo.type == "emmc":
729 parts_length = len(parts) + 2
730 else:
731 parts_length = len(parts)
732 entries = root.findall(".//data[@type='MACH_ID_BOARD_MAP']/entry")
733
734 first = False
735 section = None
736 part_index = 0
737
738 if flinfo.type == "emmc":
739 first = True
740
741 for index in range(parts_length):
742
743 if first:
744 if self.flash_type == "norplusemmc":
745 part_info = root.find(".//data[@type='NORPLUSEMMC_PARAMETER']")
746 else:
747 part_info = root.find(".//data[@type='EMMC_PARAMETER']")
748 part_fname = part_info.find(".//partition_mbn")
749 filename = part_fname.text
750 partition = "0:GPT"
751 first = False
752
753 elif index == (parts_length - 1) and flinfo.type == "emmc":
754 if self.flash_type == "norplusemmc":
755 part_info = root.find(".//data[@type='NORPLUSEMMC_PARAMETER']")
756 else:
757 part_info = root.find(".//data[@type='EMMC_PARAMETER']")
758 part_fname = part_info.find(".//partition_mbn_backup")
759 filename = part_fname.text
760 partition = "0:GPTBACKUP"
761
762 else:
763 section = parts[part_index]
764 part_index += 1
765 if flinfo.type != "emmc":
766 try:
Saravanan Jaganathan7d086402017-09-22 15:35:01 +0530767 if image_type == "all" or section[8].attrib['image_type'] == image_type:
768 filename = section[8].text
769 try:
770 if section[8].attrib['mode'] != MODE:
771 filename = section[9].text
772 else:
773 pass
774 except AttributeError, e:
775 pass
776 except KeyError, e:
777 pass
778 else:
779 continue
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530780 except IndexError, e:
781 if index == (parts_length - 1):
782 return
783 else:
784 continue
Saravanan Jaganathan7d086402017-09-22 15:35:01 +0530785 except KeyError, e:
786 continue
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530787 partition = section[0].text
788 else:
789 try:
790 diff_files = section.attrib['diff_files']
791 except KeyError, e:
792 try:
Saravanan Jaganathan7d086402017-09-22 15:35:01 +0530793 if image_type == "all" or section.attrib['image_type'] == image_type:
794 filename = section.attrib['filename']
795 partition = section.attrib['label']
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530796 if filename == "":
797 continue
798 except KeyError, e:
Saravanan Jaganathan7d086402017-09-22 15:35:01 +0530799 print "Skipping partition '%s'" % section.attrib['label']
800 pass
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530801
802 if diff_files == "true":
803 try:
Saravanan Jaganathan7d086402017-09-22 15:35:01 +0530804 if image_type == "all" or section.attrib['image_type'] == image_type:
805 filename = section.attrib['filename_' + MODE]
806 partition = section.attrib['label']
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530807 if filename == "":
808 continue
809 except KeyError, e:
Saravanan Jaganathan7d086402017-09-22 15:35:01 +0530810 print "Skipping partition '%s'" % section.attrib['label']
811 pass
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530812 diff_files = "" # Clear for next iteration
813
814 # Get machID
815 if partition != "0:CDT" and partition != "0:DDRCONFIG":
816 machid = None
817 else:
Saravanan Jaganathan7d086402017-09-22 15:35:01 +0530818 try:
819 if image_type == "all" or section.attrib['image_type'] == image_type:
820 self.__gen_flash_script_cdt(entries, partition, flinfo, script)
821 continue
822 except KeyError, e:
823 continue
Aditya Kumar Patra Sb68f13e2017-03-08 14:07:23 +0530824
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530825 if ARCH_NAME == "ipq806x":
826 # Get Layout
827 try:
828 layout = section[9].text
829 except:
830 layout = None
831
832 if layout not in ("sbl", "linux", None):
833 error("invalid layout in '%s'" % section)
834
835 img_size = self.__get_img_size(filename)
836 part_info = self.__get_part_info(partition)
837
838 section_label = partition.split(":")
839 if len(section_label) != 1:
840 section_conf = section_label[1]
841 else:
842 section_conf = section_label[0]
843
844 section_conf = section_conf.lower()
845 spi_nand = False
846
847 if self.flinfo.type == 'nand':
848 size = roundup(img_size, flinfo.pagesize)
849 tr = ' | tr \"\\000\" \"\\377\"'
850
851 if self.flinfo.type == 'emmc':
852 size = roundup(img_size, flinfo.blocksize)
853 tr = ''
854
855 if ((self.flinfo.type == 'nand' or self.flinfo.type == 'emmc') and (size != img_size)):
856 pad_size = size - img_size
857 filename_abs = os.path.join(self.images_dname, filename)
858 filename_abs_pad = filename_abs + ".padded"
859 cmd = 'cat %s > %s' % (filename_abs, filename_abs_pad)
860 ret = subprocess.call(cmd, shell=True)
861 if ret != 0:
862 error("failed to copy image")
863 cmd = 'dd if=/dev/zero count=1 bs=%s %s >> %s' % (pad_size, tr, filename_abs_pad)
864 cmd = '(' + cmd + ') 1>/dev/null 2>/dev/null'
865 ret = subprocess.call(cmd, shell=True)
866 if ret != 0:
867 error("failed to create padded image from script")
868
869 if self.flinfo.type != "emmc":
870 if part_info == None:
871 if self.flinfo.type == 'norplusnand':
872 if count > 2:
873 error("More than 2 NAND images for NOR+NAND is not allowed")
874 elif img_size > part_info.length:
875 error("img size is larger than part. len in '%s'" % section_conf)
876 else:
877 if part_info != None:
878 if (img_size > 0):
879 if img_size > (part_info.length * self.flinfo.blocksize):
880 error("img size is larger than part. len in '%s'" % section_conf)
881
882 if part_info == None and self.flinfo.type != 'norplusnand':
883 print "Flash type is norplusemmc"
884 continue
885
886 if machid:
887 script.start_if("machid", machid)
888
889 if section_conf == "qsee":
890 section_conf = "tz"
891 elif section_conf == "appsbl":
892 section_conf = "u-boot"
Aditya Kumar Patra S75bf44b2017-07-12 12:07:04 +0530893 elif section_conf == "rootfs" and (self.flash_type == "nand" or self.flash_type == "norplusnand"):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530894 section_conf = "ubi"
Venkat Raju Sana2b68fba2017-12-06 17:46:47 -0800895 elif section_conf == "wififw" and (self.flash_type == "nand" or self.flash_type == "norplusnand"):
896 section_conf = "wififw_ubi"
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530897
898 script.start_activity("Flashing %s:" % section_conf)
899
900 if ARCH_NAME == "ipq806x":
901 script.switch_layout(layout)
902 if img_size > 0:
903 filename_pad = filename + ".padded"
904 if ((self.flinfo.type == 'nand' or self.flinfo.type == 'emmc') and (size != img_size)):
905 script.imxtract(section_conf + "-" + sha1(filename_pad))
906 else:
907 script.imxtract(section_conf + "-" + sha1(filename))
908
909 part_size = Pack.norplusnand_rootfs_img_size
910 if part_info == None:
911 if self.flinfo.type == 'norplusnand':
912 offset = count * Pack.norplusnand_rootfs_img_size
913 img_size = Pack.norplusnand_rootfs_img_size
914 script.nand_write(offset, part_size, img_size, spi_nand)
915 count = count + 1
916 else:
917 if part_info.which_flash == 0:
918 offset = part_info.offset
919 script.erase(offset, part_info.length)
920 script.write(offset, img_size)
921 else:
922 offset = part_info.offset
923 script.nand_write(offset, part_info.length, img_size, spi_nand)
924
925 script.finish_activity()
926
927 if machid:
928 script.end_if()
929
930 def __gen_script_cdt(self, images, flinfo, root, section_conf, partition):
931 global ARCH_NAME
932
933 entries = root.findall(".//data[@type='MACH_ID_BOARD_MAP']/entry")
934
935 for section in entries:
936
937 board = section.find(".//board").text
938 if ARCH_NAME != "ipq806x":
939 try:
940 memory = section.find(".//memory").text
941 except AttributeError, e:
942 memory = "128M16"
943
944 filename = "cdt-" + board + "_" + memory + ".bin"
945 file_info = "ddr-" + board + "_" + memory
946 else:
947 filename = "cdt-" + board + ".bin"
948 file_info = "ddr-" + board
949
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +0530950 part_info = self.__get_part_info(partition)
951
Aditya Kumar Patra Sb68f13e2017-03-08 14:07:23 +0530952 if part_info == None and self.flinfo.type != 'norplusnand':
953 continue
954
955 if self.flinfo.type == 'nand':
956 img_size = self.__get_img_size(filename)
957 size = roundup(img_size, flinfo.pagesize)
958 if ( size != img_size ):
959 filename = filename + ".padded"
960 if self.flinfo.type == 'emmc':
961 img_size = self.__get_img_size(filename)
962 size = roundup(img_size, flinfo.blocksize)
963 if ( size != img_size ):
964 filename = filename + ".padded"
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530965 image_info = ImageInfo(file_info + "-" + sha1(filename),
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +0530966 filename, "firmware")
Aditya Kumar Patra Sb68f13e2017-03-08 14:07:23 +0530967 if filename.lower() != "none":
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530968 if image_info not in images:
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +0530969 images.append(image_info)
970
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530971 def __gen_script(self, script_fp, script, images, flinfo, root):
972 """Generate the script to flash the multi-image blob.
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +0530973
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530974 script_fp -- file object, to write script to
975 info_fp -- file object, to read flashing information from
976 script -- Script object, to append the commands to
977 images -- list of ImageInfo, appended to, based on images in config
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +0530978 """
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +0530979 global MODE
980 global SRC_DIR
981
982 diff_files = ""
983 self.__gen_flash_script(script, flinfo, root)
984 if (self.flash_type == "norplusemmc" and flinfo.type == "emmc") or (self.flash_type != "norplusemmc"):
985 if flinfo.type == "emmc":
986 script.start_activity("Flashing rootfs_data:")
987 part_info = self.partitions["rootfs_data"]
988 script.erase(part_info.offset, part_info.length)
989 script.finish_activity()
990 script.end()
991
992 if self.flash_type == "norplusemmc" and flinfo.type == "emmc":
993 srcDir_part = SRC_DIR + "/" + ARCH_NAME + "/flash_partition/" + flinfo.type + "-partition.xml"
994 else:
995 srcDir_part = SRC_DIR + "/" + ARCH_NAME + "/flash_partition/" + self.flash_type.lower() + "-partition.xml"
996 root_part = ET.parse(srcDir_part)
997 if self.flash_type != "emmc" and flinfo.type != "emmc":
998 parts = root_part.findall(".//partitions/partition")
999 elif self.flash_type != "emmc" and flinfo.type == "emmc":
1000 parts = root_part.findall(".//physical_partition[@ref='norplusemmc']/partition")
1001 else:
1002 parts = root_part.findall(".//physical_partition[@ref='emmc']/partition")
1003 if flinfo.type == "emmc":
1004 parts_length = len(parts) + 2
1005 else:
1006 parts_length = len(parts)
1007
1008 first = False
1009 section = None
1010 part_index = 0
1011
1012 if flinfo.type == "emmc":
1013 first = True
1014
1015 for index in range(parts_length):
1016
1017 if first:
1018 if self.flash_type == "norplusemmc":
1019 part_info = root.find(".//data[@type='NORPLUSEMMC_PARAMETER']")
1020 else:
1021 part_info = root.find(".//data[@type='EMMC_PARAMETER']")
1022 part_fname = part_info.find(".//partition_mbn")
1023 filename = part_fname.text
1024 partition = "0:GPT"
1025 first = False
1026
1027 elif index == (parts_length - 1) and flinfo.type == "emmc":
1028 if self.flash_type == "norplusemmc":
1029 part_info = root.find(".//data[@type='NORPLUSEMMC_PARAMETER']")
1030 else:
1031 part_info = root.find(".//data[@type='EMMC_PARAMETER']")
1032 part_fname = part_info.find(".//partition_mbn_backup")
1033 filename = part_fname.text
1034 partition = "0:GPTBACKUP"
1035
1036 else:
1037 section = parts[part_index]
1038 part_index += 1
1039 if flinfo.type != "emmc":
1040 try:
Saravanan Jaganathan7d086402017-09-22 15:35:01 +05301041 if image_type == "all" or section[8].attrib['image_type'] == image_type:
1042 filename = section[8].text
1043 try:
1044 if section[8].attrib['mode'] != MODE:
1045 filename = section[9].text
1046 except AttributeError, e:
1047 pass
1048 except KeyError, e:
1049 pass
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301050 except IndexError, e:
1051 if index == (parts_length - 1):
1052 return
1053 else:
1054 continue
Saravanan Jaganathan7d086402017-09-22 15:35:01 +05301055 except KeyError, e:
1056 continue
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301057 partition = section[0].text
1058 else:
1059
1060 try:
1061 diff_files = section.attrib['diff_files']
1062 except KeyError, e:
1063 try:
Saravanan Jaganathan7d086402017-09-22 15:35:01 +05301064 if image_type == "all" or section.attrib['image_type'] == image_type:
1065 filename = section.attrib['filename']
1066 partition = section.attrib['label']
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301067 if filename == "":
1068 continue
1069 except KeyError, e:
Saravanan Jaganathan7d086402017-09-22 15:35:01 +05301070 print "Skipping partition '%s'" % section.attrib['label']
1071 pass
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301072
1073 if diff_files == "true":
1074 try:
Saravanan Jaganathan7d086402017-09-22 15:35:01 +05301075 if image_type == "all" or section.attrib['image_type'] == image_type:
1076 filename = section.attrib['filename_' + MODE]
1077 partition = section.attrib['label']
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301078 if filename == "":
1079 continue
1080
1081 except KeyError, e:
Saravanan Jaganathan7d086402017-09-22 15:35:01 +05301082 print "Skipping partition '%s'" % section.attrib['label']
1083 pass
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301084 diff_files = "" # Clear for next iteration
1085
1086 part_info = self.__get_part_info(partition)
1087
1088 section_label = partition.split(":")
1089 if len(section_label) != 1:
1090 section_conf = section_label[1]
1091 else:
1092 section_conf = section_label[0]
1093
1094 section_conf = section_conf.lower()
1095
1096 if section_conf == "cdt" or section_conf == "ddrconfig":
Saravanan Jaganathan7d086402017-09-22 15:35:01 +05301097 try:
1098 if image_type == "all" or section[8].attrib['image_type'] == image_type:
1099 self.__gen_script_cdt(images, flinfo, root, section_conf, partition)
1100 continue
1101 except KeyError, e:
1102 continue
1103
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301104
1105 if part_info == None and self.flinfo.type != 'norplusnand':
1106 continue
1107
1108 if self.flinfo.type == 'nand':
1109 img_size = self.__get_img_size(filename)
1110 size = roundup(img_size, flinfo.pagesize)
1111 if ( size != img_size ):
1112 filename = filename + ".padded"
1113 if self.flinfo.type == 'emmc':
1114 img_size = self.__get_img_size(filename)
1115 size = roundup(img_size, flinfo.blocksize)
1116 if ( size != img_size ):
1117 filename = filename + ".padded"
1118 if section_conf == "qsee":
1119 section_conf = "tz"
1120 elif section_conf == "appsbl":
1121 section_conf = "u-boot"
Aditya Kumar Patra S75bf44b2017-07-12 12:07:04 +05301122 elif section_conf == "rootfs" and (self.flash_type == "nand" or self.flash_type == "norplusnand"):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301123 section_conf = "ubi"
Venkat Raju Sana2b68fba2017-12-06 17:46:47 -08001124 elif section_conf == "wififw" and (self.flash_type == "nand" or self.flash_type == "norplusnand"):
1125 section_conf = "wififw_ubi"
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301126 image_info = ImageInfo(section_conf + "-" + sha1(filename),
1127 filename, "firmware")
1128 if filename.lower() != "none":
1129 if image_info not in images:
1130 images.append(image_info)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301131
1132 def __mkimage(self, images):
1133 """Create the multi-image blob.
1134
1135 images -- list of ImageInfo, containing images to be part of the blob
1136 """
1137 try:
1138 its_fp = open(self.its_fname, "wb")
1139 except IOError, e:
1140 error("error opening its file '%s'" % self.its_fname, e)
1141
1142 desc = "Flashing %s %x %x"
1143 desc = desc % (self.flinfo.type, self.flinfo.pagesize,
1144 self.flinfo.blocksize)
1145
1146 image_data = []
1147 for (section, fname, imtype) in images:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301148 fname = fname.replace("\\", "\\\\")
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301149 subs = dict(name=section, desc=fname, fname=fname, imtype=imtype)
1150 image_data.append(its_image_tmpl.substitute(subs))
1151
1152 image_data = "".join(image_data)
1153 its_data = its_tmpl.substitute(desc=desc, images=image_data)
1154
1155 its_fp.write(its_data)
1156 its_fp.close()
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301157
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301158 try:
1159 cmd = ["mkimage", "-f", self.its_fname, self.img_fname]
1160 ret = subprocess.call(cmd)
1161 if ret != 0:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301162 print ret
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301163 error("failed to create u-boot image from script")
1164 except OSError, e:
1165 error("error executing mkimage", e)
1166
1167 def __create_fnames(self):
1168 """Populate the filenames."""
1169
1170 self.scr_fname = os.path.join(self.images_dname, "flash.scr")
1171 self.its_fname = os.path.join(self.images_dname, "flash.its")
1172
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301173 def __gen_board_script(self, flinfo, part_fname, images, root):
1174 global SRC_DIR
1175 global ARCH_NAME
1176
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301177 """Generate the flashing script for one board.
1178
1179 board_section -- string, board section in board config file
1180 machid -- string, board machine ID in hex format
1181 flinfo -- FlashInfo object, contains board specific flash params
1182 part_fname -- string, partition file specific to the board
1183 fconf_fname -- string, flash config file specific to the board
1184 images -- list of ImageInfo, append images used by the board here
1185 """
1186 script_fp = open(self.scr_fname, "a")
1187
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301188 if flinfo.type != "emmc":
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301189 flash_param = root.find(".//data[@type='NAND_PARAMETER']")
1190 pagesize = int(flash_param.find(".//page_size").text)
1191 pages_per_block = int(flash_param.find(".//pages_per_block").text)
1192 blocksize = pages_per_block * pagesize
1193 blocks_per_chip = int(flash_param.find(".//total_block").text)
1194 chipsize = blocks_per_chip * blocksize
1195
1196 srcDir_part = SRC_DIR + "/" + ARCH_NAME + "/flash_partition/" + flinfo.type + "-partition.xml"
1197 root_part = ET.parse(srcDir_part)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301198 mibib = MIBIB(part_fname, flinfo.pagesize, flinfo.blocksize,
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301199 flinfo.chipsize, blocksize, chipsize, root_part)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301200 self.partitions = mibib.get_parts()
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301201 if flinfo.type == "nand":
1202 script = Flash_Script(flinfo, self.ipq_nand)
1203 elif flinfo.type == "nor":
1204 script = Flash_Script(flinfo, pagesize)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301205 else:
1206 gpt = GPT(part_fname, flinfo.pagesize, flinfo.blocksize, flinfo.chipsize)
1207 self.partitions = gpt.get_parts()
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301208 script = Flash_Script(flinfo)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301209
1210 self.flinfo = flinfo
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301211
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301212 script.probe()
1213 self.__gen_script(script_fp, script, images, flinfo, root)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301214
1215 try:
1216 script_fp.write(script.dumps())
1217 except IOError, e:
1218 error("error writing to script '%s'" % script_fp.name, e)
1219
1220 script_fp.close()
1221
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301222 def __process_board_flash_emmc(self, ftype, images, root):
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301223 """Extract board info from config and generate the flash script.
1224
1225 ftype -- string, flash type 'emmc'
1226 board_section -- string, board section in config file
1227 machid -- string, board machine ID in hex format
1228 images -- list of ImageInfo, append images used by the board here
1229 """
1230
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301231 try:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301232 part_info = root.find(".//data[@type='" + self.flash_type.upper() + "_PARAMETER']")
1233 part_fname = part_info.find(".//partition_mbn")
1234 part_fname = part_fname.text
1235 part_fname = os.path.join(self.images_dname, part_fname)
1236 if ftype == "norplusemmc":
1237 part_info = root.find(".//data[@type='NORPLUSEMMC_PARAMETER']")
1238 pagesize = int(part_info.find(".//page_size_flash").text)
1239 part_info = root.find(".//data[@type='EMMC_PARAMETER']")
1240 else:
1241 pagesize = self.emmc_page_size
1242 blocksize = self.emmc_block_size
1243 chipsize = int(part_info.find(".//total_block").text)
1244 if ftype.lower() == "norplusemmc":
1245 ftype = "emmc"
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301246
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301247 except ValueError, e:
1248 error("invalid flash info in section '%s'" % board_section.find('machid').text, e)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301249
1250 flinfo = FlashInfo(ftype, pagesize, blocksize, chipsize)
1251
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301252 self.__gen_board_script(flinfo, part_fname, images, root)
1253
1254 def __process_board_flash(self, ftype, images, root):
1255 global SRC_DIR
1256 global ARCH_NAME
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301257
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301258 try:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301259 part_info = root.find(".//data[@type='" + ftype.upper() + "_PARAMETER']")
1260 part_file = SRC_DIR + "/" + ARCH_NAME + "/flash_partition/" + ftype + "-partition.xml"
1261 part_xml = ET.parse(part_file)
1262 partition = part_xml.find(".//partitions/partition[2]")
1263 part_fname = partition[8].text
1264 part_fname = os.path.join(self.images_dname, part_fname)
1265 pagesize = int(part_info.find(".//page_size").text)
1266 pages_per_block = int(part_info.find(".//pages_per_block").text)
1267 blocks_per_chip = int(part_info.find(".//total_block").text)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301268
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301269 if ftype == "norplusnand" or ftype == "norplusemmc":
1270 ftype = "nor"
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301271
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301272 except ValueError, e:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301273 error("invalid flash info in section '%s'" % board_section.find('machid').text, e)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301274
1275 blocksize = pages_per_block * pagesize
1276 chipsize = blocks_per_chip * blocksize
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301277
1278 flinfo = FlashInfo(ftype, pagesize, blocksize, chipsize)
1279
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301280 self.__gen_board_script(flinfo, part_fname, images, root)
1281
1282 def __process_board(self, images, root):
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301283
1284 try:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301285 if self.flash_type in [ "nand", "nor", "norplusnand" ]:
1286 self.__process_board_flash(self.flash_type, images, root)
1287 elif self.flash_type == "emmc":
1288 self.__process_board_flash_emmc(self.flash_type, images, root)
1289 elif self.flash_type == "norplusemmc":
1290 self.__process_board_flash("norplusemmc", images, root)
1291 self.__process_board_flash_emmc("norplusemmc", images, root)
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301292 except ValueError, e:
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301293 error("error getting board info in section '%s'" % board_section.find('machid').text, e)
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301294
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301295 def main_bconf(self, flash_type, images_dname, out_fname, root):
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301296 """Start the packing process, using board config.
1297
1298 flash_type -- string, indicates flash type, 'nand' or 'nor' or 'emmc' or 'norplusnand'
1299 images_dname -- string, name of images directory
1300 out_fname -- string, output file path
1301 """
1302 self.flash_type = flash_type
1303 self.images_dname = images_dname
1304 self.img_fname = out_fname
1305
1306 self.__create_fnames()
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301307 try:
1308 os.unlink(self.scr_fname)
1309 except OSError, e:
1310 pass
1311
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301312 images = []
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301313 self.__process_board(images, root)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301314 images.insert(0, ImageInfo("script", "flash.scr", "script"))
1315 self.__mkimage(images)
1316
1317class UsageError(Exception):
1318 """Indicates error in command arguments."""
1319 pass
1320
1321class ArgParser(object):
1322 """Class to parse command-line arguments."""
1323
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301324 DEFAULT_TYPE = "nor,nand,norplusnand,emmc,norplusemmc"
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301325
1326 def __init__(self):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301327 self.flash_type = None
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301328 self.images_dname = None
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301329 self.out_dname = None
1330 self.scr_fname = None
1331 self.its_fname = None
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301332
1333 def parse(self, argv):
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301334 global MODE
1335 global SRC_DIR
1336 global ARCH_NAME
Saravanan Jaganathan7d086402017-09-22 15:35:01 +05301337 global image_type
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301338
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301339 """Start the parsing process, and populate members with parsed value.
1340
1341 argv -- list of string, the command line arguments
1342 """
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301343
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301344 cdir = os.path.abspath(os.path.dirname(""))
1345 if len(sys.argv) > 1:
1346 try:
Saravanan Jaganathan7d086402017-09-22 15:35:01 +05301347 opts, args = getopt(sys.argv[1:], "", ["arch=", "fltype=", "srcPath=", "inImage=", "outImage=", "image_type="])
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301348 except GetoptError, e:
1349 raise UsageError(e.msg)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301350
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301351 for option, value in opts:
1352 if option == "--arch":
1353 ARCH_NAME = value
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301354
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301355 elif option == "--fltype":
1356 self.flash_type = value
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301357
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301358 elif option == "--srcPath":
1359 SRC_DIR = os.path.abspath(value)
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301360
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301361 elif option == "--inImage":
1362 self.images_dname = os.path.join(cdir, value)
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301363
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301364 elif option == "--outImage":
1365 self.out_dname = os.path.join(cdir, value)
1366
Saravanan Jaganathan7d086402017-09-22 15:35:01 +05301367 elif option == "--image_type":
1368 image_type = value
1369
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301370#Verify Arguments passed by user
1371
1372# Verify arch type
1373 if ARCH_NAME not in ["ipq40xx", "ipq806x", "ipq807x", "ipq807x_64"]:
1374 raise UsageError("Invalid arch type '%s'" % arch)
1375
1376 if ARCH_NAME == "ipq807x":
1377 MODE = "32"
1378 elif ARCH_NAME == "ipq807x_64":
1379 MODE = "64"
1380 ARCH_NAME = "ipq807x"
1381
1382# Set flash type to default type (nand) if not given by user
1383 if self.flash_type == None:
1384 self.flash_type = ArgParser.DEFAULT_TYPE
1385 for flash_type in self.flash_type.split(","):
1386 if flash_type not in [ "nand", "nor", "emmc", "norplusnand", "norplusemmc" ]:
1387 raise UsageError("invalid flash type '%s'" % flash_type)
1388
1389# Verify src Path
1390 if SRC_DIR == "":
1391 raise UsageError("Source Path is not provided")
1392
1393#Verify input image path
1394 if self.images_dname == None:
1395 raise UsageError("input images' Path is not provided")
1396
1397#Verify Output image path
1398 if self.out_dname == None:
1399 raise UsageError("Output Path is not provided")
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301400
1401 def usage(self, msg):
1402 """Print error message and command usage information.
1403
1404 msg -- string, the error message
1405 """
1406 print "pack: %s" % msg
1407 print
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301408 print "Usage:"
1409 print "python pack_hk.py [options] [Value] ..."
1410 print
1411 print "options:"
1412 print " --arch \tARCH_TYPE [ipq40xx/ipq806x/ipq807x/ipq807x_64]"
1413 print
1414 print " --fltype \tFlash Type [nor/nand/emmc/norplusnand/norplusemmc]"
1415 print " \t\tMultiple flashtypes can be passed by a comma separated string"
1416 print " \t\tDefault is all. i.e If \"--fltype\" is not passed image for all the flash-type will be created.\n"
1417 print " --srcPath \tPath to the directory containg the meta scripts and configs"
1418 print
1419 print " --inImage \tPath to the direcory containg binaries and images needed for singleimage"
1420 print
1421 print " --outImage \tPath to the directory where single image will be generated"
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301422 print
1423 print "Pack Version: %s" % version
1424
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301425def main():
1426 """Main script entry point.
1427
1428 Created to avoid polluting the global namespace.
1429 """
1430 try:
1431 parser = ArgParser()
1432 parser.parse(sys.argv)
1433 except UsageError, e:
1434 parser.usage(e.args[0])
1435 sys.exit(1)
1436
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301437 pack = Pack()
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301438
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301439 if not os.path.exists(parser.out_dname):
1440 os.makedirs(parser.out_dname)
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301441
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301442 config = SRC_DIR + "/" + ARCH_NAME + "/config.xml"
1443 root = ET.parse(config)
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301444
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301445# Format the output image name from Arch, flash type and mode
1446 for flash_type in parser.flash_type.split(","):
1447 if MODE == "64":
1448 parser.out_fname = flash_type + "-" + ARCH_NAME + "_" + MODE + "-single.img"
1449 else:
1450 parser.out_fname = flash_type + "-" + ARCH_NAME + "-single.img"
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301451
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301452 parser.out_fname = os.path.join(parser.out_dname, parser.out_fname)
Aditya Kumar Patra S117caa32017-03-21 12:19:27 +05301453
Aditya Kumar Patra Sd6885532017-05-30 12:09:25 +05301454 pack.main_bconf(flash_type, parser.images_dname,
1455 parser.out_fname, root)
Aditya Kumar Patra S12f0be02016-10-25 18:41:15 +05301456
1457if __name__ == "__main__":
1458 main()