[3298] Add command-line options to rebuild the flash or reboot

This commit is contained in:
claudiol 2018-08-29 17:42:33 -04:00
parent df33a5ac5b
commit 0a148f61e3
3 changed files with 118 additions and 23 deletions

34
flash.c
View file

@ -512,7 +512,11 @@ flash_load(x49gp_module_t *module, GKeyFile *key)
if (flash->size > st.st_size) {
fprintf(stderr, "Flash too small, rebuilding\n");
x49gp->startup_reinit = X49GP_REINIT_FLASH_FULL;
}
if (x49gp->startup_reinit >= X49GP_REINIT_FLASH) {
if (x49gp->startup_reinit == X49GP_REINIT_FLASH_FULL)
memset(phys_ram_base + flash->offset, 0xff,
flash->size - st.st_size);
@ -547,22 +551,29 @@ flash_load(x49gp_module_t *module, GKeyFile *key)
close(bootfd);
g_free(bootfile);
/* The stock firmware expects special markers in certain spots
across the flash. Without these, the user banks act up and
are not usable, and PINIT apparently won't fix it.
Let's help it out; custom firmware will have to deal with
remnants of the user banks on real calculators anyway,
so if they break here, they will too on actual hardware
because that always comes with the stock firmware and
its user banks marked properly. */
if (x49gp->startup_reinit == X49GP_REINIT_FLASH_FULL) {
/* The stock firmware expects special markers in certain
spots across the flash. Without these, the user banks
act up and are not usable, and PINIT apparently won't
fix it. Let's help it out; custom firmware will have
to deal with remnants of the user banks on real
calculators anyway, so if they break here, they will
too on actual hardware because that always comes with
the stock firmware and its user banks marked
properly. */
for (i=2;i<14;i++) {
bank_marker[1] = i;
memcpy(phys_ram_base + flash->offset + 0x40100 +
0x20000 * i, bank_marker, 5);
}
}
filename = NULL;
if (x49gp->firmware != NULL) {
filename = g_strdup(x49gp->firmware);
} else {
x49gp_ui_open_firmware(x49gp, &filename);
}
if (filename != NULL) {
fwfd = open(filename, O_RDONLY);
if (fwfd < 0) {
@ -572,6 +583,9 @@ flash_load(x49gp_module_t *module, GKeyFile *key)
fprintf(stderr, "Warning: Could not open "
"selected firmware, falling back to "
"bootloader recovery tools\n");
/* Mark firmware as invalid if there is one */
memset(phys_ram_base + flash->offset +
BOOT_SIZE, 0, 16);
} else {
/* The firmware may be shorter than
SST29VF160_SIZE - BOOT_SIZE, but if so,
@ -588,6 +602,10 @@ flash_load(x49gp_module_t *module, GKeyFile *key)
"read selected firmware, "
"falling back to bootloader "
"recovery tools\n");
/* Mark firmware as invalid
if there is one */
memset(phys_ram_base + flash->offset +
BOOT_SIZE, 0, 16);
} else {
/* Mark the firmware as valid in the
same way the bootloader does */

View file

@ -54,6 +54,12 @@ struct __x49gp_module_s__ {
struct list_head list;
};
typedef enum {
X49GP_REINIT_NONE = 0,
X49GP_REINIT_REBOOT_ONLY,
X49GP_REINIT_FLASH,
X49GP_REINIT_FLASH_FULL
} x49gp_reinit_t;
struct __x49gp_s__ {
CPUARMState *env;
@ -97,6 +103,8 @@ struct __x49gp_s__ {
const char *progpath;
const char *basename;
int debug_port;
x49gp_reinit_t startup_reinit;
char *firmware;
};
extern void x49gp_set_idle(x49gp_t *, x49gp_arm_idle_t idle);

73
main.c
View file

@ -254,6 +254,8 @@ struct options {
char *config;
int debug_port;
int start_debugger;
char *firmware;
x49gp_reinit_t reinit;
int more_options;
};
@ -275,6 +277,13 @@ static int action_debuglater(struct options *opt, struct option_def *match,
char *this_opt, char *param, char *progname);
static int action_debug(struct options *opt, struct option_def *match,
char *this_opt, char *param, char *progname);
static int action_reinit_flash(struct options *opt, struct option_def *match,
char *this_opt, char *param, char *progname);
static int action_reinit_flash_full(struct options *opt,
struct option_def *match, char *this_opt,
char *param, char *progname);
static int action_reboot(struct options *opt, struct option_def *match,
char *this_opt, char *param, char *progname);
static int action_unknown_with_param(struct options *opt,
struct option_def *match, char *this_opt,
@ -288,6 +297,9 @@ struct option_def option_defs[] = {
{ action_help, "help", 'h' },
{ action_debuglater, "enable-debug", 'D' },
{ action_debug, "debug", 'd' },
{ action_reinit_flash, "reflash", 'f' },
{ action_reinit_flash_full, "reflash-full", 'F' },
{ action_reboot, "reboot", 'r' },
{ action_longopt, NULL, '-' },
{ action_unknown_with_param, NULL, '=' },
@ -319,6 +331,20 @@ action_help(struct options *opt, struct option_def *match, char *this_opt,
" (default port: %u)\n"
" -d, --debug[=<port>] like -D, but also start the"
" debugger immediately\n"
" -f, --reflash[=firmware] rebuild the flash using the"
" supplied firmware\n"
" (default: select one"
" interactively)\n"
" (implies -r for safety"
" reasons)\n"
" -F, --reflash-full[=firmware] like -f, but don't preserve the"
" flash contents\n"
" in the area beyond the"
" firmware\n"
" -r, --reboot reboot on startup instead of"
" continuing from the\n"
" saved state in the config"
" file\n"
" -h, --help print this message and exit\n"
"The config file is formatted as INI file and contains the"
" settings for which\n"
@ -366,6 +392,45 @@ action_debug(struct options *opt, struct option_def *match, char *this_opt,
return action_debuglater(opt, match, this_opt, param, progname);
}
static int
action_reinit_flash(struct options *opt, struct option_def *match,
char *this_opt, char *param, char *progname)
{
if (opt->reinit < X49GP_REINIT_FLASH)
opt->reinit = X49GP_REINIT_FLASH;
if (param == NULL)
return FALSE;
if (opt->firmware != NULL)
fprintf(stderr, "Additional firmware file \"%s\" specified,"
" overriding\n", param);
opt->firmware = param;
return TRUE;
}
static int
action_reinit_flash_full(struct options *opt,
struct option_def *match, char *this_opt,
char *param, char *progname)
{
int result = action_reinit_flash(opt, match, this_opt, param, progname);
opt->reinit = X49GP_REINIT_FLASH_FULL;
return result;
}
static int
action_reboot(struct options *opt, struct option_def *match, char *this_opt,
char *param, char *progname)
{
if (param != NULL)
warn_unneeded_param(match, this_opt);
if (opt->reinit < X49GP_REINIT_REBOOT_ONLY)
opt->reinit = X49GP_REINIT_REBOOT_ONLY;
return param != NULL;
}
static int
action_longopt(struct options *opt, struct option_def *match, char *this_opt,
char *param, char *progname)
@ -530,6 +595,8 @@ main(int argc, char **argv)
opt.config = NULL;
opt.debug_port = 0;
opt.start_debugger = FALSE;
opt.reinit = X49GP_REINIT_NONE;
opt.firmware = NULL;
parse_options(&opt, argc, argv, progname);
x49gp = malloc(sizeof(x49gp_t));
@ -595,10 +662,12 @@ main(int argc, char **argv)
x49gp->basename = g_path_get_dirname(opt.config);
x49gp->debug_port = opt.debug_port;
x49gp->startup_reinit = opt.reinit;
x49gp->firmware = opt.firmware;
error = x49gp_modules_load(x49gp, opt.config);
if (error) {
if (error != -EAGAIN) {
if (error || opt.reinit >= X49GP_REINIT_REBOOT_ONLY) {
if (error && error != -EAGAIN) {
exit(1);
}
x49gp_modules_reset(x49gp, X49GP_RESET_POWER_ON);