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

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

merge partition code

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                 struct fis_image_desc *img = fis_lookup("RedBoot", &i);
135                 if (i != 0) {
136                         diag_printf
137                             ("UBNT_FW: RedBoot partition is not the first partition\n");
138                         return -1;
139                 }
140                 for (i = 0; i < fw.part_count; ++i) {
141                         fw_part_t *fwp = &fw.parts[i];
142                         /* do not flash bootloaders bigger than 64kb, since it makes no sense to step back */
143                         if (!strncmp(fwp->header->name, "RedBoot", 7)
144                             && ntohl(fwp->header->part_size) > 0x10000) {
145                                 diag_printf("ignore %s\n", fwp->header->name);
146                                 continue;
147                         }
148                         diag_printf("UBNT_FW: Flashing: %s\n",
149                                     fwp->header->name);
150                         int stat;
151
152                         unsigned int base = ntohl(fwp->header->baseaddr);
153                         /* convert flash mappings to fit to the current bootloader flash mapping which might be incompatible */
154                         if ((base & 0xbfc00000) == 0xbfc00000) {
155                                 base ^= 0xbfc00000;
156                         } else if ((base & 0xbe00000) == 0xbe00000) {
157                                 base ^= 0xbe00000;
158                         } else if ((base & 0xa800000) == 0xa800000) {
159                                 base ^= 0xa800000;
160                         }
161                         base |= CYGNUM_FLASH_BASE;
162                         if ((stat =
163                              flash_erase((void *)base,
164                                          ntohl(fwp->header->part_size),
165                                          (void **)&err_addr)) != 0) {
166                                 diag_printf
167                                     ("UBNT_FW: Can't erase region at %p: %s\n",
168                                      err_addr, flash_errmsg(stat));
169                                 return -1;
170                         }
171                         if ((stat =
172                              flash_program((void *)base,
173                                            (void *)fwp->data,
174                                            ntohl(fwp->data_size),
175                                            (void **)&err_addr)) != 0) {
176                                 diag_printf
177                                     ("UBNT_FW: Can't program region at %p: %s\n",
178                                      err_addr, flash_errmsg(stat));
179                                 return -1;
180                         }
181                         addPartition(fwp->header->name, base,
182                                      ntohl(fwp->header->memaddr),
183                                      ntohl(fwp->header->entryaddr),
184                                      ntohl(fwp->header->part_size),
185                                      ntohl(fwp->header->data_size));
186                 }
187                 addPartition("cfg", (flash_end + 1) - (flash_block_size * 3), 0,
188                              0, 0x10000, 0x10000);
189
190                 fis_update_directory();
191                 diag_printf("UBNT_FW: flashing done\n");
192         }
193
194         return 0;
195 }
Note: See TracBrowser for help on using the browser.