root/ar5315_microredboot/microredboot/ecos/packages/redboot/current/src/net/fwupgrade_wili.c

Revision 12385, 6.9 kB (checked in by BrainSlayer, 5 months ago)

lates image and source changes

Line 
1 /*
2 firmware upgrade code for DD-WRT webflash images
3 */
4
5 #include <redboot.h>
6 #include <cyg/io/flash.h>
7 #include <fis.h>
8 #include <flash_config.h>
9 #include "fwupgrade_wili.h"
10
11 /* some variables from flash.c */
12 extern void *flash_start, *flash_end;
13 extern int flash_block_size, flash_num_blocks;
14 #ifdef CYGOPT_REDBOOT_FIS
15 extern void *fis_work_block;
16 extern void *fis_addr;
17 extern int fisdir_size;         // Size of FIS directory.
18 #endif
19 //extern void _show_invalid_flash_address(CYG_ADDRESS flash_addr, int stat);
20 extern void fis_update_directory(void);
21
22 //#define TRACE diag_printf("DBG: %s:%d\n", __FUNCTION__, __LINE__)
23
24 #define TRACE
25
26 /*
27  * check if update file is valid
28  *  - magic signatures
29  *  - crc
30  *  - data size (must match partition sizes)
31  * setup miniroot environment
32  *  - copy libc & fwupdate to /var (new root)
33  *  - create /dev/ entries in miniroot
34  *  - use pivot_root to switch root, old root will be available at /oldroot
35  *  - restart fwupdate from miniroot (with -f switch)
36  * update flash memory (check if fwupdate is started from miniroot)
37  *  - write images to flash
38  *  - reboot
39  */
40
41 /* update file structure:
42  *
43  * header
44  * part1
45  * part2
46  * signature
47  *
48  * header:
49  * magic1 [4 bytes] GEOS
50  * version [128 bytes]
51  * reserved [128 bytes]
52  * crc [4 bytes] for [0..reserved] range
53  * crypto [4 bytes] for [0..crc] range
54  *
55  * part:
56  * magic2 [4 bytes] PART
57  * name [32 bytes] "kernel", "cramfs", "etc", "cfg", "RedBoot" (as in /proc/mtd)
58  * partition nr [4 bytes] 0, 1, 2... - will be appended to /dev/mtdblock
59  * flags1 [4 bytes] 0x0001 - image is compressed, 0x0000 - raw
60  * flags2 [4 bytes]
61  * length [4 bytes] should be less than partition size
62  * part_len [4bytes] partition size
63  * data [length bytes]
64  * crc [4 bytes] from part start till data field (incl.)
65  * crypto [4 bytes] from part start till crc field (incl.)
66  *
67  * signature:
68  * magic3 [4 bytes] END.
69  * crc [4 bytes] from the start of file till signature's magic3 field (including)
70  * crypto [4 bytes] from the start of file till signature's crc field (including)
71  */
72 /* fwupdate.bin size */
73 #define MAX_IMAGE_SIZE          0x7E0000        /* 4mb - 64k */
74
75 /* max size for single partition - typicaly this is cramfs size */
76 #define MAX_PART_SIZE           0x800000        /* 3mb - valid only for ar531x */
77
78 #define MAGIC_HEADER    "GEOS"
79 #define MAGIC_PART      "PART"
80 #define MAGIC_END       "END."
81
82 #define MAGIC_LENGTH    4
83
84 typedef unsigned int u_int32_t;
85
86 typedef struct header {
87         char magic[MAGIC_LENGTH];
88         char version[256];
89         u_int32_t crc;
90         u_int32_t pad;
91 } __attribute__((packed)) header_t;
92
93 typedef struct part {
94         char magic[MAGIC_LENGTH];
95         char name[32];
96         u_int32_t part_nr;
97         u_int32_t flags1;
98         u_int32_t flags2;
99         u_int32_t data_size;
100         u_int32_t part_size;
101 } __attribute__((packed)) part_t;
102
103 typedef struct part_crc {
104         u_int32_t crc;
105         u_int32_t pad;
106 } __attribute__((packed)) part_crc_t;
107
108 typedef struct signature {
109         char magic[MAGIC_LENGTH];
110         u_int32_t crc;
111         u_int32_t pad;
112 } __attribute__((packed)) signature_t;
113
114 #define MAX_PARTS 8
115
116 typedef struct fw_part {
117         part_t *header;
118         unsigned char *data;
119         u_int32_t data_size;
120         part_crc_t *signature;
121 } fw_part_t;
122
123 typedef struct fw {
124         u_int32_t size;
125         char version[256];
126         fw_part_t parts[MAX_PARTS];
127         int part_count;
128 } fw_t;
129
130 #define crc32 cyg_ether_crc32_accumulate
131
132 extern void fis_init(int argc, char *argv[], int force);
133
134 int fw_check_image_wili(unsigned char *addr, unsigned long maxlen, int do_flash)
135 {
136         header_t *header = (header_t *) addr;
137         fw_t fw;
138         int len = sizeof(header_t) - 2 * sizeof(u_int32_t);
139         unsigned int crc = crc32(0L, (unsigned char *)header, len);
140         signature_t *sig;
141         fw.size = maxlen;
142         if (strncmp(header->magic, MAGIC_HEADER, 4)) {
143                 return -1;
144         }
145         if (htonl(crc) != header->crc) {
146                 diag_printf("WILI_FW: header crc failed\n");
147                 return -1;
148         }
149         memcpy(fw.version, header->version, sizeof(fw.version));
150         if (do_flash)
151                 diag_printf("WILI_FW: Firmware version: '%s'\n",
152                             header->version);
153         part_t *p;
154         p = (part_t *) (addr + sizeof(header_t));
155         int i = 0;
156         while (strncmp(p->magic, MAGIC_END, MAGIC_LENGTH) != 0) {
157                 if (do_flash) {
158                         diag_printf("Partition: %s\n", p->name);
159                         diag_printf("Partition size: 0x%X\n",
160                                     ntohl(p->part_size));
161                         diag_printf("Data size: %u\n", ntohl(p->data_size));
162                 }
163                 if ((strncmp(p->magic, MAGIC_PART, MAGIC_LENGTH) == 0)
164                     && (i < MAX_PARTS)) {
165                         fw_part_t *fwp = &fw.parts[i];
166
167                         fwp->header = p;
168                         fwp->data = (unsigned char *)p + sizeof(part_t);
169                         fwp->data_size = ntohl(p->data_size);
170                         fwp->signature =
171                             (part_crc_t *) (fwp->data + fwp->data_size);
172                         crc =
173                             htonl(crc32
174                                   (0L, (unsigned char *)p,
175                                    fwp->data_size + sizeof(part_t)));
176                         if (crc != fwp->signature->crc) {
177                                 diag_printf
178                                     ("WILI_FW: Invalid '%s' CRC (claims: %u, but is %u)\n",
179                                      fwp->header->name, fwp->signature->crc,
180                                      crc);
181                                 return -1;
182                         }
183                         int index;
184                         struct fis_image_desc *img =
185                             fis_lookup(fwp->header->name, &index);
186                         if (!img) {
187                                 diag_printf
188                                     ("WILI_FW: cannot find partition %s, not flashable!\n");
189                                 return -1;
190                         }
191                         ++i;
192                 }
193
194                 p = (part_t *) ((unsigned char *)p + sizeof(part_t) +
195                                 ntohl(p->data_size) + sizeof(part_crc_t));
196
197                 /* check bounds */
198                 if (((unsigned char *)p - addr) >= maxlen) {
199                         return -3;
200                 }
201         }
202
203         fw.part_count = i;
204
205         sig = (signature_t *) p;
206         if (strncmp(sig->magic, MAGIC_END, MAGIC_LENGTH) != 0) {
207                 diag_printf("WILI_FW: Bad firmware signature\n");
208                 return -4;
209         }
210
211         crc = htonl(crc32(0L, addr, (unsigned char *)sig - addr));
212         if (crc != sig->crc) {
213                 diag_printf
214                     ("WILI_FW: Invalid signature CRC (claims: %u, but is %u)\n",
215                      sig->crc, crc);
216                 return -5;
217         }
218
219         if (do_flash) {
220                 char *arg[] = { "fis", "init" };
221                 fis_init(2, arg, 1);
222                 void *err_addr;
223                 flash_read(fis_addr, fis_work_block, fisdir_size,
224                            (void **)&err_addr);
225                 for (i = 0; i < fw.part_count; ++i) {
226                         fw_part_t *fwp = &fw.parts[i];
227                         if (!strncmp(fwp->header->name, "RedBoot", 7)
228                             && ntohl(fwp->header->part_size) > 0x10000) {
229                                 diag_printf("ignore %s\n", fwp->header->name);
230                                 continue;
231                         }
232                         diag_printf("WILI_FW: Flashing: %s\n",
233                                     fwp->header->name);
234                         int stat;
235                         int index;
236                         struct fis_image_desc *img =
237                             fis_lookup(fwp->header->name, &index);
238                         if (!img) {
239                                 diag_printf
240                                     ("WILI_FW: cannot find partition %s, not flashable. break\n");
241                                 return -1;
242                         }
243                         if ((stat =
244                              flash_erase((void *)img->flash_base,
245                                          ntohl(fwp->header->part_size),
246                                          (void **)&err_addr)) != 0) {
247                                 diag_printf
248                                     ("WILI_FW: Can't erase region at %p: %s\n",
249                                      err_addr, flash_errmsg(stat));
250                                 return -1;
251                         }
252                         if ((stat = flash_program((void *)img->flash_base,
253                                                   (void *)fwp->data,
254                                                   ntohl(fwp->data_size),
255                                                   (void **)&err_addr)) != 0) {
256                                 diag_printf
257                                     ("WILI_FW: Can't program region at %p: %s\n",
258                                      err_addr, flash_errmsg(stat));
259                                 return -1;
260                         }
261                         img->size = ntohl(fwp->header->part_size);
262                         img->data_length = ntohl(fwp->header->data_size);
263
264                 }
265                 fis_update_directory();
266                 diag_printf("WILI_FW: flashing done\n");
267         }
268
269         return 0;
270 }
Note: See TracBrowser for help on using the browser.