/*
* JR-IDE Project
* - (c) 2017 Alan Hightower
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "flash_api.h"
#define LOGERR(fmt, ...) fprintf(stderr, "\nERROR: " fmt "\n\n", ## __VA_ARGS__)
#ifndef MIN
#define MIN(a,b) (((a) > (b)) ? (b) : (a))
#endif
static int _iparse (const char *text, uint32_t *value_ptr)
{
int i, base, error = 0;
if (strncasecmp (text, "0x", 2) == 0)
{
base = 16;
text += 2;
}
else if (*text == '0')
base = 8;
else
base = 10;
*value_ptr = 0;
for (i = 0; i < strlen (text); i++)
{
*value_ptr *= base;
switch (text[i])
{
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
if (base != 16)
{
error = 1;
break;
}
*value_ptr += 10 + text[i] - 'a';
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
if (base != 16)
{
error = 1;
break;
}
*value_ptr += 10 + text[i] - 'A';
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
*value_ptr += text[i] - '0';
break;
default:
error = 1;
break;
}
}
return error;
}
static void _hex_dump (uint32_t offset, void *data, uint32_t length)
{
uint16_t i, hspaces, cspaces, count;
uint8_t *ptr = (uint8_t *) data;
cspaces = offset & 0xf;
hspaces = cspaces * 3;
length += cspaces;
offset &= ~0xf;
while (length)
{
if (!(offset & 0xf))
printf ("0x%08lx : ", offset);
count = MIN(length, 16 - cspaces);
for (i = 0; i < hspaces; i++)
printf (" ");
hspaces = 0;
for (i = 0; i < count; i++)
printf ("%02x ", ptr[i]);
printf (" ");
for (i = 0; i < cspaces; i++)
printf (" ");
offset += cspaces;
cspaces = 0;
for (i = 0; i < count; i++)
printf ("%c",
(ptr[i] >= 0x20 && ptr[i] <= 0x7f) ?
ptr[i] : '.');
printf ("\n");
offset += count;
ptr += count;
length -= count;
}
return;
}
static int _cmd_read (int argc, char *argv[])
{
uint32_t offset, remain;
uint8_t buffer[1024];
int fd = -1;
if ((argc != 2) && (argc != 3))
return -1;
if (_iparse (argv[0], &offset))
{
LOGERR("Invalid offset - '%s'", argv[0]);
return -2;
}
if (_iparse (argv[1], &remain))
{
LOGERR("Invalid length - '%s'", argv[1]);
return -2;
}
if (argc == 3)
{
if ((fd = open (argv[2], O_WRONLY | O_CREAT | O_BINARY, 0644)) < 0)
{
LOGERR("Unable to create file '%s' - %s",
argv[2], strerror (errno));
return -2;
}
}
while (remain)
{
uint16_t length = MIN(remain, sizeof (buffer));
jride_flash_read (buffer, offset, length);
if (fd >= 0)
{
if (write (fd, buffer, length) != length)
{
LOGERR("Unable to write %u bytes to file - %s",
length, strerror (errno));
close (fd);
return -2;
}
offset += length;
remain -= length;
}
else
{
_hex_dump (offset, buffer, length);
offset += length;
remain -= length;
}
}
if (fd >= 0)
{
close (fd);
printf ("Successfully dumped file '%s'\n", argv[2]);
}
return 0;
}
static int _cmd_write (int argc, char *argv[])
{
uint32_t offset, remain;
uint8_t *buffer;
struct stat stinfo;
int fd = -1;
if (argc != 2)
return -1;
if (_iparse (argv[0], &offset))
{
LOGERR("Invalid offset - '%s'", argv[0]);
return -2;
}
if (stat (argv[1], &stinfo))
{
LOGERR("Unable to locate file '%s' - %s",
argv[1], strerror (errno));
return -2;
}
if ((fd = open (argv[1], O_RDONLY | O_BINARY, 0644)) < 0)
{
LOGERR("Unable to open file '%s' - %s",
argv[1], strerror (errno));
return -2;
}
buffer = (uint8_t *) malloc (4096);
remain = stinfo.st_size;
while (remain)
{
uint16_t length = MIN(remain, 4096);
if (read (fd, buffer, length) != length)
{
LOGERR("Unable to read %u bytes from file - %s", length);
close (fd);
free (buffer);
return -2;
}
printf ("Writing %u @ %u\n", length, offset);
jride_flash_write (offset, buffer, length);
offset += length;
remain -= length;
}
close (fd);
free (buffer);
printf ("Successfully loaded %lu bytes from file '%s'\n",
stinfo.st_size, argv[1]);
return 0;
}
static int _cmd_verify (int argc, char *argv[])
{
uint32_t offset, remain;
uint8_t *a, *b;
struct stat stinfo;
uint16_t i;
int fd = -1;
if (argc != 2)
return -1;
if (_iparse (argv[0], &offset))
{
LOGERR("Invalid offset - '%s'", argv[0]);
return -2;
}
if (stat (argv[1], &stinfo))
{
LOGERR("Unable to locate file '%s' - %s",
argv[1], strerror (errno));
return -2;
}
if ((fd = open (argv[1], O_RDONLY | O_BINARY, 0644)) < 0)
{
LOGERR("Unable to open file '%s' - %s",
argv[1], strerror (errno));
return -2;
}
a = (uint8_t *) malloc (4096);
b = (uint8_t *) malloc (4096);
remain = stinfo.st_size;
while (remain)
{
uint16_t length = MIN(remain, 4096);
if (read (fd, a, length) != length)
{
LOGERR("Unable to read %u bytes from file - %s", length);
close (fd);
free (a);
free (b);
return -2;
}
jride_flash_read (b, offset, length);
for (i = 0; i < length; i++)
{
if (a[i] != b[i])
{
LOGERR("Verify failed at offset %lu\n", offset);
close (fd);
free (a);
free (b);
return -2;
}
offset++;
remain--;
}
}
close (fd);
free (a);
free (b);
printf ("File '%s' verified ok to offset %lu\n",
argv[1], offset);
return 0;
}
static int _cmd_erase (int argc, char *argv[])
{
jride_flash_erase_all();
printf ("Erased entire flash device\n");
return 0;
}
#define CMD(name, usage) { #name, usage, &_cmd_##name }
const static struct _st_command
{
const char *name;
const char *usage;
int (*func_cb)(int , char **);
} command[] = {
CMD(read, " [file] - Dump flash to file"),
CMD(write, " - Program flash from file"),
CMD(verify, " - Verify flash against file"),
CMD(erase, "- Erase entire flash device"),
};
#define commands (sizeof (command) / sizeof (command[0]))
static char *progname = NULL;
static void _print_usage (void)
{
int i;
fprintf (stderr, "\nUsage: %s [options]\n\n"
"Commands:\n\n", progname);
for (i = 0; i < commands; i++)
{
if (command[i].usage)
fprintf (stderr, "\t%s %s\n", command[i].name, command[i].usage);
else
fprintf (stderr, "\t%s\n", command[i].name);
}
fprintf (stderr, "\n");
return;
}
int main (int argc, char *argv[])
{
int i, rc;
uint16_t flash_size, bios_seg, remap_seg;
progname = basename(argv[0]);
if (argc < 2)
{
_print_usage ();
return -1;
}
for (i = 0; i < commands; i++)
{
if (strcmp (argv[1], command[i].name) == 0)
break;
}
if (i == commands)
{
LOGERR ("Unknown command '%s'", argv[1]);
_print_usage ();
return -1;
}
if (!(flash_size = jride_flash_poll (&bios_seg, &remap_seg)))
{
fprintf (stderr, "\nERROR: Unable to locate BIOS address\n\n");
return 0;
}
printf ("\nJR-IDE Flash Utility 1.0 - Found %d KB\n", flash_size);
printf (" BIOS @ %04X0 / Window @ %04X0\n\n", bios_seg, remap_seg);
rc = command[i].func_cb (argc - 2, argv + 2);
if (rc == -1)
_print_usage ();
return rc;
}