Skip to content

Commit cbae84c

Browse files
committed
nrf_compress: Fix ARM thumb filter cross-chunk issue
Fixes an issue with the ARM thumb filter when an instruction crosses two chunks of data by storing bytes from the first for use in the second, this results in the output of the first run being less than the input data size and more than the input data size for the second run Signed-off-by: Jamie McCrae <[email protected]>
1 parent cb8b903 commit cbae84c

File tree

3 files changed

+57
-5
lines changed

3 files changed

+57
-5
lines changed

subsys/nrf_compress/lzma/armthumb.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,21 @@
77
///
88
// Authors: Igor Pavlov
99
// Lasse Collin
10+
// With changes by Nordic Semiconductor ASA
1011
//
1112
///////////////////////////////////////////////////////////////////////////////
1213

1314
#include <stdio.h>
1415
#include "armthumb.h"
1516

16-
void arm_thumb_filter(uint8_t *buf, uint32_t buf_size, uint32_t pos, bool compress)
17+
void arm_thumb_filter(uint8_t *buf, uint32_t buf_size, uint32_t pos, bool compress,
18+
bool *end_part_match)
1719
{
1820
uint32_t i = 0;
21+
uint32_t last_update_address = 0;
1922

2023
while ((i + 4) <= buf_size) {
24+
2125
if ((buf[i + 1] & 0xF8) == 0xF0 && (buf[i + 3] & 0xF8) == 0xF8) {
2226
uint32_t dest;
2327
uint32_t src = (((uint32_t)(buf[i + 1]) & 7) << 19)
@@ -26,6 +30,7 @@ void arm_thumb_filter(uint8_t *buf, uint32_t buf_size, uint32_t pos, bool compre
2630
| (uint32_t)(buf[i + 2]);
2731

2832
src <<= 1;
33+
last_update_address = i;
2934

3035
if (compress) {
3136
dest = pos + (uint32_t)(i) + 4 + src;
@@ -38,9 +43,18 @@ void arm_thumb_filter(uint8_t *buf, uint32_t buf_size, uint32_t pos, bool compre
3843
buf[i + 0] = (dest >> 11);
3944
buf[i + 3] = 0xF8 | ((dest >> 8) & 0x7);
4045
buf[i + 2] = (dest);
46+
4147
i += 2;
4248
}
4349

4450
i += 2;
4551
}
52+
53+
if (i == (buf_size - 2)) {
54+
if (i > last_update_address && (buf[i + 1] & 0xF8) == 0xF0) {
55+
*end_part_match = true;
56+
} else {
57+
*end_part_match = false;
58+
}
59+
}
4660
}

subsys/nrf_compress/lzma/armthumb.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <stdint.h>
1717
#include <stdbool.h>
1818

19-
void arm_thumb_filter(uint8_t *buf, uint32_t buf_size, uint32_t pos, bool compress);
19+
void arm_thumb_filter(uint8_t *buf, uint32_t buf_size, uint32_t pos, bool compress,
20+
bool *end_part_match);
2021

2122
#endif

subsys/nrf_compress/src/arm_thumb.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,18 @@ LOG_MODULE_REGISTER(nrf_compress_arm_thumb, CONFIG_NRF_COMPRESS_LOG_LEVEL);
1616
BUILD_ASSERT((CONFIG_NRF_COMPRESS_CHUNK_SIZE % 4) == 0,
1717
"CONFIG_NRF_COMPRESS_CHUNK_SIZE must be multiple of 4");
1818

19-
static uint8_t output_buffer[CONFIG_NRF_COMPRESS_CHUNK_SIZE];
19+
/* Requires 2 extra bytes to allow checking cross-chunk 16-bit aligned ARM thumb instructions */
20+
#define EXTRA_BUFFER_SIZE 2
21+
22+
static uint8_t output_buffer[CONFIG_NRF_COMPRESS_CHUNK_SIZE + EXTRA_BUFFER_SIZE];
23+
static uint8_t temp_extra_buffer[EXTRA_BUFFER_SIZE];
2024
static uint32_t data_position = 0;
25+
static bool has_extra_buffer_data;
2126

2227
static int arm_thumb_init(void *inst)
2328
{
2429
data_position = 0;
30+
has_extra_buffer_data = false;
2531

2632
return 0;
2733
}
@@ -38,6 +44,7 @@ static int arm_thumb_deinit(void *inst)
3844
static int arm_thumb_reset(void *inst)
3945
{
4046
data_position = 0;
47+
has_extra_buffer_data = false;
4148
memset(output_buffer, 0x00, sizeof(output_buffer));
4249

4350
return 0;
@@ -52,17 +59,47 @@ static int arm_thumb_decompress(void *inst, const uint8_t *input, size_t input_s
5259
bool last_part, uint32_t *offset, uint8_t **output,
5360
size_t *output_size)
5461
{
62+
bool end_part_match = false;
63+
bool extra_buffer_used = false;
64+
5565
if (input_size > CONFIG_NRF_COMPRESS_CHUNK_SIZE) {
5666
return -EINVAL;
5767
}
5868

59-
memcpy(output_buffer, input, input_size);
60-
arm_thumb_filter(output_buffer, input_size, data_position, false);
69+
if (has_extra_buffer_data == true) {
70+
/* Copy bytes from temporary holding buffer */
71+
memcpy(output_buffer, temp_extra_buffer, sizeof(temp_extra_buffer));
72+
memcpy(&output_buffer[sizeof(temp_extra_buffer)], input, input_size);
73+
end_part_match = true;
74+
extra_buffer_used = true;
75+
has_extra_buffer_data = false;
76+
input_size += sizeof(temp_extra_buffer);
77+
} else {
78+
memcpy(output_buffer, input, input_size);
79+
}
80+
81+
arm_thumb_filter(output_buffer, input_size, data_position, false, &end_part_match);
6182
data_position += input_size;
6283
*offset = input_size;
84+
85+
if (extra_buffer_used) {
86+
*offset -= sizeof(temp_extra_buffer);
87+
}
88+
6389
*output = output_buffer;
6490
*output_size = input_size;
6591

92+
if (end_part_match == true && !last_part) {
93+
/* Partial match at end of input, need to cut the final 2 bytes off and stash
94+
* them
95+
*/
96+
memcpy(temp_extra_buffer, &output_buffer[(input_size - sizeof(temp_extra_buffer))],
97+
sizeof(temp_extra_buffer));
98+
has_extra_buffer_data = true;
99+
*output_size -= sizeof(temp_extra_buffer);
100+
data_position -= sizeof(temp_extra_buffer);
101+
}
102+
66103
return 0;
67104
}
68105

0 commit comments

Comments
 (0)