Skip to content

Commit 7d584fc

Browse files
committed
[nrf noup] boot: zephyr: decompression: Fix issues with ARM thumb filter
fixup! [nrf noup] zephyr: Add support for ARM thumb filter Fixes some issues with the ARM filter implementation which has been updated to support jump instructions that are staggered into 2 different data chunks, and whereby the final portion of data was not ran through the filter Signed-off-by: Jamie McCrae <[email protected]>
1 parent 1dbca8f commit 7d584fc

File tree

1 file changed

+120
-34
lines changed

1 file changed

+120
-34
lines changed

boot/zephyr/decompression.c

Lines changed: 120 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@
2929
#define EXPECTED_SIG_TLV IMAGE_TLV_ED25519
3030
#endif
3131

32+
#define DECOMP_BUF_SIZE CONFIG_BOOT_DECOMPRESSION_BUFFER_SIZE
33+
#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB)
34+
#define DECOMP_BUF_EXTRA_SIZE 2
35+
#else
36+
#define DECOMP_BUF_EXTRA_SIZE 0
37+
#endif
38+
#define DECOMP_BUF_ALLOC_SIZE (DECOMP_BUF_SIZE + DECOMP_BUF_EXTRA_SIZE)
39+
3240
/* Number of times that consumed data by decompression system can be 0 in a row before aborting */
3341
#define OFFSET_ZERO_CHECK_TIMES 3
3442

@@ -317,11 +325,6 @@ int bootutil_img_hash_decompress(struct enc_key_data *enc_state, int image_index
317325
BOOT_LOG_ERR("Decompression error: %d", rc);
318326
rc = BOOT_EBADSTATUS;
319327
goto finish;
320-
} else if (current_size != offset_arm_thumb) {
321-
BOOT_LOG_ERR("Decompression expected offset mismatch: %d vs %d",
322-
current_size, offset_arm_thumb);
323-
rc = BOOT_EBADSTATUS;
324-
goto finish;
325328
}
326329

327330
bootutil_sha_update(&sha_ctx, output_arm_thumb, output_size_arm_thumb);
@@ -863,7 +866,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
863866
struct nrf_compress_implementation *compression_lzma = NULL;
864867
struct nrf_compress_implementation *compression_arm_thumb = NULL;
865868
struct image_header *hdr;
866-
TARGET_STATIC uint8_t decomp_buf[CONFIG_BOOT_DECOMPRESSION_BUFFER_SIZE] __attribute__((aligned(4)));
869+
TARGET_STATIC uint8_t decomp_buf[DECOMP_BUF_ALLOC_SIZE] __attribute__((aligned(4)));
867870
TARGET_STATIC struct image_header modified_hdr;
868871

