964796e9a647666924347ca481f4c969d057784d
[platform/kernel/u-boot.git] / tools / kwbimage.c
1 /*
2  * (C) Copyright 2008
3  * Marvell Semiconductor <www.marvell.com>
4  * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24
25 /* Required to obtain the getline prototype from stdio.h */
26 #define _GNU_SOURCE
27
28 #include "mkimage.h"
29 #include <image.h>
30 #include "kwbimage.h"
31
32 /*
33  * Supported commands for configuration file
34  */
35 static table_entry_t kwbimage_cmds[] = {
36         {CMD_BOOT_FROM,         "BOOT_FROM",            "boot command", },
37         {CMD_NAND_ECC_MODE,     "NAND_ECC_MODE",        "NAND mode",    },
38         {CMD_NAND_PAGE_SIZE,    "NAND_PAGE_SIZE",       "NAND size",    },
39         {CMD_SATA_PIO_MODE,     "SATA_PIO_MODE",        "SATA mode",    },
40         {CMD_DDR_INIT_DELAY,    "DDR_INIT_DELAY",       "DDR init dly", },
41         {CMD_DATA,              "DATA",                 "Reg Write Data", },
42         {CMD_INVALID,           "",                     "",     },
43 };
44
45 /*
46  * Supported Boot options for configuration file
47  */
48 static table_entry_t kwbimage_bootops[] = {
49         {IBR_HDR_SPI_ID,        "spi",          "SPI Flash",    },
50         {IBR_HDR_NAND_ID,       "nand",         "NAND Flash",   },
51         {IBR_HDR_SATA_ID,       "sata",         "Sata port",    },
52         {IBR_HDR_PEX_ID,        "pex",          "PCIe port",    },
53         {IBR_HDR_UART_ID,       "uart",         "Serial port",  },
54         {-1,                    "",             "Invalid",      },
55 };
56
57 /*
58  * Supported NAND ecc options configuration file
59  */
60 static table_entry_t kwbimage_eccmodes[] = {
61         {IBR_HDR_ECC_DEFAULT,           "default",      "Default mode", },
62         {IBR_HDR_ECC_FORCED_HAMMING,    "hamming",      "Hamming mode", },
63         {IBR_HDR_ECC_FORCED_RS,         "rs",           "RS mode",      },
64         {IBR_HDR_ECC_DISABLED,          "disabled",     "ECC Disabled", },
65         {-1,                            "",             "",     },
66 };
67
68 static struct kwb_header kwbimage_header;
69 static int datacmd_cnt = 0;
70 static char * fname = "Unknown";
71 static int lineno = -1;
72
73 /*
74  * Report Error if xflag is set in addition to default
75  */
76 static int kwbimage_check_params (struct mkimage_params *params)
77 {
78         if (!strlen (params->imagename)) {
79                 printf ("Error:%s - Configuration file not specified, "
80                         "it is needed for kwbimage generation\n",
81                         params->cmdname);
82                 return CFG_INVALID;
83         }
84         return  ((params->dflag && (params->fflag || params->lflag)) ||
85                 (params->fflag && (params->dflag || params->lflag)) ||
86                 (params->lflag && (params->dflag || params->fflag)) ||
87                 (params->xflag) || !(strlen (params->imagename)));
88 }
89
90 static uint32_t check_get_hexval (char *token)
91 {
92         uint32_t hexval;
93
94         if (!sscanf (token, "%x", &hexval)) {
95                 printf ("Error:%s[%d] - Invalid hex data(%s)\n", fname,
96                         lineno, token);
97                 exit (EXIT_FAILURE);
98         }
99         return hexval;
100 }
101
102 /*
103  * Generates 8 bit checksum
104  */
105 static uint8_t kwbimage_checksum8 (void *start, uint32_t len, uint8_t csum)
106 {
107         register uint8_t sum = csum;
108         volatile uint8_t *p = (volatile uint8_t *)start;
109
110         /* check len and return zero checksum if invalid */
111         if (!len)
112                 return 0;
113
114         do {
115                 sum += *p;
116                 p++;
117         } while (--len);
118         return (sum);
119 }
120
121 /*
122  * Generates 32 bit checksum
123  */
124 static uint32_t kwbimage_checksum32 (uint32_t *start, uint32_t len, uint32_t csum)
125 {
126         register uint32_t sum = csum;
127         volatile uint32_t *p = start;
128
129         /* check len and return zero checksum if invalid */
130         if (!len)
131                 return 0;
132
133         if (len % sizeof(uint32_t)) {
134                 printf ("Error:%s[%d] - length is not in multiple of %zu\n",
135                         __FUNCTION__, len, sizeof(uint32_t));
136                 return 0;
137         }
138
139         do {
140                 sum += *p;
141                 p++;
142                 len -= sizeof(uint32_t);
143         } while (len > 0);
144         return (sum);
145 }
146
147 static void kwbimage_check_cfgdata (char *token, enum kwbimage_cmd cmdsw,
148                                         struct kwb_header *kwbhdr)
149 {
150         bhr_t *mhdr = &kwbhdr->kwb_hdr;
151         extbhr_t *exthdr = &kwbhdr->kwb_exthdr;
152         int i;
153
154         switch (cmdsw) {
155         case CMD_BOOT_FROM:
156                 i = get_table_entry_id (kwbimage_bootops,
157                                 "Kwbimage boot option", token);
158
159                 if (i < 0)
160                         goto INVL_DATA;
161
162                 mhdr->blockid = i;
163                 printf ("Preparing kirkwood boot image to boot "
164                         "from %s\n", token);
165                 break;
166         case CMD_NAND_ECC_MODE:
167                 i = get_table_entry_id (kwbimage_eccmodes,
168                         "NAND ecc mode", token);
169
170                 if (i < 0)
171                         goto INVL_DATA;
172
173                 mhdr->nandeccmode = i;
174                 printf ("Nand ECC mode = %s\n", token);
175                 break;
176         case CMD_NAND_PAGE_SIZE:
177                 mhdr->nandpagesize =
178                         (uint16_t) check_get_hexval (token);
179                 printf ("Nand page size = 0x%x\n", mhdr->nandpagesize);
180                 break;
181         case CMD_SATA_PIO_MODE:
182                 mhdr->satapiomode =
183                         (uint8_t) check_get_hexval (token);
184                 printf ("Sata PIO mode = 0x%x\n",
185                                 mhdr->satapiomode);
186                 break;
187         case CMD_DDR_INIT_DELAY:
188                 mhdr->ddrinitdelay =
189                         (uint16_t) check_get_hexval (token);
190                 printf ("DDR init delay = %d msec\n", mhdr->ddrinitdelay);
191                 break;
192         case CMD_DATA:
193                 exthdr->rcfg[datacmd_cnt].raddr =
194                         check_get_hexval (token);
195
196                 break;
197         case CMD_INVALID:
198                 goto INVL_DATA;
199         default:
200                 goto INVL_DATA;
201         }
202         return;
203
204 INVL_DATA:
205         printf ("Error:%s[%d] - Invalid data\n", fname, lineno);
206         exit (EXIT_FAILURE);
207 }
208
209 /*
210  * this function sets the kwbimage header by-
211  *      1. Abstracting input command line arguments data
212  *      2. parses the kwbimage configuration file and update extebded header data
213  *      3. calculates header, extended header and image checksums
214  */
215 static void kwdimage_set_ext_header (struct kwb_header *kwbhdr, char* name) {
216         bhr_t *mhdr = &kwbhdr->kwb_hdr;
217         extbhr_t *exthdr = &kwbhdr->kwb_exthdr;
218         FILE *fd = NULL;
219         int j;
220         char *line = NULL;
221         char * token, *saveptr1, *saveptr2;
222         size_t len = 0;
223         enum kwbimage_cmd cmd;
224
225         fname = name;
226         /* set dram register offset */
227         exthdr->dramregsoffs = (intptr_t)&exthdr->rcfg - (intptr_t)mhdr;
228
229         if ((fd = fopen (name, "r")) == 0) {
230                 printf ("Error:%s - Can't open\n", fname);
231                 exit (EXIT_FAILURE);
232         }
233
234         /* Simple kwimage.cfg file parser */
235         lineno=0;
236         while ((getline (&line, &len, fd)) > 0) {
237                 lineno++;
238                 token = strtok_r (line, "\r\n", &saveptr1);
239                 /* drop all lines with zero tokens (= empty lines) */
240                 if (token == NULL)
241                         continue;
242
243                 for (j = 0, cmd = CMD_INVALID, line = token; ; line = NULL) {
244                         token = strtok_r (line, " \t", &saveptr2);
245                         if (token == NULL)
246                         break;
247                         /* Drop all text starting with '#' as comments */
248                         if (token[0] == '#')
249                                 break;
250
251                         /* Process rest as valid config command line */
252                         switch (j) {
253                         case CFG_COMMAND:
254                                 cmd = get_table_entry_id (kwbimage_cmds,
255                                                 "Kwbimage command", token);
256
257                                 if (cmd == CMD_INVALID)
258                                         goto INVL_CMD;
259                                 break;
260
261                         case CFG_DATA0:
262                                 kwbimage_check_cfgdata (token, cmd, kwbhdr);
263                                 break;
264
265                         case CFG_DATA1:
266                                 if (cmd != CMD_DATA)
267                                         goto INVL_CMD;
268
269                                 exthdr->rcfg[datacmd_cnt].rdata =
270                                                 check_get_hexval (token);
271
272                                 if (datacmd_cnt > KWBIMAGE_MAX_CONFIG ) {
273                                         printf ("Error:%s[%d] - Found more "
274                                                 "than max(%zd) allowed "
275                                                 "data configurations\n",
276                                                 fname, lineno,
277                                                 KWBIMAGE_MAX_CONFIG);
278                                 exit (EXIT_FAILURE);
279                                 } else
280                                         datacmd_cnt++;
281                                 break;
282
283                         default:
284                                 goto INVL_CMD;
285                         }
286                         j++;
287                 }
288         }
289         if (line)
290                 free (line);
291
292         fclose (fd);
293         return;
294
295 /*
296  * Invalid Command error reporring
297  *
298  * command CMD_DATA needs three strings on a line
299  * whereas other commands need only two.
300  *
301  * if more than two/three (as per command type) are observed,
302  * then error will be reported
303  */
304 INVL_CMD:
305         printf ("Error:%s[%d] - Invalid command\n", fname, lineno);
306         exit (EXIT_FAILURE);
307 }
308
309 static void kwbimage_set_header (void *ptr, struct stat *sbuf, int ifd,
310                                 struct mkimage_params *params)
311 {
312         struct kwb_header *hdr = (struct kwb_header *)ptr;
313         bhr_t *mhdr = &hdr->kwb_hdr;
314         extbhr_t *exthdr = &hdr->kwb_exthdr;
315         uint32_t checksum;
316         int size;
317
318         /* Build and add image checksum header */
319         checksum = kwbimage_checksum32 ((uint32_t *)ptr, sbuf->st_size, 0);
320
321         size = write (ifd, &checksum, sizeof(uint32_t));
322         if (size != sizeof(uint32_t)) {
323                 printf ("Error:%s - Checksum write %d bytes %s\n",
324                         params->cmdname, size, params->imagefile);
325                 exit (EXIT_FAILURE);
326         }
327
328         sbuf->st_size += sizeof(uint32_t);
329
330         mhdr->blocksize = sbuf->st_size - sizeof(struct kwb_header);
331         mhdr->srcaddr = sizeof(struct kwb_header);
332         mhdr->destaddr= params->addr;
333         mhdr->execaddr =params->ep;
334         mhdr->ext = 0x1; /* header extension appended */
335
336         kwdimage_set_ext_header (hdr, params->imagename);
337         /* calculate checksums */
338         mhdr->checkSum = kwbimage_checksum8 ((void *)mhdr, sizeof(bhr_t), 0);
339         exthdr->checkSum = kwbimage_checksum8 ((void *)exthdr,
340                                                 sizeof(extbhr_t), 0);
341 }
342
343 static int kwbimage_verify_header (unsigned char *ptr, int image_size,
344                         struct mkimage_params *params)
345 {
346         struct kwb_header *hdr = (struct kwb_header *)ptr;
347         bhr_t *mhdr = &hdr->kwb_hdr;
348         extbhr_t *exthdr = &hdr->kwb_exthdr;
349         uint8_t calc_hdrcsum;
350         uint8_t calc_exthdrcsum;
351
352         calc_hdrcsum = kwbimage_checksum8 ((void *)mhdr,
353                         sizeof(bhr_t) - sizeof(uint8_t), 0);
354         if (calc_hdrcsum != mhdr->checkSum)
355                 return -FDT_ERR_BADSTRUCTURE;   /* mhdr csum not matched */
356
357         calc_exthdrcsum = kwbimage_checksum8 ((void *)exthdr,
358                         sizeof(extbhr_t) - sizeof(uint8_t), 0);
359         if (calc_hdrcsum != mhdr->checkSum)
360                 return -FDT_ERR_BADSTRUCTURE; /* exthdr csum not matched */
361
362         return 0;
363 }
364
365 static void kwbimage_print_header (const void *ptr)
366 {
367         struct kwb_header *hdr = (struct kwb_header *) ptr;
368         bhr_t *mhdr = &hdr->kwb_hdr;
369         char *name = get_table_entry_name (kwbimage_bootops,
370                                 "Kwbimage boot option",
371                                 (int) mhdr->blockid);
372
373         printf ("Image Type:   Kirkwood Boot from %s Image\n", name);
374         printf ("Data Size:    ");
375         genimg_print_size (mhdr->blocksize - sizeof(uint32_t));
376         printf ("Load Address: %08x\n", mhdr->destaddr);
377         printf ("Entry Point:  %08x\n", mhdr->execaddr);
378 }
379
380 static int kwbimage_check_image_types (uint8_t type)
381 {
382         if (type == IH_TYPE_KWBIMAGE)
383                 return EXIT_SUCCESS;
384         else
385                 return EXIT_FAILURE;
386 }
387
388 /*
389  * kwbimage type parameters definition
390  */
391 static struct image_type_params kwbimage_params = {
392         .name = "Kirkwood Boot Image support",
393         .header_size = sizeof(struct kwb_header),
394         .hdr = (void*)&kwbimage_header,
395         .check_image_type = kwbimage_check_image_types,
396         .verify_header = kwbimage_verify_header,
397         .print_header = kwbimage_print_header,
398         .set_header = kwbimage_set_header,
399         .check_params = kwbimage_check_params,
400 };
401
402 void init_kwb_image_type (void)
403 {
404         mkimage_register (&kwbimage_params);
405 }