1 ///////////////////////////////////////////////////////////////////////////////
2 // BOSSA
3 //
4 // Copyright (c) 2011-2018, ShumaTech
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //     * Redistributions of source code must retain the above copyright
10 //       notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above copyright
12 //       notice, this list of conditions and the following disclaimer in the
13 //       documentation and/or other materials provided with the distribution.
14 //     * Neither the name of the <organization> nor the
15 //       names of its contributors may be used to endorse or promote products
16 //       derived from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 ///////////////////////////////////////////////////////////////////////////////
29 #define __STDC_LIMIT_MACROS
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <assert.h>
35 #include <readline/readline.h>
36 #include <readline/history.h>
37 
38 #include "Command.h"
39 
40 #define min(a, b)   ((a) < (b) ? (a) : (b))
41 
42 using namespace std;
43 
44 Shell* Command::_shell = NULL;
45 Samba Command::_samba;
46 PortFactory Command::_portFactory;
47 Device Command::_device(_samba);
48 Device::FlashPtr& Command::_flash = _device.getFlash();
49 CommandObserver Command::_observer;
50 Flasher Command::_flasher(_samba, _device, _observer);
51 bool Command::_connected = false;
52 
Command(const char * name,const char * help,const char * usage)53 Command::Command(const char* name, const char* help, const char* usage) :
54     _name(name), _help(help), _usage(usage)
55 {
56     assert(_shell != NULL);
57 }
58 
59 void
onStatus(const char * message,...)60 CommandObserver::onStatus(const char *message, ...)
61 {
62     va_list ap;
63 
64     va_start(ap, message);
65     vprintf(message, ap);
66     va_end(ap);
67 }
68 
69 void
onProgress(int num,int div)70 CommandObserver::onProgress(int num, int div)
71 {
72     int ticks;
73     int bars = 30;
74 
75     ticks = num * bars / div;
76 
77     if (ticks == _lastTicks)
78         return;
79 
80     printf("\r[");
81     while (ticks-- > 0)
82     {
83         putchar('=');
84         bars--;
85     }
86     while (bars-- > 0)
87     {
88         putchar(' ');
89     }
90     printf("] %d%% (%d/%d pages)", num * 100 / div, num, div);
91     fflush(stdout);
92 
93     _lastTicks = 0;
94 }
95 
96 bool
error(const char * fmt,...)97 Command::error(const char* fmt, ...)
98 {
99     va_list ap;
100 
101     va_start(ap, fmt);
102     vprintf(fmt, ap);
103     va_end(ap);
104     printf(".  Try \"help %s\".\n", _name);
105 
106     return false;
107 }
108 
109 bool
argNum(int argc,int num)110 Command::argNum(int argc, int num)
111 {
112     if (argc != num)
113         return error("Command requires %d argument%s",
114                      num - 1, (num > 1) ? "s" : "", _name);
115 
116     return true;
117 }
118 
119 bool
argRange(int argc,int min,int max)120 Command::argRange(int argc, int min, int max)
121 {
122     if (argc < min || argc > max)
123         return error("Command requires %d to %d arguments", min - 1, max - 1);
124 
125     return true;
126 }
127 
128 bool
argUint32(const char * arg,uint32_t * value)129 Command::argUint32(const char* arg, uint32_t* value)
130 {
131     long long ll;
132     char *end;
133 
134     errno = 0;
135     ll = strtoll(arg, &end, 0);
136     if (errno != 0 || *end != '\0')
137         return error("Invalid number \"%s\"", arg);
138     if (ll < 0 || ll > UINT32_MAX)
139         return error("Number \"%s\" is out of range", arg);
140 
141     *value = ll;
142 
143     return true;
144 }
145 
146 bool
argBool(const char * arg,bool * value)147 Command::argBool(const char* arg, bool* value)
148 {
149     int len = strlen(arg);
150     if (strncasecmp(arg, "true", len) == 0)
151         *value = true;
152     else if (strncasecmp(arg, "false", len) == 0)
153         *value = false;
154     else
155         return error("Invalid boolean \"%s\"", arg);
156 
157     return true;
158 }
159 
160 bool
argState(const char * arg,bool * value)161 Command::argState(const char* arg, bool* value)
162 {
163     int len = strlen(arg);
164     if (strncasecmp(arg, "enable", len) == 0)
165         *value = true;
166     else if (strncasecmp(arg, "disable", len) == 0)
167         *value = false;
168     else
169         return error("Invalid state \"%s\"", arg);
170 
171     return true;
172 }
173 
174 bool
connected()175 Command::connected()
176 {
177     if (!_connected)
178     {
179         printf("No device connected.  Use \"connect\" first.\n");
180         return false;
181     }
182     return true;
183 }
184 
185 bool
flashable()186 Command::flashable()
187 {
188     if (!connected())
189         return false;
190 
191     if (_flash.get() == NULL)
192     {
193         printf("Flash on device is not supported.\n");
194         return false;
195     }
196     return true;
197 }
198 
199 bool
createDevice()200 Command::createDevice()
201 {
202     try
203     {
204         _device.create();
205     }
206     catch (DeviceUnsupportedError& e)
207     {
208         printf("Device is not supported\n");
209         return false;
210     }
211 
212     return true;
213 }
214 
215 void
hexdump(uint32_t addr,uint8_t * buf,size_t count)216 Command::hexdump(uint32_t addr, uint8_t *buf, size_t count)
217 {
218     int lpad;
219     int rpad;
220     size_t size;
221     size_t offset;
222     const uint32_t ROW_SIZE = 16;
223     const uint32_t ROW_MASK = ~(ROW_SIZE - 1);
224 
225     printf("            0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
226 
227     while (count > 0)
228     {
229         lpad = (addr % ROW_SIZE);
230         rpad = ROW_SIZE - min(lpad + count, ROW_SIZE);
231         size = ROW_SIZE - rpad - lpad;
232 
233         printf("%08x | ", addr & ROW_MASK);
234 
235         printf("%*s", 3 * lpad, "");
236         for (offset = 0; offset < size; offset++)
237             printf("%02x ", buf[offset]);
238         printf("%*s", 3 * rpad, "");
239 
240         printf("| ");
241 
242         printf("%*s", lpad, "");
243         for (offset = 0; offset < size; offset++)
244             printf("%c", isprint(buf[offset]) ? buf[offset] : '.');
245         printf("%*s", rpad, "");
246 
247         printf("\n");
248 
249         buf += size;
250         addr += size;
251         count -= size;
252     }
253 }
254 
255 const char*
binstr(uint32_t value,int bits,char low,char high)256 Command::binstr(uint32_t value, int bits, char low, char high)
257 {
258     static char buf[36];
259     char *str = buf;
260 
261     assert(bits <= 32 && bits > 0);
262 
263     for (int bitnum = bits - 1; bitnum >= 0; bitnum--)
264     {
265         *str++ = (value & (1 << bitnum)) ? high : low;
266         if (bitnum % 8 == 0)
267             *str++ = ' ';
268     }
269     *(str - 1) = '\0';
270 
271     return buf;
272 }
273 
274 void
disconnect()275 Command::disconnect()
276 {
277     _connected = false;
278 }
279 
280 bool
operator <(const Command & rhs)281 Command::operator < (const Command& rhs)
282 {
283     return (strcmp(_name, rhs._name) == -1);
284 }
285 
CommandBod()286 CommandBod::CommandBod() :
287     Command("bod",
288             "Change the brownout detect flag.",
289             "bod [BOOL]\n"
290             "  BOOL -- boolean value either \"true\" or \"false\"")
291 {}
292 
293 void
invoke(char * argv[],int argc)294 CommandBod::invoke(char* argv[], int argc)
295 {
296     bool value;
297 
298     if (!argNum(argc, 2) ||
299         !argBool(argv[1], &value) ||
300         !flashable())
301         return;
302 
303     if (!_flash->canBod())
304     {
305         printf("Unsupported on this flash device\n");
306         return;
307     }
308 
309     _flash->setBod(value);
310     printf("BOD flag set to %s\n", value ? "true" : "false");
311 }
312 
CommandBootf()313 CommandBootf::CommandBootf() :
314     Command("bootf",
315             "Change the boot to flash flag.",
316             "bootf [BOOL]\n"
317             "  BOOL -- boolean value either \"true\" or \"false\"")
318 {}
319 
320 void
invoke(char * argv[],int argc)321 CommandBootf::invoke(char* argv[], int argc)
322 {
323     bool value;
324 
325     if (!argNum(argc, 2) ||
326         !argBool(argv[1], &value) ||
327         !flashable())
328         return;
329 
330     _flash->setBootFlash(value);
331     printf("Boot to flash flag set to %s\n", value ? "true" : "false");
332 }
333 
CommandBor()334 CommandBor::CommandBor() :
335     Command("bor",
336             "Change the brownout reset flag.",
337             "bor [BOOL]\n"
338             "  BOOL -- boolean value either \"true\" or \"false\"")
339 {}
340 
341 void
invoke(char * argv[],int argc)342 CommandBor::invoke(char* argv[], int argc)
343 {
344     bool value;
345 
346     if (!argNum(argc, 2) ||
347         !argBool(argv[1], &value) ||
348         !flashable())
349         return;
350 
351     if (!_flash->canBor())
352     {
353         printf("Unsupported on this flash device\n");
354         return;
355     }
356 
357     _flash->setBor(value);
358     printf("BOR flag set to %s\n", value ? "true" : "false");
359 }
360 
CommandConnect()361 CommandConnect::CommandConnect() :
362     Command("connect",
363             "Connect to device over serial port.",
364             "connect [SERIAL]\n"
365             "  SERIAL -- host-specific serial port")
366 {}
367 
368 void
invoke(char * argv[],int argc)369 CommandConnect::invoke(char* argv[], int argc)
370 {
371     if (!argNum(argc, 2))
372         return;
373 
374     if (!_samba.connect(_portFactory.create(argv[1])))
375     {
376         printf("No device found on %s\n", argv[1]);
377         _connected = false;
378         return;
379     }
380 
381     printf("Connected to device on %s\n", argv[1]);
382     _connected = true;
383     createDevice();
384 }
385 
CommandDebug()386 CommandDebug::CommandDebug() :
387     Command("debug",
388             "Change the debug state.",
389             "debug [STATE]\n"
390             "  STATE - either \"disable\" or \"enable\"")
391 {}
392 
393 void
invoke(char * argv[],int argc)394 CommandDebug::invoke(char* argv[], int argc)
395 {
396     bool state;
397 
398     if (!argNum(argc, 2) ||
399         !argState(argv[1], &state))
400         return;
401 
402     _samba.setDebug(state);
403 }
404 
CommandDump()405 CommandDump::CommandDump() :
406     Command("dump",
407             "Dump memory in hexadecimal and ascii.",
408             "dump [ADDRESS] [COUNT]\n"
409             "  ADDRESS -- starting memory address\n"
410             "  COUNT -- count of bytes to display")
411 {}
412 
413 void
invoke(char * argv[],int argc)414 CommandDump::invoke(char* argv[], int argc)
415 {
416     uint32_t addr;
417     uint32_t count;
418 
419     if (!argNum(argc, 3) ||
420         !argUint32(argv[1], &addr) ||
421         !argUint32(argv[2], &count) ||
422         !connected())
423         return;
424 
425     std::unique_ptr<uint8_t[]> buf(new uint8_t[count]);
426 
427     try
428     {
429         _samba.read(addr, buf.get(), count);
430     }
431     catch (...)
432     {
433         throw;
434     }
435 
436     hexdump(addr, buf.get(), count);
437 }
438 
CommandErase()439 CommandErase::CommandErase() :
440     Command("erase",
441             "Erase the flash to the end.",
442             "erase <offset>"
443             "  OFFSET -- (optional) start erase operation at flash OFFSET\n"
444             "            OFFSET must be aligned to a flash page boundary")
445 {}
446 
447 void
invoke(char * argv[],int argc)448 CommandErase::invoke(char* argv[], int argc)
449 {
450     uint32_t offset = 0;
451 
452     if (!argRange(argc, 1, 2) ||
453         (argc >= 2 && !argUint32(argv[1], &offset)) ||
454         !flashable())
455         return;
456 
457     _flasher.erase(offset);
458     printf("Flash is erased\n");
459 }
460 
CommandExit()461 CommandExit::CommandExit() :
462     Command("exit",
463             "Exit the BOSSA shell.",
464             "exit")
465 {}
466 
467 void
invoke(char * argv[],int argc)468 CommandExit::invoke(char* argv[], int argc)
469 {
470     if (!argNum(argc, 1))
471         return;
472 
473     _shell->exitFlag() = true;
474 }
475 
CommandGo()476 CommandGo::CommandGo() :
477     Command("go",
478             "Execute ARM code at address.",
479             "go [ADDRESS]\n"
480             "  ADDRESS -- starting memory address of code to execute")
481 {}
482 
483 void
invoke(char * argv[],int argc)484 CommandGo::invoke(char* argv[], int argc)
485 {
486     uint32_t addr;
487 
488     if (!argNum(argc, 2) ||
489         !argUint32(argv[1], &addr) ||
490         !connected())
491         return;
492 
493     printf("Executing code at %#x\n", addr);
494     _samba.go(addr);
495 }
496 
CommandHelp()497 CommandHelp::CommandHelp() :
498     Command("help",
499             "Display help for a command.",
500             "help <COMMAND>\n"
501             "  COMMAND -- (optional) display detailed usage for this command,\n"
502             "             display summary help for all commands if not given")
503 {}
504 
505 void
invoke(char * argv[],int argc)506 CommandHelp::invoke(char* argv[], int argc)
507 {
508     if (!argRange(argc, 1, 2))
509         return;
510 
511     if (argc == 1)
512         _shell->help();
513     else
514         _shell->usage(argv[1]);
515 }
516 
CommandHistory()517 CommandHistory::CommandHistory() :
518     Command("history",
519             "List the command history.",
520             "history")
521 {}
522 
523 void
invoke(char * argv[],int argc)524 CommandHistory::invoke(char* argv[], int argc)
525 {
526     if (!argNum(argc, 1))
527         return;
528 printf("history_base=%d\n", history_base);
529     for (int i = history_base; i < history_base + history_length; i++)
530     {
531         HIST_ENTRY *entry = history_get(i);
532         if (entry)
533             printf ("  %d  %s\n", i, entry->line);
534     }
535 }
536 
CommandInfo()537 CommandInfo::CommandInfo() :
538     Command("info",
539             "Display information about the flash.",
540             "info")
541 {}
542 
543 void
invoke(char * argv[],int argc)544 CommandInfo::invoke(char* argv[], int argc)
545 {
546     FlasherInfo info;
547 
548     if (!argNum(argc, 1) ||
549         !flashable())
550         return;
551 
552     _flasher.info(info);
553 
554     info.print();
555 }
556 
CommandLock()557 CommandLock::CommandLock() :
558     Command("lock",
559             "Set lock bits in the flash.",
560             "lock <BITS>"
561             "  BITS -- (optional) comma separated list of bits,"
562             "          all bits if not given\n")
563 {}
564 
565 void
invoke(char * argv[],int argc)566 CommandLock::invoke(char* argv[], int argc)
567 {
568     string bits;
569 
570     if (!flashable())
571         return;
572 
573     for (int argn = 1; argn < argc; argn++)
574         bits += argv[argn];
575 
576     _flasher.lock(bits, true);
577     printf("Locked regions %s\n", bits.c_str());
578 }
579 
CommandMrb()580 CommandMrb::CommandMrb() :
581     Command("mrb",
582             "Read bytes from memory.",
583             "mrb [ADDRESS] <COUNT>\n"
584             "  ADDRESS -- starting memory address\n"
585             "  COUNT -- (optional) count of bytes to display, 1 if not given")
586 {}
587 
588 void
invoke(char * argv[],int argc)589 CommandMrb::invoke(char* argv[], int argc)
590 {
591     uint32_t addr;
592     uint32_t count = 1;
593     uint8_t value;
594 
595     if (!argRange(argc, 2, 3) ||
596         !argUint32(argv[1], &addr) ||
597         (argc >= 3 && !argUint32(argv[2], &count)) ||
598         !connected())
599         return;
600 
601     while (count > 0)
602     {
603         value = _samba.readByte(addr);
604         printf("%08x : %02x  %s\n", addr, value, binstr(value, 8));
605         addr++;
606         count--;
607     }
608 }
609 
CommandMrf()610 CommandMrf::CommandMrf() :
611     Command("mrf",
612             "Read memory to file.",
613             "mrf [ADDRESS] [COUNT] [FILE]\n"
614             "  ADDRESS -- memory address to read\n"
615             "  COUNT -- count of bytes to read\n"
616             "  FILE -- file name on host filesystem to write")
617 {}
618 
619 void
invoke(char * argv[],int argc)620 CommandMrf::invoke(char* argv[], int argc)
621 {
622     uint32_t addr;
623     uint32_t count;
624     FILE* infile;
625     uint8_t buf[1024];
626     ssize_t fbytes;
627 
628     if (!argNum(argc, 4) ||
629         !argUint32(argv[1], &addr) ||
630         !argUint32(argv[2], &count) ||
631         !connected())
632         return;
633 
634     infile = fopen(argv[3], "wb");
635     if (!infile)
636         throw FileOpenError(errno);
637 
638     try
639     {
640         while (count > 0)
641         {
642             fbytes = min(count, sizeof(buf));
643             _samba.read(addr, buf, fbytes);
644             fbytes = fwrite(buf, 1, fbytes, infile);
645             if (fbytes < 0)
646                 throw FileIoError(errno);
647             if ((size_t) fbytes != min(count, sizeof(buf)))
648                 throw FileShortError();
649             count -= fbytes;
650         }
651     }
652     catch (...)
653     {
654         fclose(infile);
655         throw;
656     }
657 
658     fclose(infile);
659 }
660 
CommandMrw()661 CommandMrw::CommandMrw() :
662     Command("mrw",
663             "Read words from memory.",
664             "mrw [ADDRESS] <COUNT>\n"
665             "  ADDRESS -- starting memory address\n"
666             "  COUNT -- (optional) count of words to display, 1 if not given")
667 {}
668 
669 void
invoke(char * argv[],int argc)670 CommandMrw::invoke(char* argv[], int argc)
671 {
672     uint32_t addr;
673     uint32_t count = 1;
674     uint32_t value;
675 
676     if (!argRange(argc, 2, 3) ||
677         !argUint32(argv[1], &addr) ||
678         (argc >= 3 && !argUint32(argv[2], &count)) ||
679         !connected())
680         return;
681 
682     while (count > 0)
683     {
684         value = _samba.readWord(addr);
685         printf("%08x : %08x  %s\n", addr, value, binstr(value, 32));
686         addr += 4;
687         count--;
688     }
689 }
690 
CommandMwb()691 CommandMwb::CommandMwb() :
692     Command("mwb",
693             "Write bytes to memory.",
694             "mwb [ADDRESS] <VALUE>\n"
695             "  ADDRESS -- starting memory address\n"
696             "  VALUE -- (optional) value of byte to write, if not given"
697             "           command will repeatedly prompt for input")
698 {}
699 
700 void
invoke(char * argv[],int argc)701 CommandMwb::invoke(char* argv[], int argc)
702 {
703     uint32_t addr;
704     uint32_t value;
705 
706     if (!argRange(argc, 2, 3) ||
707         !argUint32(argv[1], &addr) ||
708         (argc >= 3 && !argUint32(argv[2], &value)) ||
709         !connected())
710         return;
711 
712     do
713     {
714         if (argc == 2)
715         {
716             char* input = readline("? ");
717             if (!input)
718                 return;
719             if (*input == '\0' ||
720                 !argUint32(input, &value))
721             {
722                 free(input);
723                 return;
724             }
725             free(input);
726         }
727 
728         if (value > 255)
729         {
730             error("Value out of range");
731             return;
732         }
733 
734         _samba.writeByte(addr, value);
735         printf("%08x : %02x\n", addr, value);
736         addr++;
737     } while (argc == 2);
738 }
739 
CommandMwf()740 CommandMwf::CommandMwf() :
741     Command("mwf",
742             "Write memory from file.",
743             "mwf [ADDRESS] [FILE]\n"
744             "  ADDRESS -- memory address to write\n"
745             "  FILE -- file name on host filesystem to read")
746 {}
747 
748 void
invoke(char * argv[],int argc)749 CommandMwf::invoke(char* argv[], int argc)
750 {
751     uint32_t addr;
752     FILE* infile;
753     uint8_t buf[1024];
754     ssize_t fsize;
755     ssize_t fbytes;
756     ssize_t fpos;
757 
758     if (!argNum(argc, 3) ||
759         !argUint32(argv[1], &addr) ||
760         !connected())
761         return;
762 
763     infile = fopen(argv[2], "rb");
764     if (!infile)
765         throw FileOpenError(errno);
766 
767     try
768     {
769         if (fseek(infile, 0, SEEK_END) != 0 ||
770             (fsize = ftell(infile)) < 0)
771             throw FileIoError(errno);
772 
773         rewind(infile);
774 
775         for (fpos = 0; fpos < fsize; fpos += fbytes)
776         {
777             fbytes = fread(buf, 1, min((size_t)fsize, sizeof(buf)), infile);
778             if (fbytes < 0)
779                 throw FileIoError(errno);
780             if (fbytes == 0)
781                 break;
782             _samba.write(addr, buf, fbytes);
783         }
784     }
785     catch (...)
786     {
787         fclose(infile);
788         throw;
789     }
790     fclose(infile);
791     printf("Wrote %ld bytes to address %08x\n", (long) fsize, addr);
792 }
793 
CommandMww()794 CommandMww::CommandMww() :
795     Command("mww",
796             "Write words to memory.",
797             "mww [ADDRESS] <VALUE>\n"
798             "  ADDRESS -- starting memory address\n"
799             "  VALUE -- (optional) value of word to write, if not given"
800             "           command will repeatedly prompt for input")
801 {}
802 
803 void
invoke(char * argv[],int argc)804 CommandMww::invoke(char* argv[], int argc)
805 {
806     uint32_t addr;
807     uint32_t value;
808 
809     if (!argRange(argc, 2, 3) ||
810         !argUint32(argv[1], &addr) ||
811         (argc >= 3 && !argUint32(argv[2], &value)) ||
812         !connected())
813         return;
814 
815     do
816     {
817         if (argc == 2)
818         {
819             char* input = readline("? ");
820             if (!input)
821                 return;
822             if (*input == '\0' ||
823                 !argUint32(input, &value))
824             {
825                 free(input);
826                 return;
827             }
828             free(input);
829         }
830 
831         _samba.writeWord(addr, value);
832         printf("%08x : %08x\n", addr, value);
833         addr++;
834     } while (argc == 2);
835 }
836 
CommandPio()837 CommandPio::CommandPio() :
838     Command("pio",
839             "Parallel input/output operations.",
840             "pio [LINE] [OPERATION]\n"
841             "  LINE -- PIO line name (i.e. pa28, pc5, etc.)\n"
842             "          All lines if only port given (i.e. pa, pc, etc.)\n"
843             "  OPERATION -- operation to perform on the PIO line.\n"
844             "    status -- show the line status\n"
845             "    high -- drive the output high\n"
846             "    low -- drive the output low\n"
847             "    read -- read the input level\n"
848             "    input -- make the line an input\n"
849             "    peripheral [AB] -- set the line to a peripheral\n"
850             "      [AB] -- peripheral \"a\" or \"b\"\n"
851             "    multidrive [STATE] -- set the multi-drive state\n"
852             "      STATE - either \"disable\" or \"enable\"\n"
853             "    pullup [STATE] -- set the pull-up state\n"
854             "      STATE - either \"disable\" or \"enable\""
855             )
856 {}
857 
858 void
invoke(char * argv[],int argc)859 CommandPio::invoke(char* argv[], int argc)
860 {
861     uint32_t line;
862     uint32_t addr = 0;
863     size_t len;
864     char port;
865 
866     if (!argRange(argc, 3, 4) ||
867         !connected())
868         return;
869 
870     if (strlen(argv[1]) < 2 ||
871         tolower(argv[1][0]) != 'p')
872     {
873         error("Invalid PIO line name");
874         return;
875     }
876 
877     if (argv[1][2] == '\0')
878     {
879         line = 0xffffffff;
880     }
881     else
882     {
883         if (!argUint32(&argv[1][2], &line))
884             return;
885 
886         if (line >= 32)
887         {
888             error("Invalid PIO line number");
889             return;
890         }
891 
892         line = (1 << line);
893     }
894 
895     port = tolower(argv[1][1]);
896 
897     // Check for Cortex-M3 register set
898     Device::Family family = _device.getFamily();
899     if (family == Device::FAMILY_SAM3U)
900     {
901         // Check for SAM3U special case
902         switch (port)
903         {
904             case 'a': addr = 0x400e0c00; break;
905             case 'b': addr = 0x400e0e00; break;
906             case 'c': addr = 0x400e1000; break;
907         }
908     }
909     else if (family == Device::FAMILY_SAM3N ||
910         family == Device::FAMILY_SAM3S)
911     {
912         switch (port)
913         {
914             case 'a': addr = 0x400e0e00; break;
915             case 'b': addr = 0x400e1000; break;
916             case 'c': addr = 0x400e1200; break;
917         }
918     }
919     else if (family == Device::FAMILY_SAM7S ||
920         family == Device::FAMILY_SAM7SE ||
921         family == Device::FAMILY_SAM7X ||
922         family == Device::FAMILY_SAM7XC ||
923         family == Device::FAMILY_SAM7L)
924     {
925         switch (port)
926         {
927             case 'a': addr = 0xfffff400; break;
928             case 'b': addr = 0xfffff600; break;
929             case 'c': addr = 0xfffff800; break;
930         }
931     }
932     else
933     {
934         printf("Unsupported device\n");
935         return;
936     }
937 
938     if (addr == 0)
939     {
940         printf("Invalid PIO line \"%s\"\n", argv[1]);
941         return;
942     }
943 
944     static const uint32_t PIO_PER = 0x0;
945     static const uint32_t PIO_PDR = 0x4;
946     static const uint32_t PIO_PSR = 0x8;
947     static const uint32_t PIO_OER = 0x10;
948     static const uint32_t PIO_ODR = 0x14;
949     static const uint32_t PIO_OSR = 0x18;
950     static const uint32_t PIO_SODR = 0x30;
951     static const uint32_t PIO_CODR = 0x34;
952     static const uint32_t PIO_ODSR = 0x38;
953     static const uint32_t PIO_PDSR = 0x3c;
954     static const uint32_t PIO_MDER = 0x50;
955     static const uint32_t PIO_MDDR = 0x54;
956     static const uint32_t PIO_MDSR = 0x58;
957     static const uint32_t PIO_PUDR = 0x60;
958     static const uint32_t PIO_PUER = 0x64;
959     static const uint32_t PIO_PUSR = 0x68;
960     static const uint32_t PIO_ABSR = 0x70;
961 
962     len = strlen(argv[2]);
963     if (strncasecmp(argv[2], "status", len) == 0)
964     {
965         if (line != 0xffffffff)
966         {
967             uint32_t reg = _samba.readWord(addr + PIO_PSR);
968             printf("PIO Mode      : %s\n", (reg & line) ? "enable" : "disable");
969 
970             reg = _samba.readWord(addr + PIO_OSR);
971             printf("Direction     : %s\n", (reg & line) ? "output" : "input");
972 
973             reg = _samba.readWord(addr + PIO_PDSR);
974             printf("Input Level   : %s\n", (reg & line)? "high" : "low");
975 
976             reg = _samba.readWord(addr + PIO_ODSR);
977             printf("Output Level  : %s\n", (reg & line)? "high" : "low");
978 
979             reg = _samba.readWord(addr + PIO_MDSR);
980             printf("Multi-Drive   : %s\n", (reg & line)? "enable" : "disable");
981 
982             reg = _samba.readWord(addr + PIO_PUSR);
983             printf("Pull-Up       : %s\n", (reg & line)? "disable" : "enable");
984 
985             reg = _samba.readWord(addr + PIO_ABSR);
986             printf("Peripheral    : %s\n", (reg & line) ? "B" : "A");
987         }
988         else
989         {
990             printf("                3      2 2      1 1\n");
991             printf("                1      4 3      6 5      8 7      0\n");
992 
993             uint32_t reg = _samba.readWord(addr + PIO_PSR);
994             printf("PIO Mode      : %s\n", binstr(reg, 32, 'D', 'E'));
995 
996             reg = _samba.readWord(addr + PIO_OSR);
997             printf("Direction     : %s\n", binstr(reg, 32, 'I', 'O'));
998 
999             reg = _samba.readWord(addr + PIO_PDSR);
1000             printf("Input Level   : %s\n", binstr(reg, 32, 'L', 'H'));
1001 
1002             reg = _samba.readWord(addr + PIO_ODSR);
1003             printf("Output Level  : %s\n", binstr(reg, 32, 'L', 'H'));
1004 
1005             reg = _samba.readWord(addr + PIO_MDSR);
1006             printf("Multi-Drive   : %s\n", binstr(reg, 32, 'D', 'E'));
1007 
1008             reg = _samba.readWord(addr + PIO_PUSR);
1009             printf("Pull-Up       : %s\n", binstr(reg, 32, 'E', 'D'));
1010 
1011             reg = _samba.readWord(addr + PIO_ABSR);
1012             printf("Peripheral    : %s\n", binstr(reg, 32, 'A', 'B'));
1013         }
1014     }
1015     else if (strncasecmp(argv[2], "high", len) == 0)
1016     {
1017         _samba.writeWord(addr + PIO_SODR, line);
1018         _samba.writeWord(addr + PIO_OER, line);
1019         _samba.writeWord(addr + PIO_PER, line);
1020         printf("%s is high output\n", argv[1]);
1021     }
1022     else if (strncasecmp(argv[2], "low", len) == 0)
1023     {
1024         _samba.writeWord(addr + PIO_CODR, line);
1025         _samba.writeWord(addr + PIO_OER, line);
1026         _samba.writeWord(addr + PIO_PER, line);
1027         printf("%s is low output\n", argv[1]);
1028     }
1029     else if (strncasecmp(argv[2], "read", len) == 0)
1030     {
1031         uint32_t reg = _samba.readWord(addr +  PIO_PDSR);
1032         printf("%s is %s\n", argv[1], (reg & line) ? "high" : "low");
1033     }
1034     else if (strncasecmp(argv[2], "input", len) == 0)
1035     {
1036         _samba.writeWord(addr + PIO_ODR, line);
1037         _samba.writeWord(addr + PIO_PER, line);
1038         printf("%s is an input\n", argv[1]);
1039     }
1040     else if (strncasecmp(argv[2], "peripheral", len) == 0)
1041     {
1042         uint32_t reg;
1043 
1044         if (!argNum(argc, 4))
1045             return;
1046 
1047         reg = _samba.readWord(addr + PIO_ABSR);
1048         if (strcasecmp(argv[3], "a") == 0)
1049             reg &= ~line;
1050         else if (strcasecmp(argv[3], "b") == 0)
1051             reg |= line;
1052         else
1053         {
1054             error("Peripheral must be \"a\" or \"b\"");
1055             return;
1056         }
1057 
1058         _samba.writeWord(addr + PIO_ABSR, reg);
1059         _samba.writeWord(addr + PIO_PDR, line);
1060 
1061         printf("%s set to peripheral %s\n", argv[1], argv[3]);
1062     }
1063     else if (strncasecmp(argv[2], "pullup", len) == 0)
1064     {
1065         bool state;
1066         if (!argNum(argc, 4) ||
1067             !argState(argv[3], &state))
1068             return;
1069 
1070         if (state)
1071             _samba.writeWord(addr + PIO_PUER, line);
1072         else
1073             _samba.writeWord(addr + PIO_PUDR, line);
1074         printf("%s pullup is %s\n", argv[1], argv[3]);
1075     }
1076     else if (strncasecmp(argv[2], "multidrive", len) == 0)
1077     {
1078         bool state;
1079         if (!argNum(argc, 4) ||
1080             !argState(argv[3], &state))
1081             return;
1082 
1083         if (state)
1084             _samba.writeWord(addr + PIO_MDER, line);
1085         else
1086             _samba.writeWord(addr + PIO_MDDR, line);
1087         printf("%s multidrive is %s\n", argv[1], argv[3]);
1088     }
1089     else
1090     {
1091         printf("Invalid PIO operation\n");
1092         return;
1093     }
1094 }
1095 
CommandRead()1096 CommandRead::CommandRead() :
1097     Command("read",
1098             "Read flash into a binary file.",
1099             "read [FILE] <COUNT> <OFFSET>\n"
1100             "  FILE -- file name on host filesystem\n"
1101             "  COUNT -- (optional) count of bytes to read, defaults\n"
1102             "           to entire flash if not given\n"
1103             "  OFFSET -- (optional) start read operation at flash OFFSET\n"
1104             "            OFFSET must be aligned to a flash page boundary")
1105 {}
1106 
1107 void
invoke(char * argv[],int argc)1108 CommandRead::invoke(char* argv[], int argc)
1109 {
1110     uint32_t count = 0;
1111     uint32_t offset = 0;
1112 
1113     if (!argRange(argc, 2, 4) ||
1114         (argc >= 3 && !argUint32(argv[2], &count)) ||
1115         (argc >= 4 && !argUint32(argv[3], &offset)) ||
1116         !flashable())
1117         return;
1118 
1119     printf("count:%d offset:%d\n", count, offset);
1120 
1121     _flasher.read(argv[1], count, offset);
1122 
1123     printf("\nRead successful\n");
1124 }
1125 
CommandSecurity()1126 CommandSecurity::CommandSecurity() :
1127     Command("security",
1128             "Enable the security flag.",
1129             "security")
1130 {}
1131 
1132 void
invoke(char * argv[],int argc)1133 CommandSecurity::invoke(char* argv[], int argc)
1134 {
1135     if (!argNum(argc, 1) ||
1136         !flashable())
1137         return;
1138 
1139     _flash->setSecurity();
1140 }
1141 
CommandUnlock()1142 CommandUnlock::CommandUnlock() :
1143     Command("unlock",
1144             "Clear lock bits in the flash.",
1145             "unlock <BITS>"
1146             "  BITS -- (optional) comma separated list of bits,"
1147             "          all bits if not given\n")
1148 {}
1149 
1150 void
invoke(char * argv[],int argc)1151 CommandUnlock::invoke(char* argv[], int argc)
1152 {
1153     string bits;
1154 
1155     if (!flashable())
1156         return;
1157 
1158     for (int argn = 1; argn < argc; argn++)
1159         bits += argv[argn];
1160 
1161     _flasher.lock(bits, false);
1162     printf("Unlocked regions %s", bits.c_str());
1163 }
1164 
CommandVerify()1165 CommandVerify::CommandVerify() :
1166     Command("verify",
1167             "Verify binary file with the flash.",
1168             "verify [FILE] <OFFSET>\n"
1169             "  FILE -- file name on host filesystem\n"
1170             "  OFFSET -- (optional) start verify operation at flash OFFSET\n"
1171             "            OFFSET must be aligned to a flash page boundary")
1172 {}
1173 
1174 void
invoke(char * argv[],int argc)1175 CommandVerify::invoke(char* argv[], int argc)
1176 {
1177     uint32_t offset = 0;
1178     uint32_t pageErrors;
1179     uint32_t totalErrors;
1180 
1181     if (!argRange(argc, 2, 3) ||
1182         (argc >= 3 && !argUint32(argv[2], &offset)) ||
1183         !flashable())
1184         return;
1185 
1186     if (!_flasher.verify(argv[1], pageErrors, totalErrors, offset))
1187     {
1188         printf("\nVerify failed\nPage errors: %d\nByte errors: %d\n",
1189             pageErrors, totalErrors);
1190         return;
1191     }
1192 
1193     printf("\nVerify successful\n");
1194 }
1195 
CommandWrite()1196 CommandWrite::CommandWrite() :
1197     Command("write",
1198             "Write binary file into flash.",
1199             "write [FILE] <OFFSET>\n"
1200             "  FILE -- file name on host filesystem\n"
1201             "  OFFSET -- (optional) start write operation at flash OFFSET\n"
1202             "            OFFSET must be aligned to a flash page boundary")
1203 {}
1204 
1205 void
invoke(char * argv[],int argc)1206 CommandWrite::invoke(char* argv[], int argc)
1207 {
1208     uint32_t offset = 0;
1209 
1210     if (!argRange(argc, 2, 3) ||
1211         (argc >= 3 && !argUint32(argv[2], &offset)) ||
1212         !flashable())
1213         return;
1214 
1215     _flasher.write(argv[1], offset);
1216 
1217     printf("\nWrite successful\n");
1218 }
1219 
CommandReset()1220 CommandReset::CommandReset() :
1221     Command("reset",
1222             "Reset the CPU. (only for supported CPU)",
1223             "reset\n")
1224 {}
1225 
1226 void
invoke(char * argv[],int argc)1227 CommandReset::invoke(char* argv[], int argc)
1228 {
1229     _device.reset();
1230 }
1231 
CommandOptions()1232 CommandOptions::CommandOptions() :
1233     Command("options",
1234             "Write options to flash.",
1235             "options\n")
1236 {}
1237 
1238 void
invoke(char * argv[],int argc)1239 CommandOptions::invoke(char* argv[], int argc)
1240 {
1241     _flash->writeOptions();
1242 }
1243 
1244