3131
3232#define DECOMP_BUF_SIZE CONFIG_BOOT_DECOMPRESSION_BUFFER_SIZE
3333#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB )
34+ /* Extra buffer space for being able to writeback ARM thumb decompression output,
35+ * which may be of +2 bytes more size than its input.
36+ */
3437#define DECOMP_BUF_EXTRA_SIZE 2
3538#else
3639#define DECOMP_BUF_EXTRA_SIZE 0
@@ -184,7 +187,6 @@ int bootutil_img_hash_decompress(struct boot_loader_state *state, struct image_h
184187 struct nrf_compress_implementation * compression_arm_thumb = NULL ;
185188 TARGET_STATIC struct image_header modified_hdr ;
186189 bootutil_sha_context sha_ctx ;
187- uint8_t flash_erased_value ;
188190
189191#ifdef MCUBOOT_ENC_IMAGES
190192 struct enc_key_data * enc_state ;
@@ -301,8 +303,6 @@ int bootutil_img_hash_decompress(struct boot_loader_state *state, struct image_h
301303 modified_hdr .ih_protect_tlv_size = protected_tlv_size ;
302304 bootutil_sha_update (& sha_ctx , & modified_hdr , sizeof (modified_hdr ));
303305 read_pos = sizeof (modified_hdr );
304- flash_erased_value = flash_area_erased_val (fap );
305- memset (tmp_buf , flash_erased_value , tmp_buf_sz );
306306
307307 while (read_pos < modified_hdr .ih_hdr_size ) {
308308 uint32_t copy_size = tmp_buf_sz ;
@@ -311,6 +311,15 @@ int bootutil_img_hash_decompress(struct boot_loader_state *state, struct image_h
311311 copy_size = modified_hdr .ih_hdr_size - read_pos ;
312312 }
313313
314+ rc = flash_area_read (fap , read_pos , tmp_buf , copy_size );
315+
316+ if (rc != 0 ) {
317+ BOOT_LOG_ERR ("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d" ,
318+ (hdr -> ih_hdr_size + read_pos ), copy_size , fap -> fa_id , rc );
319+ rc = BOOT_EFLASH ;
320+ goto finish ;
321+ }
322+
314323 bootutil_sha_update (& sha_ctx , tmp_buf , copy_size );
315324 read_pos += copy_size ;
316325 }
@@ -993,6 +1002,75 @@ static int boot_copy_unprotected_tlvs(const struct image_header *hdr,
9931002 return rc ;
9941003}
9951004
1005+ #if defined(CONFIG_NRF_COMPRESS_ARM_THUMB )
1006+ /**
1007+ * @brief Helper function for in-place ARM Thumb filtering.
1008+ * This function places the decompressed data back into the same buffer
1009+ * at the beginning, overwriting the compressed data. WARNING: because
1010+ * ARM Thumb filtering can return +-2 more/less bytes than the input,
1011+ * the buffer provided needs to have free DECOMP_BUF_EXTRA_SIZE bytes at
1012+ * the beginning and provide valid data for filtering after these.
1013+ *
1014+ * @param[in] arm_thumb_impl Pointer to the ARM Thumb decompression implementation.
1015+ * @param[in,out] buf Pointer to the buffer containing the compressed data / filtered data.
1016+ * @param[in] buf_size Size of the buffer (including DECOMP_BUF_EXTRA_SIZE bytes at the beginning).
1017+ * @param[out] out_size Pointer to a variable where the size of the filtered data will be stored.
1018+ * @param[in] last_part Indicates if this is the last part of the data to be filtered.
1019+ *
1020+ * @return 0 on success, BOOT_EBADSTATUS on error.
1021+ */
1022+ static int boot_arm_thumb_filter (struct nrf_compress_implementation * const arm_thumb_impl ,
1023+ uint8_t * buf , size_t buf_size , size_t * out_size , bool last_part ) {
1024+
1025+ uint32_t filter_writeback_pos = 0 ;
1026+ uint32_t processed_size = 0 ;
1027+ int rc ;
1028+
1029+ while (processed_size < (buf_size - DECOMP_BUF_EXTRA_SIZE )) {
1030+ uint32_t offset_arm_thumb = 0 ;
1031+ uint32_t output_size_arm_thumb = 0 ;
1032+ uint8_t * output_arm_thumb = NULL ;
1033+ uint32_t current_size = (buf_size - DECOMP_BUF_EXTRA_SIZE - processed_size );
1034+ bool arm_thumb_last_packet = false;
1035+
1036+ if (current_size > CONFIG_NRF_COMPRESS_CHUNK_SIZE ) {
1037+ current_size = CONFIG_NRF_COMPRESS_CHUNK_SIZE ;
1038+ }
1039+
1040+ if (last_part && (processed_size + current_size ) == (buf_size - DECOMP_BUF_EXTRA_SIZE )) {
1041+ arm_thumb_last_packet = true;
1042+ }
1043+
1044+ rc = arm_thumb_impl -> decompress (NULL ,
1045+ & buf [processed_size +
1046+ DECOMP_BUF_EXTRA_SIZE ],
1047+ current_size ,
1048+ arm_thumb_last_packet ,
1049+ & offset_arm_thumb ,
1050+ & output_arm_thumb ,
1051+ & output_size_arm_thumb );
1052+
1053+ if (rc ) {
1054+ BOOT_LOG_ERR ("Decompression error: %d" , rc );
1055+ return BOOT_EBADSTATUS ;
1056+ }
1057+
1058+ if (output_size_arm_thumb > (buf_size - filter_writeback_pos )) {
1059+ BOOT_LOG_ERR ("Filter writeback position exceeds buffer size" );
1060+ return BOOT_EBADSTATUS ;
1061+ }
1062+
1063+ memcpy (& buf [filter_writeback_pos ], output_arm_thumb ,
1064+ output_size_arm_thumb );
1065+ filter_writeback_pos += output_size_arm_thumb ;
1066+ processed_size += offset_arm_thumb ;
1067+ }
1068+ * out_size = filter_writeback_pos ;
1069+
1070+ return 0 ;
1071+ }
1072+ #endif /* CONFIG_NRF_COMPRESS_ARM_THUMB */
1073+
9961074int boot_copy_region_decompress (struct boot_loader_state * state , const struct flash_area * fap_src ,
9971075 const struct flash_area * fap_dst , uint32_t off_src ,
9981076 uint32_t off_dst , uint32_t sz , uint8_t * buf , size_t buf_size )
@@ -1011,10 +1089,10 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
10111089 struct image_header * hdr ;
10121090 TARGET_STATIC uint8_t decomp_buf [DECOMP_BUF_ALLOC_SIZE ] __attribute__((aligned (4 )));
10131091 TARGET_STATIC struct image_header modified_hdr ;
1092+ uint16_t decomp_buf_max_size ;
10141093
10151094#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB )
1016- uint8_t excess_data_buffer [DECOMP_BUF_EXTRA_SIZE ];
1017- bool excess_data_buffer_full = false;
1095+ uint8_t unaligned_data_length = 0 ;
10181096#endif
10191097
10201098#ifdef MCUBOOT_ENC_IMAGES
@@ -1069,6 +1147,8 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
10691147
10701148 write_alignment = flash_area_align (fap_dst );
10711149
1150+ decomp_buf_max_size = DECOMP_BUF_SIZE - (DECOMP_BUF_SIZE % write_alignment );
1151+
10721152 memcpy (& modified_hdr , hdr , sizeof (modified_hdr ));
10731153
10741154 rc = bootutil_get_img_decomp_size (hdr , fap_src , & decompressed_image_size );
@@ -1199,7 +1279,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
11991279
12001280 /* Copy data to secondary buffer for writing out */
12011281 while (output_size > 0 ) {
1202- uint32_t data_size = (DECOMP_BUF_SIZE - decomp_buf_size );
1282+ uint32_t data_size = (decomp_buf_max_size - decomp_buf_size );
12031283
12041284 if (data_size > output_size ) {
12051285 data_size = output_size ;
@@ -1222,106 +1302,62 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
12221302 output_size -= data_size ;
12231303
12241304 /* Write data out from secondary buffer when it is full */
1225- if (decomp_buf_size == DECOMP_BUF_SIZE ) {
1305+ if (decomp_buf_size == decomp_buf_max_size ) {
12261306#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB )
12271307 if (hdr -> ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT ) {
1228- uint32_t filter_writeback_pos = 0 ;
1229- uint32_t processed_size = 0 ;
1308+
1309+ uint32_t filter_output_size ;
12301310
12311311 /* Run this through the ARM thumb filter */
1232- while (processed_size < DECOMP_BUF_SIZE ) {
1233- uint32_t offset_arm_thumb = 0 ;
1234- uint32_t output_size_arm_thumb = 0 ;
1235- uint8_t * output_arm_thumb = NULL ;
1236- uint32_t current_size = DECOMP_BUF_SIZE ;
1237- bool arm_thumb_last_packet = false;
1238-
1239- if (current_size > CONFIG_NRF_COMPRESS_CHUNK_SIZE ) {
1240- current_size = CONFIG_NRF_COMPRESS_CHUNK_SIZE ;
1241- }
1242-
1243- if (last_packet && (processed_size + current_size ) == DECOMP_BUF_SIZE
1244- && output_size == 0 ) {
1245- arm_thumb_last_packet = true;
1246- }
1247-
1248- rc = compression_arm_thumb -> decompress (NULL ,
1249- & decomp_buf [processed_size +
1250- DECOMP_BUF_EXTRA_SIZE ],
1251- current_size ,
1252- arm_thumb_last_packet ,
1253- & offset_arm_thumb ,
1254- & output_arm_thumb ,
1255- & output_size_arm_thumb );
1256-
1257- if (rc ) {
1258- BOOT_LOG_ERR ("Decompression error: %d" , rc );
1259- rc = BOOT_EBADSTATUS ;
1260- goto finish ;
1261- }
1262-
1263- memcpy (& decomp_buf [filter_writeback_pos ], output_arm_thumb ,
1264- output_size_arm_thumb );
1265- filter_writeback_pos += output_size_arm_thumb ;
1266- processed_size += current_size ;
1267- }
1312+ rc = boot_arm_thumb_filter (compression_arm_thumb ,
1313+ & decomp_buf [unaligned_data_length ],
1314+ decomp_buf_size - unaligned_data_length + DECOMP_BUF_EXTRA_SIZE ,
1315+ & filter_output_size ,
1316+ last_packet && output_size == 0 );
12681317
1269- if (excess_data_buffer_full == true)
1270- {
1271- /* Restore extra data removed from previous iteration to the write
1272- * buffer
1273- */
1274- memmove (& decomp_buf [DECOMP_BUF_EXTRA_SIZE ], decomp_buf ,
1275- filter_writeback_pos );
1276- memcpy (decomp_buf , excess_data_buffer , DECOMP_BUF_EXTRA_SIZE );
1277- excess_data_buffer_full = false;
1278- filter_writeback_pos += DECOMP_BUF_EXTRA_SIZE ;
1318+ if (rc ) {
1319+ goto finish ;
12791320 }
12801321
1281- if ((filter_writeback_pos % sizeof (uint32_t )) != 0 )
1282- {
1283- /* Since there are an extra 2 bytes here, remove them and stash for
1284- * later usage to prevent flash write issues with non-word boundary
1285- * writes
1286- */
1287- memcpy (excess_data_buffer , & decomp_buf [filter_writeback_pos -
1288- DECOMP_BUF_EXTRA_SIZE ],
1289- DECOMP_BUF_EXTRA_SIZE );
1290- excess_data_buffer_full = true;
1291- filter_writeback_pos -= DECOMP_BUF_EXTRA_SIZE ;
1292- }
1322+ decomp_buf_size = filter_output_size + unaligned_data_length ;
1323+ unaligned_data_length = decomp_buf_size % write_alignment ;
12931324
1294- rc = flash_area_write (fap_dst , (off_dst + hdr -> ih_hdr_size + write_pos ),
1295- decomp_buf , filter_writeback_pos );
1325+ rc = flash_area_write (fap_dst ,
1326+ (off_dst + hdr -> ih_hdr_size + write_pos ),
1327+ decomp_buf ,
1328+ (decomp_buf_size - unaligned_data_length ));
12961329
12971330 if (rc != 0 ) {
12981331 BOOT_LOG_ERR (
12991332 "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d" ,
1300- (off_dst + hdr -> ih_hdr_size + write_pos ), DECOMP_BUF_SIZE ,
1333+ (off_dst + hdr -> ih_hdr_size + write_pos ),
1334+ (decomp_buf_size - unaligned_data_length ),
13011335 fap_dst -> fa_id , rc );
13021336 rc = BOOT_EFLASH ;
13031337 goto finish ;
13041338 }
13051339
1306- write_pos += filter_writeback_pos ;
1307- decomp_buf_size = 0 ;
1308- filter_writeback_pos = 0 ;
1340+ memmove (decomp_buf ,
1341+ & decomp_buf [decomp_buf_size - unaligned_data_length ],
1342+ unaligned_data_length );
1343+ write_pos += decomp_buf_size - unaligned_data_length ;
1344+ decomp_buf_size = unaligned_data_length ;
13091345 } else
13101346#endif
13111347 {
13121348 rc = flash_area_write (fap_dst , (off_dst + hdr -> ih_hdr_size + write_pos ),
1313- decomp_buf , DECOMP_BUF_SIZE );
1349+ decomp_buf , decomp_buf_max_size );
13141350
13151351 if (rc != 0 ) {
13161352 BOOT_LOG_ERR (
13171353 "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d" ,
1318- (off_dst + hdr -> ih_hdr_size + write_pos ), DECOMP_BUF_SIZE ,
1354+ (off_dst + hdr -> ih_hdr_size + write_pos ), decomp_buf_max_size ,
13191355 fap_dst -> fa_id , rc );
13201356 rc = BOOT_EFLASH ;
13211357 goto finish ;
13221358 }
13231359
1324- write_pos += DECOMP_BUF_SIZE ;
1360+ write_pos += decomp_buf_max_size ;
13251361 decomp_buf_size = 0 ;
13261362 }
13271363 }
@@ -1336,21 +1372,42 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
13361372#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB )
13371373 if (hdr -> ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT && decomp_buf_size > 0 ) {
13381374 /* Extra data that has not been written out that needs ARM thumb filter applied */
1339- uint32_t offset_arm_thumb = 0 ;
1340- uint32_t output_size_arm_thumb = 0 ;
1341- uint8_t * output_arm_thumb = NULL ;
13421375
1343- rc = compression_arm_thumb -> decompress (NULL , & decomp_buf [DECOMP_BUF_EXTRA_SIZE ],
1344- decomp_buf_size , true, & offset_arm_thumb ,
1345- & output_arm_thumb , & output_size_arm_thumb );
1376+ uint32_t filter_output_size ;
1377+
1378+ rc = boot_arm_thumb_filter (compression_arm_thumb ,
1379+ & decomp_buf [unaligned_data_length ],
1380+ decomp_buf_size - unaligned_data_length + DECOMP_BUF_EXTRA_SIZE ,
1381+ & filter_output_size ,
1382+ true);
13461383
13471384 if (rc ) {
1348- BOOT_LOG_ERR ("Decompression error: %d" , rc );
1349- rc = BOOT_EBADSTATUS ;
13501385 goto finish ;
13511386 }
13521387
1353- memcpy (decomp_buf , output_arm_thumb , output_size_arm_thumb );
1388+ decomp_buf_size = filter_output_size + unaligned_data_length ;
1389+
1390+ if (decomp_buf_size > decomp_buf_max_size ) {
1391+ /* It can happen if ARM thumb decompression returned +2 bytes and we had near full
1392+ * decomp_buf. We still can hold these additional 2 bytes because of
1393+ * DECOMP_BUF_EXTRA_SIZE allocated. */
1394+
1395+ rc = flash_area_write (fap_dst , (off_dst + hdr -> ih_hdr_size + write_pos ),
1396+ decomp_buf , decomp_buf_max_size );
1397+
1398+ if (rc != 0 ) {
1399+ BOOT_LOG_ERR ("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d" ,
1400+ (off_dst + hdr -> ih_hdr_size + write_pos ), decomp_buf_max_size ,
1401+ fap_dst -> fa_id , rc );
1402+ rc = BOOT_EFLASH ;
1403+ goto finish ;
1404+ }
1405+ memmove (decomp_buf , & decomp_buf [decomp_buf_max_size ],
1406+ (decomp_buf_size - decomp_buf_max_size ));
1407+
1408+ decomp_buf_size = decomp_buf_size - decomp_buf_max_size ;
1409+ write_pos += decomp_buf_max_size ;
1410+ }
13541411 }
13551412#endif
13561413
@@ -1361,7 +1418,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
13611418 if (protected_tlv_size > 0 ) {
13621419 rc = boot_copy_protected_tlvs (hdr , fap_src , fap_dst , (off_dst + hdr -> ih_hdr_size +
13631420 write_pos ), protected_tlv_size ,
1364- decomp_buf , DECOMP_BUF_SIZE , & decomp_buf_size ,
1421+ decomp_buf , decomp_buf_max_size , & decomp_buf_size ,
13651422 & tlv_write_size );
13661423
13671424 if (rc ) {
@@ -1375,7 +1432,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
13751432 tlv_write_size = 0 ;
13761433 rc = boot_copy_unprotected_tlvs (hdr , fap_src , fap_dst , (off_dst + hdr -> ih_hdr_size +
13771434 write_pos ), unprotected_tlv_size ,
1378- decomp_buf , DECOMP_BUF_SIZE , & decomp_buf_size ,
1435+ decomp_buf , decomp_buf_max_size , & decomp_buf_size ,
13791436 & tlv_write_size );
13801437
13811438 if (rc ) {
0 commit comments