...@@ -455,21 +455,21 @@ def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname, ...@@ -455,21 +455,21 @@ def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname,
>>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \ >>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \
False, alias) False, alias)
'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \ 'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \
"m.poppins@cloud.net" --cc-cmd "./patman --cc-cmd cc-fname" cover p1 p2' "m.poppins@cloud.net" --cc-cmd "./patman send --cc-cmd cc-fname" cover p1 p2'
>>> EmailPatches(series, None, ['p1'], True, True, 'cc-fname', False, \ >>> EmailPatches(series, None, ['p1'], True, True, 'cc-fname', False, \
alias) alias)
'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \ 'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \
"m.poppins@cloud.net" --cc-cmd "./patman --cc-cmd cc-fname" p1' "m.poppins@cloud.net" --cc-cmd "./patman send --cc-cmd cc-fname" p1'
>>> series['cc'] = ['all'] >>> series['cc'] = ['all']
>>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \ >>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \
True, alias) True, alias)
'git send-email --annotate --to "this-is-me@me.com" --cc-cmd "./patman \ 'git send-email --annotate --to "this-is-me@me.com" --cc-cmd "./patman \
--cc-cmd cc-fname" cover p1 p2' send --cc-cmd cc-fname" cover p1 p2'
>>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \ >>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \
False, alias) False, alias)
'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \ 'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \
"f.bloggs@napier.co.nz" --cc "j.bloggs@napier.co.nz" --cc \ "f.bloggs@napier.co.nz" --cc "j.bloggs@napier.co.nz" --cc \
"m.poppins@cloud.net" --cc-cmd "./patman --cc-cmd cc-fname" cover p1 p2' "m.poppins@cloud.net" --cc-cmd "./patman send --cc-cmd cc-fname" cover p1 p2'
# Restore argv[0] since we clobbered it. # Restore argv[0] since we clobbered it.
>>> sys.argv[0] = _old_argv0 >>> sys.argv[0] = _old_argv0
...@@ -500,7 +500,7 @@ def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname, ...@@ -500,7 +500,7 @@ def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname,
cmd += to cmd += to
cmd += cc cmd += cc
cmd += ['--cc-cmd', '"%s --cc-cmd %s"' % (sys.argv[0], cc_fname)] cmd += ['--cc-cmd', '"%s send --cc-cmd %s"' % (sys.argv[0], cc_fname)]
if cover_fname: if cover_fname:
cmd.append(cover_fname) cmd.append(cover_fname)
cmd += args cmd += args
......
...@@ -28,26 +28,33 @@ from patman import terminal ...@@ -28,26 +28,33 @@ from patman import terminal
from patman import test_util from patman import test_util
from patman import test_checkpatch from patman import test_checkpatch
def AddCommonArgs(parser):
parser.add_argument('-b', '--branch', type=str,
help="Branch to process (by default, the current branch)")
parser.add_argument('-c', '--count', dest='count', type=int,
default=-1, help='Automatically create patches from top n commits')
parser.add_argument('-e', '--end', type=int, default=0,
help='Commits to skip at end of patch list')
parser.add_argument('-D', '--debug', action='store_true',
help='Enabling debugging (provides a full traceback on error)')
parser.add_argument('-s', '--start', dest='start', type=int,
default=0, help='Commit to start creating patches from (0 = HEAD)')
epilog = '''Create patches from commits in a branch, check them and email them epilog = '''Create patches from commits in a branch, check them and email them
as specified by tags you place in the commits. Use -n to do a dry run first.''' as specified by tags you place in the commits. Use -n to do a dry run first.'''
parser = ArgumentParser(epilog=epilog) parser = ArgumentParser(epilog=epilog)
parser.add_argument('-b', '--branch', type=str,
help="Branch to process (by default, the current branch)")
parser.add_argument('-c', '--count', dest='count', type=int,
default=-1, help='Automatically create patches from top n commits')
parser.add_argument('-e', '--end', type=int, default=0,
help='Commits to skip at end of patch list')
parser.add_argument('-D', '--debug', action='store_true',
help='Enabling debugging (provides a full traceback on error)')
parser.add_argument('-p', '--project', default=project.DetectProject(),
help="Project name; affects default option values and "
"aliases [default: %(default)s]")
parser.add_argument('-P', '--patchwork-url',
default='https://patchwork.ozlabs.org',
help='URL of patchwork server [default: %(default)s]')
parser.add_argument('-s', '--start', dest='start', type=int,
default=0, help='Commit to start creating patches from (0 = HEAD)')
parser.add_argument('-v', '--verbose', action='store_true', dest='verbose',
default=False, help='Verbose output of errors and warnings')
parser.add_argument('-H', '--full-help', action='store_true', dest='full_help',
default=False, help='Display the README file')
subparsers = parser.add_subparsers(dest='cmd') subparsers = parser.add_subparsers(dest='cmd')
send = subparsers.add_parser('send') send = subparsers.add_parser('send')
send.add_argument('-H', '--full-help', action='store_true', dest='full_help',
default=False, help='Display the README file')
send.add_argument('-i', '--ignore-errors', action='store_true', send.add_argument('-i', '--ignore-errors', action='store_true',
dest='ignore_errors', default=False, dest='ignore_errors', default=False,
help='Send patches email even if patch errors are found') help='Send patches email even if patch errors are found')
...@@ -58,15 +65,10 @@ send.add_argument('-m', '--no-maintainers', action='store_false', ...@@ -58,15 +65,10 @@ send.add_argument('-m', '--no-maintainers', action='store_false',
help="Don't cc the file maintainers automatically") help="Don't cc the file maintainers automatically")
send.add_argument('-n', '--dry-run', action='store_true', dest='dry_run', send.add_argument('-n', '--dry-run', action='store_true', dest='dry_run',
default=False, help="Do a dry run (create but don't email patches)") default=False, help="Do a dry run (create but don't email patches)")
send.add_argument('-p', '--project', default=project.DetectProject(),
help="Project name; affects default option values and "
"aliases [default: %(default)s]")
send.add_argument('-r', '--in-reply-to', type=str, action='store', send.add_argument('-r', '--in-reply-to', type=str, action='store',
help="Message ID that this series is in reply to") help="Message ID that this series is in reply to")
send.add_argument('-t', '--ignore-bad-tags', action='store_true', send.add_argument('-t', '--ignore-bad-tags', action='store_true',
default=False, help='Ignore bad tags / aliases') default=False, help='Ignore bad tags / aliases')
send.add_argument('-v', '--verbose', action='store_true', dest='verbose',
default=False, help='Verbose output of errors and warnings')
send.add_argument('-T', '--thread', action='store_true', dest='thread', send.add_argument('-T', '--thread', action='store_true', dest='thread',
default=False, help='Create patches as a single thread') default=False, help='Create patches as a single thread')
send.add_argument('--cc-cmd', dest='cc_cmd', type=str, action='store', send.add_argument('--cc-cmd', dest='cc_cmd', type=str, action='store',
...@@ -81,14 +83,12 @@ send.add_argument('--no-tags', action='store_false', dest='process_tags', ...@@ -81,14 +83,12 @@ send.add_argument('--no-tags', action='store_false', dest='process_tags',
default=True, help="Don't process subject tags as aliases") default=True, help="Don't process subject tags as aliases")
send.add_argument('--smtp-server', type=str, send.add_argument('--smtp-server', type=str,
help="Specify the SMTP server to 'git send-email'") help="Specify the SMTP server to 'git send-email'")
AddCommonArgs(send)
send.add_argument('patchfiles', nargs='*') send.add_argument('patchfiles', nargs='*')
test_parser = subparsers.add_parser('test', help='Run tests') test_parser = subparsers.add_parser('test', help='Run tests')
test_parser.add_argument('testname', type=str, default=None, nargs='?', test_parser.add_argument('testname', type=str, default=None, nargs='?',
help="Specify the test to run") help="Specify the test to run")
AddCommonArgs(test_parser)
status = subparsers.add_parser('status', status = subparsers.add_parser('status',
help='Check status of patches in patchwork') help='Check status of patches in patchwork')
...@@ -98,16 +98,24 @@ status.add_argument('-d', '--dest-branch', type=str, ...@@ -98,16 +98,24 @@ status.add_argument('-d', '--dest-branch', type=str,
help='Name of branch to create with collected responses') help='Name of branch to create with collected responses')
status.add_argument('-f', '--force', action='store_true', status.add_argument('-f', '--force', action='store_true',
help='Force overwriting an existing branch') help='Force overwriting an existing branch')
AddCommonArgs(status)
# Parse options twice: first to get the project and second to handle # Parse options twice: first to get the project and second to handle
# defaults properly (which depends on project). # defaults properly (which depends on project)
# Use parse_known_args() in case 'cmd' is omitted
argv = sys.argv[1:] argv = sys.argv[1:]
if len(argv) < 1 or argv[0].startswith('-'): args, rest = parser.parse_known_args(argv)
argv = ['send'] + argv
args = parser.parse_args(argv)
if hasattr(args, 'project'): if hasattr(args, 'project'):
settings.Setup(gitutil, send, args.project, '') settings.Setup(gitutil, parser, args.project, '')
args, rest = parser.parse_known_args(argv)
# If we have a command, it is safe to parse all arguments
if args.cmd:
args = parser.parse_args(argv)
else:
# No command, so insert it after the known arguments and before the ones
# that presumably relate to the 'send' subcommand
nargs = len(rest)
argv = argv[:-nargs] + ['send'] + rest
args = parser.parse_args(argv) args = parser.parse_args(argv)
if __name__ != "__main__": if __name__ != "__main__":
...@@ -174,7 +182,7 @@ elif args.cmd == 'status': ...@@ -174,7 +182,7 @@ elif args.cmd == 'status':
try: try:
control.patchwork_status(args.branch, args.count, args.start, args.end, control.patchwork_status(args.branch, args.count, args.start, args.end,
args.dest_branch, args.force, args.dest_branch, args.force,
args.show_comments) args.show_comments, args.patchwork_url)
except Exception as e: except Exception as e:
terminal.Print('patman: %s: %s' % (type(e).__name__, e), terminal.Print('patman: %s: %s' % (type(e).__name__, e),
colour=terminal.Color.RED) colour=terminal.Color.RED)
......
...@@ -452,8 +452,8 @@ class PatchStream: ...@@ -452,8 +452,8 @@ class PatchStream:
if self.is_log: if self.is_log:
if self.commit.change_id: if self.commit.change_id:
raise ValueError( raise ValueError(
"%s: Two Change-Ids: '%s' vs. '%s'" % self.commit.hash, "%s: Two Change-Ids: '%s' vs. '%s'" %
self.commit.change_id, value) (self.commit.hash, self.commit.change_id, value))
self.commit.change_id = value self.commit.change_id = value
self.skip_blank = True self.skip_blank = True
......
...@@ -16,7 +16,7 @@ from patman import tools ...@@ -16,7 +16,7 @@ from patman import tools
# Series-xxx tags that we understand # Series-xxx tags that we understand
valid_series = ['to', 'cc', 'version', 'changes', 'prefix', 'notes', 'name', valid_series = ['to', 'cc', 'version', 'changes', 'prefix', 'notes', 'name',
'cover_cc', 'process_log', 'links'] 'cover_cc', 'process_log', 'links', 'patchwork_url']
class Series(dict): class Series(dict):
"""Holds information about a patch series, including all tags. """Holds information about a patch series, including all tags.
......
...@@ -7,6 +7,7 @@ try: ...@@ -7,6 +7,7 @@ try:
except: except:
import ConfigParser import ConfigParser
import argparse
import os import os
import re import re
...@@ -216,10 +217,10 @@ nxp = Zhikang Zhang <zhikang.zhang@nxp.com> ...@@ -216,10 +217,10 @@ nxp = Zhikang Zhang <zhikang.zhang@nxp.com>
''' % (name, email), file=f) ''' % (name, email), file=f)
f.close(); f.close();
def _UpdateDefaults(parser, config): def _UpdateDefaults(main_parser, config):
"""Update the given OptionParser defaults based on config. """Update the given OptionParser defaults based on config.
We'll walk through all of the settings from the parser We'll walk through all of the settings from all parsers.
For each setting we'll look for a default in the option parser. For each setting we'll look for a default in the option parser.
If it's found we'll update the option parser default. If it's found we'll update the option parser default.
...@@ -228,13 +229,24 @@ def _UpdateDefaults(parser, config): ...@@ -228,13 +229,24 @@ def _UpdateDefaults(parser, config):
say. say.
Args: Args:
parser: An instance of an OptionParser whose defaults will be parser: An instance of an ArgumentParser whose defaults will be
updated. updated.
config: An instance of _ProjectConfigParser that we will query config: An instance of _ProjectConfigParser that we will query
for settings. for settings.
""" """
defaults = parser.parse_known_args()[0] # Find all the parsers and subparsers
defaults = vars(defaults) parsers = [main_parser]
parsers += [subparser for action in main_parser._actions
if isinstance(action, argparse._SubParsersAction)
for _, subparser in action.choices.items()]
# Collect the defaults from each parser
defaults = {}
for parser in parsers:
pdefs = parser.parse_known_args()[0]
defaults.update(vars(pdefs))
# Go through the settings and collect defaults
for name, val in config.items('settings'): for name, val in config.items('settings'):
if name in defaults: if name in defaults:
default_val = defaults[name] default_val = defaults[name]
...@@ -242,10 +254,14 @@ def _UpdateDefaults(parser, config): ...@@ -242,10 +254,14 @@ def _UpdateDefaults(parser, config):
val = config.getboolean('settings', name) val = config.getboolean('settings', name)
elif isinstance(default_val, int): elif isinstance(default_val, int):
val = config.getint('settings', name) val = config.getint('settings', name)
elif isinstance(default_val, str):
val = config.get('settings', name)
defaults[name] = val defaults[name] = val
else: else:
print("WARNING: Unknown setting %s" % name) print("WARNING: Unknown setting %s" % name)
parser.set_defaults(**defaults)
# Set all the defaults (this propagates through all subparsers)
main_parser.set_defaults(**defaults)
def _ReadAliasFile(fname): def _ReadAliasFile(fname):
"""Read in the U-Boot git alias file if it exists. """Read in the U-Boot git alias file if it exists.
......
...@@ -198,10 +198,11 @@ def compare_with_series(series, patches): ...@@ -198,10 +198,11 @@ def compare_with_series(series, patches):
return patch_for_commit, commit_for_patch, warnings return patch_for_commit, commit_for_patch, warnings
def call_rest_api(subpath): def call_rest_api(url, subpath):
"""Call the patchwork API and return the result as JSON """Call the patchwork API and return the result as JSON
Args: Args:
url (str): URL of patchwork server, e.g. 'https://patchwork.ozlabs.org'
subpath (str): URL subpath to use subpath (str): URL subpath to use
Returns: Returns:
...@@ -210,13 +211,13 @@ def call_rest_api(subpath): ...@@ -210,13 +211,13 @@ def call_rest_api(subpath):
Raises: Raises:
ValueError: the URL could not be read ValueError: the URL could not be read
""" """
url = 'https://patchwork.ozlabs.org/api/1.2/%s' % subpath full_url = '%s/api/1.2/%s' % (url, subpath)
response = requests.get(url) response = requests.get(full_url)
if response.status_code != 200: if response.status_code != 200:
raise ValueError("Could not read URL '%s'" % url) raise ValueError("Could not read URL '%s'" % full_url)
return response.json() return response.json()
def collect_patches(series, series_id, rest_api=call_rest_api): def collect_patches(series, series_id, url, rest_api=call_rest_api):
"""Collect patch information about a series from patchwork """Collect patch information about a series from patchwork
Uses the Patchwork REST API to collect information provided by patchwork Uses the Patchwork REST API to collect information provided by patchwork
...@@ -226,6 +227,7 @@ def collect_patches(series, series_id, rest_api=call_rest_api): ...@@ -226,6 +227,7 @@ def collect_patches(series, series_id, rest_api=call_rest_api):
series (Series): Series object corresponding to the local branch series (Series): Series object corresponding to the local branch
containing the series containing the series
series_id (str): Patch series ID number series_id (str): Patch series ID number
url (str): URL of patchwork server, e.g. 'https://patchwork.ozlabs.org'
rest_api (function): API function to call to access Patchwork, for rest_api (function): API function to call to access Patchwork, for
testing testing
...@@ -236,7 +238,7 @@ def collect_patches(series, series_id, rest_api=call_rest_api): ...@@ -236,7 +238,7 @@ def collect_patches(series, series_id, rest_api=call_rest_api):
ValueError: if the URL could not be read or the web page does not follow ValueError: if the URL could not be read or the web page does not follow
the expected structure the expected structure
""" """
data = rest_api('series/%s/' % series_id) data = rest_api(url, 'series/%s/' % series_id)
# Get all the rows, which are patches # Get all the rows, which are patches
patch_dict = data['patches'] patch_dict = data['patches']
...@@ -261,7 +263,7 @@ def collect_patches(series, series_id, rest_api=call_rest_api): ...@@ -261,7 +263,7 @@ def collect_patches(series, series_id, rest_api=call_rest_api):
patches = sorted(patches, key=lambda x: x.seq) patches = sorted(patches, key=lambda x: x.seq)
return patches return patches
def find_new_responses(new_rtag_list, review_list, seq, cmt, patch, def find_new_responses(new_rtag_list, review_list, seq, cmt, patch, url,
rest_api=call_rest_api): rest_api=call_rest_api):
"""Find new rtags collected by patchwork that we don't know about """Find new rtags collected by patchwork that we don't know about
...@@ -279,6 +281,7 @@ def find_new_responses(new_rtag_list, review_list, seq, cmt, patch, ...@@ -279,6 +281,7 @@ def find_new_responses(new_rtag_list, review_list, seq, cmt, patch,
seq (int): Position in new_rtag_list to update seq (int): Position in new_rtag_list to update
cmt (Commit): Commit object for this commit cmt (Commit): Commit object for this commit
patch (Patch): Corresponding Patch object for this patch patch (Patch): Corresponding Patch object for this patch
url (str): URL of patchwork server, e.g. 'https://patchwork.ozlabs.org'
rest_api (function): API function to call to access Patchwork, for rest_api (function): API function to call to access Patchwork, for
testing testing
""" """
...@@ -286,14 +289,14 @@ def find_new_responses(new_rtag_list, review_list, seq, cmt, patch, ...@@ -286,14 +289,14 @@ def find_new_responses(new_rtag_list, review_list, seq, cmt, patch,
return return
# Get the content for the patch email itself as well as all comments # Get the content for the patch email itself as well as all comments
data = rest_api('patches/%s/' % patch.id) data = rest_api(url, 'patches/%s/' % patch.id)
pstrm = PatchStream.process_text(data['content'], True) pstrm = PatchStream.process_text(data['content'], True)
rtags = collections.defaultdict(set) rtags = collections.defaultdict(set)
for response, people in pstrm.commit.rtags.items(): for response, people in pstrm.commit.rtags.items():
rtags[response].update(people) rtags[response].update(people)
data = rest_api('patches/%s/comments/' % patch.id) data = rest_api(url, 'patches/%s/comments/' % patch.id)
reviews = [] reviews = []
for comment in data: for comment in data:
...@@ -407,7 +410,7 @@ def create_branch(series, new_rtag_list, branch, dest_branch, overwrite, ...@@ -407,7 +410,7 @@ def create_branch(series, new_rtag_list, branch, dest_branch, overwrite,
return num_added return num_added
def check_patchwork_status(series, series_id, branch, dest_branch, force, def check_patchwork_status(series, series_id, branch, dest_branch, force,
show_comments, rest_api=call_rest_api, show_comments, url, rest_api=call_rest_api,
test_repo=None): test_repo=None):
"""Check the status of a series on Patchwork """Check the status of a series on Patchwork
...@@ -421,11 +424,12 @@ def check_patchwork_status(series, series_id, branch, dest_branch, force, ...@@ -421,11 +424,12 @@ def check_patchwork_status(series, series_id, branch, dest_branch, force,
dest_branch (str): Name of new branch to create, or None dest_branch (str): Name of new branch to create, or None
force (bool): True to force overwriting dest_branch if it exists force (bool): True to force overwriting dest_branch if it exists
show_comments (bool): True to show the comments on each patch show_comments (bool): True to show the comments on each patch
url (str): URL of patchwork server, e.g. 'https://patchwork.ozlabs.org'
rest_api (function): API function to call to access Patchwork, for rest_api (function): API function to call to access Patchwork, for
testing testing
test_repo (pygit2.Repository): Repo to use (use None unless testing) test_repo (pygit2.Repository): Repo to use (use None unless testing)
""" """
patches = collect_patches(series, series_id, rest_api) patches = collect_patches(series, series_id, url, rest_api)
col = terminal.Color() col = terminal.Color()
count = len(series.commits) count = len(series.commits)
new_rtag_list = [None] * count new_rtag_list = [None] * count
...@@ -440,7 +444,8 @@ def check_patchwork_status(series, series_id, branch, dest_branch, force, ...@@ -440,7 +444,8 @@ def check_patchwork_status(series, series_id, branch, dest_branch, force,
with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor: with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor:
futures = executor.map( futures = executor.map(
find_new_responses, repeat(new_rtag_list), repeat(review_list), find_new_responses, repeat(new_rtag_list), repeat(review_list),
range(count), series.commits, patch_list, repeat(rest_api)) range(count), series.commits, patch_list, repeat(url),
repeat(rest_api))
for fresponse in futures: for fresponse in futures:
if fresponse: if fresponse:
raise fresponse.exception() raise fresponse.exception()
......
...@@ -333,6 +333,7 @@ def Run(name, *args, **kwargs): ...@@ -333,6 +333,7 @@ def Run(name, *args, **kwargs):
elif for_host: elif for_host:
name, extra_args = GetHostCompileTool(name) name, extra_args = GetHostCompileTool(name)
args = tuple(extra_args) + args args = tuple(extra_args) + args
name = os.path.expanduser(name) # Expand paths containing ~
all_args = (name,) + args all_args = (name,) + args
result = command.RunPipe([all_args], capture=True, capture_stderr=True, result = command.RunPipe([all_args], capture=True, capture_stderr=True,
env=env, raise_on_error=False, binary=binary) env=env, raise_on_error=False, binary=binary)
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 Marvell International Ltd.
*/
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <arpa/inet.h>
#include <linux/compiler.h>
#include <u-boot/crc.h>
#include "mkimage.h"
#include "../arch/mips/mach-octeon/include/mach/cvmx-bootloader.h"
#define BUF_SIZE (16 * 1024)
#define NAME_LEN 100
/* word offset */
#define WOFFSETOF(type, elem) (offsetof(type, elem) / 4)
static int stage2_flag;
static int stage_1_5_flag;
static int stage_1_flag;
/* Getoptions variables must be global */
static int failsafe_flag;
static int pciboot_flag;
static int env_flag;
static const struct option long_options[] = {
/* These options set a flag. */
{"failsafe", no_argument, &failsafe_flag, 1},
{"pciboot", no_argument, &pciboot_flag, 1},
{"nandstage2", no_argument, &stage2_flag, 1},
{"spistage2", no_argument, &stage2_flag, 1},
{"norstage2", no_argument, &stage2_flag, 1},
{"stage2", no_argument, &stage2_flag, 1},
{"stage1.5", no_argument, &stage_1_5_flag, 1},
{"stage1", no_argument, &stage_1_flag, 1},
{"environment", no_argument, &env_flag, 1},
/*
* These options don't set a flag.
* We distinguish them by their indices.
*/
{"board", required_argument, 0, 0},
{"text_base", required_argument, 0, 0},
{0, 0, 0, 0}
};
static int lookup_board_type(char *board_name)
{
int i;
int board_type = 0;
char *substr = NULL;
/* Detect stage 2 bootloader boards */
if (strcasestr(board_name, "_stage2")) {
printf("Stage 2 bootloader detected from substring %s in name %s\n",
"_stage2", board_name);
stage2_flag = 1;
} else {
printf("Stage 2 bootloader NOT detected from name \"%s\"\n",
board_name);
}
if (strcasestr(board_name, "_stage1")) {
printf("Stage 1 bootloader detected from substring %s in name %s\n",
"_stage1", board_name);
stage_1_flag = 1;
}
/* Generic is a special case since there are numerous sub-types */
if (!strncasecmp("generic", board_name, strlen("generic")))
return CVMX_BOARD_TYPE_GENERIC;
/*
* If we're an eMMC stage 2 bootloader, cut off the _emmc_stage2
* part of the name.
*/
substr = strcasestr(board_name, "_emmc_stage2");
if (substr && (substr[strlen("_emmc_stage2")] == '\0')) {
/*return CVMX_BOARD_TYPE_GENERIC;*/
printf(" Converting board name %s to ", board_name);
*substr = '\0';
printf("%s\n", board_name);
}
/*
* If we're a NAND stage 2 bootloader, cut off the _nand_stage2
* part of the name.
*/
substr = strcasestr(board_name, "_nand_stage2");
if (substr && (substr[strlen("_nand_stage2")] == '\0')) {
/*return CVMX_BOARD_TYPE_GENERIC;*/
printf(" Converting board name %s to ", board_name);
*substr = '\0';
printf("%s\n", board_name);
}
/*
* If we're a SPI stage 2 bootloader, cut off the _spi_stage2
* part of the name.
*/
substr = strcasestr(board_name, "_spi_stage2");
if (substr && (substr[strlen("_spi_stage2")] == '\0')) {
printf(" Converting board name %s to ", board_name);
*substr = '\0';
printf("%s\n", board_name);
}
for (i = CVMX_BOARD_TYPE_NULL; i < CVMX_BOARD_TYPE_MAX; i++)
if (!strcasecmp(cvmx_board_type_to_string(i), board_name))
board_type = i;
for (i = CVMX_BOARD_TYPE_CUST_DEFINED_MIN;
i < CVMX_BOARD_TYPE_CUST_DEFINED_MAX; i++)
if (!strncasecmp(cvmx_board_type_to_string(i), board_name,
strlen(cvmx_board_type_to_string(i))))
board_type = i;
for (i = CVMX_BOARD_TYPE_CUST_PRIVATE_MIN;
i < CVMX_BOARD_TYPE_CUST_PRIVATE_MAX; i++)
if (!strncasecmp(cvmx_board_type_to_string(i), board_name,
strlen(cvmx_board_type_to_string(i))))
board_type = i;
return board_type;
}
static void usage(void)
{
printf("Usage: update_octeon_header <filename> <board_name> [--failsafe] [--text_base=0xXXXXX]\n");
}
int main(int argc, char *argv[])
{
int fd;
uint8_t buf[BUF_SIZE];
uint32_t data_crc = 0;
int len;
int data_len = 0;
struct bootloader_header header;
char filename[NAME_LEN];
int i;
int option_index = 0; /* getopt_long stores the option index here. */
char board_name[NAME_LEN] = { 0 };
char tmp_board_name[NAME_LEN] = { 0 };
int c;
int board_type = 0;
unsigned long long address = 0;
ssize_t ret;
const char *type_str = NULL;
int hdr_size = sizeof(struct bootloader_header);
/*
* Compile time check, if the size of the bootloader_header structure
* has changed.
*/
compiletime_assert(sizeof(struct bootloader_header) == 192,
"Octeon bootloader header size changed (!= 192)!");
/* Bail out, if argument count is incorrect */
if (argc < 3) {
usage();
return -1;
}
debug("header size is: %d bytes\n", hdr_size);
/* Parse command line options using getopt_long */
while (1) {
c = getopt_long(argc, argv, "h", long_options, &option_index);
/* Detect the end of the options. */
if (c == -1)
break;
switch (c) {
/* All long options handled in case 0 */
case 0:
/* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0)
break;
debug("option(l) %s", long_options[option_index].name);
if (!optarg) {
usage();
return -1;
}
debug(" with arg %s\n", optarg);
if (!strcmp(long_options[option_index].name, "board")) {
if (strlen(optarg) >= NAME_LEN) {
printf("strncpy() issue detected!");
exit(-1);
}
strncpy(board_name, optarg, NAME_LEN);
printf("Using user supplied board name: %s\n",
board_name);
} else if (!strcmp(long_options[option_index].name,
"text_base")) {
address = strtoull(optarg, NULL, 0);
printf("Address of image is: 0x%llx\n",
(unsigned long long)address);
if (!(address & 0xFFFFFFFFULL << 32)) {
if (address & 1 << 31) {
address |= 0xFFFFFFFFULL << 32;
printf("Converting address to 64 bit compatibility space: 0x%llx\n",
address);
}
}
}
break;
case 'h':
case '?':
/* getopt_long already printed an error message. */
usage();
return -1;
default:
abort();
}
}
if (optind < argc) {
/*
* We only support one argument - an optional bootloader
* file name
*/
if (argc - optind > 2) {
fprintf(stderr, "non-option ARGV-elements: ");
while (optind < argc)
fprintf(stderr, "%s ", argv[optind++]);
fprintf(stderr, "\n");
usage();
return -1;
}
}
if (strlen(argv[optind]) >= NAME_LEN) {
fprintf(stderr, "strncpy() issue detected!");
exit(-1);
}
strncpy(filename, argv[optind], NAME_LEN);
if (board_name[0] == '\0') {
if (strlen(argv[optind + 1]) >= NAME_LEN) {
fprintf(stderr, "strncpy() issue detected!");
exit(-1);
}
strncpy(board_name, argv[optind + 1], NAME_LEN);
}
if (strlen(board_name) >= NAME_LEN) {
fprintf(stderr, "strncpy() issue detected!");
exit(-1);
}
strncpy(tmp_board_name, board_name, NAME_LEN);
fd = open(filename, O_RDWR);
if (fd < 0) {
fprintf(stderr, "Unable to open file: %s\n", filename);
exit(-1);
}
if (failsafe_flag)
printf("Setting failsafe flag\n");
if (strlen(board_name)) {
int offset = 0;
printf("Supplied board name of: %s\n", board_name);
if (strstr(board_name, "failsafe")) {
failsafe_flag = 1;
printf("Setting failsafe flag based on board name\n");
}
/* Skip leading octeon_ if present. */
if (!strncmp(board_name, "octeon_", 7))
offset = 7;
/*
* Check to see if 'failsafe' is in the name. If so, set the
* failsafe flag. Also, ignore extra trailing characters on
* passed parameter when comparing against board names.
* We actually use the configuration name from u-boot, so it
* may have some other variant names. Variants other than
* failsafe _must_ be passed to this program explicitly
*/
board_type = lookup_board_type(board_name + offset);
if (!board_type) {
/* Retry with 'cust_' prefix to catch boards that are
* in the customer section (such as nb5)
*/
sprintf(tmp_board_name, "cust_%s", board_name + offset);
board_type = lookup_board_type(tmp_board_name);
}
/* reset to original value */
strncpy(tmp_board_name, board_name, NAME_LEN);
if (!board_type) {
/*
* Retry with 'cust_private_' prefix to catch boards
* that are in the customer private section
*/
sprintf(tmp_board_name, "cust_private_%s",
board_name + offset);
board_type = lookup_board_type(tmp_board_name);
}
if (!board_type) {
fprintf(stderr,
"ERROR: unable to determine board type\n");
exit(-1);
}
printf("Board type is: %d: %s\n", board_type,
cvmx_board_type_to_string(board_type));
} else {
fprintf(stderr, "Board name must be specified!\n");
exit(-1);
}
/*
* Check to see if there is either an existing header, or that there
* are zero valued bytes where we want to put the header
*/
len = read(fd, buf, BUF_SIZE);
if (len > 0) {
/*
* Copy the header, as the first word (jump instruction, needs
* to remain the same.
*/
memcpy(&header, buf, hdr_size);
/*
* Check to see if we have zero bytes (excluding first 4, which
* are the jump instruction)
*/
for (i = 1; i < hdr_size / 4; i++) {
if (((uint32_t *)buf)[i]) {
fprintf(stderr,
"ERROR: non-zero word found %x in location %d required for header, aborting\n",
((uint32_t *)buf)[i], i);
exit(-1);
}
}
printf("Zero bytes found in header location, adding header.\n");
} else {
fprintf(stderr, "Unable to read from file %s\n", filename);
exit(-1);
}
/* Read data bytes and generate CRC */
lseek(fd, hdr_size, SEEK_SET);
while ((len = read(fd, buf, BUF_SIZE)) > 0) {
data_crc = crc32(data_crc, buf, len);
data_len += len;
}
printf("CRC of data: 0x%x, length: %d\n", data_crc, data_len);
/* Now create the new header */
header.magic = htonl(BOOTLOADER_HEADER_MAGIC);
header.maj_rev = htons(BOOTLOADER_HEADER_CURRENT_MAJOR_REV);
header.min_rev = htons(BOOTLOADER_HEADER_CURRENT_MINOR_REV);
header.dlen = htonl(data_len);
header.dcrc = htonl(data_crc);
header.board_type = htons(board_type);
header.address = address;
if (failsafe_flag)
header.flags |= htonl(BL_HEADER_FLAG_FAILSAFE);
printf("Stage 2 flag is %sset\n", stage2_flag ? "" : "not ");
printf("Stage 1 flag is %sset\n", stage_1_flag ? "" : "not ");
if (pciboot_flag)
header.image_type = htons(BL_HEADER_IMAGE_PCIBOOT);
else if (stage2_flag)
header.image_type = htons(BL_HEADER_IMAGE_STAGE2);
else if (stage_1_flag)
header.image_type = htons(BL_HEADER_IMAGE_STAGE1);
else if (env_flag)
header.image_type = htons(BL_HEADER_IMAGE_UBOOT_ENV);
else if (stage_1_5_flag || stage_1_flag)
header.image_type = htons(BL_HEADER_IMAGE_PRE_UBOOT);
else
header.image_type = htons(BL_HEADER_IMAGE_NOR);
switch (ntohs(header.image_type)) {
case BL_HEADER_IMAGE_UNKNOWN:
type_str = "Unknown";
break;
case BL_HEADER_IMAGE_STAGE1:
type_str = "Stage 1";
break;
case BL_HEADER_IMAGE_STAGE2:
type_str = "Stage 2";
break;
case BL_HEADER_IMAGE_PRE_UBOOT:
type_str = "Pre-U-Boot";
break;
case BL_HEADER_IMAGE_STAGE3:
type_str = "Stage 3";
break;
case BL_HEADER_IMAGE_NOR:
type_str = "NOR";
break;
case BL_HEADER_IMAGE_PCIBOOT:
type_str = "PCI Boot";
break;
case BL_HEADER_IMAGE_UBOOT_ENV:
type_str = "U-Boot Environment";
break;
default:
if (ntohs(header.image_type) >= BL_HEADER_IMAGE_CUST_RESERVED_MIN &&
ntohs(header.image_type) <= BL_HEADER_IMAGE_CUST_RESERVED_MAX)
type_str = "Customer Reserved";
else
type_str = "Unsupported";
}
printf("Header image type: %s\n", type_str);
header.hlen = htons(hdr_size);
/* Now compute header CRC over all of the header excluding the CRC */
header.hcrc = crc32(0, (void *)&header, 12);
header.hcrc = htonl(crc32(header.hcrc, ((void *)&(header)) + 16,
hdr_size - 16));
/* Seek to beginning of file */
lseek(fd, 0, SEEK_SET);
/* Write header to file */
ret = write(fd, &header, hdr_size);
if (ret < 0)
perror("write");
close(fd);
printf("Header CRC: 0x%x\n", ntohl(header.hcrc));
return 0;
}