From 212dea4914292149c32969e05b5153ec10263adc Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Thu, 17 Jun 2021 14:50:06 +0200 Subject: [PATCH] Tidy up the flashing tool --- usb-flasher/build.sh | 3 +- usb-flasher/common.c | 205 ++++++++++ usb-flasher/debugger.c | 195 +++++++++ usb-flasher/{kbprog-usb.c => flasher.c} | 517 ++++++++++++------------ usb-flasher/fw.bin | 1 - 5 files changed, 664 insertions(+), 257 deletions(-) create mode 100644 usb-flasher/common.c create mode 100644 usb-flasher/debugger.c rename usb-flasher/{kbprog-usb.c => flasher.c} (61%) delete mode 120000 usb-flasher/fw.bin diff --git a/usb-flasher/build.sh b/usb-flasher/build.sh index 9a472da..23b14c1 100755 --- a/usb-flasher/build.sh +++ b/usb-flasher/build.sh @@ -2,4 +2,5 @@ set -e -gcc -o kbprog-usb kbprog-usb.c +gcc -o ppkb-flasher flasher.c +gcc -o ppkb-debugger debugger.c diff --git a/usb-flasher/common.c b/usb-flasher/common.c new file mode 100644 index 0000000..5d12aee --- /dev/null +++ b/usb-flasher/common.c @@ -0,0 +1,205 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static bool verbose; +#define debug(args...) { if (verbose) printf(args); } + +static void syscall_error(int is_err, const char* fmt, ...) +{ + va_list ap; + + if (!is_err) + return; + + fprintf(stderr, "ERROR: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, ": %s\n", strerror(errno)); + + exit(1); +} + +static void error(const char* fmt, ...) +{ + va_list ap; + + fprintf(stderr, "ERROR: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + + exit(1); +} + +static bool read_file(const char* path, char* buf, size_t size) +{ + int fd; + ssize_t ret; + + fd = open(path, O_RDONLY); + if (fd < 0) + return false; + + ret = read(fd, buf, size); + close(fd); + if (ret < 0) + return false; + + if (ret < size) { + buf[ret] = 0; + return true; + } else { + buf[size - 1] = 0; + return false; + } +} + +static int open_usb_dev(uint16_t vid, uint16_t pid) +{ + char path[256], buf[256]; + struct dirent *e; + unsigned e_vid, e_pid, bus, dev; + int fd = -1, ret; + DIR* d; + + d = opendir("/sys/bus/usb/devices"); + syscall_error(d == NULL, "opendir(/sys/bus/usb/devices) failed"); + + while (true) { + errno = 0; + e = readdir(d); + syscall_error(e == NULL && errno, "readdir(/sys/bus/usb/devices) failed"); + if (!e) + break; + + if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) + continue; + + snprintf(path, sizeof path, + "/sys/bus/usb/devices/%s/idVendor", e->d_name); + if (!read_file(path, buf, sizeof buf)) + continue; + + ret = sscanf(buf, "%x", &e_vid); + if (ret != 1) + error("Failed to parse %s", path); + + snprintf(path, sizeof path, + "/sys/bus/usb/devices/%s/idProduct", e->d_name); + if (!read_file(path, buf, sizeof buf)) + continue; + + ret = sscanf(buf, "%x", &e_pid); + if (ret != 1) + error("Failed to parse %s", path); + + if (e_vid == vid && e_pid == pid) { + snprintf(path, sizeof path, + "/sys/bus/usb/devices/%s/busnum", e->d_name); + if (!read_file(path, buf, sizeof buf)) + error("Failed to read %s", path); + + ret = sscanf(buf, "%u", &bus); + if (ret != 1) + error("Failed to parse %s", path); + + snprintf(path, sizeof path, + "/sys/bus/usb/devices/%s/devnum", e->d_name); + if (!read_file(path, buf, sizeof buf)) + error("Failed to read %s", path); + + ret = sscanf(buf, "%u", &dev); + if (ret != 1) + error("Failed to parse %s", path); + + snprintf(path, sizeof path, + "/dev/bus/usb/%03u/%03u", bus, dev); + + debug("Found %04x:%04x at %s\n", e_vid, e_pid, path); + + fd = open(path, O_RDWR); + syscall_error(fd < 0, "open(%s) failed", path); + break; + } + } + + errno = ENOENT; + closedir(d); + return fd; +} + +static int handle_urb(int usb_fd, struct usbdevfs_urb* urb, int timeout) +{ + int ret; + struct usbdevfs_urb* reaped_urb; + int retries = 0; + +retry: + ret = ioctl(usb_fd, USBDEVFS_SUBMITURB, urb); + if (ret < 0) + return ret; + + struct pollfd fd = { + .fd = usb_fd, + .events = POLLOUT, + }; + + ret = poll(&fd, 1, timeout); + if (ret <= 0) { + if (ret == 0) + errno = ETIMEDOUT; + + int save_errno = errno; + + // on timeout or other poll error, we need to discard and reap the submitted URB + ret = ioctl(usb_fd, USBDEVFS_DISCARDURB, urb); + + // even if discard fails, URB may still be reapable, we need to try reaping anyway + ret = ioctl(usb_fd, USBDEVFS_REAPURBNDELAY, &reaped_urb); + + // reap must immediately succeed, otherwise this is fatal + syscall_error(ret < 0, "USBDEVFS_REAPURBNDELAY failed"); + + errno = save_errno; + return -1; + } + + // hopefully POLLERR means we get some error immediately on reap + + ret = ioctl(usb_fd, USBDEVFS_REAPURB, &reaped_urb); + if (ret < 0) + return ret; + + // EPROTO errors are recoverable + if (urb->status == -71 && retries < 3) { + retries++; + goto retry; + } + + if (urb->status != 0) { + errno = -urb->status; + return -1; + } + + return 0; +} diff --git a/usb-flasher/debugger.c b/usb-flasher/debugger.c new file mode 100644 index 0000000..dbd736e --- /dev/null +++ b/usb-flasher/debugger.c @@ -0,0 +1,195 @@ +/** + * USB debuggign tool for Pinephone keyboard + * + * Copyright (C) 2021 Ondřej Jirman + * + * 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 . + */ + +#define DEBUG 1 +#include "common.c" + +int kb_open(void) +{ + int ret, fd; + + // first check if keyboard USB device is available, if it is + // we need to first switch to bootloader mode + + fd = open_usb_dev(0x04f3, 0xb001); + if (fd >= 0) { + struct usbdevfs_disconnect_claim dc = { + .interface = 0, + }; + + ret = ioctl(fd, USBDEVFS_DISCONNECT_CLAIM, &dc); + syscall_error(ret < 0, "USBDEVFS_DISCONNECT_CLAIM failed"); + } + + return fd; +} + +static int usb_fd = -1; + +int command(uint8_t req[8]) +{ + int ret; + struct usbdevfs_urb urb = { + .type = USBDEVFS_URB_TYPE_INTERRUPT, + .endpoint = 0x01, +// .flags = USBDEVFS_URB_ZERO_PACKET, + .buffer = req, + .buffer_length = 8, + .actual_length = 8, + }; + + ret = handle_urb(usb_fd, &urb, 100); + if (ret) + return ret; + + debug("CMD:"); + for (int i = 0; i < urb.actual_length; i++) + debug(" %02hhx", req[i]); + debug("\n"); + + return 0; +} + +int response(uint8_t res[8]) +{ + int ret; + struct usbdevfs_urb urb = { + .type = USBDEVFS_URB_TYPE_INTERRUPT, + .endpoint = 0x82, + .flags = USBDEVFS_URB_SHORT_NOT_OK, + .buffer = res, + .buffer_length = 8, + .actual_length = 0, + }; + + ret = handle_urb(usb_fd, &urb, 100); + if (ret) + return ret; + + if (urb.actual_length != 8) + error("Status response size invalid, must be 8 bytes, got %d", urb.actual_length); + + debug("RES:"); + for (int i = 0; i < urb.actual_length; i++) + debug(" %02hhx", res[i]); + debug("\n"); + + return 0; +} + +ssize_t xwrite(int fd, uint8_t* buf, size_t len) +{ + size_t off = 0; + + while (off < len) { + ssize_t ret = write(fd, buf + off, len - off); + if (ret < 0) + return ret; + + off += ret; + } + + return off; +} + +int read_stdout(void) +{ + int ret; + + uint8_t buf[64]; + struct usbdevfs_urb urb = { + .type = USBDEVFS_URB_TYPE_INTERRUPT, + .endpoint = 0x83, + .buffer = buf, + .buffer_length = 64, + .actual_length = 0, + }; + + ret = handle_urb(usb_fd, &urb, 10); + if (ret) + return ret; + + if (urb.actual_length > 0) { + ssize_t rv = xwrite(1, buf, urb.actual_length); + if (rv < 0) + return -1; + } + + return 0; +} + +int read_keys(uint8_t buf[12]) +{ + int ret; + struct usbdevfs_urb urb = { + .type = USBDEVFS_URB_TYPE_INTERRUPT, + .endpoint = 0x84, + .flags = USBDEVFS_URB_SHORT_NOT_OK, + .buffer = buf, + .buffer_length = 12, + .actual_length = 0, + }; + + ret = handle_urb(usb_fd, &urb, 10); + if (ret) + return ret; + + return 0; +} + +void print_bitmap(uint8_t* map) +{ +// printf("\033[H"); + for (int r = 0; r < 6; r++) { + if (r == 0) { + printf(" C"); + for (int c = 0; c < 12; c++) + printf("%-3d", c + 1); + printf("\n"); + } + + printf("R%d", r + 1); + for (int c = 0; c < 12; c++) + printf(" %s", map[c] & (1u << r) ? "X" : "."); + printf("\n"); + } +} + +int main(int ac, char* av[]) +{ + int ret; + uint8_t keys[12]; + + usb_fd = kb_open(); + if (usb_fd < 0) + error("Failed to open the keyboard"); + + int i = 0; + while (1) { + ret = read_stdout(); + + ret = read_keys(keys); + if (ret == 0) + print_bitmap(keys); + + i++; + } + + return 0; +} diff --git a/usb-flasher/kbprog-usb.c b/usb-flasher/flasher.c similarity index 61% rename from usb-flasher/kbprog-usb.c rename to usb-flasher/flasher.c index 516e876..d308bea 100644 --- a/usb-flasher/kbprog-usb.c +++ b/usb-flasher/flasher.c @@ -17,164 +17,12 @@ * along with this program. If not, see . */ -// {{{ includes - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DEBUG 1 - -#if DEBUG -#define debug(args...) printf(args) -#else -#define debug(args...) -#endif +#define VERSION "1.0" +#include "common.c" // }}} // {{{ utils -static void syscall_error(int is_err, const char* fmt, ...) -{ - va_list ap; - - if (!is_err) - return; - - fprintf(stderr, "ERROR: "); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fprintf(stderr, ": %s\n", strerror(errno)); - - exit(1); -} - -static void error(const char* fmt, ...) -{ - va_list ap; - - fprintf(stderr, "ERROR: "); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fprintf(stderr, "\n"); - - exit(1); -} - -bool read_file(const char* path, char* buf, size_t size) -{ - int fd; - ssize_t ret; - - fd = open(path, O_RDONLY); - if (fd < 0) - return false; - - ret = read(fd, buf, size); - close(fd); - if (ret < 0) - return false; - - if (ret < size) { - buf[ret] = 0; - return true; - } else { - buf[size - 1] = 0; - return false; - } -} - -static int open_usb_dev(uint16_t vid, uint16_t pid) -{ - char path[256], buf[256]; - struct dirent *e; - unsigned e_vid, e_pid, bus, dev; - int fd = -1, ret; - DIR* d; - - d = opendir("/sys/bus/usb/devices"); - syscall_error(d == NULL, "opendir(/sys/bus/usb/devices) failed"); - - while (true) { - errno = 0; - e = readdir(d); - syscall_error(e == NULL && errno, "readdir(/sys/bus/usb/devices) failed"); - if (!e) - break; - - if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) - continue; - - snprintf(path, sizeof path, - "/sys/bus/usb/devices/%s/idVendor", e->d_name); - if (!read_file(path, buf, sizeof buf)) - continue; - - ret = sscanf(buf, "%x", &e_vid); - if (ret != 1) - error("Failed to parse %s", path); - - snprintf(path, sizeof path, - "/sys/bus/usb/devices/%s/idProduct", e->d_name); - if (!read_file(path, buf, sizeof buf)) - continue; - - ret = sscanf(buf, "%x", &e_pid); - if (ret != 1) - error("Failed to parse %s", path); - - if (e_vid == vid && e_pid == pid) { - snprintf(path, sizeof path, - "/sys/bus/usb/devices/%s/busnum", e->d_name); - if (!read_file(path, buf, sizeof buf)) - error("Failed to read %s", path); - - ret = sscanf(buf, "%u", &bus); - if (ret != 1) - error("Failed to parse %s", path); - - snprintf(path, sizeof path, - "/sys/bus/usb/devices/%s/devnum", e->d_name); - if (!read_file(path, buf, sizeof buf)) - error("Failed to read %s", path); - - ret = sscanf(buf, "%u", &dev); - if (ret != 1) - error("Failed to parse %s", path); - - snprintf(path, sizeof path, - "/dev/bus/usb/%03u/%03u", bus, dev); - - debug("Found %04x:%04x at %s\n", e_vid, e_pid, path); - - fd = open(path, O_RDWR); - syscall_error(fd < 0, "open(%s) failed", path); - break; - } - } - - errno = ENOENT; - closedir(d); - return fd; -} - int bootloader_open(void) { int ret, fd; @@ -185,6 +33,8 @@ int bootloader_open(void) fd = open_usb_dev(0x04f3, 0x1812); if (fd >= 0) { + printf("Found USB device for the vendor firmware, swithing to USB bootloader\n"); + for (unsigned i = 0; i <= 1; i++) { struct usbdevfs_disconnect_claim dc = { .interface = i, @@ -223,14 +73,46 @@ int bootloader_open(void) had_switch = true; close(fd); + goto wait_bl; } - // open the bootloader USB device (wait for it if we just switched to bootloader mode) + fd = open_usb_dev(0x04f3, 0xb001); + if (fd >= 0) { + printf("Found debugger USB device, swithing to USB bootloader\n"); + struct usbdevfs_disconnect_claim dc = { + .interface = 0, + }; + + ret = ioctl(fd, USBDEVFS_DISCONNECT_CLAIM, &dc); + syscall_error(ret < 0, "USBDEVFS_DISCONNECT_CLAIM failed"); + + uint8_t buf[8] = { 0x01, }; + + struct usbdevfs_urb urb = { + .type = USBDEVFS_URB_TYPE_INTERRUPT, + .endpoint = 0x01, + .buffer = buf, + .buffer_length = 8, + .actual_length = 0, + }; + + ret = handle_urb(fd, &urb, 500); + syscall_error(ret < 0, "handle_urb failed"); + + had_switch = true; + close(fd); + goto wait_bl; + } + +wait_bl: + // open the bootloader USB device (wait for it if we just switched to bootloader mode) for (int i = 0;; i++) { fd = open_usb_dev(0x04f3, 0x0905); - if (fd >= 0) + if (fd >= 0) { + printf("Found USB bootloader device\n"); break; + } if (!had_switch) error("Bootloader USB device not found"); @@ -261,12 +143,11 @@ enum { EP_DATAIN = 0x84, }; -static int bootloader_fd = -1; +static int usb_fd = -1; void bootloader_command(uint8_t req[8]) { int ret; - struct usbdevfs_urb* reaped_urb; struct usbdevfs_urb urb = { .type = USBDEVFS_URB_TYPE_INTERRUPT, .endpoint = EP_CMD, @@ -276,14 +157,8 @@ void bootloader_command(uint8_t req[8]) .actual_length = 8, }; - ret = ioctl(bootloader_fd, USBDEVFS_SUBMITURB, &urb); - syscall_error(ret < 0, "USBDEVFS_SUBMITURB failed"); - - ret = ioctl(bootloader_fd, USBDEVFS_REAPURB, &reaped_urb); - syscall_error(ret < 0, "USBDEVFS_REAPURB failed"); - - if (urb.status != 0) - error("URB failed with status=%s (%d)", strerror(urb.status), urb.status); + ret = handle_urb(usb_fd, &urb, 1000); + syscall_error(ret < 0, "handle_urb failed"); debug("CMD:"); for (int i = 0; i < urb.actual_length; i++) @@ -294,7 +169,6 @@ void bootloader_command(uint8_t req[8]) void bootloader_status(uint8_t res[4]) { int ret; - struct usbdevfs_urb* reaped_urb; struct usbdevfs_urb urb = { .type = USBDEVFS_URB_TYPE_INTERRUPT, .endpoint = EP_STATUS, @@ -304,17 +178,9 @@ void bootloader_status(uint8_t res[4]) .actual_length = 0, }; - ret = ioctl(bootloader_fd, USBDEVFS_SUBMITURB, &urb); - syscall_error(ret < 0, "USBDEVFS_SUBMITURB failed"); - - ret = ioctl(bootloader_fd, USBDEVFS_REAPURB, &reaped_urb); - syscall_error(ret < 0, "USBDEVFS_REAPURB failed"); + ret = handle_urb(usb_fd, &urb, 1000); + syscall_error(ret < 0, "handle_urb failed"); - if (urb.status != 0) - error("URB failed with status=%s (%d)", strerror(urb.status), urb.status); - if (urb.actual_length != 4) - error("Status response too short, must be 4 bytes, got %d", urb.actual_length); - debug("RES:"); for (int i = 0; i < urb.actual_length; i++) debug(" %02hhx", res[i]); @@ -373,7 +239,6 @@ void bootloader_standard_status_check(void) int bootloader_read_data(uint8_t res[64]) { int ret; - struct usbdevfs_urb* reaped_urb; struct usbdevfs_urb urb = { .type = USBDEVFS_URB_TYPE_INTERRUPT, .endpoint = EP_DATAIN, @@ -384,29 +249,20 @@ int bootloader_read_data(uint8_t res[64]) // .usercontext = (void*)(uintptr_t)0, }; - ret = ioctl(bootloader_fd, USBDEVFS_SUBMITURB, &urb); - syscall_error(ret < 0, "USBDEVFS_SUBMITURB failed"); - - ret = ioctl(bootloader_fd, USBDEVFS_REAPURB, &reaped_urb); - syscall_error(ret < 0, "USBDEVFS_REAPURB failed"); + ret = handle_urb(usb_fd, &urb, 1000); + syscall_error(ret < 0, "handle_urb failed"); debug("DATA:"); for (int i = 0; i < urb.actual_length; i++) debug(" %02hhx", res[i]); debug("\n"); - if (urb.status != 0) - error("URB failed with status=%s (%d)", strerror(urb.status), urb.status); - if (urb.actual_length != 64) - error("Data response too short, must be 64 bytes, got %d", urb.actual_length); - return urb.actual_length; } void bootloader_write_data(uint8_t res[64]) { int ret; - struct usbdevfs_urb* reaped_urb; struct usbdevfs_urb urb = { .type = USBDEVFS_URB_TYPE_INTERRUPT, .endpoint = EP_DATAOUT, @@ -417,14 +273,8 @@ void bootloader_write_data(uint8_t res[64]) // .usercontext = (void*)(uintptr_t)0, }; - ret = ioctl(bootloader_fd, USBDEVFS_SUBMITURB, &urb); - syscall_error(ret < 0, "USBDEVFS_SUBMITURB failed"); - - ret = ioctl(bootloader_fd, USBDEVFS_REAPURB, &reaped_urb); - syscall_error(ret < 0, "USBDEVFS_REAPURB failed"); - - if (urb.status != 0) - error("URB failed with status=%s (%d)", strerror(urb.status), urb.status); + ret = handle_urb(usb_fd, &urb, 1000); + syscall_error(ret < 0, "handle_urb failed"); debug("DATA:"); for (int i = 0; i < urb.actual_length; i++) @@ -705,82 +555,239 @@ const char* boot_cond_text(uint8_t status) } } +static void usage(void) +{ + printf( + "Usage: ppkb-flasher [--rom-in ] [--rom-out ] [--verbose]\n" + " [--help] [...]\n" + "\n" + "Options:\n" + " -i, --rom-in Specify path to binary file you want to flash.\n" + " -o, --rom-out Specify path where you want to store the contents\n" + " of code ROM read from the device.\n" + " -s, --rom-size Specify how many bytes of code rom to flash\n" + " starting from offset 0x2000 in the rom file.\n" + " -v, --verbose Show details of what's going on.\n" + " -h, --help This help.\n" + "\n" + "Commands:\n" + " info Display information about the firmware.\n" + " read Read ROM from the device to --rom-out file.\n" + " write Flash ROM file to the device from --rom-in.\n" + " reset Perform software reset of the MCU.\n" + "\n" + "Format of the ROM files is a flat binary. Only the part of it starting\n" + "from 0x2000 will be flashed. Use -s to specify how many bytes to write.\n" + "\n" + "Pinephone keyboard flashing tool " VERSION "\n" + "Written by Ondrej Jirman , 2021\n" + "Licensed under GPLv3, see https://xff.cz/git/pinephone-keyboard/ for\n" + "more information.\n" + ); + + exit(2); +} + int main(int ac, char* av[]) { - bootloader_fd = bootloader_open(); + char* rom_in = NULL; + char* rom_out = NULL; + int size = 0x1000; + int ret; - if (ac == 2 && !strcmp(av[1], "reset")) { - cmd_software_reset(); - return 0; + while (1) { + int option_index = 0; + struct option long_options[] = { + { "rom-in", required_argument, 0, 'i' }, + { "rom-out", required_argument, 0, 'o' }, + { "size" , required_argument, 0, 's' }, + { "verbose", no_argument, 0, 'v' }, + { "help", no_argument, 0, 'h' }, + { 0, 0, 0, 0 } + }; + + int c = getopt_long(ac, av, "i:o:s:vh", long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'o': + rom_out = strdup(optarg); + break; + case 'i': + rom_in = strdup(optarg); + break; + case 's': + if (strstr("0x", optarg) == optarg) { + errno = 0; + char* next = NULL; + size = strtol(optarg + 2, &next, 16); + if (errno || next == optarg + 2) { + printf("ERROR: Can't parse --size %s\n\n", optarg); + usage(); + } + } else { + errno = 0; + char* next = NULL; + size = strtol(optarg, &next, 10); + if (errno || next == optarg) { + printf("ERROR: Can't parse --size %s\n\n", optarg); + usage(); + } + } + break; + case 'v': + verbose = 1; + break; + case 'h': + case '?': + default: + usage(); + break; + } } + if (optind == ac) + usage(); + + if (size < 64) { + printf("ERROR: --size 0x%04x too small\n\n", size); + usage(); + } + + if (size > 0x6000) { + printf("ERROR: --size 0x%04x too large\n\n", size); + usage(); + } + + if (size % 64 != 0) { + printf("ERROR: --size 0x%04x is not multiple of 64\n\n", size); + usage(); + } + + for (int i = optind; i < ac; i++) { + if (!strcmp(av[i], "read")) { + if (!rom_out) { + printf("ERROR: You must specify target file to write rom contents to via --rom-out\n\n"); + usage(); + } + } else if (!strcmp(av[i], "write")) { + if (!rom_in) { + printf("ERROR: You must source file for flashing via --rom-in\n\n"); + usage(); + } + } else if (!strcmp(av[i], "info")) { + ; + } else if (!strcmp(av[i], "reset")) { + ; + } else { + printf("ERROR: Unknown command: %s\n\n", av[i]); + usage(); + } + } + + printf("Searching for bootloader USB device\n"); + usb_fd = bootloader_open(); + + printf("Resetting bootloader state\n"); cmd_abort(); - printf("FW=0x%04hx BOOT=0x%04hx\n", cmd_get_ver_fw(), cmd_get_ver_spec()); + for (int i = optind; i < ac; i++) { + if (!strcmp(av[i], "read")) { + uint8_t rom[0x8000]; + memset(rom, 0xff, sizeof rom); - uint8_t opts[128]; - cmd_read_option(opts); + printf("Reading code ROM\n"); + cmd_read_rom(rom, 0, 0x8000); - uint16_t icid = (opts[124] | opts[125] << 8) ^ (opts[121] | opts[122] << 8); - printf("ICID=%04hx\n", icid); + int fd = open(rom_out, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd >= 0) { + ssize_t wr = write(fd, rom, 0x8000); + syscall_error(wr < 0, "write failed"); + close(fd); + } + } else if (!strcmp(av[i], "write")) { + int fd; - cmd_unlock(); + uint8_t rom[0x8000]; + memset(rom, 0xff, sizeof rom); - uint8_t bootcond = cmd_boot_condition(); - printf("Booted via %s\n", boot_cond_text(bootcond)); + fd = open(rom_in, O_RDONLY); + syscall_error(fd < 0, "open(%s) failed", rom_in); + ssize_t len = read(fd, rom, 0x8000); + syscall_error(len < 0, "read failed"); + close(fd); + if (len != 0x8000) + error("Invalid ROM file (%s) size (%d), must be 32768 bytes", rom_in, (int)len); - uint16_t csum_boot = cmd_get_checksum(CHECKSUM_TYPE_BOOT); - uint16_t csum_app = cmd_get_checksum(CHECKSUM_TYPE_MAIN); - printf("Checksums: boot=%04hx app=%04hx\n", csum_boot, csum_app); + printf("Unlocking\n"); + cmd_unlock(); - /* - * Checksums: boot=d355 app=449b - * - * Option ROM from factory: - * - * CODE0 at 116: 0xff - * - 24MHz intosc mode, WDT disabled, 256kHz low freq mode - * CODE3 at 119: 0xff - * - eeprom and hw reset disabled - * - BITS(2..0) = reset button config - * - BIT(3) = eeprom enable - * - * 0: fc 39 01 7f - * 4: fe ff ff ff - * - * ...: ff ff ff ff - * - * 120: df // read by bootloader & 0x6 = 0x6: 24MHz, - * 121: 0a 4f // part of ICID (ICID is this value XORed with CSUM at 124, wtf?) - * 123: 20 // ??? - * 124: 9b 44 // checksum (written by CMD_WRITECHECKSUM) - * 126: 49 // ??? - * 127: aa // app OK flag (0xaa = ok) - */ + printf("Entering flasing mode\n"); + cmd_entry_iap(); - int fd; - uint8_t rom[0x8000]; - memset(rom, 0xff, sizeof rom); + printf("Flashing code ROM\n"); + cmd_write_rom(rom + 0x2000, 0x2000, size); - fd = open("fw.bin", O_RDONLY); - syscall_error(fd < 0, "open(fw.bin) failed"); - ssize_t len = read(fd, rom, 0x8000); - close(fd); - if (len != 0x8000) - error("Invalid rom size, must be 32768 bytes"); + printf("Finishing flashing\n"); + cmd_finished_iap(); + } else if (!strcmp(av[i], "info")) { + printf("Bootlaoder version: 0x%04hx\n", cmd_get_ver_spec()); + printf("Firmware version: 0x%04hx\n", cmd_get_ver_fw()); - cmd_entry_iap(); - cmd_write_rom(rom + 0x2000, 0x2000, 0x600); - cmd_finished_iap(); + uint8_t opts[128]; + cmd_read_option(opts); - cmd_read_rom(rom, 0, 0x8000); - fd = open("rom.bin", O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (fd >= 0) { - write(fd, rom, 0x8000); - close(fd); + uint16_t icid = (opts[124] | opts[125] << 8) ^ (opts[121] | opts[122] << 8); + printf("ICID: 0x%04hx\n", icid); + + uint8_t bootcond = cmd_boot_condition(); + printf("Booted via: %s\n", boot_cond_text(bootcond)); + + uint16_t csum_boot = cmd_get_checksum(CHECKSUM_TYPE_BOOT); + uint16_t csum_app = cmd_get_checksum(CHECKSUM_TYPE_MAIN); + printf("Checksums: boot=0x%04hx app=0x%04hx\n", csum_boot, csum_app); + + /* + * Checksums: boot=d355 app=449b + * + * Option ROM from factory: + * + * CODE0 at 116: 0xff + * - 24MHz intosc mode, WDT disabled, 256kHz low freq mode + * CODE2: + * - BIT(0) + * CODE3 at 119: 0xff + * - eeprom and hw reset disabled + * - BITS(2..0) = reset button config + * - BIT(3) = eeprom enable + * + * 0: fc 39 01 7f + * 4: fe ff ff ff + * + * ...: ff ff ff ff + * + * 120: df // read by bootloader & 0x6 = 0x6: 24MHz, + * 121: 0a // part of ICID (ICID is this value XORed with CSUM at 124, wtf?) + * 122: 4f // part of ICID (ICID is this value XORed with CSUM at 125, wtf?) + * 123: 20 // ??? some count? + * 124: 9b 44 // checksum (written by CMD_WRITECHECKSUM) + * 126: 49 // ??? + * 127: aa // app OK flag (0xaa = ok) + */ + + printf("Option ROM dump:\n"); + for (int i = 0; i < 128; i++) + if (opts[i] != 0xff) + printf("0x%02x (%d): 0x%02hhx\n", i + 128, i, opts[i]); + } else if (!strcmp(av[i], "reset")) { + printf("Restarting the MCU\n"); + cmd_software_reset(); + } else { + printf("ERROR: Unknown command: %s\n\n", av[i]); + usage(); + } } - cmd_software_reset(); - return 0; } diff --git a/usb-flasher/fw.bin b/usb-flasher/fw.bin deleted file mode 120000 index 9427be8..0000000 --- a/usb-flasher/fw.bin +++ /dev/null @@ -1 +0,0 @@ -../firmware/build/fw.bin \ No newline at end of file