1 /*********************************************************************
2  *
3  *   LPC ISP Commands
4  *
5  *
6  * Written by Nathael Pajani <nathael.pajani@nathael.net>
7  *
8  * This programm is released under the terms of the GNU GPLv3 licence
9  * as can be found on the GNU website : <http://www.gnu.org/licenses/>
10  *
11  *********************************************************************/
14 #include <stdlib.h> /* strtoul */
15 #include <stdio.h>
16 #include <stdint.h>
17 #include <unistd.h>
18 #include <string.h> /* strncmp */
19 #include <ctype.h>
20 #include <errno.h>
22 #include <unistd.h> /* for open, close */
23 #include <fcntl.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
27 #include "isp_commands.h"
28 #include "isp_utils.h"
30 extern int trace_on;
33 #define RAM_MAX_SIZE (8 * 1024) /* 8 KB */
35 #define REP_BUFSIZE 40
39 /*
40  * read-memory
41  * aruments : address count file
42  * read 'count' bytes from 'address', store then in 'file'
43  */
44 int isp_cmd_read_memory(int arg_count, char** args)
45 {
46         /* Arguments */
47         unsigned long int addr = 0, count = 0;
48         char* out_file_name = NULL;
49         /* Reply handling */
50         char* data;
51         int ret = 0, len = 0;
53         /* Check read-memory arguments */
54         if (arg_count != 3) {
55                 printf("read-memory command needs address and count. Both must be multiple of 4.\n");
56                 return -12;
57         }
58         addr = strtoul(args[0], NULL, 0);
59         count = strtoul(args[1], NULL, 0);
60         if (trace_on) {
61                 printf("read-memory command called for 0x%08lx (%lu) bytes at address 0x%08lx.\n",
62                                 count, count, addr);
63         }
64         if ((addr & 0x03) || (count & 0x03)) {
65                 printf("Address and count must be multiple of 4 for read-memory command.\n");
66                 return -11;
67         }
68         out_file_name = args[2];
70         /* Allocate buffer */
71         data = malloc(count);
72         if (data == NULL) {
73                 printf("Unable to allocate read buffer, asked %lu.\n", count);
74                 return -10;
75         }
77         /* Read data */
78         len = isp_read_memory(data, addr, count);
79         if (len != (int)count) {
80                 printf("Read returned %d bytes instead of %lu.\n", len, count);
81         }
83         /* Write data to file */
84         ret = isp_buff_to_file(data, len, out_file_name);
86         /* Free memory */
87         free(data);
89         return ret;
90 }
92 /*
93  * write-to-ram
94  * aruments : address file do_not_perform_uuencode
95  * send 'file' to 'address' in ram with or without uuencoding data
96  */
97 int isp_cmd_write_to_ram(int arg_count, char** args)
98 {
99         /* Arguments */
100         unsigned long int addr = 0;
101         char* in_file_name = NULL;
102         char file_buff[RAM_MAX_SIZE];
103         unsigned int bytes_read = 0;
104         int ret = 0;
105         int uuencode = 1;
107         /* Check write-to-ram arguments */
108         if (arg_count < 2) {
109                 printf("write-to-ram command needs ram address. Must be multiple of 4.\n");
110                 return -15;
111         }
112         addr = strtoul(args[0], NULL, 0);
113         if (trace_on) {
114                 printf("write-to-ram command called, destination address in ram is 0x%08lx.\n", addr);
115         }
116         if (addr & 0x03) {
117                 printf("Address must be multiple of 4 for write-to-ram command.\n");
118                 return -14;
119         }
120         in_file_name = args[1];
121         if (arg_count > 2) {
122                 uuencode = strtoul(args[2], NULL, 0);
123         }
125         /* Read data */
126         bytes_read = isp_file_to_buff(file_buff, RAM_MAX_SIZE, in_file_name);
127         if (bytes_read <= 0){
128                 return -13;
129         }
131         if (trace_on) {
132                 printf("Read %d octet(s) from input file\n", bytes_read);
133         }
135         /* Pad data size to 4 */
136         if (bytes_read & 0x03) {
137                 bytes_read = (bytes_read & ~0x03) + 0x04;
138         }
140         /* And send to ram */
141         ret = isp_send_buf_to_ram(file_buff, addr, bytes_read, uuencode);
143         return ret;
146 int isp_cmd_address_wrapper(int arg_count, char** args, char* name, char cmd)
148         int ret = 0, len = 0;
149         /* Arguments */
150         unsigned long int addr1 = 0, addr2 = 0;
151         unsigned long int length = 0;
153         /* Check arguments */
154         if (arg_count != 3) {
155                 printf("%s command needs two addresses and byte count.\n", name);
156                 return -7;
157         }
158         addr1 = strtoul(args[0], NULL, 0);
159         addr2 = strtoul(args[1], NULL, 0);
160         length = strtoul(args[2], NULL, 0);
161         if (trace_on) {
162                 printf("%s command called for %lu bytes between addresses %lu and %lu.\n",
163                                 name, length, addr1, addr2);
164         }
165         switch (cmd) {
166                 case 'M':
167                         if ((addr1 & 0x03) || (addr2 & 0x03) || (length & 0x03)) {
168                                 printf("Error: addresses and count must be multiples of 4 for %s command.\n", name);
169                                 return -7;
170                         }
171                         break;
172                 case 'C':
173                         if ((addr1 & 0x00FF) || (addr2 & 0x03)) {
174                                 printf("Error: flash address must be on 256 bytes boundary, ram address on 4 bytes boundary.\n");
175                                 return -8;
176                         }
177                         /* According to section 21.5.7 of LPC11xx user's manual (UM10398), number of bytes
178                          * written should be 256 | 512 | 1024 | 4096 */
179                         len = ((length >> 8) & 0x01) + ((length >> 9) & 0x01);
180                         len += ((length >> 10) & 0x01) + ((length >> 12) & 0x01);
181                         if (len != 1) {
182                                 printf("Error: bytes count must be one of 256 | 512 | 1024 | 4096\n");
183                                 return -7;
184                         }
185                         break;
186                 default:
187                         printf("Error: unsupported command code: '%c'\n", cmd);
188                         return -6;
189         }
191         ret = isp_send_cmd_address(cmd, addr1, addr2, length, name);
192         return ret;
195 int isp_cmd_compare(int arg_count, char** args)
197         char buf[REP_BUFSIZE];
198         int ret = 0, len = 0;
199         unsigned long int offset = 0;
201         ret = isp_cmd_address_wrapper(arg_count, args, "compare", 'M');
202         switch (ret) {
203                 case CMD_SUCCESS:
204                         printf("Source and destination data are equal.\n");
205                         break;
206                 case COMPARE_ERROR:
207                         /* read remaining data */
208                         usleep( 2000 );
209                         len = isp_serial_read(buf, REP_BUFSIZE, 3);
210                         if (len <= 0) {
211                                 printf("Error reading blank-check result.\n");
212                                 return -3;
213                         }
214                         offset = strtoul(buf, NULL, 10);
215                         printf("First mismatch occured at offset 0x%08lx\n", offset);
216                         break;
217                 default :
218                         printf("Error for compare command.\n");
219                         return -1;
220         }
222         return 0;
225 int isp_cmd_copy_ram_to_flash(int arg_count, char** args)
227         int ret = 0;
229         ret = isp_cmd_address_wrapper(arg_count, args, "copy-ram-to-flash", 'C');
231         if (ret != 0) {
232                 printf("Error when trying to copy data from ram to flash.\n");
233                 return ret;
234         }
235         printf("Data copied from ram to flash.\n");
237         return 0;
240 int isp_cmd_go(int arg_count, char** args)
242         int ret = 0;
243         /* Arguments */
244         unsigned long int addr = 0;
245         char* mode = NULL;
247         /* Check go arguments */
248         if (arg_count != 2) {
249                 printf("go command needs address (> 0x200) and mode ('thumb' or 'arm').\n");
250                 return -7;
251         }
252         addr = strtoul(args[0], NULL, 0);
253         mode = args[1];
254         if (trace_on) {
255                 printf("go command called with address 0x%08lx and mode %s.\n", addr, mode);
256         }
257         if (addr < 0x200) {
258                 printf("Error: address must be 0x00000200 or greater for go command.\n");
259                 return -6;
260         }
261         if (strncmp(mode, "thumb", strlen(mode)) == 0) {
262                 mode[0] = 'T';
263         } else if (strncmp(mode, "arm", strlen(mode)) == 0) {
264                 mode[0] = 'A';
265         } else {
266                 printf("Error: mode must be 'thumb' or 'arm' for go command.\n");
267                 return -5;
268         }
270         ret = isp_send_cmd_go(addr, mode[0]);
272         return ret;
275 int isp_cmd_sectors_skel(int arg_count, char** args, char* name, char cmd)
277         int ret = 0;
278         /* Arguments */
279         unsigned long int first_sector = 0, last_sector = 0;
281         /* Check arguments */
282         if (arg_count != 2) {
283                 printf("%s command needs first and last sectors (1 sector = 4KB of flash).\n", name);
284                 return -7;
285         }
286         first_sector = strtoul(args[0], NULL, 0);
287         last_sector = strtoul(args[1], NULL, 0);
288         if (trace_on) {
289                 printf("%s command called for sectors %lu to %lu.\n", name, first_sector, last_sector);
290         }
292         ret = isp_send_cmd_sectors(name, cmd, first_sector, last_sector, 0);
294         return ret;
297 int isp_cmd_blank_check(int arg_count, char** args)
299         char* tmp = NULL;
300         unsigned long int offset = 0, content = 0;
301         char buf[REP_BUFSIZE];
302         int ret = 0, len = 0;
304         ret = isp_cmd_sectors_skel(arg_count, args, "blank-check", 'I');
305         if (ret < 0) {
306                 return ret;
307         }
309         switch (ret) {
310                 case CMD_SUCCESS:
311                         printf("Specified sector(s) all blank(s).\n");
312                         break;
313                 case SECTOR_NOT_BLANK:
314                         /* read remaining data */
315                         usleep( 2000 );
316                         len = isp_serial_read(buf, REP_BUFSIZE, 3);
317                         if (len <= 0) {
318                                 printf("Error reading blank-check result.\n");
319                                 return -3;
320                         }
321                         offset = strtoul(buf, &tmp, 10);
322                         content = strtoul(tmp, NULL, 10);
323                         printf("First non blank word is at offset 0x%08lx and contains 0x%08lx\n", offset, content);
324                         break;
325                 case INVALID_SECTOR :
326                         printf("Invalid sector for blank-check command.\n");
327                         return -2;
328                 case PARAM_ERROR:
329                         printf("Param error for blank-check command.\n");
330                         return -1;
331         }
333         return 0;
336 int isp_cmd_prepare_for_write(int arg_count, char** args)
338         int ret = isp_cmd_sectors_skel(arg_count, args, "prepare-for-write", 'P');
340         if (ret != 0) {
341                 printf("Error when trying to prepare sectors for write operation.\n");
342                 return ret;
343         }
344         printf("Sectors prepared for write operation.\n");
346         return 0;
349 int isp_cmd_erase(int arg_count, char** args)
351         int ret = isp_cmd_sectors_skel(arg_count, args, "erase", 'E');
353         if (ret != 0) {
354                 printf("Error when trying to erase sectors.\n");
355                 return ret;
356         }
357         printf("Sectors erased.\n");
359         return 0;