Import Mbed OS hard-float snapshot

This commit is contained in:
Beslan
2026-06-01 20:15:04 +03:00
commit d3738e2f89
16278 changed files with 10628036 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "stdint.h"
#include "ip_fsc.h"
/** \brief Compute IP checksum for arbitary data
*
* Compute an IP checksum, given a arbitrary gather list.
*
* See ipv6_fcf for discussion of use.
*
* This will work for any arbitrary gather list - it can handle odd
* alignments. The one limitation is that the 32-bit accumulator limits
* it to basically 64K of total data.
*/
uint16_t ip_fcf_v(uint_fast8_t count, const ns_iovec_t vec[static count])
{
uint_fast32_t acc32 = 0;
bool odd = false;
while (count) {
const uint8_t *data_ptr = vec->iov_base;
uint_fast16_t data_length = vec->iov_len;
if (odd && data_length > 0) {
acc32 += *data_ptr++;
data_length--;
odd = false;
}
while (data_length >= 2) {
acc32 += (uint_fast16_t) data_ptr[0] << 8 | data_ptr[1];
data_ptr += 2;
data_length -= 2;
}
if (data_length) {
acc32 += (uint_fast16_t) data_ptr[0] << 8;
odd = true;
}
vec++;
count--;
}
// Fold down up to 0xffff carries in the 32-bit accumulator
acc32 = (acc32 >> 16) + (acc32 & 0xffff);
// Could be one more carry from the previous addition (result <= 0x1fffe)
uint16_t sum16 = (uint16_t)((acc32 >> 16) + (acc32 & 0xffff));
return ~sum16;
}
/** \brief Compute IPv6 checksum
*
* Compute an IPv6 checksum, given fields of an IPv6 pseudoheader and payload.
*
* This returns the 1's-complement of the checksum, as required when
* generating the checksum for transmission. The result can be 0x0000;
* for UDP (only) this must be transformed to 0xFFFF to distinguish from
* a packet with no checksum.
*
* To check a packet, this function will return 0 when run on a
* packet with a valid checksum. Checksums should be checked like this rather
* than setting the checksum field to zero and comparing generated checksum with
* the original value - this would fail in the case the received packet had
* checksum 0xFFFF.
*/
uint16_t ipv6_fcf(const uint8_t src_address[static 16], const uint8_t dest_address[static 16],
uint16_t data_length, const uint8_t data_ptr[static data_length], uint8_t next_protocol)
{
// Use gather vector to lay out IPv6 pseudo-header (RFC 2460) and data
uint8_t hdr_data[] = { data_length >> 8, data_length, 0, next_protocol };
ns_iovec_t vec[4] = {
{ (void *) src_address, 16 },
{ (void *) dest_address, 16 },
{ hdr_data, 4 },
{ (void *) data_ptr, data_length }
};
return ip_fcf_v(4, vec);
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Most functions can be inlined, and definitions are in common_functions.h.
* Define COMMON_FUNCTIONS_FN before including it to generate external definitions.
*/
#define COMMON_FUNCTIONS_FN extern
#include "common_functions.h"
#include <string.h>
/* Returns mask for <split_value> (0-8) most-significant bits of a byte */
static inline uint8_t context_split_mask(uint_fast8_t split_value)
{
return (uint8_t) - (0x100u >> split_value);
}
bool bitsequal(const uint8_t *a, const uint8_t *b, uint_fast8_t bits)
{
uint_fast8_t bytes = bits / 8;
bits %= 8;
if (bytes && memcmp(a, b, bytes)) {
return false;
}
if (bits) {
uint_fast8_t split_bit = context_split_mask(bits);
if ((a[bytes] & split_bit) != (b[bytes] & split_bit)) {
return false;
}
}
return true;
}
uint8_t *bitcopy(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits)
{
uint_fast8_t bytes = bits / 8;
bits %= 8;
if (bytes) {
dst = (uint8_t *) memcpy(dst, src, bytes) + bytes;
src += bytes;
}
if (bits) {
uint_fast8_t split_bit = context_split_mask(bits);
*dst = (*src & split_bit) | (*dst & ~ split_bit);
}
return dst;
}
uint8_t *bitcopy0(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits)
{
uint_fast8_t bytes = bits / 8;
bits %= 8;
if (bytes) {
dst = (uint8_t *) memcpy(dst, src, bytes) + bytes;
src += bytes;
}
if (bits) {
uint_fast8_t split_bit = context_split_mask(bits);
*dst = (*src & split_bit);
}
return dst;
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* All functions can be inlined, and definitions are in ns_list.h.
* Define NS_LIST_FN before including it to generate external definitions.
*/
#define NS_LIST_FN extern
#include "ns_list.h"

View File

@@ -0,0 +1,16 @@
/*
* Copyright (c) 2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
egrep -hr '^#define' ../../../../ |sed -n 's/\#define\s*TRACE_GROUP_[^\s]*\s*\"\([^\"]*\)\"/\1/p' > groups.txt

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2014-2018 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include "common_functions.h"
#include "ip4string.h"
static void ipv4_itoa(char *string, uint8_t byte);
/**
* Print binary IPv4 address to a string.
* String must contain enough room for full address, 16 bytes exact.
* \param addr IPv4 address.
* \p buffer to write string to.
*/
uint_fast8_t ip4tos(const void *ip4addr, char *p)
{
uint_fast8_t outputPos = 0;
const uint8_t *byteArray = ip4addr;
for (uint_fast8_t component = 0; component < 4; ++component) {
//Convert the byte to string
ipv4_itoa(&p[outputPos], byteArray[component]);
//Move outputPos to the end of the string
while (p[outputPos] != '\0') {
outputPos += 1;
}
//Append a dot if this is not the last digit
if (component < 3) {
p[outputPos++] = '.';
}
}
// Return length of generated string, excluding the terminating null character
return outputPos;
}
static void ipv4_itoa(char *string, uint8_t byte)
{
char *baseString = string;
//Write the digits to the buffer from the least significant to the most
// This is the incorrect order but we will swap later
do {
*string++ = '0' + byte % 10;
byte /= 10;
} while (byte);
//We put the final \0, then go back one step on the last digit for the swap
*string-- = '\0';
//We now swap the digits
while (baseString < string) {
uint8_t tmp = *string;
*string-- = *baseString;
*baseString++ = tmp;
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2014-2018 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include "common_functions.h"
#include "ip4string.h"
/**
* Convert numeric IPv4 address string to a binary.
* \param ip4addr IPv4 address in string format.
* \param len Length of IPv4 string, maximum of 16..
* \param dest buffer for address. MUST be 4 bytes.
* \return boolean set to true if conversion succeded, false if it didn't
*/
bool stoip4(const char *ip4addr, size_t len, void *dest)
{
uint8_t *addr = dest;
if (len > 16) { // Too long, not possible
return false;
}
uint_fast8_t stringLength = 0, byteCount = 0;
//Iterate over each component of the IP. The exit condition is in the middle of the loop
while (true) {
//No valid character (IPv4 addresses don't have implicit 0, that is x.y..z being read as x.y.0.z)
if (stringLength == len || ip4addr[stringLength] < '0' || ip4addr[stringLength] > '9') {
return false;
}
//For each component, we convert it to the raw value
uint_fast16_t byte = 0;
while (stringLength < len && ip4addr[stringLength] >= '0' && ip4addr[stringLength] <= '9') {
byte *= 10;
byte += ip4addr[stringLength++] - '0';
//We go over the maximum value for an IPv4 component
if (byte > 0xff) {
return false;
}
}
//Append the component
addr[byteCount++] = (uint8_t) byte;
//If we're at the end, we leave the loop. It's the only way to reach the `true` output
if (byteCount == 4) {
break;
}
//If the next character is invalid, we return false
if (stringLength == len || ip4addr[stringLength++] != '.') {
return false;
}
}
return stringLength == len || ip4addr[stringLength] == '\0';
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include "common_functions.h"
#include "ip6string.h"
/**
* Print binary IPv6 address to a string.
* String must contain enough room for full address, 40 bytes exact.
* IPv4 tunneling addresses are not covered.
* \param addr IPv6 address.
* \p buffer to write string to.
*/
uint_fast8_t ip6tos(const void *ip6addr, char *p)
{
char *p_orig = p;
uint_fast8_t zero_start = 255, zero_len = 1;
const uint8_t *addr = ip6addr;
uint_fast16_t part;
/* Follow RFC 5952 - pre-scan for longest run of zeros */
for (uint_fast8_t n = 0; n < 8; n++) {
part = *addr++;
part = (part << 8) | *addr++;
if (part != 0) {
continue;
}
/* We're at the start of a run of zeros - scan to non-zero (or end) */
uint_fast8_t n0 = n;
for (n = n0 + 1; n < 8; n++) {
part = *addr++;
part = (part << 8) | *addr++;
if (part != 0) {
break;
}
}
/* Now n0->initial zero of run, n->after final zero in run. Is this the
* longest run yet? If equal, we stick with the previous one - RFC 5952
* S4.2.3. Note that zero_len being initialised to 1 stops us
* shortening a 1-part run (S4.2.2.)
*/
if (n - n0 > zero_len) {
zero_start = n0;
zero_len = n - n0;
}
/* Continue scan for initial zeros from part n+1 - we've already
* consumed part n, and know it's non-zero. */
}
/* Now go back and print, jumping over any zero run */
addr = ip6addr;
for (uint_fast8_t n = 0; n < 8;) {
if (n == zero_start) {
if (n == 0) {
*p++ = ':';
}
*p++ = ':';
addr += 2 * zero_len;
n += zero_len;
continue;
}
part = *addr++;
part = (part << 8) | *addr++;
n++;
p += sprintf(p, "%"PRIxFAST16, part);
/* One iteration writes "part:" rather than ":part", and has the
* explicit check for n == 8 below, to allow easy extension for
* IPv4-in-IPv6-type addresses ("xxxx::xxxx:a.b.c.d"): we'd just
* run the same loop for 6 parts, and output would then finish with the
* required : or ::, ready for "a.b.c.d" to be tacked on.
*/
if (n != 8) {
*p++ = ':';
}
}
*p = '\0';
// Return length of generated string, excluding the terminating null character
return p - p_orig;
}
uint_fast8_t ip6_prefix_tos(const void *prefix, uint_fast8_t prefix_len, char *p)
{
char *wptr = p;
uint8_t addr[16] = {0};
if (prefix_len > 128) {
return 0;
}
// Generate prefix part of the string
bitcopy(addr, prefix, prefix_len);
wptr += ip6tos(addr, wptr);
// Add the prefix length part of the string
wptr += sprintf(wptr, "/%"PRIuFAST8, prefix_len);
// Return total length of generated string
return wptr - p;
}

View File

@@ -0,0 +1,180 @@
/*
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include "common_functions.h"
#include "ip6string.h"
static uint16_t hex(const char *p);
static bool is_hex(char c);
/**
* Convert numeric IPv6 address string to a binary.
* IPv4 tunnelling addresses are not covered.
* \param ip6addr IPv6 address in string format.
* \param len Length of ipv6 string.
* \param dest buffer for address. MUST be 16 bytes.
* \return boolean set to true if conversion succeed, false if it didn't
*/
bool stoip6(const char *ip6addr, size_t len, void *dest)
{
uint8_t *addr;
const char *p, *q;
int_fast8_t field_no, coloncolon = -1;
addr = dest;
if (len > 39) { // Too long, not possible. We do not support IPv4-mapped IPv6 addresses
goto error;
}
// First go forward the string, until end, noting :: position if any
// We're decrementing `len` as we go forward, and stop when it reaches 0
for (field_no = 0, p = ip6addr; len && *p; p = q + 1) {
for (q = p; len && *q && (*q != ':'); len -= 1) { // Seek for ':' or end
if (!is_hex(*q++)) { // There must only be hex characters besides ':'
goto error;
}
}
if ((q - p) > 4) { // We can't have more than 4 hex digits per segment
goto error;
}
if (field_no == 8) { // If the address goes farther than 8 segments
goto error;
}
// Convert and write this part, (high-endian AKA network byte order)
addr = common_write_16_bit(hex(p), addr);
field_no++;
// We handle the colons
if (len) {
// Check if we reached "::"
if (q[0] == ':' && q[1] == ':') {
if (coloncolon != -1) { // We are not supposed to see "::" more than once per address
goto error;
}
coloncolon = field_no;
q++;
len -= 2;
} else {
len -= 1;
}
}
}
if (coloncolon != -1) {
/* Insert zeros in the appropriate place */
uint_fast8_t head_size = 2 * coloncolon;
uint_fast8_t inserted_size = 2 * (8 - field_no);
uint_fast8_t tail_size = 16 - head_size - inserted_size;
addr = dest;
memmove(addr + head_size + inserted_size, addr + head_size, tail_size);
memset(addr + head_size, 0, inserted_size);
} else if (field_no != 8) { // Report an error if we didn't get 8 fields
goto error;
}
return true;
error:
// Fill the output buffer with 0 so we stick to the old failure behavior.
// We are however more agressive and wipe the entire address, and do so more often.
memset(dest, 0, 16);
return false;
}
unsigned char sipv6_prefixlength(const char *ip6addr)
{
char *ptr = strchr(ip6addr, '/');
if (ptr) {
return (unsigned char)strtoul(ptr + 1, 0, 10);
}
return 0;
}
int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out)
{
size_t addr_len, total_len;
int_fast16_t prefix_length;
if (prefix_len_out) {
*prefix_len_out = -1;
}
total_len = addr_len = strlen(ip6addr);
const char *ptr = strchr(ip6addr, '/');
if (ptr) {
addr_len = ptr - ip6addr;
if (prefix_len_out) {
if (total_len - addr_len > 3) {
/* too many digits in prefix */
return -1;
}
prefix_length = strtoul(ptr + 1, 0, 10);
if (prefix_length < 0 || prefix_length > 128) {
/* prefix value illegal */
return -1;
}
*prefix_len_out = prefix_length;
}
}
if (!stoip6(ip6addr, addr_len, dest)) {
/* parser failure */
return -1;
}
return 0;
}
static bool is_hex(char c)
{
// 'A' (0x41) and 'a' (0x61) are mapped in the ASCII table in such a way that masking the 0x20 bit turn 'a' in 'A'
if ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'F') {
return true;
}
if (c >= '0' && c <= '9') {
return true;
}
return false;
}
static uint16_t hex(const char *p)
{
uint16_t val = 0;
for (;;) {
char c = *p++;
if ((c >= '0') && (c <= '9')) {
val = (val << 4) | (c - '0');
} else if ((c >= 'A') && (c <= 'F')) {
val = (val << 4) | (10 + (c - 'A'));
} else if ((c >= 'a') && (c <= 'f')) {
val = (val << 4) | (10 + (c - 'a'));
} else {
break; // Non hex character
}
}
return val;
}

View File

@@ -0,0 +1,640 @@
/*
* Copyright (c) 2014-2019 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#include <string.h>
#include "nsdynmemLIB.h"
#include "platform/arm_hal_interrupt.h"
#include <stdlib.h>
#include "ns_list.h"
#ifndef STANDARD_MALLOC
typedef enum mem_stat_update_t {
DEV_HEAP_ALLOC_OK,
DEV_HEAP_ALLOC_FAIL,
DEV_HEAP_FREE,
} mem_stat_update_t;
typedef struct {
ns_list_link_t link;
} hole_t;
typedef int ns_mem_word_size_t; // internal signed heap block size type
// Amount of memory regions
#define REGION_COUNT 3
/* struct for book keeping variables */
struct ns_mem_book {
ns_mem_word_size_t *heap_main[REGION_COUNT];
ns_mem_word_size_t *heap_main_end[REGION_COUNT];
mem_stat_t *mem_stat_info_ptr;
void (*heap_failure_callback)(heap_fail_t);
NS_LIST_HEAD(hole_t, link) holes_list;
ns_mem_heap_size_t heap_size;
ns_mem_heap_size_t temporary_alloc_heap_limit; /* Amount of reserved heap temporary alloc can't exceed */
};
static ns_mem_book_t *default_book; // heap pointer for original "ns_" API use
// size of a hole_t in our word units
#define HOLE_T_SIZE ((ns_mem_word_size_t) ((sizeof(hole_t) + sizeof(ns_mem_word_size_t) - 1) / sizeof(ns_mem_word_size_t)))
#define TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD 5 /* temporary allocations must leave 5% of the heap free */
static NS_INLINE hole_t *hole_from_block_start(ns_mem_word_size_t *start)
{
return (hole_t *)(start + 1);
}
static NS_INLINE ns_mem_word_size_t *block_start_from_hole(hole_t *start)
{
return ((ns_mem_word_size_t *)start) - 1;
}
static void heap_failure(ns_mem_book_t *book, heap_fail_t reason)
{
if (book->heap_failure_callback) {
book->heap_failure_callback(reason);
}
}
static int ns_dyn_mem_region_find(ns_mem_book_t *book, ns_mem_word_size_t *block_ptr, ns_mem_word_size_t size)
{
int index;
for (index = 0; index < REGION_COUNT; index++) {
if (book->heap_main[index] != 0) {
if ((block_ptr >= book->heap_main[index]) &&
(block_ptr < book->heap_main_end[index]) &&
((block_ptr + size) < book->heap_main_end[index])) {
return index;
}
}
}
return -1;
}
static int ns_dyn_mem_region_save(ns_mem_book_t *book, ns_mem_word_size_t *region_start_ptr, ns_mem_word_size_t region_size)
{
for (int i = 1; i < REGION_COUNT; i++) {
if (book->heap_main[i] == 0) {
book->heap_main[i] = region_start_ptr;
book->heap_main_end[i] = book->heap_main[i] + region_size;
return 0;
}
}
return -1;
}
#endif //STANDARD_MALLOC
void ns_dyn_mem_init(void *heap, ns_mem_heap_size_t h_size,
void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr)
{
default_book = ns_mem_init(heap, h_size, passed_fptr, info_ptr);
}
int ns_dyn_mem_region_add(void *region_ptr, ns_mem_heap_size_t region_size)
{
return ns_mem_region_add(default_book, region_ptr, region_size);
}
const mem_stat_t *ns_dyn_mem_get_mem_stat(void)
{
#ifndef STANDARD_MALLOC
return ns_mem_get_mem_stat(default_book);
#else
return NULL;
#endif
}
ns_mem_book_t *ns_mem_init(void *heap, ns_mem_heap_size_t h_size,
void (*passed_fptr)(heap_fail_t),
mem_stat_t *info_ptr)
{
#ifndef STANDARD_MALLOC
ns_mem_book_t *book;
ns_mem_word_size_t *ptr;
ns_mem_word_size_t temp_int;
/* Do memory alignment */
temp_int = ((uintptr_t)heap % sizeof(ns_mem_word_size_t));
if (temp_int) {
heap = (uint8_t *) heap + (sizeof(ns_mem_word_size_t) - temp_int);
h_size -= (sizeof(ns_mem_word_size_t) - temp_int);
}
/* Make correction for total length also */
temp_int = (h_size % sizeof(ns_mem_word_size_t));
if (temp_int) {
h_size -= (sizeof(ns_mem_word_size_t) - temp_int);
}
book = heap;
memset(book->heap_main, 0, REGION_COUNT * sizeof(ns_mem_word_size_t *));
memset(book->heap_main_end, 0, REGION_COUNT * sizeof(ns_mem_word_size_t *));
book->heap_main[0] = (ns_mem_word_size_t *) & (book[1]); // SET Heap Pointer
book->heap_size = h_size - sizeof(ns_mem_book_t); //Set Heap Size
temp_int = (book->heap_size / sizeof(ns_mem_word_size_t));
temp_int -= 2;
ptr = book->heap_main[0];
*ptr = -(temp_int);
ptr += (temp_int + 1);
*ptr = -(temp_int);
book->heap_main_end[0] = ptr;
ns_list_init(&book->holes_list);
ns_list_add_to_start(&book->holes_list, hole_from_block_start(book->heap_main[0]));
book->mem_stat_info_ptr = info_ptr;
//RESET Memory by Hea Len
if (info_ptr) {
memset(book->mem_stat_info_ptr, 0, sizeof(mem_stat_t));
book->mem_stat_info_ptr->heap_sector_size = book->heap_size;
}
book->temporary_alloc_heap_limit = book->heap_size / 100 * (100 - TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD);
#endif
//There really is no support to standard malloc in this library anymore
book->heap_failure_callback = passed_fptr;
return book;
}
int ns_mem_region_add(ns_mem_book_t *book, void *region_ptr, ns_mem_heap_size_t region_size)
{
#ifndef STANDARD_MALLOC
if (!book || !region_ptr || region_size < 3 * sizeof(ns_mem_word_size_t)) {
return -1;
}
ns_mem_word_size_t *block_ptr;
ns_mem_word_size_t temp_int;
/* Do memory alignment */
temp_int = ((uintptr_t)region_ptr % sizeof(ns_mem_word_size_t));
if (temp_int) {
region_ptr = (uint8_t *) region_ptr + (sizeof(ns_mem_word_size_t) - temp_int);
region_size -= (sizeof(ns_mem_word_size_t) - temp_int);
}
/* Make correction for total length */
temp_int = (region_size % sizeof(ns_mem_word_size_t));
if (temp_int) {
region_size -= (sizeof(ns_mem_word_size_t) - temp_int);
}
// Create hole from new heap memory
temp_int = (region_size / sizeof(ns_mem_word_size_t));
temp_int -= 2;
block_ptr = region_ptr;
*block_ptr = -(temp_int);
block_ptr += (temp_int + 1); // now block_ptr points to end of block
*block_ptr = -(temp_int);
// find place for the new hole from the holes list
hole_t *hole_to_add = hole_from_block_start(region_ptr);
hole_t *previous_hole = NULL;
ns_list_foreach(hole_t, hole_in_list_ptr, &book->holes_list) {
if (hole_in_list_ptr < hole_to_add) {
previous_hole = hole_in_list_ptr;
} else if (hole_in_list_ptr == hole_to_add) {
// trying to add memory block that is already in the list!
return -2;
}
}
// save region
if (ns_dyn_mem_region_save(book, region_ptr, (region_size / (sizeof(ns_mem_word_size_t))) - 1) != 0) {
return -3;
}
// Add new hole to the list
if (previous_hole) {
ns_list_add_after(&book->holes_list, previous_hole, hole_to_add);
} else {
ns_list_add_to_start(&book->holes_list, hole_to_add);
}
// adjust total heap size with new hole
book->heap_size += region_size;
if (book->mem_stat_info_ptr) {
book->mem_stat_info_ptr->heap_sector_size = book->heap_size;
}
// adjust temporary allocation limits to match new heap
book->temporary_alloc_heap_limit = book->heap_size / 100 * (100 - TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD);
return 0;
#else
(void) book;
(void) region_ptr;
(void) region_size;
return -1;
#endif
}
const mem_stat_t *ns_mem_get_mem_stat(ns_mem_book_t *heap)
{
#ifndef STANDARD_MALLOC
return heap->mem_stat_info_ptr;
#else
return NULL;
#endif
}
int ns_mem_set_temporary_alloc_free_heap_threshold(ns_mem_book_t *book, uint8_t free_heap_percentage, ns_mem_heap_size_t free_heap_amount)
{
#ifndef STANDARD_MALLOC
ns_mem_heap_size_t heap_limit = 0;
if (!book || !book->mem_stat_info_ptr) {
// no book or mem_stats
return -1;
}
if (free_heap_amount && free_heap_amount < book->heap_size / 2) {
heap_limit = book->heap_size - free_heap_amount;
}
if (!free_heap_amount && free_heap_percentage && free_heap_percentage < 50) {
heap_limit = book->heap_size / 100 * (100 - free_heap_percentage);
}
if (free_heap_amount == 0 && free_heap_percentage == 0) {
// feature disabled, allow whole heap to be reserved by temporary allo
heap_limit = book->heap_size;
}
if (heap_limit == 0) {
// illegal heap parameters
return -2;
}
book->temporary_alloc_heap_limit = heap_limit;
return 0;
#else
return -3;
#endif
}
extern int ns_dyn_mem_set_temporary_alloc_free_heap_threshold(uint8_t free_heap_percentage, ns_mem_heap_size_t free_heap_amount)
{
return ns_mem_set_temporary_alloc_free_heap_threshold(default_book, free_heap_percentage, free_heap_amount);
}
#ifndef STANDARD_MALLOC
static void dev_stat_update(mem_stat_t *mem_stat_info_ptr, mem_stat_update_t type, ns_mem_block_size_t size)
{
if (mem_stat_info_ptr) {
switch (type) {
case DEV_HEAP_ALLOC_OK:
mem_stat_info_ptr->heap_sector_alloc_cnt++;
mem_stat_info_ptr->heap_sector_allocated_bytes += size;
if (mem_stat_info_ptr->heap_sector_allocated_bytes_max < mem_stat_info_ptr->heap_sector_allocated_bytes) {
mem_stat_info_ptr->heap_sector_allocated_bytes_max = mem_stat_info_ptr->heap_sector_allocated_bytes;
}
mem_stat_info_ptr->heap_alloc_total_bytes += size;
break;
case DEV_HEAP_ALLOC_FAIL:
mem_stat_info_ptr->heap_alloc_fail_cnt++;
break;
case DEV_HEAP_FREE:
mem_stat_info_ptr->heap_sector_alloc_cnt--;
mem_stat_info_ptr->heap_sector_allocated_bytes -= size;
break;
}
}
}
static ns_mem_word_size_t convert_allocation_size(ns_mem_book_t *book, ns_mem_block_size_t requested_bytes)
{
if (book->heap_main[0] == 0) {
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_UNITIALIZED);
} else if (requested_bytes < 1) {
heap_failure(book, NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID);
} else if (requested_bytes > (book->heap_size - 2 * sizeof(ns_mem_word_size_t))) {
heap_failure(book, NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID);
}
return (requested_bytes + sizeof(ns_mem_word_size_t) - 1) / sizeof(ns_mem_word_size_t);
}
// Checks that block length indicators are valid
// Block has format: Size of data area [1 word] | data area [abs(size) words]| Size of data area [1 word]
// If Size is negative it means area is unallocated
static int8_t ns_mem_block_validate(ns_mem_word_size_t *block_start)
{
int8_t ret_val = -1;
ns_mem_word_size_t *end = block_start;
ns_mem_word_size_t size_start = *end;
end += (1 + abs(size_start));
if (size_start != 0 && size_start == *end) {
ret_val = 0;
}
return ret_val;
}
#endif
// For direction, use 1 for direction up and -1 for down
static void *ns_mem_internal_alloc(ns_mem_book_t *book, const ns_mem_block_size_t alloc_size, int direction)
{
#ifndef STANDARD_MALLOC
if (!book) {
/* We can not do anything except return NULL because we can't find book
keeping block */
return NULL;
}
if (book->mem_stat_info_ptr && direction == 1) {
if (book->mem_stat_info_ptr->heap_sector_allocated_bytes > book->temporary_alloc_heap_limit) {
/* Not enough heap for temporary memory allocation */
dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0);
return NULL;
}
}
ns_mem_word_size_t *block_ptr = NULL;
platform_enter_critical();
ns_mem_word_size_t data_size = convert_allocation_size(book, alloc_size);
if (!data_size) {
goto done;
}
// ns_list_foreach, either forwards or backwards, result to ptr
for (hole_t *cur_hole = direction > 0 ? ns_list_get_first(&book->holes_list)
: ns_list_get_last(&book->holes_list);
cur_hole;
cur_hole = direction > 0 ? ns_list_get_next(&book->holes_list, cur_hole)
: ns_list_get_previous(&book->holes_list, cur_hole)
) {
ns_mem_word_size_t *p = block_start_from_hole(cur_hole);
if (ns_mem_block_validate(p) != 0 || *p >= 0) {
//Validation failed, or this supposed hole has positive (allocated) size
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
break;
}
if (-*p >= data_size) {
// Found a big enough block
block_ptr = p;
break;
}
}
if (!block_ptr) {
goto done;
}
// Separate declaration from initialization to keep IAR happy as the gotos skip this block.
ns_mem_word_size_t block_data_size;
block_data_size = -*block_ptr;
if (block_data_size >= (data_size + 2 + HOLE_T_SIZE)) {
ns_mem_word_size_t hole_size = block_data_size - data_size - 2;
ns_mem_word_size_t *hole_ptr;
//There is enough room for a new hole so create it first
if (direction > 0) {
hole_ptr = block_ptr + 1 + data_size + 1;
// Hole will be left at end of area.
// Would like to just replace this block_ptr with new descriptor, but
// they could overlap, so ns_list_replace might fail
//ns_list_replace(&holes_list, block_ptr, hole_from_block_start(hole_ptr));
hole_t *before = ns_list_get_previous(&book->holes_list, hole_from_block_start(block_ptr));
ns_list_remove(&book->holes_list, hole_from_block_start(block_ptr));
if (before) {
ns_list_add_after(&book->holes_list, before, hole_from_block_start(hole_ptr));
} else {
ns_list_add_to_start(&book->holes_list, hole_from_block_start(hole_ptr));
}
} else {
hole_ptr = block_ptr;
// Hole remains at start of area - keep existing descriptor in place.
block_ptr += 1 + hole_size + 1;
}
hole_ptr[0] = -hole_size;
hole_ptr[1 + hole_size] = -hole_size;
} else {
// Not enough room for a left-over hole, so use the whole block
data_size = block_data_size;
ns_list_remove(&book->holes_list, hole_from_block_start(block_ptr));
}
block_ptr[0] = data_size;
block_ptr[1 + data_size] = data_size;
done:
if (book->mem_stat_info_ptr) {
if (block_ptr) {
//Update Allocate OK
dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_OK, (data_size + 2) * sizeof(ns_mem_word_size_t));
} else {
//Update Allocate Fail, second parameter is used for stats
dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0);
}
}
platform_exit_critical();
return block_ptr ? block_ptr + 1 : NULL;
#else
void *retval = NULL;
if (alloc_size) {
platform_enter_critical();
retval = malloc(alloc_size);
platform_exit_critical();
}
return retval;
#endif
}
void *ns_mem_alloc(ns_mem_book_t *heap, ns_mem_block_size_t alloc_size)
{
return ns_mem_internal_alloc(heap, alloc_size, -1);
}
void *ns_mem_temporary_alloc(ns_mem_book_t *heap, ns_mem_block_size_t alloc_size)
{
return ns_mem_internal_alloc(heap, alloc_size, 1);
}
void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size)
{
return ns_mem_alloc(default_book, alloc_size);
}
void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size)
{
return ns_mem_temporary_alloc(default_book, alloc_size);
}
#ifndef STANDARD_MALLOC
static void ns_mem_free_and_merge_with_adjacent_blocks(ns_mem_book_t *book, ns_mem_word_size_t *cur_block, ns_mem_word_size_t data_size)
{
// Theory of operation: Block is always in form | Len | Data | Len |
// So we need to check length of previous (if current not heap start)
// and next (if current not heap end) blocks. Negative length means
// free memory so we can merge freed block with those.
hole_t *existing_start = NULL;
hole_t *existing_end = NULL;
ns_mem_word_size_t *start = cur_block;
ns_mem_word_size_t *end = cur_block + data_size + 1;
ns_mem_word_size_t *region_start;
ns_mem_word_size_t *region_end;
int region_index = ns_dyn_mem_region_find(book, cur_block, data_size);
if (region_index >= 0) {
region_start = book->heap_main[region_index];
region_end = book->heap_main_end[region_index];
} else {
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
// can't find region for the block, return
return;
}
//invalidate current block
*start = -data_size;
*end = -data_size;
ns_mem_word_size_t merged_data_size = data_size;
if (start != region_start) {
if (*(start - 1) < 0) {
ns_mem_word_size_t *block_end = start - 1;
ns_mem_word_size_t block_size = 1 + (-*block_end) + 1;
merged_data_size += block_size;
start -= block_size;
if (*start != *block_end) {
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
}
if (block_size >= 1 + HOLE_T_SIZE + 1) {
existing_start = hole_from_block_start(start);
}
}
}
if (end != region_end) {
if (*(end + 1) < 0) {
ns_mem_word_size_t *block_start = end + 1;
ns_mem_word_size_t block_size = 1 + (-*block_start) + 1;
merged_data_size += block_size;
end += block_size;
if (*end != *block_start) {
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
}
if (block_size >= 1 + HOLE_T_SIZE + 1) {
existing_end = hole_from_block_start(block_start);
}
}
}
hole_t *to_add = hole_from_block_start(start);
hole_t *before = NULL;
if (existing_end) {
// Extending hole described by "existing_end" downwards.
// Will replace with descriptor at bottom of merged block.
// (Can't use ns_list_replace, because of danger of overlap)
// Optimisation - note our position for insertion below.
before = ns_list_get_next(&book->holes_list, existing_end);
ns_list_remove(&book->holes_list, existing_end);
}
if (existing_start) {
// Extending hole described by "existing_start" upwards.
// No need to modify that descriptor - it remains at the bottom
// of the merged block to describe it.
} else {
// Didn't find adjacent descriptors, but may still
// be merging with small blocks without descriptors.
if (merged_data_size >= HOLE_T_SIZE) {
// Locate hole position in list, if we don't already know
// from merging with the block above.
if (!existing_end) {
ns_list_foreach(hole_t, ptr, &book->holes_list) {
if (ptr > to_add) {
before = ptr;
break;
}
}
}
if (before) {
ns_list_add_before(&book->holes_list, before, to_add);
} else {
ns_list_add_to_end(&book->holes_list, to_add);
}
}
}
*start = -merged_data_size;
*end = -merged_data_size;
}
#endif
static bool pointer_address_validate(ns_mem_book_t *book, ns_mem_word_size_t *ptr, ns_mem_word_size_t size)
{
if (ns_dyn_mem_region_find(book, ptr, size) >= 0) {
return true;
}
return false;
}
void ns_mem_free(ns_mem_book_t *book, void *block)
{
#ifndef STANDARD_MALLOC
if (!block) {
return;
}
ns_mem_word_size_t *ptr = block;
ns_mem_word_size_t size;
platform_enter_critical();
ptr --;
//Read Current Size
size = *ptr;
if (!pointer_address_validate(book, ptr, size)) {
heap_failure(book, NS_DYN_MEM_POINTER_NOT_VALID);
} else if (size < 0) {
heap_failure(book, NS_DYN_MEM_DOUBLE_FREE);
} else {
if (ns_mem_block_validate(ptr) != 0) {
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
} else {
ns_mem_free_and_merge_with_adjacent_blocks(book, ptr, size);
if (book->mem_stat_info_ptr) {
//Update Free Counter
dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_FREE, (size + 2) * sizeof(ns_mem_word_size_t));
}
}
}
platform_exit_critical();
#else
platform_enter_critical();
free(block);
platform_exit_critical();
#endif
}
void ns_dyn_mem_free(void *block)
{
ns_mem_free(default_book, block);
}

