/* * Copyright (C) 2014 BlueKitchen GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * 4. Any redistribution, use, or modification is done solely for * personal benefit and not for any commercial purpose or for * monetary gain. * * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH 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 MATTHIAS * RINGWALD 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. * * Please inquire about commercial licensing options at * contact@bluekitchen-gmbh.com * */ #define __BTSTACK_FILE__ "sm_mbedtls_allocator.c" #include "btstack_config.h" #include #include #include #include "sm_mbedtls_allocator.h" #include "btstack_util.h" #include "btstack_debug.h" #ifdef ENABLE_LE_SECURE_CONNECTIONS #ifdef HAVE_HCI_CONTROLLER_DHKEY_SUPPORT #error "Support for DHKEY Support in HCI Controller not implemented yet. Please use software implementation" #else #define USE_MBEDTLS_FOR_ECDH #endif #endif #ifdef USE_MBEDTLS_FOR_ECDH #include "mbedtls/config.h" #ifndef HAVE_MALLOC // #define DEBUG_ALLOCATIONS size_t mbed_memory_allocated_current; size_t mbed_memory_allocated_max; size_t mbed_memory_space_max; size_t mbed_memory_max; size_t mbed_memory_smallest_buffer = 0xfffffff; unsigned int mbed_memory_num_allocations; #define NUM_SIZES 150 int current_individual_allocation[NUM_SIZES]; int max_individual_allocation[NUM_SIZES]; int max_total_allocation[NUM_SIZES]; // customized allocator for use with BTstack's Security Manager // assumptions: // - allocations are multiple of 8 // - smallest allocation is 8 static uint32_t sm_allocator_size; static uint8_t * sm_allocator_buffer; static uint32_t sm_allocator_used; static sm_allocator_node_t * sm_mbedtls_node_for_offset(uint32_t offset){ if (offset > sm_allocator_size){ printf("Error! offset %u\n", offset); } return (sm_allocator_node_t *) (sm_allocator_buffer + offset); } static void dump_allocations(void){ size_t overhead = mbed_memory_num_allocations * sizeof(void*); printf("SM Per Block - Summary: Allocations %u. Current %lu (+ %zu = %zu used), Max %lu.\n", mbed_memory_num_allocations, mbed_memory_allocated_current, overhead, mbed_memory_allocated_current + overhead, mbed_memory_allocated_max); int i; unsigned int total = 0; printf("- current : [ "); for (i=0;isize, current->next); bytes_free += current->size; current_pos = current->next; current = sm_mbedtls_node_for_offset(current_pos); if (current_pos == 0) break; } size_t overhead = mbed_memory_num_allocations * sizeof(void*); printf("- Summary: Allocations %u. Current %lu (+ %zu = %zu used), Max %lu. Free %zu. Total: %zu\n", mbed_memory_num_allocations, mbed_memory_allocated_current, overhead, mbed_memory_allocated_current + overhead, mbed_memory_allocated_max, bytes_free, bytes_free + mbed_memory_allocated_current + overhead ); dump_allocations(); #endif } static inline void sm_mbedtls_allocator_update_max(){ #if 1 uint32_t current_pos = 0; sm_allocator_node_t * current = sm_mbedtls_node_for_offset(current_pos); while (1){ if (current_pos + 8 > mbed_memory_space_max) { mbed_memory_space_max = current_pos + 8; printf("SM Alloc: space used %zu (%zu data + %u allocations)\n", mbed_memory_space_max, mbed_memory_allocated_current, mbed_memory_num_allocations); } current_pos = current->next; current = sm_mbedtls_node_for_offset(current_pos); if (current_pos == 0) break; } #endif } void * sm_mbedtls_allocator_calloc(size_t count, size_t size){ size_t num_bytes = count * size; size_t total = num_bytes + sizeof(void *); mbed_memory_allocated_current += num_bytes; mbed_memory_smallest_buffer = btstack_min(mbed_memory_smallest_buffer, num_bytes); mbed_memory_num_allocations++; // printf("SM Alloc %zu bytes\n", num_bytes); // if (num_bytes > 1000){ // printf("big alloc!\n"); // } int index = num_bytes / 8; current_individual_allocation[index]++; if (current_individual_allocation[index] > max_individual_allocation[index]){ max_individual_allocation[index] = current_individual_allocation[index]; dump_allocations(); } // mbed_memory_allocated_max = btstack_max(mbed_memory_allocated_max, mbed_memory_allocated_current); if (mbed_memory_allocated_current > mbed_memory_allocated_max){ memcpy(max_total_allocation, current_individual_allocation, sizeof(max_total_allocation)); mbed_memory_allocated_max = mbed_memory_allocated_current; dump_allocations(); } uint32_t prev_pos, current_pos, node_pos; sm_allocator_node_t * prev, * current, * node; // find exact block prev_pos = 0; prev = sm_mbedtls_node_for_offset(prev_pos); current_pos = prev->next; while (current_pos){ current = sm_mbedtls_node_for_offset(current_pos); if (current->size == total){ prev->next = current->next; memset(current, 0, total); *(uint32_t*)current = total; sm_mbedtls_allocator_update_max(); #ifdef DEBUG_ALLOCATIONS printf("sm_mbedtls_allocator_calloc(%zu,%zu) = total %zu -> pos %u\n", count, size, total, current_pos); #endif sm_mbedtls_allocator_status(); return &sm_allocator_buffer[current_pos + sizeof(void *)]; } // next prev = current; prev_pos = current_pos; current_pos = current->next; } // find first large enough block prev_pos = 0; prev = sm_mbedtls_node_for_offset(prev_pos); current_pos = prev->next; while (current_pos){ current = sm_mbedtls_node_for_offset(current_pos); if (current->size > total){ #ifdef DEBUG_ALLOCATIONS printf("sm_mbedtls_allocator_calloc splitting block at %u, size %u (prev %u)\n", current_pos, current->size, prev_pos); #endif node_pos = current_pos + total; node = sm_mbedtls_node_for_offset(node_pos); node->next = current->next; node->size = current->size - total; #ifdef DEBUG_ALLOCATIONS printf("sm_mbedtls_allocator_calloc new block at %u, size %u\n", node_pos, node->size); #endif prev->next = node_pos; memset(current, 0, total); *(uint32_t*)current = total; sm_mbedtls_allocator_update_max(); #ifdef DEBUG_ALLOCATIONS printf("sm_mbedtls_allocator_calloc(%zu,%zu) = total %zu -> pos %u\n", count, size, total, current_pos); #endif sm_mbedtls_allocator_status(); return &sm_allocator_buffer[current_pos + sizeof(void *)]; } // next prev = current; prev_pos = current_pos; current_pos = current->next; } #ifdef DEBUG_ALLOCATIONS // failed to allocate printf("sm_mbedtls_allocator_calloc error, no free chunk found!\n"); exit(10); #else log_error("sm_mbedtls_allocator_calloc error, no free chunk found to allocate %zu bytes\n", total); return 0; #endif } void sm_mbedtls_allocator_free(void * data){ uint32_t prev_pos, current_pos, next_pos; sm_allocator_node_t * current, * prev, * next; current = (sm_allocator_node_t*) (((uint8_t *) data) - sizeof(void *)); current_pos = ((uint8_t *) current) - ((uint8_t *) sm_allocator_buffer); size_t total = *(uint32_t*) current; size_t num_bytes = total - sizeof(void *); mbed_memory_allocated_current -= num_bytes; mbed_memory_num_allocations--; int index = num_bytes / 8; current_individual_allocation[index]--; // printf("SM Free %zu bytes\n", num_bytes); #ifdef DEBUG_ALLOCATIONS printf("sm_mbedtls_allocator_free: pos %u, total %zu\n", current_pos, total); #endif // find previous node prev_pos = 0; prev = sm_mbedtls_node_for_offset(prev_pos); while (prev->next < current_pos){ prev_pos = prev->next; prev = sm_mbedtls_node_for_offset(prev_pos); } // setup new node current->next = prev->next; current->size = total; prev->next = current_pos; // merge with previous ? #ifdef DEBUG_ALLOCATIONS printf("sm_mbedtls_allocator_free: prev %u, %u\n", prev_pos, prev->size); #endif if (prev_pos + prev->size == current_pos){ #ifdef DEBUG_ALLOCATIONS printf("sm_mbedtls_allocator_free: merge with previous\n"); #endif prev->size += current->size; prev->next = current->next; current = prev; current_pos = prev_pos; } // merge with next node? next_pos = current->next; if (current_pos + current->size == next_pos){ next = sm_mbedtls_node_for_offset(next_pos); #ifdef DEBUG_ALLOCATIONS printf("sm_mbedtls_allocator_free: merge with next at pos %u, size %u\n", next_pos, next->size); #endif current->size += next->size; current->next = next->next; } sm_mbedtls_allocator_status(); } void sm_mbedtls_allocator_init(uint8_t * buffer, uint32_t size){ sm_allocator_buffer = buffer; sm_allocator_size = size; sm_allocator_node_t * anchor = sm_mbedtls_node_for_offset(0); anchor->next = sizeof(sm_allocator_node_t); anchor->size = 0; sm_allocator_node_t * first = sm_mbedtls_node_for_offset(anchor->next); first->next = 0; first->size = size - sizeof(sm_allocator_node_t); sm_allocator_used = 2 * sizeof(sm_allocator_node_t); sm_mbedtls_allocator_status(); } #if 0 void * sm_mbedtls_allocator_calloc(size_t count, size_t size){ size_t total = count * size; mbed_memory_allocated_current += total; mbed_memory_allocated_max = btstack_max(mbed_memory_allocated_max, mbed_memory_allocated_current); mbed_memory_smallest_buffer = btstack_min(mbed_memory_smallest_buffer, total); mbed_memory_num_allocations++; void * result = calloc(4 + total, 1); *(uint32_t*) result = total; printf("sm_mbedtls_allocator_calloc(%zu, %zu) -> res %p. Total %lu, Max %lu, Smallest %lu, Count %u\n", count, size, result, mbed_memory_allocated_current, mbed_memory_allocated_max, mbed_memory_smallest_buffer, mbed_memory_num_allocations); return ((uint8_t *) result) + 4; } void sm_mbedtls_allocator_free(void * data){ void * orig = ((uint8_t *) data) - 4; size_t total = *(uint32_t *)orig; mbed_memory_allocated_current -= total; mbed_memory_num_allocations--; printf("sm_mbedtls_allocator_free(%p) - %zu bytes. Total %lu, Count %u\n", data, total, mbed_memory_allocated_current, mbed_memory_num_allocations); free(orig); } #endif #endif #endif