31
31
32
32
#define DECOMP_BUF_SIZE CONFIG_BOOT_DECOMPRESSION_BUFFER_SIZE
33
33
#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
+ */
34
37
#define DECOMP_BUF_EXTRA_SIZE 2
35
38
#else
36
39
#define DECOMP_BUF_EXTRA_SIZE 0
@@ -184,7 +187,6 @@ int bootutil_img_hash_decompress(struct boot_loader_state *state, struct image_h
184
187
struct nrf_compress_implementation * compression_arm_thumb = NULL ;
185
188
TARGET_STATIC struct image_header modified_hdr ;
186
189
bootutil_sha_context sha_ctx ;
187
- uint8_t flash_erased_value ;
188
190
189
191
#ifdef MCUBOOT_ENC_IMAGES
190
192
struct enc_key_data * enc_state ;
@@ -301,8 +303,6 @@ int bootutil_img_hash_decompress(struct boot_loader_state *state, struct image_h
301
303
modified_hdr .ih_protect_tlv_size = protected_tlv_size ;
302
304
bootutil_sha_update (& sha_ctx , & modified_hdr , sizeof (modified_hdr ));
303
305
read_pos = sizeof (modified_hdr );
304
- flash_erased_value = flash_area_erased_val (fap );
305
- memset (tmp_buf , flash_erased_value , tmp_buf_sz );
306
306
307
307
while (read_pos < modified_hdr .ih_hdr_size ) {
308
308
uint32_t copy_size = tmp_buf_sz ;
@@ -311,6 +311,15 @@ int bootutil_img_hash_decompress(struct boot_loader_state *state, struct image_h
311
311
copy_size = modified_hdr .ih_hdr_size - read_pos ;
312
312
}
313
313
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
+
314
323
bootutil_sha_update (& sha_ctx , tmp_buf , copy_size );
315
324
read_pos += copy_size ;
316
325
}
@@ -993,6 +1002,75 @@ static int boot_copy_unprotected_tlvs(const struct image_header *hdr,
993
1002
return rc ;
994
1003
}
995
1004
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
+
996
1074
int boot_copy_region_decompress (struct boot_loader_state * state , const struct flash_area * fap_src ,
997
1075
const struct flash_area * fap_dst , uint32_t off_src ,
998
1076
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
1011
1089
struct image_header * hdr ;
1012
1090
TARGET_STATIC uint8_t decomp_buf [DECOMP_BUF_ALLOC_SIZE ] __attribute__((aligned (4 )));
1013
1091
TARGET_STATIC struct image_header modified_hdr ;
1092
+ uint16_t decomp_buf_max_size ;
1014
1093
1015
1094
#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 ;
1018
1096
#endif
1019
1097
1020
1098
#ifdef MCUBOOT_ENC_IMAGES
@@ -1069,6 +1147,8 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
1069
1147
1070
1148
write_alignment = flash_area_align (fap_dst );
1071
1149
1150
+ decomp_buf_max_size = DECOMP_BUF_SIZE - (DECOMP_BUF_SIZE % write_alignment );
1151
+
1072
1152
memcpy (& modified_hdr , hdr , sizeof (modified_hdr ));
1073
1153
1074
1154
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
1199
1279
1200
1280
/* Copy data to secondary buffer for writing out */
1201
1281
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 );
1203
1283
1204
1284
if (data_size > output_size ) {
1205
1285
data_size = output_size ;
@@ -1222,106 +1302,62 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
1222
1302
output_size -= data_size ;
1223
1303
1224
1304
/* 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 ) {
1226
1306
#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB )
1227
1307
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 ;
1230
1310
1231
1311
/* 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 );
1268
1317
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 ;
1279
1320
}
1280
1321
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 ;
1293
1324
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 ));
1296
1329
1297
1330
if (rc != 0 ) {
1298
1331
BOOT_LOG_ERR (
1299
1332
"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 ),
1301
1335
fap_dst -> fa_id , rc );
1302
1336
rc = BOOT_EFLASH ;
1303
1337
goto finish ;
1304
1338
}
1305
1339
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 ;
1309
1345
} else
1310
1346
#endif
1311
1347
{
1312
1348
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 );
1314
1350
1315
1351
if (rc != 0 ) {
1316
1352
BOOT_LOG_ERR (
1317
1353
"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 ,
1319
1355
fap_dst -> fa_id , rc );
1320
1356
rc = BOOT_EFLASH ;
1321
1357
goto finish ;
1322
1358
}
1323
1359
1324
- write_pos += DECOMP_BUF_SIZE ;
1360
+ write_pos += decomp_buf_max_size ;
1325
1361
decomp_buf_size = 0 ;
1326
1362
}
1327
1363
}
@@ -1336,21 +1372,42 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
1336
1372
#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB )
1337
1373
if (hdr -> ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT && decomp_buf_size > 0 ) {
1338
1374
/* 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 ;
1342
1375
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);
1346
1383
1347
1384
if (rc ) {
1348
- BOOT_LOG_ERR ("Decompression error: %d" , rc );
1349
- rc = BOOT_EBADSTATUS ;
1350
1385
goto finish ;
1351
1386
}
1352
1387
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
+ }
1354
1411
}
1355
1412
#endif
1356
1413
@@ -1361,7 +1418,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
1361
1418
if (protected_tlv_size > 0 ) {
1362
1419
rc = boot_copy_protected_tlvs (hdr , fap_src , fap_dst , (off_dst + hdr -> ih_hdr_size +
1363
1420
write_pos ), protected_tlv_size ,
1364
- decomp_buf , DECOMP_BUF_SIZE , & decomp_buf_size ,
1421
+ decomp_buf , decomp_buf_max_size , & decomp_buf_size ,
1365
1422
& tlv_write_size );
1366
1423
1367
1424
if (rc ) {
@@ -1375,7 +1432,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
1375
1432
tlv_write_size = 0 ;
1376
1433
rc = boot_copy_unprotected_tlvs (hdr , fap_src , fap_dst , (off_dst + hdr -> ih_hdr_size +
1377
1434
write_pos ), unprotected_tlv_size ,
1378
- decomp_buf , DECOMP_BUF_SIZE , & decomp_buf_size ,
1435
+ decomp_buf , decomp_buf_max_size , & decomp_buf_size ,
1379
1436
& tlv_write_size );
1380
1437
1381
1438
if (rc ) {
0 commit comments