multiboot_tool/multiboot.c

423 lines
11 KiB
C
Raw Normal View History

2014-12-26 11:36:32 +01:00
/***************************************************************************
* Copyright (C) 10/2010 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; version 2 of the License, *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include "filedata.h"
#include "list.h"
#include "multiboot.h"
#include "optarg.h"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
#define ACTION_READ 0x01
#define ACTION_WRITE 0x02
2019-08-11 11:16:26 +02:00
static struct multiboot_ops * prog_ops[] =
2014-12-26 12:08:48 +01:00
{
2019-08-11 11:16:26 +02:00
&twi_ops,
&mpm_ops,
&funk_ops,
&eprog_ops,
2020-01-17 23:26:41 +01:00
&butterfly_ops,
2014-12-26 12:08:48 +01:00
};
2017-03-07 20:09:48 +01:00
struct mboot_action
{
2014-12-26 11:36:32 +01:00
struct list_head list;
char *filename;
int memtype;
int mode;
};
static LIST_HEAD(action_list);
2017-03-07 20:09:48 +01:00
static struct option main_optargs[] =
{
{ "help", 0, 0, 'h'}, /* [ -h ] */
{ "progress", 1, 0, 'p'}, /* [ -p <0|1|2> ] */
{ "read", 1, 0, 'r'}, /* [ -r <flash|eeprom>:<file.hex> ] */
{ "write", 1, 0, 'w'}, /* [ -w <flash|eeprom>:<file.hex> ] */
{ "no-verify", 0, 0, 'n'}, /* [ -n ] */
{ 0, 0, 0, 0}
2014-12-26 11:36:32 +01:00
};
2017-03-07 20:09:48 +01:00
/* *************************************************************************
* progress_mode0_cb
* ************************************************************************* */
2014-12-26 11:36:32 +01:00
static void progress_mode0_cb(const char *msg, int pos, int size)
{
2019-08-11 11:16:26 +02:00
/* unused parameter */
(void)msg;
(void)pos;
(void)size;
2014-12-26 11:36:32 +01:00
/* no progress output */
2017-03-07 20:09:48 +01:00
} /* progress_mode0_cb */
2014-12-26 11:36:32 +01:00
2017-03-07 20:09:48 +01:00
/* *************************************************************************
* progress_mode1_cb
* ************************************************************************* */
2014-12-26 11:36:32 +01:00
static void progress_mode1_cb(const char *msg, int pos, int size)
{
if (pos != -1 && size > 0)
2017-03-07 20:09:48 +01:00
{
2019-08-11 11:16:26 +02:00
char stars[51];
2014-12-26 11:36:32 +01:00
int i;
2019-08-11 11:16:26 +02:00
int count = (pos * 50 / size);
2017-03-07 20:09:48 +01:00
2019-08-11 11:16:26 +02:00
for (i = 0; i < 50; i++)
2017-03-07 20:09:48 +01:00
{
2014-12-26 11:36:32 +01:00
stars[i] = (i < count) ? '*' : ' ';
2017-03-07 20:09:48 +01:00
}
2014-12-26 11:36:32 +01:00
2019-08-11 11:16:26 +02:00
stars[50] = '\0';
2014-12-26 11:36:32 +01:00
printf("%-15s: [%s] (%d)\r", msg, stars, pos);
}
if (pos == size)
2017-03-07 20:09:48 +01:00
{
2014-12-26 11:36:32 +01:00
printf("\n");
2017-03-07 20:09:48 +01:00
}
} /* progress_mode1_cb */
2014-12-26 11:36:32 +01:00
2017-03-07 20:09:48 +01:00
/* *************************************************************************
* progress_mode2_cb
* ************************************************************************* */
2014-12-26 11:36:32 +01:00
static void progress_mode2_cb(const char *msg, int pos, int size)
{
static int old_count;
if (pos != -1 && size > 0)
2017-03-07 20:09:48 +01:00
{
if (pos == 0)
{
2014-12-26 11:36:32 +01:00
old_count = 0;
printf("%-15s: [", msg);
2017-03-07 20:09:48 +01:00
}
else if (pos <=size)
{
2014-12-26 11:36:32 +01:00
int i;
int count = (pos * 50 / size);
2017-03-07 20:09:48 +01:00
2014-12-26 11:36:32 +01:00
for (i = old_count; i < count; i++)
2017-03-07 20:09:48 +01:00
{
2014-12-26 11:36:32 +01:00
printf("*");
2017-03-07 20:09:48 +01:00
}
2014-12-26 11:36:32 +01:00
old_count = count;
2017-03-07 20:09:48 +01:00
if (pos == size)
{
2014-12-26 11:36:32 +01:00
printf("] (%d)\n", pos);
}
}
}
2017-03-07 20:09:48 +01:00
} /* progress_mode2_cb */
2014-12-26 11:36:32 +01:00
2017-03-07 20:09:48 +01:00
/* *************************************************************************
* add_action
* ************************************************************************* */
2014-12-26 11:36:32 +01:00
static int add_action(struct multiboot *mboot, int mode, const char *arg)
{
struct mboot_action *action = malloc(sizeof(struct mboot_action));
2017-03-07 20:09:48 +01:00
if (action == NULL)
{
2014-12-26 11:36:32 +01:00
perror("malloc()");
return -1;
}
char *argcopy = strdup(arg);
2017-03-07 20:09:48 +01:00
if (argcopy == NULL)
{
2014-12-26 11:36:32 +01:00
perror("strdup()");
free(action);
return -1;
}
char *tok = strtok(argcopy, ":");
2017-03-07 20:09:48 +01:00
if (tok == NULL)
{
2014-12-26 11:36:32 +01:00
fprintf(stderr, "invalid argument: '%s'\n", arg);
free(argcopy);
free(action);
return -1;
}
action->memtype = mboot->ops->get_memtype(mboot, tok);
2017-03-07 20:09:48 +01:00
if (action->memtype == -1)
{
2014-12-26 11:36:32 +01:00
fprintf(stderr, "invalid memtype: '%s'\n", tok);
free(argcopy);
free(action);
return -1;
}
tok = strtok(NULL, ":");
2017-03-07 20:09:48 +01:00
if (tok == NULL)
{
2014-12-26 11:36:32 +01:00
fprintf(stderr, "invalid argument: '%s'\n", arg);
free(argcopy);
free(action);
return -1;
}
action->filename = strdup(tok);
2017-03-07 20:09:48 +01:00
if (action->filename == NULL)
{
2014-12-26 11:36:32 +01:00
perror("strdup()");
free(argcopy);
free(action);
return -1;
}
action->mode = mode;
list_add_tail(&action->list, &action_list);
free(argcopy);
return 0;
2017-03-07 20:09:48 +01:00
} /* add_action */
2014-12-26 11:36:32 +01:00
2017-03-07 20:09:48 +01:00
/* *************************************************************************
* main_optarg_cb
* ************************************************************************* */
2014-12-26 11:36:32 +01:00
static int main_optarg_cb(int val, const char *arg, void *privdata)
{
struct multiboot *mboot = (struct multiboot *)privdata;
2017-03-07 20:09:48 +01:00
switch (val)
{
case 'r': /* read */
2019-08-11 11:16:26 +02:00
if ((mboot->ops->read == NULL) ||
(add_action(mboot, ACTION_READ, arg) < 0)
)
2017-03-07 20:09:48 +01:00
{
return -1;
}
break;
2014-12-26 11:36:32 +01:00
2017-03-07 20:09:48 +01:00
case 'w': /* write */
2019-08-11 11:16:26 +02:00
if ((mboot->ops->write == NULL) ||
(add_action(mboot, ACTION_WRITE, arg) < 0)
)
2017-03-07 20:09:48 +01:00
{
return -1;
}
break;
2014-12-26 11:36:32 +01:00
2017-03-07 20:09:48 +01:00
case 'n': /* no verify after write */
mboot->verify = 0;
break;
2014-12-26 11:36:32 +01:00
2017-03-07 20:09:48 +01:00
case 'p':
switch (*arg)
{
case '0':
mboot->progress_cb = progress_mode0_cb;
break;
2014-12-26 11:36:32 +01:00
2017-03-07 20:09:48 +01:00
case '1':
mboot->progress_cb = progress_mode1_cb;
break;
2014-12-26 11:36:32 +01:00
2017-03-07 20:09:48 +01:00
case '2':
mboot->progress_cb = progress_mode2_cb;
break;
2014-12-26 11:36:32 +01:00
2017-03-07 20:09:48 +01:00
default:
fprintf(stderr, "invalid progress bar mode: '%s'\n", arg);
return -1;
2014-12-26 11:36:32 +01:00
}
2017-03-07 20:09:48 +01:00
break;
2014-12-26 11:36:32 +01:00
}
return 0;
}
2017-03-07 20:09:48 +01:00
/* *************************************************************************
* main
* ************************************************************************* */
2014-12-26 11:36:32 +01:00
int main(int argc, char *argv[])
{
2014-12-26 12:08:48 +01:00
struct multiboot *mboot = NULL;
2014-12-26 11:36:32 +01:00
char *progname = strrchr(argv[0], '/');
progname = (progname != NULL) ? (progname +1) : argv[0];
2019-08-11 11:16:26 +02:00
unsigned int i;
for (i = 0; i < ARRAY_SIZE(prog_ops); i++)
2017-03-07 20:09:48 +01:00
{
2019-08-11 11:16:26 +02:00
struct multiboot_ops * ops = prog_ops[i];
2014-12-26 12:08:48 +01:00
2019-08-11 11:16:26 +02:00
if (strcmp(progname, ops->exec_name) == 0)
2017-03-07 20:09:48 +01:00
{
2019-08-11 11:16:26 +02:00
mboot = ops->alloc();
2017-03-07 20:09:48 +01:00
if (mboot == NULL)
{
2019-08-11 11:16:26 +02:00
fprintf(stderr, "failed to allocate '%s'\n",
progname);
2014-12-26 12:08:48 +01:00
return -1;
}
}
2014-12-26 11:36:32 +01:00
}
2017-03-07 20:09:48 +01:00
if (mboot == NULL)
{
2014-12-26 12:08:48 +01:00
fprintf(stderr, "invalid progname\n");
2014-12-26 11:36:32 +01:00
return -1;
2014-12-26 12:08:48 +01:00
}
2014-12-26 11:36:32 +01:00
mboot->verify = 1;
mboot->progress_cb = progress_mode1_cb;
2017-03-07 20:09:48 +01:00
optarg_register(main_optargs, ARRAY_SIZE(main_optargs),
main_optarg_cb, (void *)mboot);
2014-12-26 11:36:32 +01:00
int abort = optarg_parse(argc, argv);
2017-03-07 20:09:48 +01:00
if ((abort == -1) ||
(mboot->ops->open(mboot) != 0)
)
{
2014-12-26 11:36:32 +01:00
return -1;
2017-03-07 20:09:48 +01:00
}
2014-12-26 11:36:32 +01:00
setbuf(stdout, NULL);
struct mboot_action *action, *tmp;
2017-03-07 20:09:48 +01:00
list_for_each_entry(action, &action_list, list)
{
2014-12-26 11:36:32 +01:00
abort = 1;
2017-03-07 20:09:48 +01:00
if (action->mode == ACTION_READ)
{
2014-12-26 11:36:32 +01:00
int memsize = mboot->ops->get_memsize(mboot, action->memtype);
if (memsize == 0)
2017-03-07 20:09:48 +01:00
{
2014-12-26 11:36:32 +01:00
break;
2017-03-07 20:09:48 +01:00
}
2014-12-26 11:36:32 +01:00
struct databuf *dbuf = dbuf_alloc(memsize);
if (dbuf == NULL)
2017-03-07 20:09:48 +01:00
{
2014-12-26 11:36:32 +01:00
break;
2017-03-07 20:09:48 +01:00
}
2014-12-26 11:36:32 +01:00
int result = mboot->ops->read(mboot, dbuf, action->memtype);
2017-03-07 20:09:48 +01:00
if (result != 0)
{
2014-12-26 11:36:32 +01:00
fprintf(stderr, "failed to read from device\n");
dbuf_free(dbuf);
break;
}
result = file_write(action->filename, dbuf);
2017-03-07 20:09:48 +01:00
if (result != 0)
{
2014-12-26 11:36:32 +01:00
fprintf(stderr, "failed to write file '%s'\n", action->filename);
dbuf_free(dbuf);
break;
}
dbuf_free(dbuf);
abort = 0;
2017-03-07 20:09:48 +01:00
}
else if (action->mode == ACTION_WRITE)
{
2014-12-26 11:36:32 +01:00
unsigned int size;
int result;
result = file_getsize(action->filename, &size);
if (result != 0)
2017-03-07 20:09:48 +01:00
{
2014-12-26 11:36:32 +01:00
break;
2017-03-07 20:09:48 +01:00
}
2014-12-26 11:36:32 +01:00
struct databuf *dbuf = dbuf_alloc(size);
if (dbuf == NULL)
2017-03-07 20:09:48 +01:00
{
2014-12-26 11:36:32 +01:00
break;
2017-03-07 20:09:48 +01:00
}
2014-12-26 11:36:32 +01:00
result = file_read(action->filename, dbuf);
2017-03-07 20:09:48 +01:00
if (result != 0)
{
2014-12-26 11:36:32 +01:00
fprintf(stderr, "failed to read file '%s'\n", action->filename);
dbuf_free(dbuf);
break;
}
uint32_t memsize = mboot->ops->get_memsize(mboot, action->memtype);
if ((memsize == 0) || (memsize < dbuf->length))
2017-03-07 20:09:48 +01:00
{
2014-12-26 11:36:32 +01:00
fprintf(stderr, "invalid memsize: 0x%04x > 0x%04x\n", dbuf->length, memsize);
dbuf_free(dbuf);
break;
}
result = mboot->ops->write(mboot, dbuf, action->memtype);
2017-03-07 20:09:48 +01:00
if (result != 0)
{
2014-12-26 11:36:32 +01:00
fprintf(stderr, "failed to write to device\n");
dbuf_free(dbuf);
break;
}
2019-08-11 11:16:26 +02:00
if (mboot->verify &&
(mboot->ops->verify != NULL)
)
2017-03-07 20:09:48 +01:00
{
2014-12-26 11:36:32 +01:00
result = mboot->ops->verify(mboot, dbuf, action->memtype);
2017-03-07 20:09:48 +01:00
if (result != 0)
{
2014-12-26 11:36:32 +01:00
fprintf(stderr, "failed to verify\n");
dbuf_free(dbuf);
break;
}
}
dbuf_free(dbuf);
abort = 0;
}
}
2017-03-07 20:09:48 +01:00
list_for_each_entry_safe(action, tmp, &action_list, list)
{
2014-12-26 11:36:32 +01:00
free(action->filename);
free(action);
}
mboot->ops->close(mboot);
mboot->ops->free(mboot);
optarg_free();
return abort;
2017-03-07 20:09:48 +01:00
} /* main */