/* * 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; }