#!/usr/bin/python2 ############################################################ # # Flat Image Tree Generator # ############################################################ import subprocess import yaml import tempfile import os, sys toolsdir = os.path.dirname(os.path.abspath(__file__)) onldir = os.path.dirname(toolsdir) pydir = os.path.join(onldir, "packages/base/all/vendor-config-onl/src/python") sys.path.append(pydir) import onl.YamlUtils from onlpm import * pm = defaultPm() 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: pm.require(pkg, force=False, build_missing=True) self.data = pm.opr.get_file(pkg, fname) else: self.data = data try: self.name = os.path.basename(fname) except: import pdb pdb.set_trace() raise 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 in [ 'armel', 'armhf' ] 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, fdata, arch): Image.__init__(self, "kernel", fdata, compression='gzip') self.os = '"linux"' # Fixme -- thse should be parameterized if arch == 'powerpc': self.load = "<0x0>" self.entry = "<0x0>" elif arch in [ 'armel', 'armhf' ]: self.load = "<0x61008000>" self.entry = "<0x61008000>" elif arch == 'arm64': self.load = "<0x80080000>" self.entry = "<0x80080000>" 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, fdata, arch): Image.__init__(self, "ramdisk", fdata, compression='gzip') # Fixme -- thse should be parameterized if arch == 'powerpc': self.load = "<0x1000000>" self.entry ="<0x1000000>" elif arch in [ 'armel', 'armhf' ]: self.load = "<0x0000000>" self.entry ="<0x0000000>" elif arch == 'arm64': 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, fdata, arch): Image.__init__(self, "flat_dt", fdata, compression="none") if arch == 'arm64': self.load = "<0x90000000>" self.entry ="<0x90000000>" 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) sys.stderr.write("*** platform %s kernel %s\n" % (name, kernel,)) self.add_config(name, kernel, dtb, initrd) def add_yaml(self, name, fname, defaults=None): if defaults is not None: d = onl.YamlUtils.merge(defaults, fname) else: with open(fname) as fd: d = yaml.load(fd) self.add_dict(name, d) def add_platform_package(self, package): print package platform = package.replace(":%s" % ops.arch, "").replace("onl-platform-config-", "") vpkg = "onl-vendor-config-onl:all" pm.require(vpkg, force=False, build_missing=True) y1 = pm.opr.get_file(vpkg, "platform-config-defaults-uboot.yml") pm.require(package, force=False, build_missing=True) y2 = pm.opr.get_file(package, platform + '.yml') self.add_yaml(platform, y2, defaults=y1) 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 self.kernels: ki = KernelImage(k, ops.arch) kdict[ki.name] = ki ddict = {} for d in self.dtbs: di = DtbImage(d, ops.arch) ddict[di.name] = di idict = {} for i in self.initrds: ii = InitrdImage(i, ops.arch) idict[ii.name] = ii 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 kdict.values(): k.write(f) f.write("""\n""") f.write(""" /* DTB Images */\n""") for d in ddict.values(): d.write(f) f.write("""\n""") f.write(""" /* Initrd Images */\n""") for i in idict.values(): i.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""" % (KernelImage(kernel, ops.arch).name)) f.write(""" ramdisk = "%s";\n""" % (InitrdImage(initrd, ops.arch).name)) f.write(""" fdt = "%s";\n""" % (DtbImage(dtb, ops.arch).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', 'armhf', 'arm64'], 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 = [ pm.list_platforms(ops.arch) ] if ops.add_platform == [['initrd']]: # Add support for the platforms listed in the initrd's platform manifest (package,f) = initrd.split(':') pkg = package + ':' + ops.arch pm.require(pkg, force=False, build_missing=True) mfile = pm.opr.get_file(pkg, "manifest.json") 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)