869872
hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
@@ -950,6 +953,10 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
950953
while (pos < hdr->ih_img_size) {
951954
uint32_t copy_size = hdr->ih_img_size - pos;
952955
uint32_t tmp_off = 0;
956+
#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB)
957+
uint8_t excess_data_buffer[DECOMP_BUF_EXTRA_SIZE];
958+
bool excess_data_buffer_full = false;
959+
#endif
953960

954961
if (copy_size > buf_size) {
955962
copy_size = buf_size;
@@ -985,8 +992,8 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
985992
last_packet = true;
986993
}
987994

988-
rc = compression_lzma->decompress(NULL, &buf[tmp_off], chunk_size, last_packet, &offset,
989-
&output, &output_size);
995+
rc = compression_lzma->decompress(NULL, &buf[tmp_off], chunk_size, last_packet,
996+
&offset, &output, &output_size);
990997

991998
if (rc) {
992999
BOOT_LOG_ERR("Decompression error: %d", rc);
@@ -996,42 +1003,55 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
9961003

9971004
/* Copy data to secondary buffer for writing out */
9981005
while (output_size > 0) {
999-
uint32_t data_size = (sizeof(decomp_buf) - decomp_buf_size);
1006+
uint32_t data_size = (DECOMP_BUF_SIZE - decomp_buf_size);
10001007

10011008
if (data_size > output_size) {
10021009
data_size = output_size;
10031010
}
10041011

1005-
memcpy(&decomp_buf[decomp_buf_size], &output[compression_buffer_pos], data_size);
1012+
#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB)
1013+
if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT) {
1014+
memcpy(&decomp_buf[decomp_buf_size + DECOMP_BUF_EXTRA_SIZE],
1015+
&output[compression_buffer_pos], data_size);
1016+
} else
1017+
#endif
1018+
{
1019+
memcpy(&decomp_buf[decomp_buf_size], &output[compression_buffer_pos],
1020+
data_size);
1021+
}
1022+
10061023
compression_buffer_pos += data_size;
10071024

10081025
decomp_buf_size += data_size;
10091026
output_size -= data_size;
10101027

10111028
/* Write data out from secondary buffer when it is full */
1012-
if (decomp_buf_size == sizeof(decomp_buf)) {
1029+
if (decomp_buf_size == DECOMP_BUF_SIZE) {
1030+
#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB)
10131031
if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT) {
1014-
/* Run this through the ARM thumb filter */
1015-
uint32_t offset_arm_thumb = 0;
1016-
uint32_t output_size_arm_thumb = 0;
1032+
uint32_t filter_writeback_pos = 0;
10171033
uint32_t processed_size = 0;
1018-
uint8_t *output_arm_thumb = NULL;
10191034

1020-
while (processed_size < sizeof(decomp_buf)) {
1021-
uint32_t current_size = sizeof(decomp_buf);
1035+
/* Run this through the ARM thumb filter */
1036+
while (processed_size < DECOMP_BUF_SIZE) {
1037+
uint32_t offset_arm_thumb = 0;
1038+
uint32_t output_size_arm_thumb = 0;
1039+
uint8_t *output_arm_thumb = NULL;
1040+
uint32_t current_size = DECOMP_BUF_SIZE;
10221041
bool arm_thumb_last_packet = false;
10231042

10241043
if (current_size > CONFIG_NRF_COMPRESS_CHUNK_SIZE) {
10251044
current_size = CONFIG_NRF_COMPRESS_CHUNK_SIZE;
10261045
}
10271046

1028-
if (last_packet && (processed_size + current_size) ==
1029-
sizeof(decomp_buf)) {
1047+
if (last_packet && (processed_size + current_size) == DECOMP_BUF_SIZE
1048+
&& output_size == 0) {
10301049
arm_thumb_last_packet = true;
10311050
}
10321051

10331052
rc = compression_arm_thumb->decompress(NULL,
1034-
&decomp_buf[processed_size],
1053+
&decomp_buf[processed_size +
1054+
DECOMP_BUF_EXTRA_SIZE],
10351055
current_size,
10361056
arm_thumb_last_packet,
10371057
&offset_arm_thumb,
@@ -1044,25 +1064,70 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
10441064
goto finish;
10451065
}
10461066

1047-
memcpy(&decomp_buf[processed_size], output_arm_thumb, current_size);
1067+
memcpy(&decomp_buf[filter_writeback_pos], output_arm_thumb,
1068+
output_size_arm_thumb);
1069+
filter_writeback_pos += output_size_arm_thumb;
10481070
processed_size += current_size;
10491071
}
1050-
}
10511072

1052-
rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos),
1053-
decomp_buf, sizeof(decomp_buf));
1073+
if (excess_data_buffer_full == true)
1074+
{
1075+
/* Restore extra data removed from previous iteration to the write
1076+
* buffer
1077+
*/
1078+
memmove(&decomp_buf[DECOMP_BUF_EXTRA_SIZE], decomp_buf,
1079+
filter_writeback_pos);
1080+
memcpy(decomp_buf, excess_data_buffer, DECOMP_BUF_EXTRA_SIZE);
1081+
excess_data_buffer_full = false;
1082+
filter_writeback_pos += DECOMP_BUF_EXTRA_SIZE;
1083+
}
10541084

1055-
if (rc != 0) {
1056-
BOOT_LOG_ERR(
1057-
"Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d",
1058-
(off_dst + hdr->ih_hdr_size + write_pos), sizeof(decomp_buf),
1059-
fap_dst->fa_id, rc);
1060-
rc = BOOT_EFLASH;
1061-
goto finish;
1062-
}
1085+
if ((filter_writeback_pos % sizeof(uint32_t)) != 0)
1086+
{
1087+
/* Since there are an extra 2 bytes here, remove them and stash for
1088+
* later usage to prevent flash write issues with non-word boundary
1089+
* writes
1090+
*/
1091+
memcpy(excess_data_buffer, &decomp_buf[filter_writeback_pos -
1092+
DECOMP_BUF_EXTRA_SIZE],
1093+
DECOMP_BUF_EXTRA_SIZE);
1094+
excess_data_buffer_full = true;
1095+
filter_writeback_pos -= DECOMP_BUF_EXTRA_SIZE;
1096+
}
1097+
1098+
rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos),
1099+
decomp_buf, filter_writeback_pos);
1100+
1101+
if (rc != 0) {
1102+
BOOT_LOG_ERR(
1103+
"Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d",
1104+
(off_dst + hdr->ih_hdr_size + write_pos), DECOMP_BUF_SIZE,
1105+
fap_dst->fa_id, rc);
1106+
rc = BOOT_EFLASH;
1107+
goto finish;
1108+
}
1109+
1110+
write_pos += filter_writeback_pos;
1111+
decomp_buf_size = 0;
1112+
filter_writeback_pos = 0;
1113+
} else
1114+
#endif
1115+
{
1116+
rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos),
1117+
decomp_buf, DECOMP_BUF_SIZE);
1118+
1119+
if (rc != 0) {
1120+
BOOT_LOG_ERR(
1121+
"Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d",
1122+
(off_dst + hdr->ih_hdr_size + write_pos), DECOMP_BUF_SIZE,
1123+
fap_dst->fa_id, rc);
1124+
rc = BOOT_EFLASH;
1125+
goto finish;
1126+
}
10631127