View File

@@ -0,0 +1,229 @@
// ----------------------------------------------------------------------------
// Copyright 2016-2017 ARM Ltd.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------------------------------------------------------
#include <string.h>
#include <ns_types.h>
#include <nsdynmemLIB.h>
#include "ns_list.h"
#include "platform/arm_hal_nvm.h"
#include "ns_nvm_helper.h"
#define TRACE_GROUP "nnvm"
/* NVM operations */
#define NS_NVM_NONE 0x00
#define NS_NVM_INIT 0x01
#define NS_NVM_KEY_CREATE 0x02
#define NS_NVM_KEY_READ 0x03
#define NS_NVM_KEY_WRITE 0x04
#define NS_NVM_FLUSH 0x05
#define NS_NVM_KEY_DELETE 0x06
typedef struct {
ns_nvm_callback *callback;
const char *client_key_name;
void *client_context;
int operation;
uint8_t *buffer;
uint16_t *buffer_len;
void *original_request;
ns_list_link_t link;
} ns_nvm_request_t;
static bool ns_nvm_initialized = false;
static bool ns_nvm_operation_in_progress = false;
static ns_nvm_request_t *ns_nvm_create_request(ns_nvm_callback *callback, void *context, const char *key_name, uint8_t *buf, uint16_t *buf_len, uint8_t operation);
static int ns_nvm_operation_start(ns_nvm_request_t *request);
static int ns_nvm_operation_continue(ns_nvm_request_t *request, bool free_request);
static void ns_nvm_operation_end(ns_nvm_request_t *ns_nvm_request_ptr, int client_retval);
static NS_LIST_DEFINE(ns_nvm_request_list, ns_nvm_request_t, link);
/*
* Callback from platform NVM adaptation
*/
void ns_nvm_callback_func(platform_nvm_status status, void *args)
{
ns_nvm_request_t *ns_nvm_request_ptr = (ns_nvm_request_t *)args;
int client_retval = NS_NVM_OK;
if (status == PLATFORM_NVM_ERROR) {
client_retval = NS_NVM_ERROR;
} else if (status == PLATFORM_NVM_KEY_NOT_FOUND) {
client_retval = NS_NVM_DATA_NOT_FOUND;
}
switch (ns_nvm_request_ptr->operation) {
case NS_NVM_INIT:
ns_nvm_operation_continue(ns_nvm_request_ptr->original_request, true);
ns_dyn_mem_free(ns_nvm_request_ptr);
break;
case NS_NVM_FLUSH:
case NS_NVM_KEY_READ:
ns_nvm_operation_end(ns_nvm_request_ptr, client_retval);
break;
case NS_NVM_KEY_CREATE:
if (status == PLATFORM_NVM_OK) {
ns_nvm_request_ptr->operation = NS_NVM_KEY_WRITE;
platform_nvm_write(ns_nvm_callback_func, ns_nvm_request_ptr->client_key_name, ns_nvm_request_ptr->buffer, ns_nvm_request_ptr->buffer_len, ns_nvm_request_ptr);
} else {
ns_nvm_operation_end(ns_nvm_request_ptr, client_retval);
}
break;
case NS_NVM_KEY_DELETE:
case NS_NVM_KEY_WRITE:
if (status == PLATFORM_NVM_OK) {
// write ok, flush the changes
ns_nvm_request_ptr->operation = NS_NVM_FLUSH;
platform_nvm_flush(ns_nvm_callback_func, ns_nvm_request_ptr);
} else {
// write failed, inform client
ns_nvm_operation_end(ns_nvm_request_ptr, client_retval);
}
break;
}
}
int ns_nvm_key_delete(ns_nvm_callback *callback, const char *key_name, void *context)
{
if (!callback || !key_name) {
return NS_NVM_ERROR;
}
ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(callback, context, key_name, NULL, NULL, NS_NVM_KEY_DELETE);
return ns_nvm_operation_start(ns_nvm_request_ptr);
}
int ns_nvm_data_read(ns_nvm_callback *callback, const char *key_name, uint8_t *buf, uint16_t *buf_len, void *context)
{
if (!callback || !key_name || !buf || !buf_len) {
return NS_NVM_ERROR;
}
ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(callback, context, key_name, buf, buf_len, NS_NVM_KEY_READ);
return ns_nvm_operation_start(ns_nvm_request_ptr);
}
int ns_nvm_data_write(ns_nvm_callback *callback, const char *key_name, uint8_t *buf, uint16_t *buf_len, void *context)
{
if (!callback || !key_name || !buf || !buf_len) {
return NS_NVM_ERROR;
}
ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(callback, context, key_name, buf, buf_len, NS_NVM_KEY_WRITE);
return ns_nvm_operation_start(ns_nvm_request_ptr);
}
static int ns_nvm_operation_start(ns_nvm_request_t *nvm_request)
{
int ret = NS_NVM_OK;
platform_nvm_status pnvm_status;
if (!nvm_request) {
return NS_NVM_MEMORY;
}
if (ns_nvm_initialized == true) {
// NVM already initialized, continue directly
if (!ns_nvm_operation_in_progress) {
ret = ns_nvm_operation_continue(nvm_request, true);
} else {
// add request to list and handle when existing calls has been handled.
ns_list_add_to_end(&ns_nvm_request_list, nvm_request);
}
} else {
ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(NULL, NULL, NULL, NULL, NULL, NS_NVM_INIT);
if (!ns_nvm_request_ptr) {
ns_dyn_mem_free(nvm_request);
ns_dyn_mem_free(ns_nvm_request_ptr);
return NS_NVM_MEMORY;
}
ns_nvm_request_ptr->original_request = nvm_request;
pnvm_status = platform_nvm_init(ns_nvm_callback_func, ns_nvm_request_ptr);
if (pnvm_status != PLATFORM_NVM_OK) {
ns_dyn_mem_free(nvm_request);
ns_dyn_mem_free(ns_nvm_request_ptr);
return NS_NVM_ERROR;
}
ns_list_init(&ns_nvm_request_list);
ns_nvm_initialized = true;
ns_nvm_operation_in_progress = true;
}
return ret;
}
static ns_nvm_request_t *ns_nvm_create_request(ns_nvm_callback *callback, void *context, const char *key_name, uint8_t *buf, uint16_t *buf_len, uint8_t operation)
{
ns_nvm_request_t *ns_nvm_request_ptr = ns_dyn_mem_temporary_alloc(sizeof(ns_nvm_request_t));
if (!ns_nvm_request_ptr) {
return NULL;
}
ns_nvm_request_ptr->client_context = context;
ns_nvm_request_ptr->callback = callback;
ns_nvm_request_ptr->client_key_name = key_name;
ns_nvm_request_ptr->operation = operation;
ns_nvm_request_ptr->buffer = buf;
ns_nvm_request_ptr->buffer_len = buf_len;
return ns_nvm_request_ptr;
}
static int ns_nvm_operation_continue(ns_nvm_request_t *request, bool free_request)
{
platform_nvm_status ret = PLATFORM_NVM_OK;
ns_nvm_operation_in_progress = true;
switch (request->operation) {
case NS_NVM_KEY_WRITE:
request->operation = NS_NVM_KEY_CREATE;
ret = platform_nvm_key_create(ns_nvm_callback_func, request->client_key_name, *request->buffer_len, 0, request);
break;
case NS_NVM_KEY_READ:
ret = platform_nvm_read(ns_nvm_callback_func, request->client_key_name, request->buffer, request->buffer_len, request);
break;
case NS_NVM_KEY_DELETE:
ret = platform_nvm_key_delete(ns_nvm_callback_func, request->client_key_name, request);
break;
}
if (ret != PLATFORM_NVM_OK) {
if (free_request == true) {
// free request if requested
ns_dyn_mem_free(request);
}
ns_nvm_operation_in_progress = false;
return NS_NVM_ERROR;
}
return NS_NVM_OK;
}
static void ns_nvm_operation_end(ns_nvm_request_t *ns_nvm_request_ptr, int client_retval)
{
ns_nvm_request_ptr->callback(client_retval, ns_nvm_request_ptr->client_context);
ns_dyn_mem_free(ns_nvm_request_ptr);
ns_nvm_operation_in_progress = false;
ns_list_foreach_safe(ns_nvm_request_t, pending_req, &ns_nvm_request_list) {
// there are pending requests to be processed
ns_list_remove(&ns_nvm_request_list, pending_req);
int ret = ns_nvm_operation_continue(pending_req, false);
if (ret != NS_NVM_OK) {
ns_nvm_operation_end(pending_req, ret);
} else {
break;
}
}
}