Files
OpenNetworkLinux/tools/flat-image-tree.py
2016-05-02 13:00:02 -07:00

336 lines
10 KiB
Python
Executable File

#!/usr/bin/python
############################################################
#
# Flat Image Tree Generator
#
############################################################
import subprocess
import yaml
import tempfile
import json
class Image(object):
"""Base ITS Image Class"""
def __init__(self, type_, data, compression='none'):
self.type = type_
self.compression = compression
self.load = None
self.entry = None
self.os = None
if type(data) == str:
if ',' in data:
pkg, fname = [x.strip() for x in data.split(',')]
else:
pkg, fname = None, data
elif type(data) == list:
pkg, fname = data
elif type(data) == dict:
fname = data['=']
pkg = data.get('package', None)
else:
raise ValueError("invalid image specifier: %s" % repr(data))
if pkg is not None:
cmd = ('onlpm', '--quiet', '--find-file', pkg, fname,)
self.data = subprocess.check_output(cmd).strip()
else:
self.data = data
self.name = os.path.basename(self.data)
self.description = self.name
def wl(self, line, indent=" "):
self.handle.write("%s%s\n" % (indent, line))
def start_image(self, f):
self.handle = f
self.wl("""%s {""" % self.name)
self.wl(""" description = "%s";""" % self.description)
self.wl(""" type = "%s";""" % self.type)
self.wl(""" data = /incbin/("%s");""" % self.data)
self.wl(""" arch = "%s";""" % ("arm" if ops.arch == 'armel' else ops.arch))
self.wl(""" compression = "%s";""" % self.compression)
if self.os:
self.wl(""" os = %s;""" % self.os)
if self.load:
self.wl(""" load = %s;""" % self.load)
if self.entry:
self.wl(""" entry = %s;""" % self.entry)
def include_hashes(self,f):
self.wl(""" hash@1 {""")
self.wl(""" algo = "crc32";""")
self.wl(""" };""")
def end_image(self, f):
self.wl("""};""")
class KernelImage(Image):
"""Kernel image entry"""
def __init__(self, fname, arch):
Image.__init__(self, "kernel", fname, compression='gzip')
self.os = '"linux"'
# Fixme -- thse should be parameterized
if arch == 'powerpc':
self.load = "<0x0>"
self.entry = "<0x0>"
elif arch == 'armel':
self.load = "<0x61008000>"
self.entry = "<0x61008000>"
def write(self, f):
self.start_image(f)
self.include_hashes(f)
self.end_image(f)
class InitrdImage(Image):
"""Initrd image entry"""
def __init__(self, fname, arch):
Image.__init__(self, "ramdisk", fname, compression='gzip')
# Fixme -- thse should be parameterized
if arch == 'powerpc':
self.load = "<0x1000000>"
self.entry ="<0x1000000>"
elif arch == 'armel':
self.load = "<0x0000000>"
self.entry ="<0x0000000>"
self.os = '"linux"'
def write(self, f):
self.start_image(f)
self.include_hashes(f)
self.end_image(f)
class DtbImage(Image):
"""DTB Image Entry"""
def __init__(self, fname):
Image.__init__(self, "flat_dt", fname, compression="none")
def write(self, f):
self.start_image(f)
self.end_image(f)
class FlatImageTree(object):
"""Generates a FIT .its file"""
def __init__(self, description):
self.kernels = []
self.dtbs = []
self.initrds = []
self.description = description
self.configurations = {}
def add_initrd(self, initrd):
self.initrds.append(initrd)
def add_kernel(self, kernel):
self.kernels.append(kernel)
def add_dtb(self, dtb):
self.dtbs.append(dtb)
def add_config(self, name, kernel, dtb, initrd=None):
if name in self.configurations:
raise KeyError("Configuration '%s' already exists." % name)
self.add_kernel(kernel)
self.add_dtb(dtb)
if initrd:
self.add_initrd(initrd)
else:
# Use the first initrd as the default.
if len(self.initrds) == 0:
raise ValueError("No default initrd available while adding configuration '%s'" % name)
else:
initrd = self.initrds[0]
self.configurations[name] = (kernel, dtb, initrd)
def add_dict(self, name, d):
if name in d:
d = d[name]
if 'flat_image_tree' in d:
d = d['flat_image_tree']
kernel = d.get('kernel', None)
if kernel is None:
raise KeyError("Configuration for %s does not contain a kernel key." % name)
dtb = d.get('dtb', None)
if dtb is None:
raise KeyError("Configuration for %s does not contain a dtb key." % name)
initrd = d.get('initrd', None)
self.add_config(name, kernel, dtb, initrd)
def add_yaml(self, name, fname):
d = yaml.load(open(fname))
self.add_dict(name, d)
def add_platform_package(self, package):
print package
platform = package.replace(":%s" % ops.arch, "").replace("onl-platform-config-", "")
y = subprocess.check_output("onlpm --quiet --find-file %s %s.yml" % (package, platform), shell=True).strip()
self.add_yaml(platform, y)
def add_platform(self, platform):
if (":%s" % ops.arch) in platform:
self.add_platform_package(platform)
else:
self.add_platform_package("onl-platform-config-%s:%s" % (platform, ops.arch))
def write(self, fname):
with open(fname, "w") as f:
self.writef(f)
def writef(self, f):
kdict = {}
for k in set(self.kernels):
kdict[k] = KernelImage(k, ops.arch)
ddict = {}
for d in set(self.dtbs):
ddict[d] = DtbImage(d)
idict = {}
for i in set(self.initrds):
idict[i] = InitrdImage(i, ops.arch)
f.write("""/* \n""")
f.write(""" * %s\n""" % self.description)
f.write(""" */\n""")
f.write("""\n""")
f.write("""/dts-v1/;\n""")
f.write("""/ {\n""")
f.write(""" description = "%s";\n""" % self.description)
f.write(""" #address-cells = <0x1>;\n""")
f.write("""\n""")
f.write(""" images {\n\n""")
f.write(""" /* Kernel Images */\n""")
for k in set(self.kernels):
KernelImage(k, ops.arch).write(f)
f.write("""\n""")
f.write(""" /* DTB Images */\n""")
for d in set(self.dtbs):
DtbImage(d).write(f)
f.write("""\n""")
f.write(""" /* Initrd Images */\n""")
for i in set(self.initrds):
InitrdImage(i, ops.arch).write(f)
f.write(""" };\n""")
f.write(""" configurations {\n""")
for (name, (kernel, dtb, initrd)) in self.configurations.iteritems():
f.write(""" %s {\n""" % name)
f.write(""" description = "%s";\n""" % name)
f.write(""" kernel = "%s";\n""" % (kdict[kernel].name))
f.write(""" ramdisk = "%s";\n""" % (idict[initrd].name))
f.write(""" fdt = "%s";\n""" % (ddict[dtb].name))
f.write(""" };\n\n""")
f.write(""" };\n""")
f.write("""};\n""")
############################################################
if __name__ == '__main__':
import os
import sys
import argparse
ap = argparse.ArgumentParser(description="UBoot Flat Image Tree Generator.")
ap.add_argument("--initrd", nargs='+', action='append', help="Add initrds.")
ap.add_argument("--kernel", nargs='+', action='append', help="Add kernels.")
ap.add_argument("--dtb", nargs='+', action='append', help="Add dtbs.")
ap.add_argument("--add-yaml", nargs='+', action='append', help="Add a configuration from a yaml configuration file.")
ap.add_argument("--add-platform", nargs='+', action='append', help="Add the given ONL platforms to the configuration.")
ap.add_argument("--desc", nargs=1, help="Flat Image Tree description", default="ONL Flat Image Tree.")
ap.add_argument("--itb", metavar='itb-file', help="Compile result to an image tree blob file.")
ap.add_argument("--its", metavar='its-file', help="Write result to an image tree source file.")
ap.add_argument("--arch", choices=['powerpc', 'armel'], required=True)
ops=ap.parse_args()
fit = FlatImageTree(ops.desc)
initrd=None
if ops.initrd:
for ilist in ops.initrd:
for initrd in ilist:
fit.add_initrd(initrd)
# hack for now
initrd = initrd
if ops.kernel:
for klist in ops.kernel:
for kernel in klist:
fit.add_kernel(kernel)
if ops.dtb:
for dlist in ops.dtb:
for dtb in dlist:
fit.add_dtb(dtb)
if ops.add_yaml:
for ylist in ops.add_yaml:
for y in ylist:
fit.add_yaml(y)
if ops.add_platform == [['all']]:
ops.add_platform = [ subprocess.check_output("onlpm --list-platforms --arch %s" % (ops.arch), shell=True).split() ]
if ops.add_platform == [['initrd']]:
# Add support for the platforms listed in the initrd's platform manifest
(package,f) = initrd.split(':')
mfile = subprocess.check_output("onlpm --find-file %s:%s manifest.json" % (package, ops.arch), shell=True).strip()
manifest = json.load(open(mfile))
ops.add_platform = [[ "%s" % p for p in manifest['platforms'] ]]
if ops.add_platform:
for plist in ops.add_platform:
for platform in plist:
fit.add_platform(platform)
if ops.itb is None:
if ops.its is None:
fit.writef(sys.stdout)
else:
fit.write(ops.its)
else:
its = ops.its
if its is None:
its = tempfile.NamedTemporaryFile(delete=False)
fit.writef(its)
its.close()
its = its.name
else:
fit.write(its)
if os.system("mkimage -f %s %s" % (its, ops.itb)) != 0:
raise RuntimeError("Device tree compilation failed. See %s." % its)
if ops.its is None:
os.unlink(its)