summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2019-06-06 20:57:15 +1000
committerChris Johns <chrisj@rtems.org>2019-06-06 20:57:15 +1000
commit2fe9313b447965bc38efaefcc8fdea90a273d5d8 (patch)
tree3d57408a89748f4c225e1a2e30ce36f3cf168421
parent7f0748495ea57fcd80791c45ded1dd9a7b1b941f (diff)
boot-image: Add support for 1st and 2nd loaders.
-rw-r--r--misc/tools/boot.py582
-rw-r--r--misc/tools/rtems-boot.ini64
2 files changed, 432 insertions, 214 deletions
diff --git a/misc/tools/boot.py b/misc/tools/boot.py
index 206dc8d..8cbae4b 100644
--- a/misc/tools/boot.py
+++ b/misc/tools/boot.py
@@ -32,133 +32,261 @@ import sys
import tempfile
from rtemstoolkit import check
+from rtemstoolkit import configuration
from rtemstoolkit import error
from rtemstoolkit import execute
from rtemstoolkit import host
from rtemstoolkit import log
+from rtemstoolkit import macros
from rtemstoolkit import path
from rtemstoolkit import version
-class settings(object):
- def __init__(self, bootloader = 'none', base = None):
+def _check_exes(exes):
+ ok = True
+ first = True
+ for exe in exes:
+ log.output('check exe: %s' % (exe))
+ if not check.check_exe(None, exe):
+ if first:
+ log.notice('Host executable(s) not found:')
+ first = False
+ log.notice(' %s' % (exe))
+ ok = False
+ return ok
+
+def _command(cmd, cwd):
+ e = execute.capture_execution()
+ cwd = path.abspath(cwd)
+ log.output('>> cwd: %s' % (cwd))
+ log.output('> %s' % (cmd))
+ exit_code, proc, output = e.shell(cmd, cwd = path.host(cwd))
+ log.output(['> ' + l for l in output.split(os.linesep)])
+ log.output('> exit: %d' % (exit_code))
+ if exit_code != 0:
+ err = 'executing failure: (exit:%d) %s' % (exit_code, cmd)
+ raise error.general(err)
+ return output
+
+class config(object):
+
+ mandatory_configs = [
+ 'image_size',
+ 'part_type',
+ 'part_label',
+ 'fs_format',
+ 'fs_size',
+ 'fs_alignment',
+ 'tool_prefix',
+ 'bootloaders'
+ ]
+
+ def __init__(self, command_path, bootloader):
+ #
+ # Check if there is a defaults.mc file under the command path. If so
+ # this is the tester being run from within the git repo. If not found
+ # assume the tools have been installed and the defaults is in the
+ # install prefix.
+ #
+ boot_ini = 'tools/rtems-boot.ini'
+ if path.exists(path.join(command_path, boot_ini)):
+ rtdir = command_path
+ else:
+ rtdir = '%{_prefix}/share/rtems'
+ boot_ini = '%s/%s' % (rtdir, boot_ini)
self.build = 'build'
- self.bootloader = bootloader
- self.base = base
- self.image_size = '64m'
- self.part_type = 'MBR'
- self.fs_format = 'fat16'
- self.fs_size = '63m'
- self.fs_alignment = '1m'
- self.first_stage = None
- self.second_stage = None
- self.output = None
- self.kernel = None
- self.net_server_ip = None
- self.net_ip = None
- self.files = []
- self.config = None
+ self.macros = macros.macros(rtdir = rtdir, show_minimal = True)
+ self.config = configuration.configuration()
+ self.load_config(bootloader, boot_ini)
self.clean = True
- def config_find(self, key, raw = False):
- if key not in self.config:
- raise error.general('config item not found: %s' % (key))
- item = self.config[key]
- if not raw:
- if item == 'y':
- item = True
- elif item == 'n':
- item = False
- elif item[0] == '"' and item[-1] == '"':
- item = item[1:-1]
- return item
-
- def bootloader_file(self, name):
- return path.join(self.base, name)
+ def __getitem__(self, key):
+ if self.macros.has_key(key) and self.macros[key] != 'None':
+ return self.macros.expand('%%{%s}' % (key))
+ return None
+
+ def __setitem__(self, key, value):
+ if value is None:
+ value = 'None'
+ self.macros[key] = value
+
+ def get_mandatory_configs(self):
+ return self.mandatory_configs
+
+ def check_mandatory_configs(self):
+ for c in self.get_mandatory_configs():
+ if not self.macros.has_key(c):
+ raise error.general('boot config missing: %s' % (c))
+
+ def load_config(self, bootloader, config):
+ self.config.load(config)
+ #
+ # Check the config file has the basic data and structure.
+ #
+ bootloaders = self.config.comma_list('default', 'bootloaders')
+ for bl in bootloaders:
+ if not self.config.has_section(bl):
+ raise error.general('boot config: missing bootloader section: %s' % (bl))
+ for b in self.config.comma_list(bl, 'boards'):
+ if not self.config.has_section(b):
+ raise error.general('boot config: missing board section: %s' % (b))
+ #
+ # Is the bootloader valid?
+ #
+ if bootloader not in bootloaders:
+ raise error.general('boot config: unknown bootloader: %s' % (bootloader))
+ self.macros['bootloader'] = bootloader
+ self.macros['version_str'] = version.string()
+ self.macros['version'] = str(version.version())
+ self.macros['revision'] = str(version.revision())
+ if version.released():
+ self.macros['released'] = '1'
+ #
+ # Map the config to macros. The [default] section is global. The
+ # remaining sections are added as macro maps so the specalised
+ # bootloaders can enable reading from a macro map to provide specific
+ # values for a specific config such as a board.
+ #
+ for s in self.config.get_sections():
+ if s != 'default':
+ self.macros.set_write_map(s, add = True)
+ for i in self.config.get_items(s):
+ self.macros[i[0]] = i[1]
+ self.macros.unset_write_map()
+ self.macros.set_read_map('global')
+ self.macros.set_read_map(bootloader)
+
+ def section_macro_map(self, section, nesting_level = 0):
+ nesting_level += 1
+ if nesting_level >= 100:
+ err = 'boot config: too many map levels (looping?): %s' % (section)
+ raise error.general(err)
+ if section not in self.macros.maps():
+ raise error.general('boot config: maps section not found: %s' % (section))
+ self.macros.set_read_map(section)
+ for s in self.config.comma_list(section, 'uses', err = False):
+ self.section_macro_map(s, nesting_level)
+
+ def boards(self):
+ return self.config.comma_list(self['bootloader'], 'boards')
def log(self):
- log.output('Settings')
- log.output(' Image: {0}'.format(self.output))
- log.output(' Bootloader: {0}'.format(self.bootloader))
- log.output(' Base: {0}'.format(self.base))
- log.output(' Image Size: {0}'.format(self.image_size))
- log.output(' Part Type: {0}'.format(self.part_type))
- log.output(' FS Format: {0}'.format(self.fs_format))
- log.output(' FS Size: {0}'.format(self.fs_size))
- log.output(' FS Align: {0}'.format(self.fs_alignment))
- log.output(' First stage: {0}'.format(self.first_stage))
- log.output(' Second stage: {0}'.format(self.second_stage))
- log.output(' Kernel: {0}'.format(self.kernel))
- log.output(' Net Server IP: {0}'.format(self.net_server_ip))
- log.output(' Net IP: {0}'.format(self.net_ip))
- log.output(' Files: {0}'.format(len(self.files)))
- for f in self.files:
- log.output(' : {0}'.format(f))
- if self.config is not None:
- log.output(' Config: {0}'.format(len(self.config)))
- for c in self.config:
- log.output(' : {0} = {1}'.format(c, self.config[c]))
-
- def install_configuration(self, image, dst):
- pass
+ log.output('Configuration:')
+ log.output(' Bootloader: {0}'.format(self.macros['bootloader']))
+ log.output(' Image: {0}'.format(self.macros['output']))
+ log.output(' Image Size: {0}'.format(self.macros['image_size']))
+ log.output(' Part Type: {0}'.format(self.macros['part_type']))
+ log.output(' FS Format: {0}'.format(self.macros['fs_format']))
+ log.output(' FS Size: {0}'.format(self.macros['fs_size']))
+ log.output(' FS Align: {0}'.format(self.macros['fs_alignment']))
+ log.output(' Kernel: {0}'.format(self.macros['kernel']))
+ log.output(' Net Server IP: {0}'.format(self.macros['net_server_ip']))
+ log.output(' Net IP: {0}'.format(self.macros['net_ip']))
+ log.output(' Files: {0}'.format(len(self.files())))
+ log.output('Macros:')
+ macro_str = str(self.macros).split(os.linesep)
+ log.output(os.linesep.join([' ' + l for l in macro_str]))
+
+ def get_exes(self):
+ return []
-class uboot_settings(settings):
-
- boards = {
- 'arm-ti-am335x-am335x_evm' : {
- 'SPL' : 'MLO',
- 'IMG' : 'u-boot.img',
- 'RTEMS-LOADADDR' : '0x82000000'
- },
- 'arm-xilinx-zynq-zynq-common' : {
- 'SPL' : 'spl/boot.bin',
- 'IMG' : 'u-boot.img',
- 'RTEMS-LOADADDR' : '0x02000000'
- },
- }
-
- templates = {
- 'rtems-kernel': [
- 'loadaddr=@RTEMS-LOADADDR@',
- 'bootfile=@KERNE@'
- ]
- }
-
- def __init__(self, uboot):
- super(uboot_settings, self).__init__('u-boot', uboot)
- self._config_load(self.bootloader_file('.config'))
- if self.board_name() not in self.boards:
- raise error.general('board not found: %s' %(self.board_name()))
- log.output('Board: %s' % (self.board_name()))
- board = self.boards[self.board_name()]
- self.first_stage = self.bootloader_file(board['SPL'])
- self.second_stage = self.bootloader_file(board['IMG'])
-
- def _config_load(self, config):
- if not path.exists(config):
- raise error.general('could not find u-boot\'s config: %s' %(config))
- with open(config, 'r') as f:
- items = f.readlines()
- self.config_path = config
- items = [l[:l.find('#')] for l in items]
- items = [l for l in items if len(l) > 0 or len(l) > 0 and l[0] != os.linesep]
- self.config = {}
- for c in items:
- cs = c.split('=')
- self.config[cs[0].strip()] = cs[1].strip()
-
- def board_name(self):
- return '%s-%s-%s-%s' % (self.config_find('CONFIG_SYS_ARCH'),
- self.config_find('CONFIG_SYS_VENDOR'),
- self.config_find('CONFIG_SYS_BOARD'),
- self.config_find('CONFIG_SYS_CONFIG_NAME'))
-
- def install_configuration(self, image, dst):
+ def check_exes(self):
+ return _check_exes(self.get_exes())
+
+ def files(self):
+ return [f.strip() for f in self.comma_split(self['files']) if len(f) > 0]
+
+ def install_configuration(self, image, mountpoint):
pass
+ def kernel_convert(self, kernel):
+ return kernel
+
+ def kernel_image(self):
+ return self['kernel_image'].replace('@KERNEL@', path.basename(self['kernel']))
+
+ def filter_text(self, lines):
+ out = []
+ for line in lines:
+ if '@KERNEL@' in line:
+ line = line.replace('@KERNEL@', path.basename(self['kernel']))
+ if '@KERNEL_IMAGE@' in line:
+ line = line.replace('@KERNEL_IMAGE@', self.kernel_image())
+ out += [line]
+ return out
+
+ def comma_split(self, value):
+ return [s.strip() for s in value.split(',')]
+
+class uboot_config(config):
+
+ def __init__(self, command_path, paths, board):
+ self.uboot = { 'paths': paths, 'board': board }
+ super(uboot_config, self).__init__(command_path, 'u-boot')
+ if self.board() not in self.boards():
+ raise error.general('board not found: %s' %(self.board()))
+ log.output('Board: %s' % (self.board()))
+ self.section_macro_map(self.board())
+ self.macros.set_read_map(self['bootloader'] + '-templates')
+ self.macros.lock_read_map()
+ log.output(str(self.macros))
+
+ def load_config(self, bootloader, config):
+ super(uboot_config, self).load_config(bootloader, config)
+ paths_count = len(self.uboot['paths'])
+ if paths_count == 1:
+ self.macros['ubootdir'] = path.abspath(self.uboot['paths'][0])
+ if not path.exists(self['first_stage']):
+ err = 'u-boot: first stage loader not found: %s' % (self['first_stage'])
+ raise error.general(err)
+ if not path.exists(self['second_stage']):
+ err = 'u-boot: second stage loader not found: %s' % \
+ (self['second_stage'])
+ raise error.general(err)
+ elif paths_count == 2:
+ self.macros['first_stage'] = self.uboot['paths'][0]
+ self.macros['second_stage'] = self.uboot['paths'][1]
+ self.macros['mkimage'] = 'mkimage'
+ else:
+ raise error.general('u-boot: invalid number of paths')
+
+ def get_mandatory_configs(self):
+ cfgs = super(uboot_config, self).get_mandatory_configs()
+ return cfgs + ['objcopy',
+ 'arch',
+ 'vendor',
+ 'board',
+ 'config_name',
+ 'first_stage',
+ 'second_stage',
+ 'kernel_converter']
+
+ def board(self):
+ return self.uboot['board']
+
+ def get_exes(self):
+ exes = super(uboot_config, self).get_exes()
+ if self['executables'] is not None:
+ exes += self.comma_split(self['executables'])
+ return exes
+
+ def install_configuration(self, image, mountpoint):
+ if self.macros.has_key('kernel'):
+ image.install_text(self.filter_text(self.comma_split(self['exe'])),
+ path.join(mountpoint, self['boot_config']))
+
+ def kernel_convert(self, kernel):
+ cmds = self.comma_split(self['kernel_converter'])
+ for c in range(0, len(cmds)):
+ if '@KERNEL@' in cmds[c]:
+ cmds[c] = cmds[c].replace('@KERNEL@', kernel)
+ for cmd in cmds:
+ _command(cmd, self['build'])
+ return self['kernel_image'].replace('@KERNEL@', kernel)
+
class image(object):
- def __init__(self, settings):
- self.settings = settings
+ def __init__(self, conf):
+ self.conf = conf
self.detach_images = []
self.unmount_paths = []
self.remove_paths = []
@@ -171,8 +299,8 @@ class image(object):
#
# Ge the absolute paths to fixed locations.
#
- output = path.abspath(self.settings.output)
- build = path.abspath(self.settings.build)
+ output = path.abspath(self.conf['output'])
+ build = path.abspath(self.conf['build'])
mountpoint = path.join(build, 'mnt')
#
@@ -186,62 +314,63 @@ class image(object):
# Create the blank image file. This is attached as a device,
# partitioned, formatted and the files written to it.
#
- log.notice('Create image: %s size %s' % (self.settings.output,
- self.settings.image_size))
- self.image_create(output, self.settings.image_size)
+ log.notice('Create image: %s size %s' % (self.conf['output'],
+ self.conf['image_size']))
+ self.image_create(output, self.conf['image_size'])
#
# Attach the image so it is a device.
#
- log.notice('Attach image to device: %s' % (self.settings.output))
+ log.notice('Attach image to device: %s' % (self.conf['output']))
device = self.image_attach(output)
#
# Partition the image. The device may change.
#
log.notice('Partition device: %s as %s' % (device,
- self.settings.part_type))
+ self.conf['part_type']))
device = self.partition(output,
device,
- self.settings.part_type,
- self.settings.fs_format,
- self.settings.fs_size,
- self.settings.fs_alignment)
-
+ self.conf['part_type'],
+ self.conf['part_label'],
+ self.conf['fs_format'],
+ self.conf['fs_size'],
+ self.conf['fs_alignment'])
part = self.device_partition(device, 1)
#
# Format the first partition.
#
- log.notice('Format: %s as %s' % (part, self.settings.fs_format))
- self.format_partition(part, self.settings.fs_format)
+ log.notice('Format: %s as %s' % (part, self.conf['fs_format']))
+ self.format_partition(part, self.conf['fs_format'])
#
# Mount the file system.
#
log.notice('Mount: %s' % (part))
- self.mount(self.settings.fs_format, part, mountpoint)
+ self.mount(self.conf['fs_format'], part, mountpoint)
#
# Install the first stage and second stage boot loaders.
#
- self.install(self.settings.first_stage, mountpoint)
- self.install(self.settings.second_stage, mountpoint)
+ self.install(self.conf['first_stage'], mountpoint)
+ self.install(self.conf['second_stage'], mountpoint)
#
# Install a kernel if present
#
- if self.settings.kernel is not None:
- self.install(self.settings.kernel, mountpoint)
+ if self.conf['kernel'] is not None:
+ kernel_image = self.kernel_image(self.conf['kernel'])
+ self.install(kernel_image, mountpoint)
#
# Install the bootloader configuration.
#
- self.settings.install_configuration(self, mountpoint)
+ self.conf.install_configuration(self, mountpoint)
#
# Install any user files if present.
#
- for f in self.settings.files:
+ for f in self.conf.files():
self.install(f, mountpoint)
#
@@ -259,6 +388,15 @@ class image(object):
log.output('Copy : %s -> %s' % (asrc, adst))
path.copy(asrc, adst)
+ def install_text(self, text, dst):
+ dst_base = path.basename(dst)
+ log.notice('Install: %s' % (dst_base))
+ adst = path.abspath(dst)
+ log.output('Copy : text[%d] -> %s' % (len(text), adst))
+ log.output([' ] ' + l for l in text])
+ with open(adst, "w") as o:
+ o.write(os.linesep.join(text))
+
def image_create(self, path_, size):
self.host_image_create(path_, size, path.exists(path_))
@@ -272,8 +410,8 @@ class image(object):
self.detach_images.remove(device)
self.host_image_detach(device)
- def partition(self, image_, device, ptype, pformat, psize, palign):
- return self.host_partition(image_, device, ptype, pformat, psize, palign)
+ def partition(self, image_, device, ptype, plabel, pformat, psize, palign):
+ return self.host_partition(image_, device, ptype, plabel, pformat, psize, palign)
def format_partition(self, device, pformat):
self.host_format_partition(device, pformat)
@@ -292,32 +430,32 @@ class image(object):
self.unmount_paths.remove(path_)
def cleanup(self):
- log.notice('Cleanup')
+ log.notice('Cleaning up')
for m in self.unmount_paths:
log.output('unmount: %s' % (m))
self.unmount(m)
for i in self.detach_images:
log.output('detach: %s' % (i))
self.image_detach(i)
- for r in self.remove_paths:
- log.output('remove: %s' % (r))
- path.removeall(r)
+ if self.conf.clean:
+ for r in self.remove_paths:
+ log.output('remove: %s' % (r))
+ path.removeall(r)
+
+ def kernel_image(self, kernel):
+ dst = path.join(path.abspath(self.conf['build']), path.basename(kernel))
+ log.output('Copy: %s -> %s' % (kernel, dst))
+ path.copy(kernel, dst)
+ return self.conf.kernel_convert(dst)
def get_exes(self):
return ['dd']
def check_exes(self):
- ok = True
- for exe in self.get_exes():
- log.output('check exe: %s' % (exe))
- if not check.check_exe(None, exe):
- log.notice('host executable not found: %s' % (exe))
- ok = False
- if not ok:
- raise error.general('command(s) not found; please fix.')
+ return _check_exes(self.get_exes())
def si_units(self, units):
- siunits = {'k': 1024,
+ siunits = { 'k': 1024,
'm': 1024 * 1024,
'g': 1024 * 1024 * 1024 }
if units not in siunits:
@@ -333,9 +471,9 @@ class image(object):
if suffix not in ['k', 'm', 'g']:
err = 'invalid SI unit (k, m, g): %s: %s' % (suffix, size)
raise error.general(err)
- units = {'k': 1024,
- 'm': 1024 * 1024,
- 'g': 1024 * 1024 * 1024 }[suffix]
+ units = { 'k': 1024,
+ 'm': 1024 * 1024,
+ 'g': 1024 * 1024 * 1024 }[suffix]
size = size[:-1]
if not size.isdigit():
raise error.general('invalid size: %s' % (orig))
@@ -363,21 +501,11 @@ class image(object):
raise error.general('build path is not readable: %s' % (where))
if not path.iswritable(where):
raise error.general('build path is not writeable: %s' % (where))
- if cleanup and self.settings.clean:
+ if cleanup and self.conf.clean:
self.remove_paths += [where]
def command(self, cmd):
- e = execute.capture_execution()
- build = path.abspath(self.settings.build)
- log.output('>> cwd: %s' % (build))
- log.output('> %s' % (cmd))
- exit_code, proc, output = e.shell(cmd, cwd = path.host(build))
- log.output(['> ' + l for l in output.split(os.linesep)])
- log.output('> exit: %d' % (exit_code))
- if exit_code != 0:
- err = 'executing failure: (exit:%d) %s' % (exit_code, cmd)
- raise error.general(err)
- return output
+ return _command(cmd, self.conf['build'])
def host_image_create(self, path_, size, exists):
img_size, img_units = self.si_size_units(size)
@@ -391,7 +519,7 @@ class image(object):
def host_image_detach(self, device):
raise error.general('no platform support: host_image_detach')
- def host_partition(self, image_, device, ptype, pformat, psize, palign):
+ def host_partition(self, image_, device, ptype, plabel, pformat, psize, palign):
raise error.general('no platform support: host_partition')
def host_format_partition(self, device, pformat):
@@ -407,8 +535,8 @@ class image(object):
raise error.general('no platform support: host_unmount')
class freebsd_image(image):
- def __init__(self, settings):
- super(freebsd_image, self).__init__(settings)
+ def __init__(self, conf):
+ super(freebsd_image, self).__init__(conf)
def get_exes(self):
exes = super(freebsd_image, self).get_exes()
@@ -424,7 +552,7 @@ class freebsd_image(image):
def host_image_detach(self, device):
self.command('sudo mdconfig -d -u %s' % (device))
- def host_partition(self, image_, device, ptype, pformat, psize, palign):
+ def host_partition(self, image_, device, ptype, plabel, pformat, psize, palign):
types = { 'MBR': 'MBR' }
formats = { 'fat16': 'fat16',
'fat32': 'fat32' }
@@ -466,8 +594,8 @@ class freebsd_image(image):
self.command('sudo umount %s' % (path_))
class linux_image(image):
- def __init__(self, settings):
- super(linux_image, self).__init__(settings)
+ def __init__(self, conf):
+ super(linux_image, self).__init__(conf)
def get_exes(self):
exes = super(linux_image, self).get_exes()
@@ -552,9 +680,9 @@ class linux_image(image):
self.command('sudo umount %s' % (path_))
class darwin_image(image):
- def __init__(self, settings):
- super(darwin_image, self).__init__(settings)
- if not self.settings.output.endswith('.img'):
+ def __init__(self, conf):
+ super(darwin_image, self).__init__(conf)
+ if not self.conf['output'].endswith('.img'):
log.notice('Output file does not end with `.img`. ' + \
'Needed on MacOS due to a bug (Id: 51283993)')
raise error.general('output file does not end with `.img`')
@@ -574,7 +702,7 @@ class darwin_image(image):
def host_image_detach(self, device):
self.command('sudo hdiutil detach %s' % (device))
- def host_partition(self, image_, device, ptype, pformat, psize, palign):
+ def host_partition(self, image_, device, ptype, plabel, pformat, psize, palign):
types = { 'MBR': 'MBR' }
formats = { 'fat16': 'MS-DOS FAT16',
'fat32': 'MS-DOS FAT32' }
@@ -588,7 +716,7 @@ class darwin_image(image):
#
cmd = "sudo diskutil partitionDisk %s 2 %s " % (device, types[ptype])
cmd += "'Free Space' '%%noformat%%' %s " % (palign)
- cmd += "'%s' RTEMS %s" % (formats[pformat], psize)
+ cmd += "'%s' %s %s" % (formats[pformat], plabel, psize)
self.command(cmd)
#
# MacOS mounts the filesystem once the partitioning has finished,
@@ -631,8 +759,7 @@ def load_log(logfile):
log.default = log.log(streams = [logfile])
def log_default():
- return 'rtems-log-uboot-image-%s.txt' % \
- (datetime.datetime.now().strftime('%Y%m%d-%H%M%S'))
+ return 'rtems-log-boot-image.txt'
class valid_dir(argparse.Action):
def __call__(self, parser, namespace, values, option_string = None):
@@ -663,6 +790,24 @@ class valid_file(argparse.Action):
value = current + [value]
setattr(namespace, self.dest, value)
+class valid_paths(argparse.Action):
+ def __call__(self, parser, namespace, value, option_string = None):
+ current = getattr(namespace, self.dest)
+ if current is None:
+ current = []
+ if isinstance(value, list):
+ values = value
+ else:
+ values = [values]
+ for value in values:
+ if not path.isfile(value) and not path.isdir(value):
+ err = 'is not a valid file or directory: %s' % (value)
+ raise argparse.ArgumentError(self, err)
+ if not path.isreadable(value):
+ raise argparse.ArgumentError(self, 'is not readable: %s' % (value))
+ current += [value]
+ setattr(namespace, self.dest, current)
+
class valid_format(argparse.Action):
def __call__(self, parser, namespace, value, option_string = None):
current = getattr(namespace, self.dest)
@@ -705,62 +850,66 @@ def run(args = sys.argv, command_path = None):
notice = None
builder = None
try:
- description = 'RTEMS Boot Image builder creates a boot image for'
- description += 'for a range of boards.'
+ description = 'Provide one path to a u-boot build or provide two '
+ description += 'paths to the built the first and second stage loaders, '
+ description += 'for example a first stage loader is \'MLO\' and a second '
+ description += '\'u-boot.img\'.'
argsp = argparse.ArgumentParser(prog = 'rtems-boot-image',
description = description)
argsp.add_argument('-l', '--log',
- help = 'Log file (default: %(default)s.',
+ help = 'log file (default: %(default)s).',
type = str, default = log_default())
argsp.add_argument('-v', '--trace',
- help = 'Enable trace logging for debugging.',
+ help = 'enable trace logging for debugging.',
action = 'store_true')
argsp.add_argument('-s', '--image-size',
- help = 'Image size in mega-bytes (default: %(default)s).',
+ help = 'image size in mega-bytes (default: %(default)s).',
type = str, action = valid_si, default = '64m')
argsp.add_argument('-F', '--fs-format',
- help = 'Root file system format (default: %(default)s).',
+ help = 'root file system format (default: %(default)s).',
type = str, action = valid_format, default = 'fat16')
argsp.add_argument('-S', '--fs-size',
- help = 'Root file system size in SI units ' + \
+ help = 'root file system size in SI units ' + \
'(default: %(default)s).',
type = str, action = valid_si, default = '63m')
argsp.add_argument('-A', '--fs-align',
- help = 'Root file system alignment in SI units ' + \
+ help = 'root file system alignment in SI units ' + \
'(default: %(default)s).',
type = str, action = valid_si, default = '63m')
argsp.add_argument('-k', '--kernel',
- help = 'Install the kernel (default: %(default)r).',
+ help = 'install the kernel (default: %(default)r).',
type = str, action = valid_file, default = None)
argsp.add_argument('-f', '--file',
- help = 'Install the file (default: None).',
+ help = 'install the file (default: None).',
type = str, action = valid_file, default = [])
- argsp.add_argument('-N', '--net-boot',
- help = 'Configure a network boot using TFTP ' + \
+ argsp.add_argument('--net-boot',
+ help = 'configure a network boot using TFTP ' + \
'(default: %(default)r).',
action = 'store_true')
- argsp.add_argument('-B', '--net-boot-server',
- help = 'Network boot server IP address ' + \
+ argsp.add_argument('--net-boot-server',
+ help = 'network boot server IP address ' + \
'(default: %(default)r).',
type = str, action = valid_ip, default = None)
- argsp.add_argument('-I', '--net-boot-ip',
- help = 'Network boot IP address (default: %(default)r).',
+ argsp.add_argument('--net-boot-ip',
+ help = 'network boot IP address (default: %(default)r).',
type = str, action = valid_ip, default = None)
argsp.add_argument('-U', '--custom-uenv',
- help = 'Install the custom uEnv.txt file ' + \
+ help = 'install the custom uEnv.txt file ' + \
'(default: %(default)r).',
type = str, action = valid_file, default = None)
- argsp.add_argument('-b', '--build',
- help = 'Path to a directory to build the image in' + \
- ' (default: %(default)s).',
- action = valid_dir, default = 'build')
+ argsp.add_argument('-b', '--board',
+ help = 'name of the board (default: %(default)r).',
+ type = str, required = True)
+ argsp.add_argument('--no-clean',
+ help = 'do not clean up when finished (default: %(default)r).',
+ action = 'store_false', default = False)
argsp.add_argument('-o', '--output',
- help = 'Image output file name',
+ help = 'image output file name',
type = str, required = True)
- argsp.add_argument('uboot',
- help = 'The path to a built u-boot.',
- nargs = 1, type = str, action = valid_dir)
+ argsp.add_argument('paths',
+ help = 'files or paths, the number and type sets the mode.',
+ nargs = '+', action = valid_paths)
argopts = argsp.parse_args(args[1:])
@@ -773,28 +922,33 @@ def run(args = sys.argv, command_path = None):
log.output('Platform: %s' % (host.name))
- config = uboot_settings(argopts.uboot)
+ conf = uboot_config(command_path, argopts.paths, argopts.board)
+ conf.check_mandatory_configs()
- config.output = argopts.output
- config.net_server_ip = argopts.net_boot_server
- config.net_ip = argopts.net_boot_ip
- config.build = argopts.build
- config.image_size = argopts.image_size
- config.fs_format = argopts.fs_format
- config.fs_size = argopts.fs_size
- config.fs_align = argopts.fs_align
- config.kernel = argopts.kernel
- config.files = argopts.file
- config.uenv_txt = argopts.custom_uenv
+ conf.clean = argopts.no_clean
+ conf['output'] = argopts.output
+ conf['net_server_ip'] = argopts.net_boot_server
+ conf['net_ip'] = argopts.net_boot_ip
+ conf['build'] = 'build' # need an option for this at some point
+ conf['image_size'] = argopts.image_size
+ conf['fs_format'] = argopts.fs_format
+ conf['fs_size'] = argopts.fs_size
+ conf['fs_align'] = argopts.fs_align
+ conf['kernel'] = argopts.kernel
+ conf['files'] = ','.join(argopts.file)
+ conf['uenv_txt'] = argopts.custom_uenv
- config.log()
+ conf.log()
if host.name not in builders:
err = 'no builder; platform not supported: %s' % (host.name)
raise error.general(err)
- builder = builders[host.name](config)
- builder.check_exes()
+ builder = builders[host.name](conf)
+
+ if not conf.check_exes() or not builder.check_exes():
+ raise error.general('command(s) not found; please fix.')
+
builder.build()
except error.general as gerr:
diff --git a/misc/tools/rtems-boot.ini b/misc/tools/rtems-boot.ini
new file mode 100644
index 0000000..631a107
--- /dev/null
+++ b/misc/tools/rtems-boot.ini
@@ -0,0 +1,64 @@
+;
+; Bootloader Parameters
+;
+
+[default]
+image_size = 64m
+part_type = MBR
+part_label = RTEMS
+fs_format = fat16
+fs_size = 63m
+fs_alignment = 1m
+tool_prefix = %{arch}-rtems%{version}-
+objcopy = %{tool_prefix}objcopy
+bootloaders = u-boot
+
+[u-boot]
+boards = u-boot-beaglebone,
+ u-boot-zedboard
+bootdelay = 5
+mkimage = %{ubootdir}/tools/mkimage
+executables = cat, gzip, %{mkimage}, %{objcopy}
+boot_config = uEnv.txt
+
+[u-boot-beaglebone]
+uses = u-boot-arm-ti-am335x_evm
+
+[u-boot-zedboard]
+uses = u-boot-arm-xilinx-zynq-common
+
+[u-boot-arm-ti-am335x_evm]
+arch = arm
+vendor = ti
+board = am335x
+config_name = am335x_evm
+first_stage = %{ubootdir}/MLO
+boot_device = mmc 0
+second_stage = %{ubootdir}/u-boot.img
+start_address = 0x80000000
+entry_address = 0x80000000
+kernel_loadaddr = 0x82000000
+kernel_converter = %{objcopy} @KERNEL@ -O binary @KERNEL@.bin,
+ cat @KERNEL@.bin | gzip -9 > @KERNEL@.gz,
+ %{mkimage} -A arm -O RTEMS -T kernel -a %{start_address}
+ -e %{entry_address} -n "RTEMS" -d @KERNEL@.gz @KERNEL@.img
+kernel_image = @KERNEL@.img
+
+[u-boot-arm-xilinx-zynq-common]
+arch = arm
+vendor = xilinx
+board = zynq
+config_name = zynq-common
+first_stage = %{ubootdior}/spl/boot.bin
+second_state = %{ubootdir}/u-boot.img
+kernel_loadaddr = 0x02000000
+kernel_converter = %{objcopy} -R -S --strip-debug -O binary @KERNEL@ @KERNEL@.bin,
+ cat @KERNEL@.bin | gzip -9 @KERNEL@.gz
+kernel_image = @KERNEL@.img
+
+[u-boot-templates]
+exe = setenv bootdelay %{bootdelay},
+ loadaddr=%{kernel_loadaddr},
+ bootfile=@KERNEL_IMAGE@,
+ uenvcmd=run boot_exe,
+ boot_exe=load %{boot_device} %{kernel_loadaddr}; bootm %{kernel_loadaddr}