@@ -76,6 +76,38 @@ typedef struct image_header {
7676#define HEADER_NAME_OFFSET offsetof(image_header_t, ih_name)
7777#define HEADER_SIZE sizeof(image_header_t)
7878
79+ #define TOC0_HEADER_SIZE 0x30
80+ #define TOC0_ITEM_SIZE 0x20
81+ #define TOC0_MAIN_MAGIC_OFFSET 0x08
82+ #define TOC0_CHECKSUM_OFFSET 0x0c
83+ #define TOC0_NUM_ITEMS_OFFSET 0x18
84+ #define TOC0_LENGTH_OFFSET 0x1c
85+ #define TOC0_MAIN_END_OFFSET 0x2c
86+ #define TOC0_ITEM_NAME_OFFSET 0x00
87+ #define TOC0_ITEM_OFFSET_OFFSET 0x04
88+ #define TOC0_ITEM_SIZE_OFFSET 0x08
89+ #define TOC0_ITEM_LOAD_OFFSET 0x14
90+ #define TOC0_ITEM_END_OFFSET 0x1c
91+ #define TOC0_MAIN_INFO_MAGIC 0x89119800
92+ #define TOC0_ITEM_INFO_NAME_FIRMWARE 0x00010202
93+ #define EGON_HEADER_SIZE 0x60
94+ #define EGON_CHECKSUM_SEED 0x5F0A6C39
95+ #define SPL_HEADER_VERSION 2
96+
97+ static uint32_t get_le32 (const void * ptr )
98+ {
99+ uint32_t val ;
100+
101+ memcpy (& val , ptr , sizeof (val ));
102+ return le32toh (val );
103+ }
104+
105+ static void put_le32 (void * ptr , uint32_t val )
106+ {
107+ val = htole32 (val );
108+ memcpy (ptr , & val , sizeof (val ));
109+ }
110+
79111/*
80112 * Utility function to determine the image type from a mkimage-compatible
81113 * header at given buffer (address).
@@ -775,7 +807,7 @@ uint32_t aw_fel_write_and_execute_spl(feldev_handle *dev, uint8_t *buf, size_t l
775807 if (len < 32 || memcmp (buf + 4 , "eGON.BT0" , 8 ) != 0 )
776808 pr_fatal ("SPL: eGON header is not found\n" );
777809
778- spl_checksum = 2 * le32toh (buf32 [3 ]) - 0x5F0A6C39 ;
810+ spl_checksum = 2 * le32toh (buf32 [3 ]) - EGON_CHECKSUM_SEED ;
779811 spl_len = le32toh (buf32 [4 ]);
780812
781813 if (spl_len > len || (spl_len % 4 ) != 0 )
@@ -970,6 +1002,112 @@ static void aw_fel_write_uboot_image(feldev_handle *dev, uint8_t *buf,
9701002 uboot_size = data_size ;
9711003}
9721004
1005+ static bool is_toc0_image (const uint8_t * buf , size_t len )
1006+ {
1007+ return len >= TOC0_HEADER_SIZE && memcmp (buf , "TOC0.GLH" , 8 ) == 0 ;
1008+ }
1009+
1010+ static uint8_t * toc0_make_egon_spl (const soc_info_t * soc_info ,
1011+ const uint8_t * buf ,
1012+ size_t len , size_t * egon_len ,
1013+ size_t * payload_offset )
1014+ {
1015+ uint32_t toc0_len , num_items , checksum , hdr_checksum ;
1016+ uint32_t code_offset = 0 , code_size = 0 , load_addr = 0 ;
1017+ uint32_t code_pos , branch_words ;
1018+ uint64_t egon_size ;
1019+ uint8_t * egon ;
1020+ size_t i ;
1021+
1022+ if (!soc_info )
1023+ pr_fatal ("TOC0: Unsupported SoC type\n" );
1024+ if (len < TOC0_HEADER_SIZE )
1025+ pr_fatal ("TOC0: invalid header\n" );
1026+
1027+ num_items = get_le32 (buf + TOC0_NUM_ITEMS_OFFSET );
1028+ toc0_len = get_le32 (buf + TOC0_LENGTH_OFFSET );
1029+ hdr_checksum = get_le32 (buf + TOC0_CHECKSUM_OFFSET );
1030+ if ((toc0_len & 3 ) || toc0_len < TOC0_HEADER_SIZE ||
1031+ toc0_len > len || num_items == 0 ||
1032+ num_items > (toc0_len - TOC0_HEADER_SIZE ) / TOC0_ITEM_SIZE )
1033+ pr_fatal ("TOC0: invalid header\n" );
1034+ if (get_le32 (buf + TOC0_MAIN_MAGIC_OFFSET ) != TOC0_MAIN_INFO_MAGIC ||
1035+ memcmp (buf + TOC0_MAIN_END_OFFSET , "MIE;" , 4 ) != 0 )
1036+ pr_fatal ("TOC0: invalid main info header\n" );
1037+
1038+ checksum = EGON_CHECKSUM_SEED ;
1039+ for (i = 0 ; i < toc0_len ; i += 4 )
1040+ checksum += get_le32 (buf + i );
1041+ if (checksum != 2 * hdr_checksum )
1042+ pr_fatal ("TOC0: checksum mismatch\n" );
1043+
1044+ for (i = 0 ; i < num_items ; i ++ ) {
1045+ const uint8_t * item = buf + TOC0_HEADER_SIZE +
1046+ i * TOC0_ITEM_SIZE ;
1047+ uint32_t item_name ;
1048+ uint32_t item_offset , item_size , item_load ;
1049+
1050+ if (memcmp (item + TOC0_ITEM_END_OFFSET , "IIE;" , 4 ) != 0 )
1051+ pr_fatal ("TOC0: invalid item header\n" );
1052+
1053+ item_name = get_le32 (item + TOC0_ITEM_NAME_OFFSET );
1054+ if (item_name != TOC0_ITEM_INFO_NAME_FIRMWARE )
1055+ continue ;
1056+
1057+ item_offset = get_le32 (item + TOC0_ITEM_OFFSET_OFFSET );
1058+ item_size = get_le32 (item + TOC0_ITEM_SIZE_OFFSET );
1059+ item_load = get_le32 (item + TOC0_ITEM_LOAD_OFFSET );
1060+ if (item_size == 0 || item_load == 0 )
1061+ continue ;
1062+ if (item_offset > toc0_len || item_size > toc0_len - item_offset )
1063+ pr_fatal ("TOC0: invalid SPL item bounds\n" );
1064+
1065+ code_offset = item_offset ;
1066+ code_size = item_size ;
1067+ load_addr = item_load ;
1068+ break ;
1069+ }
1070+
1071+ if (!code_size )
1072+ pr_fatal ("TOC0: no loadable SPL item found\n" );
1073+ if (load_addr < soc_info -> spl_addr )
1074+ pr_fatal ("TOC0: SPL load address 0x%08x is below 0x%08x\n" ,
1075+ load_addr , soc_info -> spl_addr );
1076+
1077+ code_pos = load_addr - soc_info -> spl_addr ;
1078+ if (code_pos < EGON_HEADER_SIZE || (code_pos & 3 ))
1079+ pr_fatal ("TOC0: unsupported SPL load offset 0x%x\n" , code_pos );
1080+
1081+ egon_size = (uint64_t )code_pos + code_size ;
1082+ egon_size = (egon_size + 3 ) & ~(uint64_t )3 ;
1083+ if (egon_size > soc_info -> sram_size )
1084+ pr_fatal ("TOC0: SPL item too large\n" );
1085+ * egon_len = (size_t )egon_size ;
1086+ egon = calloc (1 , * egon_len );
1087+ if (!egon )
1088+ pr_fatal ("TOC0: failed to allocate SPL buffer\n" );
1089+
1090+ branch_words = (code_pos - 8 ) >> 2 ;
1091+ put_le32 (egon , 0xea000000 | (branch_words & 0x00ffffff ));
1092+ memcpy (egon + 4 , "eGON.BT0" , 8 );
1093+ put_le32 (egon + 0x10 , (uint32_t )* egon_len );
1094+ memcpy (egon + 0x14 , "SPL" , 3 );
1095+ egon [0x17 ] = SPL_HEADER_VERSION ;
1096+ memcpy (egon + code_pos , buf + code_offset , code_size );
1097+
1098+ checksum = EGON_CHECKSUM_SEED ;
1099+ for (i = 0 ; i < * egon_len ; i += 4 )
1100+ checksum += get_le32 (egon + i );
1101+ put_le32 (egon + 0x0c , checksum );
1102+
1103+ * payload_offset = toc0_len ;
1104+ pr_info ("TOC0: wrapped SPL item %u bytes from 0x%x, load 0x%08x\n" ,
1105+ code_size , code_offset , load_addr );
1106+ pr_info ("TOC0: payload starts at 0x%x\n" , toc0_len );
1107+
1108+ return egon ;
1109+ }
1110+
9731111static const char * spl_get_dtb_name (uint8_t * spl_buf )
9741112{
9751113 uint32_t dt_offset ;
@@ -1001,7 +1139,25 @@ void aw_fel_process_spl_and_uboot(feldev_handle *dev, const char *filename)
10011139 uint32_t offset ;
10021140 /* load file into memory buffer */
10031141 uint8_t * buf = load_file (filename , & size );
1004- const char * dt_name = spl_get_dtb_name (buf );
1142+ const char * dt_name ;
1143+
1144+ if (is_toc0_image (buf , size )) {
1145+ size_t egon_spl_size , payload_offset ;
1146+ uint8_t * egon_spl = toc0_make_egon_spl (dev -> soc_info , buf ,
1147+ size , & egon_spl_size ,
1148+ & payload_offset );
1149+
1150+ aw_fel_write_and_execute_spl (dev , egon_spl , egon_spl_size );
1151+ free (egon_spl );
1152+
1153+ if (size > payload_offset )
1154+ aw_fel_write_uboot_image (dev , buf + payload_offset ,
1155+ size - payload_offset , NULL );
1156+ free (buf );
1157+ return ;
1158+ }
1159+
1160+ dt_name = spl_get_dtb_name (buf );
10051161
10061162 /* write and execute the SPL from the buffer */
10071163 offset = aw_fel_write_and_execute_spl (dev , buf , size );
0 commit comments