@ -53,6 +53,8 @@
# define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
# define MAX_PARTITIONS 32
/** An image partition table entry */
struct image_partition_entry {
const char * name ;
@ -67,12 +69,15 @@ struct flash_partition_entry {
uint32_t size ;
} ;
/** Firmware layout description */
struct device_info {
const char * id ;
const char * vendor ;
const char * support_list ;
char support_trail ;
const struct flash_partition_entry * partitions ;
void * ( * generate_sysupgrade_image ) ( const struct flash_partition_entry * flash_parts , const struct image_partition_entry * image_parts , size_t * len ) ;
const struct flash_partition_entry partitions [ MAX_PARTITIONS + 1 ] ;
const char * first_sysupgrade_partition ;
const char * last_sysupgrade_partition ;
} ;
/** The content of the soft-version structure */
@ -109,20 +114,61 @@ static const uint8_t md5_salt[16] = {
} ;
/** Vendor information for CPE210/220/510/520 */
static const char cpe510_vendor [ ] = " CPE510(TP-LINK|UN|N300-5):1.0 \r \n " ;
/** Firmware layout table */
static struct device_info boards [ ] = {
/** Firmware layout for the CPE210/220 */
{
. id = " CPE210 " ,
. vendor = " CPE510(TP-LINK|UN|N300-5):1.0 \r \n " ,
. support_list =
" SupportList: \r \n "
" CPE210(TP-LINK|UN|N300-2):1.0 \r \n "
" CPE210(TP-LINK|UN|N300-2):1.1 \r \n "
" CPE210(TP-LINK|US|N300-2):1.1 \r \n "
" CPE210(TP-LINK|EU|N300-2):1.1 \r \n "
" CPE220(TP-LINK|UN|N300-2):1.1 \r \n "
" CPE220(TP-LINK|US|N300-2):1.1 \r \n "
" CPE220(TP-LINK|EU|N300-2):1.1 \r \n " ,
. support_trail = ' \xff ' ,
. partitions = {
{ " fs-uboot " , 0x00000 , 0x20000 } ,
{ " partition-table " , 0x20000 , 0x02000 } ,
{ " default-mac " , 0x30000 , 0x00020 } ,
{ " product-info " , 0x31100 , 0x00100 } ,
{ " signature " , 0x32000 , 0x00400 } ,
{ " os-image " , 0x40000 , 0x170000 } ,
{ " soft-version " , 0x1b0000 , 0x00100 } ,
{ " support-list " , 0x1b1000 , 0x00400 } ,
{ " file-system " , 0x1c0000 , 0x600000 } ,
{ " user-config " , 0x7c0000 , 0x10000 } ,
{ " default-config " , 0x7d0000 , 0x10000 } ,
{ " log " , 0x7e0000 , 0x10000 } ,
{ " radio " , 0x7f0000 , 0x10000 } ,
{ NULL , 0 , 0 }
} ,
/** Vendor information for C2600 */
static const char c2600_vendor [ ] = " " ;
. first_sysupgrade_partition = " os-image " ,
. last_sysupgrade_partition = " file-system " ,
} ,
/** Vendor information for EAP120 */
static const char eap120_vendor [ ] = " EAP120(TP-LINK|UN|N300-2):1.0 \r \n " ;
/** Firmware layout for the CPE510/520 */
{
. id = " CPE510 " ,
. vendor = " CPE510(TP-LINK|UN|N300-5):1.0 \r \n " ,
. support_list =
" SupportList: \r \n "
" CPE510(TP-LINK|UN|N300-5):1.0 \r \n "
" CPE510(TP-LINK|UN|N300-5):1.1 \r \n "
" CPE510(TP-LINK|UN|N300-5):1.1 \r \n "
" CPE510(TP-LINK|US|N300-5):1.1 \r \n "
" CPE510(TP-LINK|EU|N300-5):1.1 \r \n "
" CPE520(TP-LINK|UN|N300-5):1.1 \r \n "
" CPE520(TP-LINK|US|N300-5):1.1 \r \n "
" CPE520(TP-LINK|EU|N300-5):1.1 \r \n " ,
. support_trail = ' \xff ' ,
/**
The flash partition table for CPE210 / 220 / 510 / 520 ;
it is the same as the one used by the stock images .
*/
static const struct flash_partition_entry cpe510_partitions [ ] = {
. partitions = {
{ " fs-uboot " , 0x00000 , 0x20000 } ,
{ " partition-table " , 0x20000 , 0x02000 } ,
{ " default-mac " , 0x30000 , 0x00020 } ,
@ -137,13 +183,22 @@ static const struct flash_partition_entry cpe510_partitions[] = {
{ " log " , 0x7e0000 , 0x10000 } ,
{ " radio " , 0x7f0000 , 0x10000 } ,
{ NULL , 0 , 0 }
} ;
} ,
/**
The flash partition table for C2600 ;
it is the same as the one used by the stock images .
*/
static const struct flash_partition_entry c2600_partitions [ ] = {
. first_sysupgrade_partition = " os-image " ,
. last_sysupgrade_partition = " file-system " ,
} ,
/** Firmware layout for the C2600 */
{
. id = " C2600 " ,
. vendor = " " ,
. support_list =
" SupportList: \r \n "
" {product_name:Archer C2600,product_ver:1.0.0,special_id:00000000} \r \n " ,
. support_trail = ' \x00 ' ,
. partitions = {
{ " SBL1 " , 0x00000 , 0x20000 } ,
{ " MIBIB " , 0x20000 , 0x20000 } ,
{ " SBL2 " , 0x40000 , 0x20000 } ,
@ -170,9 +225,24 @@ static const struct flash_partition_entry c2600_partitions[] = {
{ " usb-config " , 0x1fd0000 , 0x10000 } ,
{ " log " , 0x1fe0000 , 0x20000 } ,
{ NULL , 0 , 0 }
} ;
} ,
static const struct flash_partition_entry c5_partitions [ ] = {
. first_sysupgrade_partition = " os-image " ,
. last_sysupgrade_partition = " file-system "
} ,
/** Firmware layout for the C9 */
{
. id = " ARCHERC9 " ,
. vendor = " " ,
. support_list =
" SupportList: \n "
" {product_name:ArcherC9, "
" product_ver:1.0.0, "
" special_id:00000000} \n " ,
. support_trail = ' \x00 ' ,
. partitions = {
{ " fs-uboot " , 0x00000 , 0x40000 } ,
{ " os-image " , 0x40000 , 0x200000 } ,
{ " file-system " , 0x240000 , 0xc00000 } ,
@ -189,12 +259,22 @@ static const struct flash_partition_entry c5_partitions[] = {
{ " radio_bk " , 0xfe0000 , 0x10000 } ,
{ " radio " , 0xff0000 , 0x10000 } ,
{ NULL , 0 , 0 }
} ;
} ,
/** The flash partition table for EAP120;
it is the same as the one used by the stock images .
*/
static const struct flash_partition_entry eap120_partitions [ ] = {
. first_sysupgrade_partition = " os-image " ,
. last_sysupgrade_partition = " file-system "
} ,
/** Firmware layout for the EAP120 */
{
. id = " EAP120 " ,
. vendor = " EAP120(TP-LINK|UN|N300-2):1.0 \r \n " ,
. support_list =
" SupportList: \r \n "
" EAP120(TP-LINK|UN|N300-2):1.0 \r \n " ,
. support_trail = ' \xff ' ,
. partitions = {
{ " fs-uboot " , 0x00000 , 0x20000 } ,
{ " partition-table " , 0x20000 , 0x02000 } ,
{ " default-mac " , 0x30000 , 0x00020 } ,
@ -208,56 +288,14 @@ static const struct flash_partition_entry eap120_partitions[] = {
{ " log " , 0x7e0000 , 0x10000 } ,
{ " radio " , 0x7f0000 , 0x10000 } ,
{ NULL , 0 , 0 }
} ;
/**
The support list for CPE210 / 220
*/
static const char cpe210_support_list [ ] =
" SupportList: \r \n "
" CPE210(TP-LINK|UN|N300-2):1.0 \r \n "
" CPE210(TP-LINK|UN|N300-2):1.1 \r \n "
" CPE210(TP-LINK|US|N300-2):1.1 \r \n "
" CPE210(TP-LINK|EU|N300-2):1.1 \r \n "
" CPE220(TP-LINK|UN|N300-2):1.1 \r \n "
" CPE220(TP-LINK|US|N300-2):1.1 \r \n "
" CPE220(TP-LINK|EU|N300-2):1.1 \r \n "
;
} ,
/**
The support list for CPE210 / 220 / 510 / 520
*/
static const char cpe510_support_list [ ] =
" SupportList: \r \n "
" CPE510(TP-LINK|UN|N300-5):1.0 \r \n "
" CPE510(TP-LINK|UN|N300-5):1.1 \r \n "
" CPE510(TP-LINK|UN|N300-5):1.1 \r \n "
" CPE510(TP-LINK|US|N300-5):1.1 \r \n "
" CPE510(TP-LINK|EU|N300-5):1.1 \r \n "
" CPE520(TP-LINK|UN|N300-5):1.1 \r \n "
" CPE520(TP-LINK|US|N300-5):1.1 \r \n "
" CPE520(TP-LINK|EU|N300-5):1.1 \r \n "
;
. first_sysupgrade_partition = " os-image " ,
. last_sysupgrade_partition = " file-system "
} ,
/**
The support list for C2600
*/
static const char c2600_support_list [ ] =
" SupportList: \r \n "
" {product_name:Archer C2600,product_ver:1.0.0,special_id:00000000} \r \n " ;
static const char c9_support_list [ ] =
" SupportList: \n "
" {product_name:ArcherC9, "
" product_ver:1.0.0, "
" special_id:00000000} \n " ;
/**
The support list for EAP120
*/
static const char eap120_support_list [ ] =
" SupportList: \r \n "
" EAP120(TP-LINK|UN|N300-2):1.0 \r \n " ;
{ }
} ;
# define error(_ret, _errno, _str, ...) \
do { \
@ -358,7 +396,7 @@ static struct image_partition_entry make_soft_version(uint32_t rev) {
}
/** Generates the support-list partition */
static struct image_partition_entry make_support_list ( struct device_info * info ) {
static struct image_partition_entry make_support_list ( const struct device_info * info ) {
size_t len = strlen ( info - > support_list ) ;
struct image_partition_entry entry = alloc_image_partition ( " support-list " , len + 9 ) ;
@ -431,12 +469,22 @@ static struct image_partition_entry read_file(const char *part_name, const char
I think partition - table must be the first partition in the firmware image .
*/
static void put_partitions ( uint8_t * buffer , const struct image_partition_entry * parts ) {
size_t i ;
static void put_partitions ( uint8_t * buffer , const struct flash_partition_entry * flash_parts , const struct image_partition_entry * parts ) {
size_t i , j ;
char * image_pt = ( char * ) buffer , * end = image_pt + 0x800 ;
size_t base = 0x800 ;
for ( i = 0 ; parts [ i ] . name ; i + + ) {
for ( j = 0 ; flash_parts [ j ] . name ; j + + ) {
if ( ! strcmp ( flash_parts [ j ] . name , parts [ i ] . name ) ) {
if ( parts [ i ] . size > flash_parts [ j ] . size )
error ( 1 , 0 , " %s partition too big (more than %u bytes) " , flash_parts [ j ] . name , ( unsigned ) flash_parts [ j ] . size ) ;
break ;
}
}
assert ( flash_parts [ j ] . name ) ;
memcpy ( buffer + base , parts [ i ] . data , parts [ i ] . size ) ;
size_t len = end - image_pt ;
@ -477,7 +525,7 @@ static void put_md5(uint8_t *md5, uint8_t *buffer, unsigned int len) {
1014 - 1813 Image partition table ( 2048 bytes , padded with 0xff )
1814 - xxxx Firmware partitions
*/
static void * generate_factory_image ( const char * vendor , const struct image_partition_entry * parts , size_t * len ) {
static void * generate_factory_image ( const struct device_info * info , const struct image_partition_entry * parts , size_t * len ) {
* len = 0x1814 ;
size_t i ;
@ -491,13 +539,13 @@ static void * generate_factory_image(const char *vendor, const struct image_part
memset ( image , 0xff , * len ) ;
put32 ( image , * len ) ;
if ( vendor ) {
size_t vendor_len = strlen ( vendor ) ;
if ( info - > vendor ) {
size_t vendor_len = strlen ( info - > vendor ) ;
put32 ( image + 0x14 , vendor_len ) ;
memcpy ( image + 0x18 , vendor , vendor_len ) ;
memcpy ( image + 0x18 , info - > vendor , vendor_len ) ;
}
put_partitions ( image + 0x1014 , parts ) ;
put_partitions ( image + 0x1014 , info - > partitions , parts ) ;
put_md5 ( image + 0x04 , image + 0x14 , * len - 0x14 ) ;
return image ;
@ -510,67 +558,39 @@ static void * generate_factory_image(const char *vendor, const struct image_part
should be generalized when TP - LINK starts building its safeloader into hardware with
different flash layouts .
*/
static void * generate_sysupgrade_image ( const struct flash_partition_entry * flash_parts , const struct image_partition_entry * image_parts , size_t * len ) {
const struct flash_partition_entry * flash_os_image = & flash_parts [ 5 ] ;
const struct flash_partition_entry * flash_soft_version = & flash_parts [ 6 ] ;
const struct flash_partition_entry * flash_support_list = & flash_parts [ 7 ] ;
const struct flash_partition_entry * flash_file_system = & flash_parts [ 8 ] ;
const struct image_partition_entry * image_os_image = & image_parts [ 3 ] ;
const struct image_partition_entry * image_soft_version = & image_parts [ 1 ] ;
const struct image_partition_entry * image_support_list = & image_parts [ 2 ] ;
const struct image_partition_entry * image_file_system = & image_parts [ 4 ] ;
assert ( strcmp ( flash_os_image - > name , " os-image " ) = = 0 ) ;
assert ( strcmp ( flash_soft_version - > name , " soft-version " ) = = 0 ) ;
assert ( strcmp ( flash_support_list - > name , " support-list " ) = = 0 ) ;
assert ( strcmp ( flash_file_system - > name , " file-system " ) = = 0 ) ;
assert ( strcmp ( image_os_image - > name , " os-image " ) = = 0 ) ;
assert ( strcmp ( image_soft_version - > name , " soft-version " ) = = 0 ) ;
assert ( strcmp ( image_support_list - > name , " support-list " ) = = 0 ) ;
assert ( strcmp ( image_file_system - > name , " file-system " ) = = 0 ) ;
if ( image_os_image - > size > flash_os_image - > size )
error ( 1 , 0 , " kernel image too big (more than %u bytes) " , ( unsigned ) flash_os_image - > size ) ;
if ( image_file_system - > size > flash_file_system - > size )
error ( 1 , 0 , " rootfs image too big (more than %u bytes) " , ( unsigned ) flash_file_system - > size ) ;
* len = flash_file_system - > base - flash_os_image - > base + image_file_system - > size ;
uint8_t * image = malloc ( * len ) ;
if ( ! image )
error ( 1 , errno , " malloc " ) ;
memset ( image , 0xff , * len ) ;
memcpy ( image , image_os_image - > data , image_os_image - > size ) ;
memcpy ( image + flash_soft_version - > base - flash_os_image - > base , image_soft_version - > data , image_soft_version - > size ) ;
memcpy ( image + flash_support_list - > base - flash_os_image - > base , image_support_list - > data , image_support_list - > size ) ;
memcpy ( image + flash_file_system - > base - flash_os_image - > base , image_file_system - > data , image_file_system - > size ) ;
return image ;
}
static void * generate_sysupgrade_image_c2600 ( const struct flash_partition_entry * flash_parts , const struct image_partition_entry * image_parts , size_t * len ) {
const struct flash_partition_entry * flash_os_image = & flash_parts [ 11 ] ;
const struct flash_partition_entry * flash_file_system = & flash_parts [ 12 ] ;
const struct image_partition_entry * image_os_image = & image_parts [ 3 ] ;
const struct image_partition_entry * image_file_system = & image_parts [ 4 ] ;
static void * generate_sysupgrade_image ( const struct device_info * info , const struct image_partition_entry * image_parts , size_t * len ) {
size_t i , j ;
size_t flash_first_partition_index = 0 ;
size_t flash_last_partition_index = 0 ;
const struct flash_partition_entry * flash_first_partition = NULL ;
const struct flash_partition_entry * flash_last_partition = NULL ;
const struct image_partition_entry * image_last_partition = NULL ;
/** Find first and last partitions */
for ( i = 0 ; info - > partitions [ i ] . name ; i + + ) {
if ( ! strcmp ( info - > partitions [ i ] . name , info - > first_sysupgrade_partition ) ) {
flash_first_partition = & info - > partitions [ i ] ;
flash_first_partition_index = i ;
} else if ( ! strcmp ( info - > partitions [ i ] . name , info - > last_sysupgrade_partition ) ) {
flash_last_partition = & info - > partitions [ i ] ;
flash_last_partition_index = i ;
}
}
assert ( strcmp ( flash_os_image - > name , " os-image " ) = = 0 ) ;
assert ( strcmp ( flash_file_system - > name , " file-system " ) = = 0 ) ;
assert ( flash_first_partition & & flash_last_partition ) ;
assert ( flash_first_partition_index < flash_last_partition_index ) ;
assert ( strcmp ( image_os_image - > name , " os-image " ) = = 0 ) ;
assert ( strcmp ( image_file_system - > name , " file-system " ) = = 0 ) ;
/** Find last partition from image to calculate needed size */
for ( i = 0 ; image_parts [ i ] . name ; i + + ) {
if ( ! strcmp ( image_parts [ i ] . name , info - > last_sysupgrade_partition ) ) {
image_last_partition = & image_parts [ i ] ;
break ;
}
}
if ( image_os_image - > size > flash_os_image - > size )
error ( 1 , 0 , " kernel image too big (more than %u bytes) " , ( unsigned ) flash_os_image - > size ) ;
if ( image_file_system - > size > flash_file_system - > size )
error ( 1 , 0 , " rootfs image too big (more than %u bytes) " , ( unsigned ) flash_file_system - > size ) ;
assert ( image_last_partition ) ;
* len = flash_file_system - > base - flash_os_image - > base + image_file_system - > size ;
* len = flash_last_partition - > base - flash_first_partition - > base + image_last_partition - > size ;
uint8_t * image = malloc ( * len ) ;
if ( ! image )
@ -578,89 +598,30 @@ static void * generate_sysupgrade_image_c2600(const struct flash_partition_entry
memset ( image , 0xff , * len ) ;
memcpy ( image , image_os_image - > data , image_os_image - > size ) ;
memcpy ( image + flash_file_system - > base - flash_os_image - > base , image_file_system - > data , image_file_system - > size ) ;
return image ;
}
static void * generate_sysupgrade_image_eap120 ( const struct flash_partition_entry * flash_parts , const struct image_partition_entry * image_parts , size_t * len )
{
const struct flash_partition_entry * flash_os_image = & flash_parts [ 6 ] ;
const struct flash_partition_entry * flash_file_system = & flash_parts [ 7 ] ;
const struct image_partition_entry * image_os_image = & image_parts [ 3 ] ;
const struct image_partition_entry * image_file_system = & image_parts [ 4 ] ;
assert ( strcmp ( flash_os_image - > name , " os-image " ) = = 0 ) ;
assert ( strcmp ( flash_file_system - > name , " file-system " ) = = 0 ) ;
assert ( strcmp ( image_os_image - > name , " os-image " ) = = 0 ) ;
assert ( strcmp ( image_file_system - > name , " file-system " ) = = 0 ) ;
if ( image_os_image - > size > flash_os_image - > size )
error ( 1 , 0 , " kernel image too big (more than %u bytes) " , ( unsigned ) flash_os_image - > size ) ;
if ( image_file_system - > size > flash_file_system - > size )
error ( 1 , 0 , " rootfs image too big (more than %u bytes) " , ( unsigned ) flash_file_system - > size ) ;
* len = flash_file_system - > base - flash_os_image - > base + image_file_system - > size ;
uint8_t * image = malloc ( * len ) ;
if ( ! image )
error ( 1 , errno , " malloc " ) ;
for ( i = flash_first_partition_index ; i < = flash_last_partition_index ; i + + ) {
for ( j = 0 ; image_parts [ j ] . name ; j + + ) {
if ( ! strcmp ( info - > partitions [ i ] . name , image_parts [ j ] . name ) ) {
if ( image_parts [ j ] . size > info - > partitions [ i ] . size )
error ( 1 , 0 , " %s partition too big (more than %u bytes) " , info - > partitions [ i ] . name , ( unsigned ) info - > partitions [ i ] . size ) ;
memcpy ( image + info - > partitions [ i ] . base - flash_first_partition - > base , image_parts [ j ] . data , image_parts [ j ] . size ) ;
break ;
}
memset ( image , 0xff , * len ) ;
memcpy ( image , image_os_image - > data , image_os_image - > size ) ;
memcpy ( image + flash_file_system - > base - flash_os_image - > base , image_file_system - > data , image_file_system - > size ) ;
assert ( image_parts [ j ] . name ) ;
}
}
return image ;
}
struct device_info cpe210_info = {
. vendor = cpe510_vendor ,
. support_list = cpe210_support_list ,
. support_trail = ' \xff ' ,
. partitions = cpe510_partitions ,
. generate_sysupgrade_image = & generate_sysupgrade_image ,
} ;
struct device_info cpe510_info = {
. vendor = cpe510_vendor ,
. support_list = cpe510_support_list ,
. support_trail = ' \xff ' ,
. partitions = cpe510_partitions ,
. generate_sysupgrade_image = & generate_sysupgrade_image ,
} ;
struct device_info c2600_info = {
. vendor = c2600_vendor ,
. support_list = c2600_support_list ,
. support_trail = ' \x00 ' ,
. partitions = c2600_partitions ,
. generate_sysupgrade_image = & generate_sysupgrade_image_c2600 ,
} ;
struct device_info e9_info = {
. vendor = c2600_vendor ,
. support_list = c9_support_list ,
. support_trail = ' \x00 ' ,
. partitions = c5_partitions ,
} ;
struct device_info eap120_info = {
. vendor = eap120_vendor ,
. support_list = eap120_support_list ,
. support_trail = ' \xff ' ,
. partitions = eap120_partitions ,
. generate_sysupgrade_image = & generate_sysupgrade_image_eap120 ,
} ;
/** Generates an image according to a given layout and writes it to a file */
static void build_image ( const char * output ,
const char * kernel_image ,
const char * rootfs_image ,
uint32_t rev ,
bool add_jffs2_eof ,
bool sysupgrade ,
struct device_info * info ) {
const struct device_info * info ) {
struct image_partition_entry parts [ 6 ] = { } ;
parts [ 0 ] = make_partition_table ( info - > partitions ) ;
@ -672,9 +633,9 @@ static void build_image(const char *output,
size_t len ;
void * image ;
if ( sysupgrade )
image = info - > generate_sysupgrade_image ( info - > partitions , parts , & len ) ;
image = generate_sysupgrade_image ( info , parts , & len ) ;
else
image = generate_factory_image ( info - > vendor , parts , & len ) ;
image = generate_factory_image ( info , parts , & len ) ;
FILE * file = fopen ( output , " wb " ) ;
if ( ! file )
@ -711,11 +672,22 @@ static void usage(const char *argv0) {
} ;
static const struct device_info * find_board ( const char * id )
{
struct device_info * board = NULL ;
for ( board = boards ; board - > id ! = NULL ; board + + )
if ( strcasecmp ( id , board - > id ) = = 0 )
return board ;
return NULL ;
}
int main ( int argc , char * argv [ ] ) {
const char * board = NULL , * kernel_image = NULL , * rootfs_image = NULL , * output = NULL ;
bool add_jffs2_eof = false , sysupgrade = false ;
unsigned rev = 0 ;
struct device_info * info ;
const struct device_info * info ;
while ( true ) {
int c ;
@ -772,17 +744,9 @@ int main(int argc, char *argv[]) {
if ( ! output )
error ( 1 , 0 , " no output filename has been specified " ) ;
if ( strcmp ( board , " CPE210 " ) = = 0 )
info = & cpe210_info ;
else if ( strcmp ( board , " CPE510 " ) = = 0 )
info = & cpe510_info ;
else if ( strcmp ( board , " C2600 " ) = = 0 )
info = & c2600_info ;
else if ( strcmp ( board , " EAP120 " ) = = 0 )
info = & eap120_info ;
else if ( strcmp ( board , " ARCHERC9 " ) = = 0 )
info = & e9_info ;
else
info = find_board ( board ) ;
if ( info = = NULL )
error ( 1 , 0 , " unsupported board %s " , board ) ;
build_image ( output , kernel_image , rootfs_image , rev , add_jffs2_eof , sysupgrade , info ) ;