/* * This file is part of the Black Magic Debug project. * * Copyright (C) 2011 Black Sphere Technologies Ltd. * Written by Gareth McMullin * * 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 . */ /* This file implements a basic command interpreter for GDB 'monitor' * commands. */ #include "general.h" #include "exception.h" #include "command.h" #include "gdb_packet.h" #include "jtag_scan.h" #include "target.h" #include "morse.h" #include "adiv5.h" #include "version.h" #ifdef PLATFORM_HAS_TRACESWO # include "traceswo.h" #endif static bool cmd_version(void); static bool cmd_help(target *t); static bool cmd_jtag_scan(target *t, int argc, char **argv); static bool cmd_swdp_scan(void); static bool cmd_targets(target *t); static bool cmd_morse(void); static bool cmd_connect_srst(target *t, int argc, const char **argv); #ifdef PLATFORM_HAS_POWER_SWITCH static bool cmd_target_power(target *t, int argc, const char **argv); #endif #ifdef PLATFORM_HAS_TRACESWO static bool cmd_traceswo(void); #endif const struct command_s cmd_list[] = { {"version", (cmd_handler)cmd_version, "Display firmware version info"}, {"help", (cmd_handler)cmd_help, "Display help for monitor commands"}, {"jtag_scan", (cmd_handler)cmd_jtag_scan, "Scan JTAG chain for devices" }, {"swdp_scan", (cmd_handler)cmd_swdp_scan, "Scan SW-DP for devices" }, {"targets", (cmd_handler)cmd_targets, "Display list of available targets" }, {"morse", (cmd_handler)cmd_morse, "Display morse error message" }, {"connect_srst", (cmd_handler)cmd_connect_srst, "Configure connect under SRST: (enable|disable)" }, #ifdef PLATFORM_HAS_POWER_SWITCH {"tpwr", (cmd_handler)cmd_target_power, "Supplies power to the target: (enable|disable)"}, #endif #ifdef PLATFORM_HAS_TRACESWO {"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture" }, #endif {NULL, NULL, NULL} }; int command_process(target *t, char *cmd) { struct target_command_s *tc; const struct command_s *c; int argc = 0; const char **argv; /* Initial estimate for argc */ for(char *s = cmd; *s; s++) if((*s == ' ') || (*s == '\t')) argc++; argv = alloca(sizeof(const char *) * argc); /* Tokenize cmd to find argv */ for(argc = 0, argv[argc] = strtok(cmd, " \t"); argv[argc]; argv[++argc] = strtok(NULL, " \t")); /* Look for match and call handler */ for(c = cmd_list; c->cmd; c++) { /* Accept a partial match as GDB does. * So 'mon ver' will match 'monitor version' */ if(!strncmp(argv[0], c->cmd, strlen(argv[0]))) return !c->handler(t, argc, argv); } if (!t) return -1; for (tc = t->commands; tc; tc = tc->next) for(c = tc->cmds; c->cmd; c++) if(!strncmp(argv[0], c->cmd, strlen(argv[0]))) return !c->handler(t, argc, argv); return -1; } bool cmd_version(void) { gdb_out("Black Magic Probe (Firmware " FIRMWARE_VERSION ")\n"); gdb_out("Copyright (C) 2015 Black Sphere Technologies Ltd.\n"); gdb_out("License GPLv3+: GNU GPL version 3 or later " "\n\n"); return true; } bool cmd_help(target *t) { struct target_command_s *tc; const struct command_s *c; gdb_out("General commands:\n"); for(c = cmd_list; c->cmd; c++) gdb_outf("\t%s -- %s\n", c->cmd, c->help); if (!t) return -1; for (tc = t->commands; tc; tc = tc->next) { gdb_outf("%s specific commands:\n", tc->specific_name); for(c = tc->cmds; c->cmd; c++) gdb_outf("\t%s -- %s\n", c->cmd, c->help); } return true; } static bool cmd_jtag_scan(target *t, int argc, char **argv) { (void)t; uint8_t irlens[argc]; gdb_outf("Target voltage: %s\n", platform_target_voltage()); if (argc > 1) { /* Accept a list of IR lengths on command line */ for (int i = 1; i < argc; i++) irlens[i-1] = atoi(argv[i]); irlens[argc-1] = 0; } int devs = -1; volatile struct exception e; TRY_CATCH (e, EXCEPTION_ALL) { devs = jtag_scan(argc > 1 ? irlens : NULL); } switch (e.type) { case EXCEPTION_TIMEOUT: gdb_outf("Timeout during scan. Is target stuck in WFI?\n"); break; case EXCEPTION_ERROR: gdb_outf("Exception: %s\n", e.msg); break; } if(devs < 0) { gdb_out("JTAG device scan failed!\n"); return false; } if(devs == 0) { gdb_out("JTAG scan found no devices!\n"); return false; } gdb_outf("Device IR Len IDCODE Description\n"); for(int i = 0; i < jtag_dev_count; i++) gdb_outf("%d\t%d\t0x%08lX %s\n", i, jtag_devs[i].ir_len, jtag_devs[i].idcode, jtag_devs[i].descr); gdb_out("\n"); cmd_targets(NULL); return true; } bool cmd_swdp_scan(void) { gdb_outf("Target voltage: %s\n", platform_target_voltage()); int devs = -1; volatile struct exception e; TRY_CATCH (e, EXCEPTION_ALL) { devs = adiv5_swdp_scan(); } switch (e.type) { case EXCEPTION_TIMEOUT: gdb_outf("Timeout during scan. Is target stuck in WFI?\n"); break; case EXCEPTION_ERROR: gdb_outf("Exception: %s\n", e.msg); break; } if(devs < 0) { gdb_out("SW-DP scan failed!\n"); return false; } cmd_targets(NULL); return true; } bool cmd_targets(target *cur_target) { struct target_s *t; int i; if(!target_list) { gdb_out("No usable targets found.\n"); return false; } gdb_out("Available Targets:\n"); gdb_out("No. Att Driver\n"); for(t = target_list, i = 1; t; t = t->next, i++) gdb_outf("%2d %c %s\n", i, t==cur_target?'*':' ', t->driver); return true; } bool cmd_morse(void) { if(morse_msg) gdb_outf("%s\n", morse_msg); return true; } static bool cmd_connect_srst(target *t, int argc, const char **argv) { (void)t; if (argc == 1) gdb_outf("Assert SRST during connect: %s\n", connect_assert_srst ? "enabled" : "disabled"); else connect_assert_srst = !strcmp(argv[1], "enable"); return true; } #ifdef PLATFORM_HAS_POWER_SWITCH static bool cmd_target_power(target *t, int argc, const char **argv) { (void)t; if (argc == 1) gdb_outf("Target Power: %s\n", platform_target_get_power() ? "enabled" : "disabled"); else platform_target_set_power(!strncmp(argv[1], "enable", strlen(argv[1]))); return true; } #endif #ifdef PLATFORM_HAS_TRACESWO static bool cmd_traceswo(void) { extern char serial_no[9]; traceswo_init(); gdb_outf("%s:%02X:%02X\n", serial_no, 5, 0x85); return true; } #endif