42dd99dfde2ccab86dfee6057bcd3c2ca95cf7f6
1 /*********************************************************************
2  *
3  *   LPC ISP Commands
4  *
5  *
6  *  Copyright (C) 2012 Nathael Pajani <nathael.pajani@nathael.net>
7  *
8  *  This program is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  *********************************************************************/
24 #include <stdlib.h> /* strtoul */
25 #include <stdio.h>
26 #include <stdint.h>
27 #include <unistd.h>
28 #include <string.h> /* strncmp */
29 #include <ctype.h>
30 #include <errno.h>
32 #include <unistd.h> /* for open, close */
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
37 #include "isp_commands.h"
38 #include "isp_utils.h"
40 extern int trace_on;
43 #define RAM_MAX_SIZE (8 * 1024) /* 8 KB */
45 #define REP_BUFSIZE 40
49 /*
50  * read-memory
51  * aruments : address count file uuencoded
52  * read 'count' bytes from 'address', store then in 'file', and maybe decode uuencoded data.
53  */
54 int isp_cmd_read_memory(int arg_count, char** args)
55 {
56         /* Arguments */
57         unsigned long int addr = 0, count = 0;
58         char* out_file_name = NULL;
59         /* Reply handling */
60         char* data;
61         int ret = 0, len = 0;
62         unsigned int uuencoded = 1;
64         /* Check read-memory arguments */
65         if (arg_count < 3) {
66                 printf("read-memory command needs address and count. Both must be multiple of 4.\n");
67                 return -12;
68         }
69         addr = strtoul(args[0], NULL, 0);
70         count = strtoul(args[1], NULL, 0);
71         if (trace_on) {
72                 printf("read-memory command called for 0x%08lx (%lu) bytes at address 0x%08lx.\n",
73                                 count, count, addr);
74         }
75         if ((addr & 0x03) || (count & 0x03)) {
76                 printf("Address and count must be multiple of 4 for read-memory command.\n");
77                 return -11;
78         }
79         out_file_name = args[2];
80         if (arg_count > 3) {
81                 uuencoded = strtoul(args[3], NULL, 0);
82         }
84         /* Allocate buffer */
85         data = malloc(count);
86         if (data == NULL) {
87                 printf("Unable to allocate read buffer, asked %lu.\n", count);
88                 return -10;
89         }
91         /* Read data */
92         len = isp_read_memory(data, addr, count, uuencoded);
93         if (len != (int)count) {
94                 printf("Read returned %d bytes instead of %lu.\n", len, count);
95         }
97         /* Write data to file */
98         ret = isp_buff_to_file(data, len, out_file_name);
100         /* Free memory */
101         free(data);
103         return ret;
106 /*
107  * write-to-ram
108  * aruments : address file do_not_perform_uuencode
109  * send 'file' to 'address' in ram with or without uuencoding data
110  */
111 int isp_cmd_write_to_ram(int arg_count, char** args)
113         /* Arguments */
114         unsigned long int addr = 0;
115         char* in_file_name = NULL;
116         char file_buff[RAM_MAX_SIZE];
117         unsigned int bytes_read = 0;
118         int ret = 0;
119         int uuencode = 1;
121         /* Check write-to-ram arguments */
122         if (arg_count < 2) {
123                 printf("write-to-ram command needs ram address. Must be multiple of 4.\n");
124                 return -15;
125         }
126         addr = strtoul(args[0], NULL, 0);
127         if (trace_on) {
128                 printf("write-to-ram command called, destination address in ram is 0x%08lx.\n", addr);
129         }
130         if (addr & 0x03) {
131                 printf("Address must be multiple of 4 for write-to-ram command.\n");
132                 return -14;
133         }
134         in_file_name = args[1];
135         if (arg_count > 2) {
136                 uuencode = strtoul(args[2], NULL, 0);
137         }
139         /* Read data */
140         bytes_read = isp_file_to_buff(file_buff, RAM_MAX_SIZE, in_file_name);
141         if (bytes_read <= 0){
142                 return -13;
143         }
145         if (trace_on) {
146                 printf("Read %d octet(s) from input file\n", bytes_read);
147         }
149         /* Pad data size to 4 */
150         if (bytes_read & 0x03) {
151                 bytes_read = (bytes_read & ~0x03) + 0x04;
152         }
154         /* And send to ram */
155         ret = isp_send_buf_to_ram(file_buff, addr, bytes_read, uuencode);
157         return ret;
160 int isp_cmd_address_wrapper(int arg_count, char** args, char* name, char cmd)
162         int ret = 0, len = 0;
163         /* Arguments */
164         unsigned long int addr1 = 0, addr2 = 0;
165         unsigned long int length = 0;
167         /* Check arguments */
168         if (arg_count != 3) {
169                 printf("%s command needs two addresses and byte count.\n", name);
170                 return -7;
171         }
172         addr1 = strtoul(args[0], NULL, 0);
173         addr2 = strtoul(args[1], NULL, 0);
174         length = strtoul(args[2], NULL, 0);
175         if (trace_on) {
176                 printf("%s command called for %lu bytes between addresses %lu and %lu.\n",
177                                 name, length, addr1, addr2);
178         }
179         switch (cmd) {
180                 case 'M':
181                         if ((addr1 & 0x03) || (addr2 & 0x03) || (length & 0x03)) {
182                                 printf("Error: addresses and count must be multiples of 4 for %s command.\n", name);
183                                 return -7;
184                         }
185                         break;
186                 case 'C':
187                         if ((addr1 & 0x00FF) || (addr2 & 0x03)) {
188                                 printf("Error: flash address must be on 256 bytes boundary, ram address on 4 bytes boundary.\n");
189                                 return -8;
190                         }
191                         /* According to section 21.5.7 of LPC11xx user's manual (UM10398), number of bytes
192                          * written should be 256 | 512 | 1024 | 4096 */
193                         len = ((length >> 8) & 0x01) + ((length >> 9) & 0x01);
194                         len += ((length >> 10) & 0x01) + ((length >> 12) & 0x01);
195                         if (len != 1) {
196                                 printf("Error: bytes count must be one of 256 | 512 | 1024 | 4096\n");
197                                 return -7;
198                         }
199                         break;
200                 default:
201                         printf("Error: unsupported command code: '%c'\n", cmd);
202                         return -6;
203         }
205         ret = isp_send_cmd_address(cmd, addr1, addr2, length, name);
206         return ret;
209 int isp_cmd_compare(int arg_count, char** args)
211         char buf[REP_BUFSIZE];
212         int ret = 0, len = 0;
213         unsigned long int offset = 0;
215         ret = isp_cmd_address_wrapper(arg_count, args, "compare", 'M');
216         switch (ret) {
217                 case CMD_SUCCESS:
218                         printf("Source and destination data are equal.\n");
219                         break;
220                 case COMPARE_ERROR:
221                         /* read remaining data */
222                         usleep( 2000 );
223                         len = isp_serial_read(buf, REP_BUFSIZE, 3);
224                         if (len <= 0) {
225                                 printf("Error reading blank-check result.\n");
226                                 return -3;
227                         }
228                         offset = strtoul(buf, NULL, 10);
229                         printf("First mismatch occured at offset 0x%08lx\n", offset);
230                         break;
231                 default :
232                         printf("Error for compare command.\n");
233                         return -1;
234         }
236         return 0;
239 int isp_cmd_copy_ram_to_flash(int arg_count, char** args)
241         int ret = 0;
243         ret = isp_cmd_address_wrapper(arg_count, args, "copy-ram-to-flash", 'C');
245         if (ret != 0) {
246                 printf("Error when trying to copy data from ram to flash.\n");
247                 return ret;
248         }
249         printf("Data copied from ram to flash.\n");
251         return 0;
254 int isp_cmd_go(int arg_count, char** args)
256         int ret = 0;
257         /* Arguments */
258         unsigned long int addr = 0;
259         char* mode = NULL;
261         /* Check go arguments */
262         if (arg_count != 2) {
263                 printf("go command needs address (> 0x200) and mode ('thumb' or 'arm').\n");
264                 return -7;
265         }
266         addr = strtoul(args[0], NULL, 0);
267         mode = args[1];
268         if (trace_on) {
269                 printf("go command called with address 0x%08lx and mode %s.\n", addr, mode);
270         }
271         if (addr < 0x200) {
272                 printf("Error: address must be 0x00000200 or greater for go command.\n");
273                 return -6;
274         }
275         if (strncmp(mode, "thumb", strlen(mode)) == 0) {
276                 mode[0] = 'T';
277         } else if (strncmp(mode, "arm", strlen(mode)) == 0) {
278                 mode[0] = 'A';
279         } else {
280                 printf("Error: mode must be 'thumb' or 'arm' for go command.\n");
281                 return -5;
282         }
284         ret = isp_send_cmd_go(addr, mode[0]);
286         return ret;
289 int isp_cmd_sectors_skel(int arg_count, char** args, char* name, char cmd)
291         int ret = 0;
292         /* Arguments */
293         unsigned long int first_sector = 0, last_sector = 0;
295         /* Check arguments */
296         if (arg_count != 2) {
297                 printf("%s command needs first and last sectors (1 sector = 4KB of flash).\n", name);
298                 return -7;
299         }
300         first_sector = strtoul(args[0], NULL, 0);
301         last_sector = strtoul(args[1], NULL, 0);
302         if (trace_on) {
303                 printf("%s command called for sectors %lu to %lu.\n", name, first_sector, last_sector);
304         }
306         ret = isp_send_cmd_sectors(name, cmd, first_sector, last_sector, 0);
308         return ret;
311 int isp_cmd_blank_check(int arg_count, char** args)
313         char* tmp = NULL;
314         unsigned long int offset = 0, content = 0;
315         char buf[REP_BUFSIZE];
316         int ret = 0, len = 0;
318         ret = isp_cmd_sectors_skel(arg_count, args, "blank-check", 'I');
319         if (ret < 0) {
320                 return ret;
321         }
323         switch (ret) {
324                 case CMD_SUCCESS:
325                         printf("Specified sector(s) all blank(s).\n");
326                         break;
327                 case SECTOR_NOT_BLANK:
328                         /* read remaining data */
329                         usleep( 2000 );
330                         len = isp_serial_read(buf, REP_BUFSIZE, 3);
331                         if (len <= 0) {
332                                 printf("Error reading blank-check result.\n");
333                                 return -3;
334                         }
335                         offset = strtoul(buf, &tmp, 10);
336                         content = strtoul(tmp, NULL, 10);
337                         printf("First non blank word is at offset 0x%08lx and contains 0x%08lx\n", offset, content);
338                         break;
339                 case INVALID_SECTOR :
340                         printf("Invalid sector for blank-check command.\n");
341                         return -2;
342                 case PARAM_ERROR:
343                         printf("Param error for blank-check command.\n");
344                         return -1;
345         }
347         return 0;
350 int isp_cmd_prepare_for_write(int arg_count, char** args)
352         int ret = isp_cmd_sectors_skel(arg_count, args, "prepare-for-write", 'P');
354         if (ret != 0) {
355                 printf("Error when trying to prepare sectors for write operation.\n");
356                 return ret;
357         }
358         printf("Sectors prepared for write operation.\n");
360         return 0;
363 int isp_cmd_erase(int arg_count, char** args)
365         int ret = isp_cmd_sectors_skel(arg_count, args, "erase", 'E');
367         if (ret != 0) {
368                 printf("Error when trying to erase sectors.\n");
369                 return ret;
370         }
371         printf("Sectors erased.\n");
373         return 0;