1064-
write_pos += sizeof(decomp_buf);
1065-
decomp_buf_size = 0;
1128+
write_pos += DECOMP_BUF_SIZE;
1129+
decomp_buf_size = 0;
1130+
}
10661131
}
10671132
}
10681133

@@ -1072,6 +1137,27 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl
10721137
pos += copy_size;
10731138
}
10741139

1140+
#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB)
1141+
if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT && decomp_buf_size > 0) {
1142+
/* Extra data that has not been written out that needs ARM thumb filter applied */
1143+
uint32_t offset_arm_thumb = 0;
1144+
uint32_t output_size_arm_thumb = 0;
1145+
uint8_t *output_arm_thumb = NULL;
1146+
1147+
rc = compression_arm_thumb->decompress(NULL, &decomp_buf[DECOMP_BUF_EXTRA_SIZE],
1148+
decomp_buf_size, true, &offset_arm_thumb,
1149+
&output_arm_thumb, &output_size_arm_thumb);
1150+
1151+
if (rc) {
1152+
BOOT_LOG_ERR("Decompression error: %d", rc);
1153+
rc = BOOT_EBADSTATUS;
1154+
goto finish;
1155+
}
1156+
1157+
memcpy(decomp_buf, output_arm_thumb, output_size_arm_thumb);
1158+
}
1159+
#endif
1160+
10751161
/* Clean up decompression system */
10761162
(void)compression_lzma->deinit(NULL);
10771163
(void)compression_arm_thumb->deinit(NULL);

0 commit comments

Comments
 (0)