/* * Copyright (c) 2016-2022 Texas Instruments Incorporated - http://www.ti.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* * ======== memory.c ======== */ #if defined(__ti__) && !defined(__clang__) #pragma FUNC_EXT_CALLED(malloc); #pragma FUNC_EXT_CALLED(memalign); #pragma FUNC_EXT_CALLED(free); #pragma FUNC_EXT_CALLED(calloc); #pragma FUNC_EXT_CALLED(realloc); #pragma FUNC_EXT_CALLED(aligned_alloc); #define ATTRIBUTE #elif defined(__IAR_SYSTEMS_ICC__) #define ATTRIBUTE #else #define ATTRIBUTE __attribute__((used)) #endif #include #include #include #include #include #include #if defined(__GNUC__) && !defined(__ti__) #include #endif extern void * pvPortRealloc(void * pv, size_t size); /* * This Header is only needed to support advanced memory services - namely * realloc() and memalign(). If the user doesn't require those features, they * can remove the overhead and save both code and data. */ #if defined(TI_POSIX_FREERTOS_MEMORY_ENABLEADV) /* * Header is a union to make sure that the size is a power of 2. * * On the MSP430 small model (MSP430X), size_t is 2 bytes, which makes * the size of this struct 6 bytes. */ typedef union Header { struct { void * actualBuf; size_t size; } header; int pad[2]; /* 4 words on 28L, 8 bytes on most others */ } Header; #endif /* * ======== malloc ======== */ void ATTRIBUTE * malloc(size_t size) { #if defined(TI_POSIX_FREERTOS_MEMORY_ENABLEADV) Header * packet; size_t allocSize; allocSize = size + sizeof(Header); /* * If size is very large and allocSize overflows, the result will be * smaller than size. In this case, don't try to allocate. */ if ((size == 0) || (allocSize < size)) { errno = EINVAL; return (NULL); } packet = (Header *) pvPortMalloc(allocSize); if (packet == NULL) { errno = ENOMEM; return (NULL); } packet->header.actualBuf = (void *) packet; packet->header.size = allocSize; return (packet + 1); #else void * packet; if (size == 0) { errno = EINVAL; return (NULL); } packet = pvPortMalloc(size); if (packet == NULL) { errno = ENOMEM; return (NULL); } return (packet); #endif } /* * ======== calloc ======== */ void ATTRIBUTE * calloc(size_t nmemb, size_t size) { size_t nbytes; void * retval; /* guard against divide by zero exception below */ if (nmemb == 0) { errno = EINVAL; return (NULL); } nbytes = nmemb * size; /* return NULL if there's an overflow */ if (nmemb && size != (nbytes / nmemb)) { errno = EOVERFLOW; return (NULL); } retval = malloc(nbytes); if (retval != NULL) { (void) memset(retval, (int) '\0', nbytes); } return (retval); } #ifndef DeviceFamily_CC3220 /* * ======== realloc ======== */ void ATTRIBUTE * realloc(void * ptr, size_t size) { #if defined(TI_POSIX_FREERTOS_MEMORY_ENABLEADV) void * retval; Header * packet; size_t oldSize; if (ptr == NULL) { retval = malloc(size); } else if (size == 0) { errno = EINVAL; retval = NULL; } else { packet = (Header *) ptr - 1; retval = malloc(size); if (retval != NULL) { oldSize = packet->header.size - sizeof(Header); (void) memcpy(retval, ptr, (size < oldSize) ? size : oldSize); free(ptr); } } return (retval); #else void * packet; if (size == 0) { errno = EINVAL; return (NULL); } packet = pvPortRealloc(ptr, size); if (packet == NULL) { errno = ENOMEM; return (NULL); } return (packet); #endif } #else /* * ======== realloc ======== */ void ATTRIBUTE * realloc(void * ptr, size_t size) { #if defined(TI_POSIX_FREERTOS_MEMORY_ENABLEADV) void * retval; Header * packet; size_t oldSize; if (ptr == NULL) { retval = malloc(size); } else if (size == 0) { errno = EINVAL; retval = NULL; } else { packet = (Header *) ptr - 1; retval = malloc(size); if (retval != NULL) { oldSize = packet->header.size - sizeof(Header); (void) memcpy(retval, ptr, (size < oldSize) ? size : oldSize); free(ptr); } } return (retval); #else /* Unsupported implementation */ return (NULL); #endif } #endif /* * ======== free ======== */ void ATTRIBUTE free(void * ptr) { #if defined(TI_POSIX_FREERTOS_MEMORY_ENABLEADV) Header * packet; if (ptr != NULL) { packet = ((Header *) ptr) - 1; vPortFree(packet->header.actualBuf); } #else vPortFree(ptr); #endif } /* * ======== memalign ======== */ void ATTRIBUTE * memalign(size_t boundary, size_t size) { #if defined(TI_POSIX_FREERTOS_MEMORY_ENABLEADV) Header * packet; void * tmp; /* return NULL if size is 0, or alignment is not a power-of-2 */ if (size == 0 || (boundary & (boundary - 1))) { errno = EINVAL; return (NULL); } if (boundary < sizeof(Header)) { boundary = sizeof(Header); } /* * Allocate 'align + size + sizeof(Header)' so that we have room for * the 'packet' and can return an aligned buffer. */ tmp = pvPortMalloc(boundary + size + sizeof(Header)); if (tmp == NULL) { errno = ENOMEM; return (NULL); } if ((unsigned int) tmp & (boundary - 1)) { /* tmp is not already aligned */ packet = (Header *) (((unsigned int) tmp + boundary) & ~(boundary - 1)) - 1; if (packet < (Header *) tmp) { /* don't have room for Header before aligned address */ packet = (Header *) ((unsigned int) packet + boundary); } } else { /* tmp is already aligned to boundary (by chance) */ packet = ((Header *) (((unsigned int) tmp + boundary))) - 1; } packet->header.actualBuf = tmp; packet->header.size = size + sizeof(Header); return (packet + 1); #else /* user called an unsupported function */ return (NULL); #endif } /* * ======== aligned_alloc ======== */ void ATTRIBUTE * aligned_alloc(size_t alignment, size_t size) { /* use existing implementation to allocate buffer */ return (memalign(alignment, size)); } #if defined(__GNUC__) && !defined(__ti__) /* * ======== _malloc_r ======== */ void ATTRIBUTE * _malloc_r(struct _reent * rptr, size_t size) { return malloc(size); } /* * ======== _calloc_r ======== */ void ATTRIBUTE * _calloc_r(struct _reent * rptr, size_t nmemb, size_t size) { return calloc(nmemb, size); } /* * ======== _free_r ======== */ void ATTRIBUTE _free_r(struct _reent * rptr, void * ptr) { free(ptr); } /* * ======== _realloc_r ======== */ void ATTRIBUTE * _realloc_r(struct _reent * rptr, void * ptr, size_t size) { return realloc(ptr, size); } #endif