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