- add missing image handling files
[fw/openocd] / src / target / image.c
1 /***************************************************************************
2  *   Copyright (C) 2007 by Dominic Rath                                    *
3  *   Dominic.Rath@gmx.de                                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "image.h"
28
29 #include "types.h"
30 #include "replacements.h"
31 #include "log.h"
32
33 #include "fileio.h"
34 #include "target.h"
35
36 int image_ihex_buffer_complete(image_t *image)
37 {
38         image_ihex_t *ihex = image->type_private;
39         fileio_t *fileio = &ihex->fileio;
40         u32 raw_bytes_read, raw_bytes;
41         int retval;
42         u32 full_address = image->base_address;
43         char *buffer = malloc(ihex->raw_size);
44         u32 cooked_bytes = 0x0;
45         
46         ihex->raw_size = fileio->size;
47         ihex->buffer = malloc(ihex->raw_size >> 1);
48         
49         if ((retval = fileio_read(fileio, ihex->raw_size, (u8*)buffer, &raw_bytes_read)) != ERROR_OK)
50         {
51                 free(buffer);
52                 ERROR("failed buffering IHEX file, read failed");
53                 return ERROR_FILEIO_OPERATION_FAILED;
54         }
55         
56         if (raw_bytes_read != ihex->raw_size)
57         {
58                 free(buffer);
59                 ERROR("failed buffering complete IHEX file, only partially read");
60                 return ERROR_FILEIO_OPERATION_FAILED;
61         }
62         
63         image->size = 0x0;
64         raw_bytes = 0x0;
65         while (raw_bytes < raw_bytes_read)
66         {
67                 u32 count;
68                 u32 address;
69                 u32 record_type;
70                 u32 checksum;
71                 
72                 if (sscanf(&buffer[raw_bytes], ":%2x%4x%2x", &count, &address, &record_type) != 3)
73                 {
74                         return ERROR_IMAGE_FORMAT_ERROR;
75                 }
76                 raw_bytes += 9;
77                 
78                 if (record_type == 0)
79                 {
80                         if ((full_address & 0xffff) != address)
81                         {
82                                 free(buffer);
83                                 ERROR("can't handle non-linear IHEX file");
84                                 return ERROR_IMAGE_FORMAT_ERROR;
85                         }
86                         
87                         while (count-- > 0)
88                         {
89                                 sscanf(&buffer[raw_bytes], "%2hhx", &ihex->buffer[cooked_bytes]);
90                                 raw_bytes += 2;
91                                 cooked_bytes += 1;
92                                 full_address++;
93                         }
94                 }
95                 else if (record_type == 1)
96                 {
97                         free(buffer);
98                         image->size = cooked_bytes;
99                         return ERROR_OK;
100                 }
101                 else if (record_type == 4)
102                 {
103                         u16 upper_address;
104                         
105                         sscanf(&buffer[raw_bytes], "%4hx", &upper_address);
106                         raw_bytes += 4;
107                         
108                         if ((full_address >> 16) != upper_address)
109                         {
110                                 free(buffer);
111                                 ERROR("can't handle non-linear IHEX file");
112                                 return ERROR_IMAGE_FORMAT_ERROR;
113                         }
114                 }
115                 else if (record_type == 5)
116                 {
117                         u32 start_address;
118                         
119                         sscanf(&buffer[raw_bytes], "%8x", &start_address);
120                         raw_bytes += 8;
121                         
122                         image->start_address_set = 1;
123                         image->start_address = be_to_h_u32((u8*)&start_address);
124                 }
125                 else
126                 {
127                         free(buffer);
128                         ERROR("unhandled IHEX record type: %i", record_type);
129                         return ERROR_IMAGE_FORMAT_ERROR;
130                 }
131                 
132                 sscanf(&buffer[raw_bytes], "%2x", &checksum);
133                 raw_bytes += 2;
134                 
135                 /* consume new-line character(s) */
136                 if ((buffer[raw_bytes] == '\n') || (buffer[raw_bytes] == '\r'))
137                         raw_bytes++;
138
139                 if ((buffer[raw_bytes] == '\n') || (buffer[raw_bytes] == '\r'))
140                         raw_bytes++;
141         }
142
143         free(buffer);
144         ERROR("premature end of IHEX file, no end-of-file record found");
145         return ERROR_IMAGE_FORMAT_ERROR;
146 }
147
148 int image_open(image_t *image, void *source, enum fileio_access access)
149 {
150         int retval = ERROR_OK;
151         
152         if (image->type == IMAGE_BINARY)
153         {
154                 image_binary_t *image_binary;
155                 char *url = source;
156                 
157                 image_binary = image->type_private = malloc(sizeof(image_binary_t));
158                 
159                 if ((retval = fileio_open(&image_binary->fileio, url, access, FILEIO_BINARY)) != ERROR_OK)
160                 {
161                         strncpy(image->error_str, image_binary->fileio.error_str, IMAGE_MAX_ERROR_STRING); 
162                         ERROR(image->error_str);
163                         return retval;
164                 }
165                 
166                 if (access == FILEIO_WRITE)
167                         image->size = 0;
168                 else
169                         image->size = image_binary->fileio.size;
170                 
171                 return ERROR_OK;
172         }
173         else if (image->type == IMAGE_IHEX)
174         {
175                 image_ihex_t *image_ihex;
176                 char *url = source;
177                 
178                 if (access != FILEIO_READ)
179                 {
180                         snprintf(image->error_str, IMAGE_MAX_ERROR_STRING,
181                                 "can't open IHEX file for writing");
182                         ERROR(image->error_str);
183                         return ERROR_FILEIO_ACCESS_NOT_SUPPORTED;
184                 }
185                 
186                 image_ihex = image->type_private = malloc(sizeof(image_ihex_t));
187                 
188                 if ((retval = fileio_open(&image_ihex->fileio, url, FILEIO_READ, FILEIO_TEXT)) != ERROR_OK)
189                 {
190                         strncpy(image->error_str, image_ihex->fileio.error_str, IMAGE_MAX_ERROR_STRING); 
191                         ERROR(image->error_str);
192                         return retval;
193                 }
194                 
195                 image_ihex->position = 0;
196                 image_ihex->raw_size = image_ihex->fileio.size;
197                 
198                 if ((retval = image_ihex_buffer_complete(image)) != ERROR_OK)
199                 {
200                         snprintf(image->error_str, IMAGE_MAX_ERROR_STRING,
201                                 "failed buffering IHEX image, check daemon output for additional information");
202                         ERROR(image->error_str);
203                         fileio_close(&image_ihex->fileio);
204                         return retval;
205                 }
206         }
207         else if (image->type == IMAGE_MEMORY)
208         {
209                 image_memory_t *image_memory;
210                 target_t *target = source;
211                 
212                 image_memory = image->type_private = malloc(sizeof(image_memory_t));
213                 
214                 image_memory->target = target;
215         }
216         
217         return retval;
218 };
219
220 int image_read(image_t *image, u32 size, u8 *buffer, u32 *size_read)
221 {
222         int retval;
223         
224         if (image->type == IMAGE_BINARY)
225         {
226                 image_binary_t *image_binary = image->type_private;
227                 
228                 if ((retval = fileio_read(&image_binary->fileio, size, buffer, size_read)) != ERROR_OK)
229                 {
230                         strncpy(image->error_str, image_binary->fileio.error_str, IMAGE_MAX_ERROR_STRING);
231                         return retval;
232                 }
233         }
234         else if (image->type == IMAGE_IHEX)
235         {
236                 image_ihex_t *image_ihex = image->type_private;
237         
238                 if ((image_ihex->position + size) > image->size)
239                 {
240                         /* don't read past the end of the file */
241                         size = (image->size - image_ihex->position);
242                 }
243         
244                 memcpy(buffer, image_ihex->buffer + image_ihex->position, size);
245                 image_ihex->position += size;
246                 *size_read = size;
247                 image->error_str[0] = '\0';
248                 
249                 return ERROR_OK;
250         }
251         else if (image->type == IMAGE_MEMORY)
252         {
253                 /* TODO: handle target memory pseudo image */
254         }
255         
256         return ERROR_OK;
257 }
258
259 int image_write(image_t *image, u32 size, u8 *buffer, u32 *size_written)
260 {
261         int retval = ERROR_FILEIO_OPERATION_NOT_SUPPORTED;
262         
263         if (image->type == IMAGE_BINARY)
264         {
265                 image_binary_t *image_binary = image->type_private;
266                 
267                 if ((retval = fileio_write(&image_binary->fileio, size, buffer, size_written)) != ERROR_OK)
268                 {
269                         strncpy(image->error_str, image_binary->fileio.error_str, IMAGE_MAX_ERROR_STRING);
270                         return retval;
271                 }
272         }
273         else if (image->type == IMAGE_IHEX)
274         {
275                 return ERROR_FILEIO_OPERATION_NOT_SUPPORTED;
276         }
277         else if (image->type == IMAGE_MEMORY)
278         {
279                 /* TODO: handle target memory pseudo image */
280         }
281         
282         if (retval != ERROR_OK)
283                 return retval;
284                 
285         image->size += size;
286         
287         return ERROR_OK;
288 }
289
290 int image_close(image_t *image)
291 {
292         if (image->type == IMAGE_BINARY)
293         {
294                 image_binary_t *image_binary = image->type_private;
295                 
296                 fileio_close(&image_binary->fileio);
297         }
298         else if (image->type == IMAGE_IHEX)
299         {
300                 image_ihex_t *image_ihex = image->type_private;
301                 
302                 fileio_close(&image_ihex->fileio);
303                 
304                 if (image_ihex->buffer)
305                         free(image_ihex->buffer);
306         }
307         else if (image->type == IMAGE_MEMORY)
308         {
309                 /* do nothing for now */
310         }
311
312         free(image->type_private);
313         
314         return ERROR_OK;
315 }
316
317 int identify_image_type(image_type_t *type, char *type_string)
318 {
319         if (type_string)
320         {
321                 if (!strcmp(type_string, "bin"))
322                 {
323                         *type = IMAGE_BINARY;
324                 }
325                 else if (!strcmp(type_string, "ihex"))
326                 {
327                         *type = IMAGE_IHEX;
328                 }
329                 else
330                 {
331                         return ERROR_IMAGE_TYPE_UNKNOWN;
332                 }
333         }
334         else
335         {
336                 *type = IMAGE_BINARY;
337         }
338         
339         return ERROR_OK;
340 }