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

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

lates image and source changes

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 extern void addPartition(char *name, unsigned int flashbase,
46                          unsigned int memaddr, unsigned int entryaddr,
47                          unsigned int partsize, unsigned int datasize);
48
49 #define crc32 cyg_ether_crc32_accumulate
50
51 extern void fis_init(int argc, char *argv[], int force);
52
53 int fw_check_image_ubnt(unsigned char *addr, unsigned long maxlen, int do_flash)
54 {
55         header_t *header = (header_t *) addr;
56         fw_t fw;
57         int len = sizeof(header_t) - (2 * sizeof(u_int32_t));
58         unsigned int crc = crc32(0L, (unsigned char *)header, len);
59         signature_t *sig;
60         fw.size = maxlen;
61         if (htonl(crc) != header->crc) {
62                 diag_printf("UBNT_FW: header crc failed\n");
63                 return -1;
64         }
65         memcpy(fw.version, header->version, sizeof(fw.version));
66         if (do_flash)
67                 diag_printf("UBNT_FW: Firmware version: '%s'\n",
68                             header->version);
69         part_t *p;
70         p = (part_t *) (addr + sizeof(header_t));
71         int i = 0;
72         while (strncmp(p->magic, MAGIC_END, MAGIC_LENGTH) != 0) {
73                 if (do_flash) {
74                         diag_printf("Partition: %s [%u]\n", p->name,
75                                     ntohl(p->index));
76                         diag_printf("Partition size: 0x%X\n",
77                                     ntohl(p->part_size));
78                         diag_printf("Data size: %u\n", ntohl(p->data_size));
79                 }
80                 if ((strncmp(p->magic, MAGIC_PART, MAGIC_LENGTH) == 0)
81                     && (i < MAX_PARTS)) {
82                         fw_part_t *fwp = &fw.parts[i];
83
84                         fwp->header = p;
85                         fwp->data = (unsigned char *)p + sizeof(part_t);
86                         fwp->data_size = ntohl(p->data_size);
87                         fwp->signature =
88                             (part_crc_t *) (fwp->data + fwp->data_size);
89                         crc =
90                             htonl(crc32
91                                   (0L, (unsigned char *)p,
92                                    fwp->data_size + sizeof(part_t)));
93                         if (crc != fwp->signature->crc) {
94                                 diag_printf
95                                     ("UBNT_FW: Invalid '%s' CRC (claims: %u, but is %u)\n",
96                                      fwp->header->name, fwp->signature->crc,
97                                      crc);
98                                 return -1;
99                         }
100                         ++i;
101                 }
102
103                 p = (part_t *) ((unsigned char *)p + sizeof(part_t) +
104                                 ntohl(p->data_size) + sizeof(part_crc_t));
105
106                 /* check bounds */
107                 if (((unsigned char *)p - addr) >= maxlen) {
108                         return -3;
109                 }
110         }
111
112         fw.part_count = i;
113
114         sig = (signature_t *) p;
115         if (strncmp(sig->magic, MAGIC_END, MAGIC_LENGTH) != 0) {
116                 diag_printf("UBNT_FW: Bad firmware signature\n");
117                 return -4;
118         }
119
120         crc = htonl(crc32(0L, addr, (unsigned char *)sig - addr));
121         if (crc != sig->crc) {
122                 diag_printf
123                     ("UBNT_FW: Invalid signature CRC (claims: %u, but is %u)\n",
124                      sig->crc, crc);
125                 return -5;
126         }
127
128         if (do_flash) {
129                 char *arg[] = { "fis", "init" };
130                 fis_init(2, arg, 1);
131                 void *err_addr;
132                 flash_read(fis_addr, fis_work_block, fisdir_size,
133                            (void **)&err_addr);
134                 for (i = 0; i < fw.part_count; ++i) {
135                         fw_part_t *fwp = &fw.parts[i];
136                         /* do not flash bootloaders bigger than 64kb, since it makes no sense to step back */
137                         if (!strncmp(fwp->header->name, "RedBoot", 7)
138                             && ntohl(fwp->header->part_size) > 0x10000) {
139                                 diag_printf("ignore %s\n", fwp->header->name);
140                                 continue;
141                         }
142                         diag_printf("UBNT_FW: Flashing: %s\n",
143                                     fwp->header->name);
144                         int stat;
145
146                         unsigned int base = ntohl(fwp->header->baseaddr);
147                         /* convert flash mappings to fit to the current bootloader flash mapping which might be incompatible */
148                         if ((base & 0xbfc00000) == 0xbfc00000) {
149                                 base ^= 0xbfc00000;
150                         } else if ((base & 0xbe00000) == 0xbe00000) {
151                                 base ^= 0xbe00000;
152                         } else if ((base & 0xa800000) == 0xa800000) {
153                                 base ^= 0xa800000;
154                         }
155                         base |= CYGNUM_FLASH_BASE;
156                         if ((stat =
157                              flash_erase((void *)base,
158                                          ntohl(fwp->header->part_size),
159                                          (void **)&err_addr)) != 0) {
160                                 diag_printf
161                                     ("UBNT_FW: Can't erase region at %p: %s\n",
162                                      err_addr, flash_errmsg(stat));
163                                 return -1;
164                         }
165                         if ((stat =
166                              flash_program((void *)base,
167                                            (void *)fwp->data,
168                                            ntohl(fwp->data_size),
169                                            (void **)&err_addr)) != 0) {
170                                 diag_printf
171                                     ("UBNT_FW: Can't program region at %p: %s\n",
172                                      err_addr, flash_errmsg(stat));
173                                 return -1;
174                         }
175                         addPartition(fwp->header->name, base,
176                                      ntohl(fwp->header->memaddr),
177                                      ntohl(fwp->header->entryaddr),
178                                      ntohl(fwp->header->part_size),
179                                      ntohl(fwp->header->data_size));
180                 }
181                 addPartition("cfg",
182                              ((unsigned int)flash_end + 1) -
183                              (flash_block_size * 3), 0, 0, 0x10000, 0x10000);
184
185                 fis_update_directory();
186                 diag_printf("UBNT_FW: flashing done\n");
187         }
188
189         return 0;
190 }
Note: See TracBrowser for help on using the browser.