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

Revision 12368, 5.3 kB (checked in by BrainSlayer, 5 months ago)

tftp server added, supports wiligear, ubiquiti and dd-wrt webflash format

Line 
1 /*
2 firmware upgrade code for UBNT images
3 huge parts are taken from ubnt fwsplit utility
4
5 2009, Sebastian Gottschall
6 */
7
8 #include <redboot.h>
9 #include <cyg/io/flash.h>
10 #include <fis.h>
11 #include <flash_config.h>
12 #include "fwupgrade_ubnt.h"
13
14 /* some variables from flash.c */
15 extern void *flash_start, *flash_end;
16 extern int flash_block_size, flash_num_blocks;
17 #ifdef CYGOPT_REDBOOT_FIS
18 extern void *fis_work_block;
19 extern void *fis_addr;
20 extern int fisdir_size;         // Size of FIS directory.
21 #endif
22 //extern void _show_invalid_flash_address(CYG_ADDRESS flash_addr, int stat);
23 extern void fis_update_directory(void);
24
25 //#define TRACE diag_printf("DBG: %s:%d\n", __FUNCTION__, __LINE__)
26
27 #define TRACE
28
29 #define MAX_PARTS 8
30
31 typedef struct fw_part {
32         part_t *header;
33         unsigned char *data;
34         u_int32_t data_size;
35         part_crc_t *signature;
36 } fw_part_t;
37
38 typedef struct fw {
39         u_int32_t size;
40         char version[256];
41         fw_part_t parts[MAX_PARTS];
42         int part_count;
43 } fw_t;
44
45 #define crc32 cyg_ether_crc32_accumulate
46
47 extern void fis_init(int argc, char *argv[], int force);
48
49 int fw_check_image_ubnt(unsigned char *addr, unsigned long maxlen, int do_flash)
50 {
51         header_t *header = (header_t *) addr;
52         fw_t fw;
53         int len = sizeof(header_t) - (2 * sizeof(u_int32_t));
54         unsigned int crc = crc32(0L, (unsigned char *)header, len);
55         signature_t *sig;
56         fw.size = maxlen;
57         if (htonl(crc) != header->crc) {
58                 diag_printf("UBNT_FW: header crc failed\n");
59                 return -1;
60         }
61         memcpy(fw.version, header->version, sizeof(fw.version));
62         if (do_flash)
63                 diag_printf("UBNT_FW: Firmware version: '%s'\n",
64                             header->version);
65         part_t *p;
66         p = (part_t *) (addr + sizeof(header_t));
67         int i = 0;
68         while (strncmp(p->magic, MAGIC_END, MAGIC_LENGTH) != 0) {
69                 if (do_flash) {
70                         diag_printf("Partition: %s [%u]\n", p->name,
71                                     ntohl(p->index));
72                         diag_printf("Partition size: 0x%X\n",
73                                     ntohl(p->part_size));
74                         diag_printf("Data size: %u\n", ntohl(p->data_size));
75                 }
76                 if ((strncmp(p->magic, MAGIC_PART, MAGIC_LENGTH) == 0)
77                     && (i < MAX_PARTS)) {
78                         fw_part_t *fwp = &fw.parts[i];
79
80                         fwp->header = p;
81                         fwp->data = (unsigned char *)p + sizeof(part_t);
82                         fwp->data_size = ntohl(p->data_size);
83                         fwp->signature =
84                             (part_crc_t *) (fwp->data + fwp->data_size);
85                         crc =
86                             htonl(crc32
87                                   (0L, (unsigned char *)p,
88                                    fwp->data_size + sizeof(part_t)));
89                         if (crc != fwp->signature->crc) {
90                                 diag_printf
91                                     ("UBNT_FW: Invalid '%s' CRC (claims: %u, but is %u)\n",
92                                      fwp->header->name, fwp->signature->crc,
93                                      crc);
94                                 return -1;
95                         }
96                         ++i;
97                 }
98
99                 p = (part_t *) ((unsigned char *)p + sizeof(part_t) +
100                                 ntohl(p->data_size) + sizeof(part_crc_t));
101
102                 /* check bounds */
103                 if (((unsigned char *)p - addr) >= maxlen) {
104                         return -3;
105                 }
106         }
107
108         fw.part_count = i;
109
110         sig = (signature_t *) p;
111         if (strncmp(sig->magic, MAGIC_END, MAGIC_LENGTH) != 0) {
112                 diag_printf("UBNT_FW: Bad firmware signature\n");
113                 return -4;
114         }
115
116         crc = htonl(crc32(0L, addr, (unsigned char *)sig - addr));
117         if (crc != sig->crc) {
118                 diag_printf
119                     ("UBNT_FW: Invalid signature CRC (claims: %u, but is %u)\n",
120                      sig->crc, crc);
121                 return -5;
122         }
123
124         if (do_flash) {
125                 char *arg[] = { "fis", "init" };
126                 fis_init(2, arg, 1);
127                 void *err_addr;
128                 flash_read(fis_addr, fis_work_block, fisdir_size,
129                            (void **)&err_addr);
130                 struct fis_image_desc *img = fis_lookup("RedBoot", &i);
131                 if (i != 0) {
132                         diag_printf
133                             ("UBNT_FW: RedBoot partition is not the first partition\n");
134                         return -1;
135                 }
136                 for (i = 0; i < fw.part_count; ++i) {
137                         fw_part_t *fwp = &fw.parts[i];
138                         /* do not flash bootloaders bigger than 64kb, since it makes no sense to step back */
139                         if (!strncmp(fwp->header->name, "RedBoot", 7)
140                             && ntohl(fwp->header->part_size) > 0x10000) {
141                                 diag_printf("ignore %s\n", fwp->header->name);
142                                 continue;
143                         }
144                         diag_printf("UBNT_FW: Flashing: %s\n",
145                                     fwp->header->name);
146                         int stat;
147
148                         unsigned int base = ntohl(fwp->header->baseaddr);
149                         /* convert flash mappings to fit to the current bootloader flash mapping which might be incompatible */
150                         if ((base & 0xbfc00000) == 0xbfc00000) {
151                                 base ^= 0xbfc00000;
152                         } else if ((base & 0xbe00000) == 0xbe00000) {
153                                 base ^= 0xbe00000;
154                         } else if ((base & 0xa800000) == 0xa800000) {
155                                 base ^= 0xa800000;
156                         }
157                         base |= CYGNUM_FLASH_BASE;
158                         if ((stat =
159                              flash_erase((void *)base,
160                                          ntohl(fwp->header->part_size),
161                                          (void **)&err_addr)) != 0) {
162                                 diag_printf
163                                     ("UBNT_FW: Can't erase region at %p: %s\n",
164                                      err_addr, flash_errmsg(stat));
165                                 return -1;
166                         }
167                         if ((stat =
168                              flash_program((void *)base,
169                                            (void *)fwp->data,
170                                            ntohl(fwp->data_size),
171                                            (void **)&err_addr)) != 0) {
172                                 diag_printf
173                                     ("UBNT_FW: Can't program region at %p: %s\n",
174                                      err_addr, flash_errmsg(stat));
175                                 return -1;
176                         }
177                         int index;
178                         img = (struct fis_image_desc *)fis_work_block;
179                         for (index = 0;
180                              index < fisdir_size / sizeof(*img);
181                              index++, img++) {
182                                 if (img->name[0] == (unsigned char)0xFF) {
183                                         break;
184                                 }
185                         }
186                         strcpy(img->name, fwp->header->name);
187                         img->flash_base = base;
188                         img->mem_base = ntohl(fwp->header->memaddr);
189                         img->entry_point = ntohl(fwp->header->entryaddr);       // Hope it's been set
190                         img->size = ntohl(fwp->header->part_size);
191                         img->data_length = ntohl(fwp->header->data_size);
192
193                 }
194                 fis_update_directory();
195                 diag_printf("UBNT_FW: flashing done\n");
196         }
197
198         return 0;
199 }
Note: See TracBrowser for help on using the browser.