blob: c58b37a9681a4ea133c62207d01ac74e93970730 [file] [log] [blame]
/* Copyright 2018 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* The command line tool to invoke firmware updater.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include "futility.h"
#include "updater.h"
#ifdef USE_FLASHROM
enum {
OPT_DUMMY = 0x1000,
OPT_DETECT_MODEL_ONLY,
OPT_FACTORY,
OPT_FAST,
OPT_FORCE,
OPT_GBB_FLAGS,
OPT_HOST_ONLY,
OPT_MANIFEST,
OPT_MODEL,
OPT_OUTPUT_DIR,
OPT_QUIRKS,
OPT_QUIRKS_LIST,
OPT_REPACK,
OPT_SERVO_NORESET,
OPT_SIGNATURE,
OPT_SYS_PROPS,
OPT_UNLOCK_ME,
OPT_UNPACK,
OPT_WRITE_PROTECTION,
};
/* Command line options */
static struct option const long_opts[] = {
SHARED_FLASH_ARGS_LONGOPTS
/* name has_arg *flag val */
{"help", 0, NULL, 'h'},
{"debug", 0, NULL, 'd'},
{"verbose", 0, NULL, 'v'},
{"image", 1, NULL, 'i'},
{"ec_image", 1, NULL, 'e'},
{"try", 0, NULL, 't'},
{"archive", 1, NULL, 'a'},
{"mode", 1, NULL, 'm'},
{"detect-model-only", 0, NULL, OPT_DETECT_MODEL_ONLY},
{"factory", 0, NULL, OPT_FACTORY},
{"fast", 0, NULL, OPT_FAST},
{"force", 0, NULL, OPT_FORCE},
{"gbb_flags", 1, NULL, OPT_GBB_FLAGS},
{"host_only", 0, NULL, OPT_HOST_ONLY},
{"quirks", 1, NULL, OPT_QUIRKS},
{"list-quirks", 0, NULL, OPT_QUIRKS_LIST},
{"manifest", 0, NULL, OPT_MANIFEST},
{"model", 1, NULL, OPT_MODEL},
{"output_dir", 1, NULL, OPT_OUTPUT_DIR},
{"repack", 1, NULL, OPT_REPACK},
{"signature_id", 1, NULL, OPT_SIGNATURE},
{"sys_props", 1, NULL, OPT_SYS_PROPS},
{"unlock_me", 0, NULL, OPT_UNLOCK_ME},
{"unpack", 1, NULL, OPT_UNPACK},
{"wp", 1, NULL, OPT_WRITE_PROTECTION},
/* TODO(hungte) Remove following deprecated options. */
{"noupdate_ec", 0, NULL, OPT_HOST_ONLY},
{"nocheck_keys", 0, NULL, OPT_FORCE},
{"update_main", 0, NULL, OPT_DUMMY},
{"update_ec", 0, NULL, OPT_DUMMY},
{"check_keys", 0, NULL, OPT_DUMMY},
{NULL, 0, NULL, 0},
};
static const char *const short_opts =
"hdvi:e:ta:m:" SHARED_FLASH_ARGS_SHORTOPTS;
static void print_help(int argc, char *argv[])
{
printf("\n"
"Usage: " MYNAME " %s [OPTIONS]\n"
"\n"
"Updates firmware in one of the following modes (default to recovery):\n"
" autoupdate:\tUpdate RW[A|B], or recovery if RO changed.\n"
" recovery: \tUpdate RW[A&B], (RO, RO:GBB[keys] - if RO changed)\n"
" factory: \tUpdate RW[A&B], RO, RO:GBB[keys,flags]\n"
"\n"
"Note: firmware sections with PRESERVE flags like VPD and\n"
" HWID in GBB are always preserved.\n"
" GBB flags are preserved in autoupdate and recovery modes.\n"
"\n"
"OPTIONS:\n"
"\n"
"-i, --image=FILE \tAP (host) firmware image (image.bin)\n"
"-e, --ec_image=FILE \tEC firmware image (i.e, ec.bin)\n"
"-t, --try \tTry A/B update on reboot if possible\n"
"-a, --archive=PATH \tRead resources from archive\n"
" --unpack=DIR \tExtracts archive to DIR\n"
" --fast \tReduce read cycles and do not verify\n"
" --quirks=LIST \tSpecify the quirks to apply\n"
" --list-quirks \tPrint all available quirks\n"
"-m, --mode=MODE \tRun updater in the specified mode\n"
" --manifest \tScan the archive to print a manifest in JSON\n"
SHARED_FLASH_ARGS_HELP
"\n"
" * Option --manifest requires either -a,--archive or -i,--image\n"
" With -i,--image additional images are accepted with options\n"
" -e,--ec_image.\n"
" * If both --manifest and --fast are specified, the updater\n"
" will not scan the archive and simply dump the previously\n"
" cached manifest (may be out-dated) from the archive.\n"
" Works only with -a,--archive option.\n"
" * Use of -p,--programmer with option other than '%s',\n"
" or with --ccd effectively disables ability to update EC and PD\n"
" firmware images.\n"
" * Emulation works only with AP (host) firmware image, and does\n"
" not accept EC or PD firmware image, and does not work\n"
" with --mode=output\n"
" * Model detection with option --detect-model-only requires\n"
" archive path -a,--archive\n"
" * The --quirks provides a set of options to override the\n"
" default behavior. Run --list-quirks to get the options,\n"
" and --quirks OPTION to turn on. To disable a quirk that\n"
" was default turned on from the firmware image CBFS, do\n"
" --quirks OPTION=0 to turn off.\n"
"\n"
"Legacy and compatibility options:\n"
" --factory \tAlias for --mode=factory\n"
" --force \tForce update (skip checking contents)\n"
" --output_dir=DIR\tSpecify the target for --mode=output\n"
" --unlock_me \t(deprecated) Unlock the Intel ME before flashing\n"
"\n"
"Debugging and testing options:\n"
" --wp=1|0 \tSpecify write protection status\n"
" --host_only \tUpdate only AP (host) firmware\n"
" --model=MODEL \tOverride system model for images\n"
" --detect-model-only\tDetect model by reading the FRID and exit\n"
" --gbb_flags=FLAG\tOverride new GBB flags\n"
" --signature_id=S\tOverride signature ID for key files\n"
" --sys_props=LIST\tList of system properties to override\n"
"-d, --debug \tPrint debugging messages\n"
"-v, --verbose \tPrint verbose messages\n"
"",
argv[0], FLASHROM_PROGRAMMER_INTERNAL_AP);
}
static int do_update(int argc, char *argv[])
{
struct updater_config_arguments args = {0};
int i, errorcnt = 0;
const char *prepare_ctrl_name = NULL;
char *servo_programmer = NULL;
char *endptr;
struct updater_config *cfg = updater_new_config();
assert(cfg);
opterr = 0;
while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
if (handle_flash_argument(&args, i, optarg))
continue;
switch (i) {
case 'h':
print_help(argc, argv);
updater_delete_config(cfg);
return !!errorcnt;
case 'd':
debugging_enabled = 1;
args.verbosity++;
break;
case 'v':
args.verbosity++;
break;
case 'i':
args.image = optarg;
break;
case 'e':
args.ec_image = optarg;
break;
case 't':
args.try_update = 1;
break;
case 'a':
args.archive = optarg;
break;
case 'm':
args.mode = optarg;
break;
case OPT_REPACK:
args.repack = optarg;
ERROR("Sorry, --repack is only for the script.\n");
errorcnt ++;
break;
case OPT_UNPACK:
args.unpack = optarg;
break;
case OPT_UNLOCK_ME:
WARN("--unlock_me will be deprecated by --quirks unlock_csme_nissa.\n");
args.unlock_me = true;
break;
case OPT_QUIRKS:
args.quirks = optarg;
break;
case OPT_QUIRKS_LIST:
updater_list_config_quirks(cfg);
updater_delete_config(cfg);
return 0;
case OPT_OUTPUT_DIR:
args.output_dir = optarg;
break;
case OPT_MODEL:
args.model = optarg;
break;
case OPT_DETECT_MODEL_ONLY:
args.detect_model_only = true;
break;
case OPT_SIGNATURE:
args.signature_id = optarg;
break;
case OPT_WRITE_PROTECTION:
args.write_protection = optarg;
break;
case OPT_SYS_PROPS:
args.sys_props = optarg;
break;
case OPT_MANIFEST:
args.do_manifest = 1;
break;
case OPT_FACTORY:
args.is_factory = 1;
break;
case OPT_HOST_ONLY:
args.host_only = 1;
break;
case OPT_FORCE:
args.force_update = 1;
break;
case OPT_FAST:
args.fast_update = 1;
break;
case OPT_GBB_FLAGS:
args.gbb_flags = strtoul(optarg, &endptr, 0);
if (*endptr) {
ERROR("Invalid flags: %s\n", optarg);
errorcnt++;
} else {
args.override_gbb_flags = 1;
}
break;
case OPT_DUMMY:
break;
case '?':
errorcnt++;
if (optopt)
ERROR("Unrecognized option: -%c\n", optopt);
else if (argv[optind - 1])
ERROR("Unrecognized option (possibly '%s')\n",
argv[optind - 1]);
else
ERROR("Unrecognized option.\n");
break;
default:
errorcnt++;
ERROR("Failed parsing options.\n");
}
}
if (optind < argc) {
errorcnt++;
ERROR("Unexpected arguments.\n");
}
if (!errorcnt && args.detect_servo) {
servo_programmer = host_detect_servo(&prepare_ctrl_name);
if (!servo_programmer)
errorcnt++;
else if (!args.programmer)
args.programmer = servo_programmer;
}
/*
* Some boards may need to fetch firmware before starting to
* update (i.e., in updater_setup_config) so we want to turn on
* cpu_fw_spi mode now.
*/
prepare_servo_control(prepare_ctrl_name, true);
const bool update_needed = updater_should_update(&args);
if (!errorcnt)
errorcnt += updater_setup_config(cfg, &args);
if (!errorcnt && update_needed) {
int r;
STATUS("Starting firmware updater.\n");
r = update_firmware(cfg);
if (r != UPDATE_ERR_DONE) {
r = VB2_MIN(r, UPDATE_ERR_UNKNOWN);
ERROR("%s\n", updater_error_messages[r]);
errorcnt++;
}
/* Use stdout for the final result. */
printf(">> %s: Firmware updater %s.\n",
errorcnt ? "FAILED": "DONE",
errorcnt ? "aborted" : "exits successfully");
}
prepare_servo_control(prepare_ctrl_name, false);
free(servo_programmer);
updater_delete_config(cfg);
return !!errorcnt;
}
#define CMD_HELP_STR "Update system firmware"
#else /* USE_FLASHROM */
static int do_update(int argc, char *argv[])
{
FATAL(MYNAME " was built without flashrom support, `update` command unavailable!\n");
return -1;
}
#define CMD_HELP_STR "Update system firmware (unavailable in this build)"
#endif /* !USE_FLASHROM */
DECLARE_FUTIL_COMMAND(update, do_update, VBOOT_VERSION_ALL, CMD_HELP_STR);