Skip to content

Commit

Permalink
tlv: update tlv module to support storage header
Browse files Browse the repository at this point in the history
use storage header to detect magic header and size.
size will be used to embedd information
if the mfg has been processed.

Signed-off-by: Robert Gałat <[email protected]>
  • Loading branch information
RobertGalatNordic committed Aug 26, 2024
1 parent cb2f961 commit 003f3a0
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 26 deletions.
138 changes: 126 additions & 12 deletions tests/unit_tests/tlv/src/ram_backend_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,40 +18,47 @@

uint8_t TLV_RAM_STORAGE[64] = { 0 };

tlv_ctx RAM_TLV_OBJECT = (tlv_ctx){ .first_entry_offset = 0,
.last_valid_offset = sizeof(TLV_RAM_STORAGE),
tlv_ctx RAM_TLV_OBJECT = (tlv_ctx){ .start_offset = 0,
.end_offset = sizeof(TLV_RAM_STORAGE),
.storage = { .ctx = TLV_RAM_STORAGE,
.read = tlv_storage_ram_read,
.write = tlv_storage_ram_write } };

tlv_ctx RAM_TLV_OBJECT_WITH_MAGIC = (tlv_ctx){ .start_offset = 0,
.end_offset = sizeof(TLV_RAM_STORAGE),
.tlv_storage_start_marker_size = 8,
.storage = { .ctx = TLV_RAM_STORAGE,
.read = tlv_storage_ram_read,
.write = tlv_storage_ram_write } };

tlv_ctx RAM_TLV_OBJECT_NO_WRITE = (tlv_ctx){
.first_entry_offset = 0,
.last_valid_offset = sizeof(TLV_RAM_STORAGE),
.start_offset = 0,
.end_offset = sizeof(TLV_RAM_STORAGE),
.storage = { .ctx = TLV_RAM_STORAGE, .read = tlv_storage_ram_read, .write = NULL }
};

tlv_ctx RAM_TLV_OBJECT_NO_READ = (tlv_ctx){
.first_entry_offset = 0,
.last_valid_offset = sizeof(TLV_RAM_STORAGE),
.start_offset = 0,
.end_offset = sizeof(TLV_RAM_STORAGE),
.storage = { .ctx = TLV_RAM_STORAGE, .read = NULL, .write = tlv_storage_ram_write }
};

tlv_ctx RAM_TLV_OBJECT_OFFSET = (tlv_ctx){ .first_entry_offset = 3,
.last_valid_offset = sizeof(TLV_RAM_STORAGE),
tlv_ctx RAM_TLV_OBJECT_OFFSET = (tlv_ctx){ .start_offset = 3,
.end_offset = sizeof(TLV_RAM_STORAGE),
.storage = { .ctx = TLV_RAM_STORAGE,
.read = tlv_storage_ram_read,
.write = tlv_storage_ram_write } };

tlv_ctx RAM_TLV_OBJECT_LAST_OFFSET_LE_FIRST =
(tlv_ctx){ .first_entry_offset = 0,
.last_valid_offset = 0,
(tlv_ctx){ .start_offset = 0,
.end_offset = 0,
.storage = { .ctx = TLV_RAM_STORAGE,
.read = tlv_storage_ram_read,
.write = tlv_storage_ram_write } };

tlv_ctx RAM_TLV_OBJECT_LAST_OFFSET_ONLY_HEADER =
(tlv_ctx){ .first_entry_offset = 0,
.last_valid_offset = 5,
(tlv_ctx){ .start_offset = 0,
.end_offset = 5,
.storage = { .ctx = TLV_RAM_STORAGE,
.read = tlv_storage_ram_read,
.write = tlv_storage_ram_write } };
Expand Down Expand Up @@ -126,6 +133,40 @@ static void test_tlv_write(struct test_tlv_write_parameters parameters)
zassert_mem_equal(TLV_RAM_STORAGE, parameters.final_storage_content, 64);
}

struct test_tlv_read_start_marker_parameters {
int expected_return;
tlv_ctx tlv;
uint8_t expect_read_data[64];
uint8_t read_size;
uint8_t initial_storage_content[64];
};

static void test_tlv_read_start_marker(struct test_tlv_read_start_marker_parameters parameters)
{
memcpy(TLV_RAM_STORAGE, parameters.initial_storage_content, 64);
uint8_t read_data[64] = { 0 };
int ret = tlv_read_start_marker(&parameters.tlv, read_data, parameters.read_size);
zassert_equal(ret, parameters.expected_return);
zassert_mem_equal(read_data, parameters.expect_read_data, parameters.read_size);
}

struct test_tlv_write_start_marker_parameters {
int expected_return;
tlv_ctx tlv;
uint8_t write_data[64];
uint8_t write_size;
uint8_t initial_storage_content[64];
uint8_t final_storage_content[64];
};

static void test_tlv_write_start_marker(struct test_tlv_write_start_marker_parameters parameters)
{
memcpy(TLV_RAM_STORAGE, parameters.initial_storage_content, 64);
int ret = tlv_write_start_marker(&parameters.tlv, parameters.write_data,
parameters.write_size);
zassert_equal(ret, parameters.expected_return);
zassert_mem_equal(TLV_RAM_STORAGE, parameters.final_storage_content, 64);
}
/* tlv lookup */
PARAMETRIZED_TEST(valid_ctx, test_tlv_lookup_0_ram_empty, test_tlv_lookup,
(struct test_tlv_lookup_parameters){
Expand Down Expand Up @@ -361,8 +402,72 @@ PARAMETRIZED_TEST(valid_ctx, test_tlv_write_floded_ff, test_tlv_write,
.final_storage_content = { 0x01, 0x1, 0x0, 0x4, 0x1, 0x2, 0x3, 0x4,
[8 ... 63] = 0xff } })

PARAMETRIZED_TEST(valid_ctx, test_tlv_write_floded_ff_magic, test_tlv_write,
(struct test_tlv_write_parameters){
.tlv = RAM_TLV_OBJECT_WITH_MAGIC,
.initial_storage_content = { [0 ... 63] = 0xff },
.tlv_type = 0x101,
.expected_return = 0,
.write_data = { 0x1, 0x2, 0x3, 0x4 },
.write_size = 4,
.final_storage_content = { [0 ... 7] = 0xff,
0x01,
0x1,
0x0,
0x4,
0x1,
0x2,
0x3,
0x4,
[16 ... 63] = 0xff } })

PARAMETRIZED_TEST(valid_ctx, test_tlv_read_start_marker_real, test_tlv_read_start_marker,
(struct test_tlv_read_start_marker_parameters){
.tlv = RAM_TLV_OBJECT_WITH_MAGIC,
.initial_storage_content = { 0x53, 0x49, 0x44, 0x30, 0x00, 0x00, 0x00,
0x08, [8 ... 63] = 0xff },
.expected_return = 0,
.expect_read_data = { 0x53, 0x49, 0x44, 0x30, 0x00, 0x00, 0x00, 0x08 },
.read_size = 8 })

PARAMETRIZED_TEST(valid_ctx, test_tlv_write_start_marker_real, test_tlv_write_start_marker,
(struct test_tlv_write_start_marker_parameters){
.tlv = RAM_TLV_OBJECT_WITH_MAGIC,
.initial_storage_content = { [0 ... 63] = 0xff },
.write_data = { 0x53, 0x49, 0x44, 0x30, 0x00, 0x00, 0x00, 0x08 },
.write_size = 8,
.expected_return = 0,
.final_storage_content = { 0x53, 0x49, 0x44, 0x30, 0x00, 0x00, 0x00, 0x08,
[8 ... 63] = 0xff } })

PARAMETRIZED_TEST(valid_ctx, test_tlv_read_start_marker_real_nomem, test_tlv_read_start_marker,
(struct test_tlv_read_start_marker_parameters){
.tlv = RAM_TLV_OBJECT_WITH_MAGIC,
.initial_storage_content = { 0x53, 0x49, 0x44, 0x30, 0x00, 0x00, 0x00,
0x08, [8 ... 63] = 0xff },
.expected_return = -ENOMEM,
.expect_read_data = { 0x53, 0x49, 0x44, 0x30, 0x00, 0x00, 0x00, 0x08 },
.read_size = 5 })

PARAMETRIZED_TEST(valid_ctx, test_tlv_write_start_marker_real_nomem, test_tlv_write_start_marker,
(struct test_tlv_write_start_marker_parameters){
.tlv = RAM_TLV_OBJECT_WITH_MAGIC,
.initial_storage_content = { [0 ... 63] = 0xff },
.write_data = { 0x53, 0x49, 0x44, 0x30, 0x00, 0x00, 0x00, 0x08 },
.write_size = 12,
.expected_return = -ENOMEM,
.final_storage_content = { [0 ... 63] = 0xff } })
/* ctx not fully provided */

PARAMETRIZED_TEST(missing_read, test_tlv_read_start_marker_real, test_tlv_read_start_marker,
(struct test_tlv_read_start_marker_parameters){
.tlv = RAM_TLV_OBJECT_NO_READ,
.initial_storage_content = { 0x53, 0x49, 0x44, 0x30, 0x00, 0x00, 0x00,
0x08, [8 ... 63] = 0xff },
.expected_return = -EINVAL,
.expect_read_data = { 0 },
.read_size = 8 })

PARAMETRIZED_TEST(missing_read, test_tlv_lookup_1_filled, test_tlv_lookup,
(struct test_tlv_lookup_parameters){
.tlv = RAM_TLV_OBJECT_NO_READ,
Expand Down Expand Up @@ -392,6 +497,15 @@ PARAMETRIZED_TEST(missing_read, test_tlv_write_empty, test_tlv_write,
.write_size = 3,
})

PARAMETRIZED_TEST(missing_write, test_tlv_write_start_marker_real, test_tlv_write_start_marker,
(struct test_tlv_write_start_marker_parameters){
.tlv = RAM_TLV_OBJECT_NO_WRITE,
.initial_storage_content = { [0 ... 63] = 0xff },
.write_data = { 0x53, 0x49, 0x44, 0x30, 0x00, 0x00, 0x00, 0x08 },
.write_size = 8,
.expected_return = -EINVAL,
.final_storage_content = { [0 ... 63] = 0xff } })

PARAMETRIZED_TEST(missing_write, test_tlv_lookup_1_filled, test_tlv_lookup,
(struct test_tlv_lookup_parameters){
.tlv = RAM_TLV_OBJECT_NO_WRITE,
Expand Down
32 changes: 29 additions & 3 deletions utils/include/tlv/tlv.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@ typedef struct tlv_ctx {
tlv_storage_write_t write;
tlv_storage_read_t read;
} storage;
uint32_t first_entry_offset;
uint32_t last_valid_offset;
/*starting offset of the tlv memory region, including storage marker*/
uint32_t start_offset;
/*first offset outside valid memory range, that can not be written*/
uint32_t end_offset;
/* size of starting marker, after the marker the first tlv entry is stored.*/
uint32_t tlv_storage_start_marker_size;
} tlv_ctx;

typedef uint16_t tlv_type;
Expand All @@ -54,6 +58,28 @@ typedef struct {
tlv_size payload_size;
} tlv_header;

/**
* @brief read the header of the TLV storage
* The header usually contains some magic value that signal start of data
*
* @param ctx tlv context
* @param data [OUT] content of header
* @param data_size size of the header to read, need to match the size passed in ctx
* @return int 0 on success, negative in case of error
*/
int tlv_read_start_marker(tlv_ctx *ctx, uint8_t *data, uint8_t data_size);

/**
* @brief Write the header of the TLV storage
* The header usually contains some magic value that signal start of data
*
* @param ctx tlv context
* @param data [IN] content of header
* @param data_size size of the header to read, need to match the size passed in ctx
* @return int 0 on success, negative in case of error
*/
int tlv_write_start_marker(tlv_ctx *ctx, uint8_t *data, uint8_t data_size);

/**
* @brief Find TLV header
*
Expand Down Expand Up @@ -94,4 +120,4 @@ int tlv_read(tlv_ctx *ctx, tlv_type type, uint8_t *data, uint16_t data_size);
* -ENOMEM when can not fit data in storage
* other errors are passed from storage handlers.
*/
int tlv_write(tlv_ctx *ctx, tlv_type type, uint8_t *data, uint16_t data_size);
int tlv_write(tlv_ctx *ctx, tlv_type type, const uint8_t *data, uint16_t data_size);
47 changes: 36 additions & 11 deletions utils/tlv/tlv.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ int tlv_lookup(tlv_ctx *ctx, tlv_type type, tlv_header *lookup_data)
return -EINVAL;
}

for (uint32_t offset = ctx->first_entry_offset;
(offset + sizeof(tlv_header)) <= ctx->last_valid_offset;) {
for (uint32_t offset = ctx->start_offset + ctx->tlv_storage_start_marker_size;
(offset + sizeof(tlv_header)) <= ctx->end_offset;) {
uint8_t header_raw[4];
int ret =
ctx->storage.read(ctx->storage.ctx, offset, header_raw, sizeof(header_raw));
Expand All @@ -43,7 +43,9 @@ int tlv_lookup(tlv_ctx *ctx, tlv_type type, tlv_header *lookup_data)
tlv_header header = bytes_to_header(header_raw);
offset += sizeof(header);
if (header.type == type) {
*lookup_data = header;
if (lookup_data) {
*lookup_data = header;
}
return 0;
}

Expand All @@ -58,8 +60,8 @@ int tlv_read(tlv_ctx *ctx, tlv_type type, uint8_t *data, uint16_t data_size)
return -EINVAL;
}

for (uint32_t offset = ctx->first_entry_offset;
(offset + sizeof(tlv_header)) <= ctx->last_valid_offset;) {
for (uint32_t offset = ctx->start_offset + ctx->tlv_storage_start_marker_size;
(offset + sizeof(tlv_header)) <= ctx->end_offset;) {
uint8_t header_raw[4];
int ret =
ctx->storage.read(ctx->storage.ctx, offset, header_raw, sizeof(header_raw));
Expand All @@ -72,7 +74,7 @@ int tlv_read(tlv_ctx *ctx, tlv_type type, uint8_t *data, uint16_t data_size)

if (header.type == type) {
if (data_size <= header.payload_size.data_size) {
if (offset + data_size > ctx->last_valid_offset) {
if (offset + data_size > ctx->end_offset) {
return -ENODATA;
}
return ctx->storage.read(ctx->storage.ctx, offset, data, data_size);
Expand All @@ -87,9 +89,10 @@ int tlv_read(tlv_ctx *ctx, tlv_type type, uint8_t *data, uint16_t data_size)
static uint32_t get_next_free_offset(tlv_ctx *ctx)
{
if (ctx->storage.read == NULL) {
return ctx->last_valid_offset;
return ctx->end_offset;
}
for (uint32_t offset = ctx->first_entry_offset; offset <= ctx->last_valid_offset;) {
for (uint32_t offset = ctx->start_offset + ctx->tlv_storage_start_marker_size;
offset <= ctx->end_offset;) {
uint8_t header_raw[4];
int ret =
ctx->storage.read(ctx->storage.ctx, offset, header_raw, sizeof(header_raw));
Expand All @@ -103,17 +106,17 @@ static uint32_t get_next_free_offset(tlv_ctx *ctx)
offset += sizeof(header_raw);
offset += header.payload_size.data_size + header.payload_size.padding;
}
return ctx->last_valid_offset;
return ctx->end_offset;
}

int tlv_write(tlv_ctx *ctx, tlv_type type, uint8_t *data, uint16_t data_size)
int tlv_write(tlv_ctx *ctx, tlv_type type, const uint8_t *data, uint16_t data_size)
{
if (ctx == NULL || ctx->storage.read == NULL || ctx->storage.write == NULL) {
return -EINVAL;
}

uint32_t next_free_offset = get_next_free_offset(ctx);
if (ctx->last_valid_offset <
if (ctx->end_offset <
(next_free_offset + sizeof(tlv_header) + data_size + CALCULATE_PADDING(data_size))) {
return -ENOMEM;
}
Expand Down Expand Up @@ -148,3 +151,25 @@ int tlv_write(tlv_ctx *ctx, tlv_type type, uint8_t *data, uint16_t data_size)
}
return 0;
}

int tlv_read_start_marker(tlv_ctx *ctx, uint8_t *data, uint8_t data_size)
{
if (ctx == NULL || ctx->storage.read == NULL) {
return -EINVAL;
}
if (data_size != ctx->tlv_storage_start_marker_size) {
return -ENOMEM;
}
return ctx->storage.read(ctx->storage.ctx, ctx->start_offset, data, data_size);
}

int tlv_write_start_marker(tlv_ctx *ctx, uint8_t *data, uint8_t data_size)
{
if (ctx == NULL || ctx->storage.write == NULL) {
return -EINVAL;
}
if (data_size != ctx->tlv_storage_start_marker_size) {
return -ENOMEM;
}
return ctx->storage.write(ctx->storage.ctx, ctx->start_offset, data, data_size);
}

0 comments on commit 003f3a0

Please sign in to comment.