BA
/
BaBoRo1
Embed:
(wiki syntax)
Show/hide line numbers
secure_allocator.c
00001 /* 00002 * Copyright (c) 2016, 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 "rtx_lib.h" 00019 00020 /* uVisor uses rtx_memory instead of implementing its own dynamic, 00021 * non-fixed-size memory allocator. To do this, uVisor creates multiple 00022 * non-fixed-size allocator pools (one per page) and allocates memory from 00023 * these pools. uVisor must manage the memory for these pools' control blocks, 00024 * so it must know the size of these control blocks. */ 00025 00026 /* The following memory pool control block structs are copied from 00027 * rtx_memory.c, so that uVisor can manage the memory for these control blocks 00028 * within pages. */ 00029 typedef struct mem_head_s { 00030 uint32_t size; // Memory Pool size 00031 uint32_t used; // Used Memory 00032 } mem_head_t; 00033 00034 // Memory Block Header structure 00035 typedef struct mem_block_s { 00036 struct mem_block_s *next; // Next Memory Block in list 00037 uint32_t info; // Info: length = <31:2>:'00', type = <1:0> 00038 } mem_block_t; 00039 /* End copy */ 00040 00041 #include "secure_allocator.h" 00042 #include "uvisor-lib/uvisor-lib.h" 00043 00044 #include <stdio.h> 00045 #include <stdlib.h> 00046 #include <string.h> 00047 00048 /* Use printf with caution inside malloc: printf may allocate memory itself, 00049 so using printf in malloc may lead to recursive calls! */ 00050 #define DPRINTF(...) {} 00051 00052 /* offsetof is a gcc built-in function, this is the manual implementation */ 00053 #define OFFSETOF(type, member) ((uint32_t) (&(((type *)(0))->member))) 00054 00055 /* Internal structure currently only contains the page table. */ 00056 typedef struct { 00057 UvisorPageTable table; 00058 } SecureAllocatorInternal; 00059 00060 static inline UvisorPageTable * table(SecureAllocator allocator) { 00061 return &(((SecureAllocatorInternal *) allocator)->table); 00062 } 00063 00064 SecureAllocator secure_allocator_create_with_pool( 00065 void * mem, 00066 size_t bytes) 00067 { 00068 SecureAllocatorInternal * allocator = mem; 00069 /* Signal that this is non-page allocated memory. */ 00070 allocator->table.page_size = bytes; 00071 allocator->table.page_count = 0; 00072 /* The internal rtx_Memory memory pool structure must be placed AFTER 00073 * table.page_origins[0] !!! */ 00074 size_t offset = OFFSETOF(SecureAllocatorInternal, table.page_origins) + sizeof(((UvisorPageTable) {0}).page_origins); 00075 uintptr_t page_origin = (uintptr_t) mem + offset; 00076 00077 /* Align page_origin to a multiple of 8 (because RTX requries 8-byte 00078 * alignment of the origin). */ 00079 page_origin = (page_origin + (0x8 - 1)) & -0x8; 00080 offset = page_origin - (uintptr_t) mem; 00081 size_t size = bytes - offset; 00082 /* Align size to a multiple of 8 (because RTX requires 8-byte alignment of 00083 * the size) */ 00084 size &= -0x8; 00085 00086 /* Create pool allocator structure inside the memory. */ 00087 if (!osRtxMemoryInit((void *) page_origin, size)) { 00088 /* Abort if failed. */ 00089 DPRINTF("secure_allocator_create_with_pool: pool allocator %p with offset %d creation failed (size %u bytes)\n\n", page_origin, offset, bytes - offset); 00090 return NULL; 00091 } 00092 /* Remember the pool allocator pointer though. */ 00093 allocator->table.page_origins[0] = (void *) page_origin; 00094 DPRINTF("secure_allocator_create_with_pool: Created pool allocator %p with offset %d\n\n", page_origin, offset); 00095 return allocator; 00096 } 00097 00098 SecureAllocator secure_allocator_create_with_pages( 00099 size_t size, 00100 size_t maximum_malloc_size) 00101 { 00102 const uint32_t page_size = uvisor_get_page_size(); 00103 /* The rtx_Memory allocator puts one pool allocator structure at both the 00104 * beginning and end of the memory pool. */ 00105 const size_t block_overhead = 2 * sizeof(mem_block_t); 00106 const size_t page_size_with_overhead = page_size + block_overhead; 00107 /* Calculate the integer part of required the page count. */ 00108 size_t page_count = size / page_size_with_overhead; 00109 /* Add another page if the remainder is not zero. */ 00110 if (size - page_count * page_size_with_overhead) { 00111 page_count++; 00112 } 00113 DPRINTF("secure_allocator_create_with_pages: Requesting %u pages for at least %uB\n", page_count, size); 00114 00115 /* Compute the maximum allocation within our blocks. */ 00116 size_t maximum_allocation_size = page_size - block_overhead; 00117 /* If the required maximum allocation is larger than we can provide, abort. */ 00118 if (maximum_malloc_size > maximum_allocation_size) { 00119 DPRINTF("secure_allocator_create_with_pages: Maximum allocation request %uB is larger then available %uB\n\n", maximum_malloc_size, maximum_allocation_size); 00120 return NULL; 00121 } 00122 00123 /* Compute the required memory size for the page table. */ 00124 size_t allocator_type_size = sizeof(SecureAllocatorInternal); 00125 /* Add size for each additional page. */ 00126 allocator_type_size += (page_count - 1) * sizeof(((UvisorPageTable) {0}).page_origins); 00127 /* Allocate this much memory. */ 00128 SecureAllocatorInternal * const allocator = malloc(allocator_type_size); 00129 /* If malloc failed, abort. */ 00130 if (allocator == NULL) { 00131 DPRINTF("secure_allocator_create_with_pages: SecureAllocatorInternal failed to be allocated!\n\n"); 00132 return NULL; 00133 } 00134 00135 /* Prepare the page table. */ 00136 allocator->table.page_size = page_size; 00137 allocator->table.page_count = page_count; 00138 /* Get me some pages. */ 00139 if (uvisor_page_malloc((UvisorPageTable *) &(allocator->table))) { 00140 free(allocator); 00141 DPRINTF("secure_allocator_create_with_pages: Not enough free pages available!\n\n"); 00142 return NULL; 00143 } 00144 00145 /* Initialize a memory pool structure in all pages. */ 00146 for(size_t ii = 0; ii < page_count; ii++) { 00147 /* Add each page as a pool. */ 00148 osStatus_t status = osRtxMemoryInit(allocator->table.page_origins[ii], page_size); 00149 if (status == osOK) { 00150 DPRINTF("secure_allocator_create_with_pages: Created memory pool allocator %p with offset %d page %u\n", allocator->table.page_origins[ii], 0, ii); 00151 } else { 00152 DPRINTF("secure_allocator_create_with_pages: Failed creating memory pool allocator %p with offset %d page %u\n", allocator->table.page_origins[ii], 0, ii); 00153 } 00154 } 00155 DPRINTF("\n"); 00156 /* Aaaand across the line. */ 00157 return (SecureAllocator) allocator; 00158 } 00159 00160 int secure_allocator_destroy( 00161 SecureAllocator allocator) 00162 { 00163 DPRINTF("secure_allocator_destroy: Destroying memory pool allocator at %p\n", table(allocator)->page_origins[0]); 00164 00165 /* Check if we are working on statically allocated memory. */ 00166 SecureAllocatorInternal * alloc = (SecureAllocatorInternal * const) allocator; 00167 if (alloc->table.page_count == 0) { 00168 DPRINTF("secure_allocator_destroy: %p is not page-backed memory, not freeing!\n", allocator); 00169 return -1; 00170 } 00171 00172 /* Free all pages. */ 00173 if (uvisor_page_free(&(alloc->table))) { 00174 DPRINTF("secure_allocator_destroy: Unable to free pages!\n\n"); 00175 return -1; 00176 } 00177 00178 /* Free the allocator structure. */ 00179 free(allocator); 00180 00181 DPRINTF("\n"); 00182 return 0; 00183 } 00184 00185 void * secure_malloc( 00186 SecureAllocator allocator, 00187 size_t size) 00188 { 00189 size_t index = 0; 00190 do { 00191 /* Search in this page. */ 00192 void * mem = osRtxMemoryAlloc(table(allocator)->page_origins[index], size, 0); 00193 /* Return if we found something. */ 00194 if (mem) { 00195 DPRINTF("secure_malloc: Found %4uB in page %u at %p\n", size, index, mem); 00196 return mem; 00197 } 00198 /* Otherwise, go to the next page. */ 00199 index++; 00200 } /* Continue search if more pages are available. */ 00201 while (index < table(allocator)->page_count); 00202 00203 DPRINTF("secure_malloc: Out of memory in allocator %p \n", allocator); 00204 /* We found nothing. */ 00205 return NULL; 00206 } 00207 00208 void * secure_aligned_alloc( 00209 SecureAllocator allocator, 00210 size_t alignment, 00211 size_t size) 00212 { 00213 /* Alignment must be a power of two! */ 00214 if (alignment & ((1UL << ((31UL - __builtin_clz(alignment)) - 1)))) { 00215 return NULL; 00216 } 00217 /* TODO: THIS IS A NAIVE IMPLEMENTATION, which wastes much memory. */ 00218 void * ptr = secure_malloc(allocator, size + alignment - 1); 00219 if (ptr == NULL) { 00220 return NULL; 00221 } 00222 return (void *) (((uint32_t) ptr + alignment - 1) & ~(alignment - 1)); 00223 } 00224 00225 void * secure_calloc( 00226 SecureAllocator allocator, 00227 size_t nmemb, 00228 size_t size) 00229 { 00230 if ((uint64_t) nmemb * size > SIZE_MAX) { 00231 /* (size * nmemb) has overflowed. */ 00232 return NULL; 00233 } 00234 void * ptr = secure_malloc(allocator, size * nmemb); 00235 if (ptr == NULL) { 00236 return NULL; 00237 } 00238 memset(ptr, 0, size * nmemb); 00239 return ptr; 00240 } 00241 00242 void * secure_realloc( 00243 SecureAllocator allocator, 00244 void * ptr, 00245 size_t new_size) 00246 { 00247 /* TODO: THIS IS A NAIVE IMPLEMENTATION, which always allocates new 00248 memory, and copies the memory, then frees the old memory. */ 00249 00250 /* Allocate new memory. */ 00251 void * new_ptr = secure_malloc(allocator, new_size); 00252 /* If memory allocation failed, abort. */ 00253 if (new_ptr == NULL) { 00254 return NULL; 00255 } 00256 00257 /* Passing NULL as ptr is legal, realloc acts as malloc then. */ 00258 if (ptr) { 00259 /* Get the size of the ptr memory. */ 00260 size_t size = ((mem_block_t *) ((uint32_t) ptr - sizeof(mem_block_t)))->info & ~0x3; 00261 /* Copy the memory to the new location, min(new_size, size). */ 00262 memcpy(new_ptr, ptr, new_size < size ? new_size : size); 00263 /* Free the previous memory. */ 00264 secure_free(allocator, ptr); 00265 } 00266 return new_ptr; 00267 } 00268 00269 void secure_free( 00270 SecureAllocator allocator, 00271 void * ptr) 00272 { 00273 size_t index = 0; 00274 do { 00275 /* Search in this page. */ 00276 int ret = osRtxMemoryFree(table(allocator)->page_origins[index], ptr); 00277 /* Return if free was successful. */ 00278 if (ret == 1) { 00279 DPRINTF("secure_free: Freed %p in page %u.\n", ptr, index); 00280 return; 00281 } 00282 /* Otherwise, go to the next page. */ 00283 index++; 00284 } /* Continue search if more pages are available. */ 00285 while (index < table(allocator)->page_count); 00286 00287 DPRINTF("secure_free: %p not found in allocator %p!\n", ptr, allocator); 00288 /* We found nothing. */ 00289 return; 00290 }
Generated on Tue Jul 12 2022 12:22:19 by
