Skip to content

Commit

Permalink
[3298] Add command-line options to rebuild the flash or reboot
Browse files Browse the repository at this point in the history
  • Loading branch information
claudiol committed Aug 29, 2018
1 parent df33a5a commit 0a148f6
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 23 deletions.
48 changes: 33 additions & 15 deletions flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -512,9 +512,13 @@ 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) {

memset(phys_ram_base + flash->offset, 0xff,
flash->size - st.st_size);
if (x49gp->startup_reinit == X49GP_REINIT_FLASH_FULL)
memset(phys_ram_base + flash->offset, 0xff,
flash->size - st.st_size);

bootfd = x49gp_module_open_rodata(module,
calc == UI_CALCULATOR_HP49GP ?
Expand Down Expand Up @@ -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. */
for (i=2;i<14;i++) {
bank_marker[1] = i;
memcpy(phys_ram_base + flash->offset + 0x40100 +
0x20000 * i, bank_marker, 5);
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;
x49gp_ui_open_firmware(x49gp, &filename);
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) {
Expand All @@ -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,
Expand All @@ -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 */
Expand Down
10 changes: 9 additions & 1 deletion include/x49gp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -96,7 +102,9 @@ struct __x49gp_s__ {
const char *progname;
const char *progpath;
const char *basename;
int debug_port;
int debug_port;
x49gp_reinit_t startup_reinit;
char *firmware;
};

extern void x49gp_set_idle(x49gp_t *, x49gp_arm_idle_t idle);
Expand Down
83 changes: 76 additions & 7 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ struct options {
char *config;
int debug_port;
int start_debugger;
char *firmware;
x49gp_reinit_t reinit;

int more_options;
};
Expand All @@ -272,9 +274,16 @@ struct option_def {
static int action_help(struct options *opt, struct option_def *match,
char *this_opt, char *param, char *progname);
static int action_debuglater(struct options *opt, struct option_def *match,
char *this_opt, char *param, char *progname);
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,
Expand All @@ -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, '=' },
Expand Down Expand Up @@ -315,11 +327,25 @@ action_help(struct options *opt, struct option_def *match, char *this_opt,
fprintf(stderr, "Emulator for HP 49G+ / 50G calculators\n"
"Usage: %s [<options>] [<config-file>]\n"
"Valid options:\n"
" -D, --enable-debug[=<port] enable the debugger interface\n"
" (default port: %u)\n"
" -d, --debug[=<port>] like -D, but also start the"
" -D, --enable-debug[=<port] enable the debugger interface\n"
" (default port: %u)\n"
" -d, --debug[=<port>] like -D, but also start the"
" debugger immediately\n"
" -h, --help print this message and exit\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"
"persistence makes sense, like calculator model, CPU"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 0a148f6

Please sign in to comment.