takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers emac_TestMemoryManager.cpp Source File

emac_TestMemoryManager.cpp

00001 /*
00002  * Copyright (c) 2018, ARM Limited, All Rights Reserved
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License"); you may
00006  * not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  * http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00013  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include <stdio.h>
00019 #include <stdarg.h>
00020 #include <string.h>
00021 #include <list>
00022 #include <stdlib.h>
00023 
00024 #include "unity.h"
00025 
00026 #include "rtos/Mutex.h"
00027 
00028 extern "C" {
00029 #include "arm_hal_interrupt_private.h"
00030 }
00031 #include "nsdynmemLIB.h"
00032 
00033 #include "EMACMemoryManager.h"
00034 #include "emac_TestMemoryManager.h"
00035 
00036 #define BUF_HEAD        "headheadheadhead"
00037 #define BUF_HEAD_SIZE   16
00038 #define BUF_TAIL        "tailtailtailtail"
00039 #define BUF_TAIL_SIZE   16
00040 
00041 #define CHECK_ASSERT(value, fmt, ...) check_value(value, fmt, ##__VA_ARGS__)
00042 
00043 #define BUF_POOL_SIZE   (14 + 40 + 20 + 536) /* Ethernet + IP + TCP + payload */
00044 
00045 #define MEM_MNGR_TRACE "test mem mngr: "
00046 
00047 char s_trace_buffer[100] = MEM_MNGR_TRACE;
00048 
00049 /* For LPC boards define the heap memory bank ourselves to give us section placement
00050    control */
00051 #ifndef ETHMEM_SECTION
00052 #if defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM)
00053 #  if defined (__ICCARM__)
00054 #     define ETHMEM_SECTION
00055 #  elif defined(TOOLCHAIN_GCC_CR)
00056 #     define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32")))
00057 #  else
00058 #     define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned))
00059 #  endif
00060 #elif defined(TARGET_LPC1768) || defined(TARGET_LPC1769)
00061 #  if defined (__ICCARM__)
00062 #     define ETHMEM_SECTION
00063 #  elif defined(TOOLCHAIN_GCC_CR)
00064 #     define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32")))
00065 #  else
00066 #     define ETHMEM_SECTION __attribute__((section("AHBSRAM0"),aligned))
00067 #  endif
00068 #endif
00069 #endif
00070 
00071 #ifdef ETHMEM_SECTION
00072 // Use nanostack libservice dynamic memory library
00073 #define EMAC_HEAP_SIZE 16300
00074 
00075 #if defined (__ICCARM__)
00076 #pragma location = ".ethusbram"
00077 #endif
00078 ETHMEM_SECTION static unsigned char ns_heap[EMAC_HEAP_SIZE];
00079 
00080 void emac_heap_error_handler(heap_fail_t event)
00081 {
00082     MBED_ASSERT(0);
00083 }
00084 #endif
00085 
00086 EmacTestMemoryManager::EmacTestMemoryManager()
00087     : m_mem_mutex(),
00088       m_mem_buffers(),
00089       m_alloc_unit(BUF_POOL_SIZE),
00090       m_memory_available(true)
00091 {
00092 #ifdef ETHMEM_SECTION
00093     static bool ns_heap_init = false;
00094     if (!ns_heap_init) {
00095         platform_critical_init(); // Create mutex for dynamic memory library
00096         ns_dyn_mem_init(ns_heap, EMAC_HEAP_SIZE, emac_heap_error_handler, NULL);
00097         ns_heap_init = true;
00098     }
00099 #endif
00100 }
00101 
00102 emac_mem_buf_t *EmacTestMemoryManager::alloc_heap(uint32_t size, uint32_t align)
00103 {
00104     return alloc_heap(size, align, MEM_CHECK);
00105 }
00106 
00107 emac_mem_buf_t *EmacTestMemoryManager::alloc_heap(uint32_t size, uint32_t align, uint8_t opt)
00108 {
00109     validate_list();
00110 
00111     CHECK_ASSERT(size, "alloc_heap() invalid parameter size");
00112 
00113     check_align(align);
00114 
00115     if ((opt & MEM_CHECK) && !m_memory_available) {
00116         return NULL;
00117     }
00118 
00119     m_mem_mutex.lock();
00120 
00121     emac_memory_t *buf = new emac_memory_t;
00122 
00123     CHECK_ASSERT(buf, "alloc_heap() no memory");
00124 
00125 #ifdef ETHMEM_SECTION
00126     buf->buffer = ns_dyn_mem_alloc(BUF_HEAD_SIZE + size + align + BUF_TAIL_SIZE);
00127 #else
00128     buf->buffer = std::malloc(BUF_HEAD_SIZE + size + align + BUF_TAIL_SIZE);
00129 #endif
00130 
00131     CHECK_ASSERT(buf->buffer, "alloc_heap() no memory");
00132 
00133     buf->next = 0;
00134     buf->ptr = static_cast<char *>(buf->buffer) + BUF_HEAD_SIZE;
00135     buf->orig_len = size;
00136     buf->len = size;
00137     buf->first = true;
00138 
00139     if (opt & MEM_NO_ALIGN) {
00140         if (reinterpret_cast<uint32_t>(buf->ptr) % sizeof(uint16_t) == 0) {
00141             buf->ptr = static_cast<char *>(buf->ptr) + 1;
00142         }
00143     } else if (align) {
00144         uint32_t remainder = reinterpret_cast<uint32_t>(buf->ptr) % align;
00145         if (remainder) {
00146             uint32_t offset = align - remainder;
00147             if (offset >= align) {
00148                 offset = align;
00149             }
00150             buf->ptr = static_cast<char *>(buf->ptr) + offset;
00151         }
00152     }
00153 
00154     char *buffer_head = static_cast<char *>(buf->ptr) - BUF_HEAD_SIZE;
00155     memcpy(buffer_head, BUF_HEAD, BUF_HEAD_SIZE);
00156 
00157     char *buffer_tail = static_cast<char *>(buf->ptr) + buf->len;
00158     memcpy(buffer_tail, BUF_TAIL, BUF_TAIL_SIZE);
00159 
00160     m_mem_buffers.push_front(buf);
00161 
00162     m_mem_mutex.unlock();
00163 
00164     return buf;
00165 }
00166 
00167 emac_mem_buf_t *EmacTestMemoryManager::alloc_pool(uint32_t size, uint32_t align)
00168 {
00169     return alloc_pool(size, align, MEM_CHECK);
00170 }
00171 
00172 emac_mem_buf_t *EmacTestMemoryManager::alloc_pool(uint32_t size, uint32_t align, uint8_t opt)
00173 {
00174     validate_list();
00175 
00176     CHECK_ASSERT(size, "alloc_pool() invalid parameter size");
00177 
00178     check_align(align);
00179 
00180     if ((opt & MEM_CHECK) && !m_memory_available) {
00181         return NULL;
00182     }
00183 
00184     // Contiguous allocation
00185     if (size + align <= m_alloc_unit) {
00186         return alloc_heap(size, align, opt);
00187     }
00188 
00189     unsigned int pool_buffer_max_size = m_alloc_unit - align;
00190 
00191     CHECK_ASSERT(pool_buffer_max_size > 0, "alloc_pool() invalid align");
00192 
00193     emac_memory_t *first_buf = 0;
00194     emac_memory_t *prev_buf = 0;
00195     unsigned int size_left = size;
00196 
00197     while (size_left != 0) {
00198         unsigned int alloc_size;
00199 
00200         // New alloc size buffer needed
00201         if (size_left > pool_buffer_max_size) {
00202             size_left = size_left - pool_buffer_max_size;
00203             alloc_size = pool_buffer_max_size;
00204             // New smaller than alloc size buffer needed
00205         } else {
00206             alloc_size = size_left;
00207             size_left = 0;
00208         }
00209 
00210         emac_memory_t *new_buf = static_cast<emac_memory_t *>(alloc_heap(alloc_size, align, opt));
00211 
00212         if (prev_buf) {
00213             new_buf->first = false;
00214             prev_buf->next = new_buf;
00215         } else {
00216             first_buf = new_buf;
00217         }
00218         prev_buf = new_buf;
00219     }
00220 
00221     return first_buf;
00222 }
00223 
00224 uint32_t EmacTestMemoryManager::get_pool_alloc_unit(uint32_t align) const
00225 {
00226     validate_list();
00227 
00228     check_align(align);
00229 
00230     return m_alloc_unit - align;
00231 }
00232 
00233 void EmacTestMemoryManager::free(emac_mem_buf_t *buf)
00234 {
00235     validate_list();
00236 
00237     CHECK_ASSERT(buf, "free(): buffer parameter is null");
00238 
00239     emac_memory_t *mem_buf = static_cast<emac_memory_t *>(buf);
00240 
00241     CHECK_ASSERT(mem_buf->first, "free() not first in chain");
00242 
00243     std::list<emac_memory_t *>::iterator mem_buf_entry;
00244 
00245     m_mem_mutex.lock();
00246 
00247     while (mem_buf) {
00248         for (mem_buf_entry = m_mem_buffers.begin(); mem_buf_entry != m_mem_buffers.end(); ++mem_buf_entry) {
00249             if (*mem_buf_entry == mem_buf) {
00250                 break;
00251             }
00252         }
00253 
00254         if (mem_buf_entry == m_mem_buffers.end()) {
00255             CHECK_ASSERT(0, "free(): %p buffer already freed", mem_buf);
00256             m_mem_mutex.unlock();
00257             return;
00258         }
00259 
00260         char *buffer_head = static_cast<char *>(mem_buf->ptr) - BUF_HEAD_SIZE;
00261         if (memcmp(buffer_head, BUF_HEAD, BUF_HEAD_SIZE) != 0) {
00262             CHECK_ASSERT(0, "free(): %p head overwrite", mem_buf);
00263         }
00264 
00265         char *buffer_tail = static_cast<char *>(mem_buf->ptr) + mem_buf->orig_len;
00266         if (memcmp(buffer_tail, BUF_TAIL, BUF_TAIL_SIZE) != 0) {
00267             CHECK_ASSERT(0, "free(): %p tail overwrite", mem_buf);
00268         }
00269 
00270         emac_memory_t *next = mem_buf->next;
00271 
00272         m_mem_buffers.erase(mem_buf_entry);
00273 
00274 #ifdef ETHMEM_SECTION
00275         ns_dyn_mem_free(mem_buf->buffer);
00276 #else
00277         std::free(mem_buf->buffer);
00278 #endif
00279         delete mem_buf;
00280 
00281         mem_buf = next;
00282     }
00283 
00284     m_mem_mutex.unlock();
00285 }
00286 
00287 uint32_t EmacTestMemoryManager::get_total_len(const emac_mem_buf_t *buf) const
00288 {
00289     validate_list();
00290 
00291     if (!validate_ptr(buf)) {
00292         CHECK_ASSERT(0, "get_total_len(): %p invalid buffer", buf);
00293         return 0;
00294     }
00295 
00296     uint32_t total_len = 0;
00297 
00298     for (emac_memory_t *mem_buf = (emac_memory_t *) buf; mem_buf != NULL; mem_buf = mem_buf->next) {
00299         total_len += mem_buf->len;
00300     }
00301 
00302     return total_len;
00303 }
00304 
00305 void EmacTestMemoryManager::copy(emac_mem_buf_t *to_buf, const emac_mem_buf_t *from_buf)
00306 {
00307     validate_list();
00308 
00309     if (!validate_ptr(to_buf)) {
00310         CHECK_ASSERT(0, "copy(): %p invalid to buffer", to_buf);
00311         return;
00312     }
00313 
00314     if (!validate_ptr(from_buf)) {
00315         CHECK_ASSERT(0, "copy(): %p invalid from buffer", from_buf);
00316         return;
00317     }
00318 
00319     if (get_total_len(to_buf) != get_total_len(from_buf)) {
00320         CHECK_ASSERT(0, "copy(): %p to and %p from buffer total lengths not same", to_buf, from_buf);
00321         return;
00322     }
00323 
00324     unsigned int to_buf_offset = 0;
00325     unsigned int from_buf_offset = 0;
00326 
00327     emac_memory_t *to_mem_buf = static_cast<emac_memory_t *>(to_buf);
00328     const emac_memory_t *from_mem_buf = static_cast<const emac_memory_t *>(from_buf);
00329 
00330     while (to_mem_buf && from_mem_buf) {
00331         unsigned int buf_copy_len;
00332 
00333         // Is there data in from buffer
00334         buf_copy_len = from_mem_buf->len - from_buf_offset;
00335         if (buf_copy_len == 0) {
00336             from_mem_buf = from_mem_buf->next;
00337             from_buf_offset = 0;
00338             continue;
00339         }
00340 
00341         // Is there space left in to buffer
00342         if (buf_copy_len > to_mem_buf->len - to_buf_offset) {
00343             buf_copy_len = to_mem_buf->len - to_buf_offset;
00344         }
00345         if (buf_copy_len == 0) {
00346             to_mem_buf = to_mem_buf->next;
00347             to_buf_offset = 0;
00348             continue;
00349         }
00350 
00351         // Copy data
00352         memcpy(static_cast<char *>(to_mem_buf->ptr) + to_buf_offset, static_cast<const char *>(from_mem_buf->ptr) + from_buf_offset, buf_copy_len);
00353         from_buf_offset += buf_copy_len;
00354         to_buf_offset += buf_copy_len;
00355     }
00356 }
00357 
00358 void EmacTestMemoryManager::cat(emac_mem_buf_t *to_buf, emac_mem_buf_t *cat_buf)
00359 {
00360     validate_list();
00361 
00362     if (!validate_ptr(to_buf)) {
00363         CHECK_ASSERT(0, "cat(): %p invalid to buffer", to_buf);
00364         return;
00365     }
00366 
00367     if (!validate_ptr(cat_buf)) {
00368         CHECK_ASSERT(0, "cat(): %p invalid cat buffer", cat_buf);
00369         return;
00370     }
00371 
00372     emac_memory_t *cat_mem_buf = static_cast<emac_memory_t *>(cat_buf);
00373 
00374     if (!cat_mem_buf->first) {
00375         CHECK_ASSERT(0, "cat(): %p cat buffer does not point to head of chain", cat_buf);
00376         return;
00377     }
00378 
00379     emac_memory_t *to_mem_buf = static_cast<emac_memory_t *>(to_buf);
00380 
00381     while (to_mem_buf->next != 0) {
00382         to_mem_buf = to_mem_buf->next;
00383     }
00384 
00385     to_mem_buf->next = cat_mem_buf;
00386     cat_mem_buf->first = false;
00387 }
00388 
00389 emac_mem_buf_t *EmacTestMemoryManager::get_next(const emac_mem_buf_t *buf) const
00390 {
00391     validate_list();
00392 
00393     if (!validate_ptr(buf)) {
00394         CHECK_ASSERT(0, "get_next(): %p invalid buffer", buf);
00395         return NULL;
00396     }
00397 
00398     const emac_memory_t *mem_buf = static_cast<const emac_memory_t *>(buf);
00399     return mem_buf->next;
00400 }
00401 
00402 void *EmacTestMemoryManager::get_ptr(const emac_mem_buf_t *buf) const
00403 {
00404     validate_list();
00405 
00406     if (!validate_ptr(buf)) {
00407         CHECK_ASSERT(0, "get_ptr(): %p invalid buffer", buf);
00408         return NULL;
00409     }
00410 
00411     const emac_memory_t *mem_buf = static_cast<const emac_memory_t *>(buf);
00412     return mem_buf->ptr;
00413 }
00414 
00415 uint32_t EmacTestMemoryManager::get_len(const emac_mem_buf_t *buf) const
00416 {
00417     validate_list();
00418 
00419     if (!validate_ptr(buf)) {
00420         CHECK_ASSERT(0, "get_len(): %p invalid buffer", buf);
00421         return 0;
00422     }
00423 
00424     const emac_memory_t *mem_buf = static_cast<const emac_memory_t *>(buf);
00425     return mem_buf->len;
00426 }
00427 
00428 void EmacTestMemoryManager::set_len(emac_mem_buf_t *buf, uint32_t len)
00429 {
00430     validate_list();
00431 
00432     if (!validate_ptr(buf)) {
00433         CHECK_ASSERT(0, "set_len(): %p invalid buffer", buf);
00434         return;
00435     }
00436 
00437     emac_memory_t *mem_buf = static_cast<emac_memory_t *>(buf);
00438 
00439     if (len > mem_buf->orig_len) {
00440         CHECK_ASSERT(0, "set_len(): %p new length %i must be less or equal allocated size %i", buf, len, mem_buf->orig_len);
00441         return;
00442     }
00443 
00444     if (!mem_buf->first) {
00445         CHECK_ASSERT(0, "set_len(): %p buffer does not point to head of chain", buf);
00446         return;
00447     }
00448 
00449     mem_buf->len = len;
00450 }
00451 
00452 void EmacTestMemoryManager::set_alloc_unit(uint32_t alloc_unit)
00453 {
00454     validate_list();
00455 
00456     m_alloc_unit = alloc_unit;
00457 }
00458 
00459 void EmacTestMemoryManager::set_memory_available(bool memory)
00460 {
00461     m_memory_available = memory;
00462 }
00463 
00464 void EmacTestMemoryManager::get_memory_statistics(int *buffers, int *memory)
00465 {
00466     if (!buffers || !memory) {
00467         return;
00468     }
00469 
00470     *buffers = 0;
00471     *memory = 0;
00472 
00473     m_mem_mutex.lock();
00474 
00475     const emac_memory_t *mem_buf;
00476 
00477     for (std::list<emac_memory_t *>::const_iterator it = m_mem_buffers.begin(); it != m_mem_buffers.end(); ++it) {
00478         mem_buf = static_cast<const emac_memory_t *>(*it);
00479         ++(*buffers);
00480         *memory += mem_buf->orig_len;
00481     }
00482 
00483     m_mem_mutex.unlock();
00484 }
00485 
00486 template <typename TYPE> void EmacTestMemoryManager::check_value(TYPE value, const char *fmt, ...) const
00487 {
00488     if (!value) {
00489         va_list ap;
00490         va_start(ap, fmt);
00491         snprintf(s_trace_buffer + sizeof(MEM_MNGR_TRACE) - 1, sizeof(s_trace_buffer) - sizeof(MEM_MNGR_TRACE) - 1, fmt, ap);
00492         va_end(ap);
00493         TEST_ASSERT_MESSAGE(0, s_trace_buffer);
00494     }
00495 }
00496 
00497 bool EmacTestMemoryManager::validate_ptr(const emac_mem_buf_t *buf) const
00498 {
00499     if (!buf) {
00500         return false;
00501     }
00502 
00503     m_mem_mutex.lock();
00504 
00505     const emac_memory_t *mem_buf = static_cast<const emac_memory_t *>(buf);
00506 
00507     for (std::list<emac_memory_t *>::const_iterator it = m_mem_buffers.begin(); it != m_mem_buffers.end(); ++it) {
00508         emac_memory_t *list_buf = static_cast<emac_memory_t *>(*it);
00509         if (list_buf == mem_buf) {
00510             m_mem_mutex.unlock();
00511             return true;
00512         }
00513     }
00514 
00515     m_mem_mutex.unlock();
00516 
00517     return false;
00518 }
00519 
00520 void EmacTestMemoryManager::check_align(uint32_t align) const
00521 {
00522     if (align > 64) {
00523         CHECK_ASSERT(0, "check_align(): invalid alignment value");
00524     }
00525 }
00526 
00527 void EmacTestMemoryManager::validate_list() const
00528 {
00529     m_mem_mutex.lock();
00530 
00531     const emac_memory_t *mem_buf;
00532 
00533     for (std::list<emac_memory_t *>::const_iterator it = m_mem_buffers.begin(); it != m_mem_buffers.end(); ++it) {
00534         mem_buf = static_cast<const emac_memory_t *>(*it);
00535 
00536         char *buffer_head = static_cast<char *>(mem_buf->ptr) - BUF_HEAD_SIZE;
00537         if (memcmp(buffer_head, BUF_HEAD, BUF_HEAD_SIZE) != 0) {
00538             CHECK_ASSERT(0, "validate_list(): %p head overwrite", mem_buf);
00539         }
00540 
00541         char *buffer_tail = static_cast<char *>(mem_buf->ptr) + mem_buf->orig_len;
00542         if (memcmp(buffer_tail, BUF_TAIL, BUF_TAIL_SIZE) != 0) {
00543             CHECK_ASSERT(0, "validate_list(): %p tail overwrite", mem_buf);
00544 
00545         }
00546     }
00547 
00548     m_mem_mutex.unlock();
00549 }
00550 
00551 EmacTestMemoryManager &EmacTestMemoryManager::get_instance()
00552 {
00553     static EmacTestMemoryManager test_memory_manager;
00554     return test_memory_manager;
00555 }
00556