| 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.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 |
#define TRX_MAGIC 0x30524448 /* "HDR0" */ |
|---|
| 27 |
#define TRX_VERSION 1 |
|---|
| 28 |
#define TRX_MAX_LEN 0x8A0000 |
|---|
| 29 |
#define TRX_NO_HEADER 1 /* Do not write TRX header */ |
|---|
| 30 |
|
|---|
| 31 |
//#if __BYTE_ORDER == __BIG_ENDIAN |
|---|
| 32 |
unsigned int bswap_32(unsigned int *values) |
|---|
| 33 |
{ |
|---|
| 34 |
unsigned char *p = (unsigned char *)values; |
|---|
| 35 |
unsigned char a; |
|---|
| 36 |
a = p[3]; |
|---|
| 37 |
p[3] = p[0]; |
|---|
| 38 |
p[0] = a; |
|---|
| 39 |
a = p[2]; |
|---|
| 40 |
p[2] = p[1]; |
|---|
| 41 |
p[1] = a; |
|---|
| 42 |
return *values; |
|---|
| 43 |
} |
|---|
| 44 |
|
|---|
| 45 |
#define STORE32_LE(X) bswap_32(X) |
|---|
| 46 |
|
|---|
| 47 |
//#elif __BYTE_ORDER == __LITTLE_ENDIAN |
|---|
| 48 |
//#define STORE32_LE(X) (X) |
|---|
| 49 |
//#else |
|---|
| 50 |
//#error unkown endianness! |
|---|
| 51 |
//#endif |
|---|
| 52 |
|
|---|
| 53 |
struct trx_header { |
|---|
| 54 |
unsigned int magic; /* "HDR0" */ |
|---|
| 55 |
unsigned int len; /* Length of file including header */ |
|---|
| 56 |
unsigned int crc32; /* 32-bit CRC from flag_version to end of file */ |
|---|
| 57 |
unsigned int flag_version; /* 0:15 flags, 16:31 version */ |
|---|
| 58 |
unsigned int offsets[3]; /* Offsets of partitions from start of header */ |
|---|
| 59 |
}; |
|---|
| 60 |
|
|---|
| 61 |
extern void fis_init(int argc, char *argv[], int force); |
|---|
| 62 |
|
|---|
| 63 |
void addPartition(char *name, unsigned int flashbase, unsigned int memaddr, |
|---|
| 64 |
unsigned int entryaddr, unsigned int partsize, |
|---|
| 65 |
unsigned int datasize) |
|---|
| 66 |
{ |
|---|
| 67 |
int index; |
|---|
| 68 |
struct fis_image_desc *img = (struct fis_image_desc *)fis_work_block; |
|---|
| 69 |
for (index = 0; index < fisdir_size / sizeof(*img); index++, img++) { |
|---|
| 70 |
if (img->name[0] == (unsigned char)0xFF) { |
|---|
| 71 |
break; |
|---|
| 72 |
} |
|---|
| 73 |
} |
|---|
| 74 |
strcpy(img->name, name); |
|---|
| 75 |
img->flash_base = flashbase; |
|---|
| 76 |
img->mem_base = memaddr; |
|---|
| 77 |
img->entry_point = entryaddr; // Hope it's been set |
|---|
| 78 |
img->size = partsize; |
|---|
| 79 |
img->data_length = datasize; |
|---|
| 80 |
} |
|---|
| 81 |
|
|---|
| 82 |
int fw_check_image_ddwrt(unsigned char *addr, unsigned long maxlen, |
|---|
| 83 |
int do_flash) |
|---|
| 84 |
{ |
|---|
| 85 |
struct trx_header *base = (struct trx_header *)addr; |
|---|
| 86 |
struct trx_header trx; |
|---|
| 87 |
memcpy(&trx, base, sizeof(trx)); |
|---|
| 88 |
trx.magic = STORE32_LE(&trx.magic); |
|---|
| 89 |
trx.len = STORE32_LE(&trx.len); |
|---|
| 90 |
trx.crc32 = STORE32_LE(&trx.crc32); |
|---|
| 91 |
if (trx.magic != TRX_MAGIC || trx.len < sizeof(struct trx_header)) { |
|---|
| 92 |
diag_printf("DD-WRT_FW: Bad trx header\n"); |
|---|
| 93 |
return -1; |
|---|
| 94 |
} |
|---|
| 95 |
//if (STORE32_LE(&trx.flag_version) & TRX_NO_HEADER) |
|---|
| 96 |
trx.len -= sizeof(struct trx_header); |
|---|
| 97 |
|
|---|
| 98 |
unsigned int crc; |
|---|
| 99 |
crc = |
|---|
| 100 |
cyg_crc32_accumulate(0xffffffff, (unsigned char *)&trx.flag_version, |
|---|
| 101 |
sizeof(struct trx_header) - 12); |
|---|
| 102 |
crc = |
|---|
| 103 |
cyg_crc32_accumulate(crc, addr + sizeof(struct trx_header), |
|---|
| 104 |
trx.len); |
|---|
| 105 |
if (crc == trx.crc32) { |
|---|
| 106 |
if (!do_flash) |
|---|
| 107 |
diag_printf("DD-WRT_FW: DD-WRT FW CRC Okay\n"); |
|---|
| 108 |
} else { |
|---|
| 109 |
diag_printf |
|---|
| 110 |
("DD-WRT_FW: DD-WRT FW CRC Failed (Calculated=0x%08X,Real=0x%08X\n", |
|---|
| 111 |
crc, trx.crc32); |
|---|
| 112 |
return -1; |
|---|
| 113 |
} |
|---|
| 114 |
if (do_flash) { |
|---|
| 115 |
char *arg[] = { "fis", "init" }; |
|---|
| 116 |
fis_init(2, arg, 1); |
|---|
| 117 |
void *err_addr; |
|---|
| 118 |
flash_read(fis_addr, fis_work_block, fisdir_size, |
|---|
| 119 |
(void **)&err_addr); |
|---|
| 120 |
struct fis_image_desc *img = NULL; |
|---|
| 121 |
int i, stat; |
|---|
| 122 |
img = fis_lookup("RedBoot", &i); |
|---|
| 123 |
unsigned int flash_addr = img->flash_base + img->size; |
|---|
| 124 |
diag_printf("DD-WRT_FW: flash base is 0x%08X\n", flash_addr); |
|---|
| 125 |
if ((stat = |
|---|
| 126 |
flash_erase((void *)flash_addr, trx.len, |
|---|
| 127 |
(void **)&err_addr)) != 0) { |
|---|
| 128 |
diag_printf("DD-WRT_FW: Can't erase region at %p: %s\n", |
|---|
| 129 |
err_addr, flash_errmsg(stat)); |
|---|
| 130 |
return -1; |
|---|
| 131 |
} |
|---|
| 132 |
if ((stat = |
|---|
| 133 |
flash_program((void *)flash_addr, |
|---|
| 134 |
(void *)(addr + sizeof(struct trx_header)), |
|---|
| 135 |
trx.len, (void **)&err_addr)) != 0) { |
|---|
| 136 |
diag_printf |
|---|
| 137 |
("DD-WRT_FW: Can't program region at %p: %s\n", |
|---|
| 138 |
err_addr, flash_errmsg(stat)); |
|---|
| 139 |
return -1; |
|---|
| 140 |
} |
|---|
| 141 |
addPartition("linux", flash_addr, 0x80041000, 0x80041000, |
|---|
| 142 |
trx.len, trx.len); |
|---|
| 143 |
fis_update_directory(); |
|---|
| 144 |
diag_printf("DD-WRT_FW: flashing done\n"); |
|---|
| 145 |
} |
|---|
| 146 |
return 0; |
|---|
| 147 |
} |
|---|