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.
Dependents: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
features/FEATURE_UVISOR/source/rtx/secure_allocator.c@0:098463de4c5d, 2017-01-25 (annotated)
- Committer:
- group-onsemi
- Date:
- Wed Jan 25 20:34:15 2017 +0000
- Revision:
- 0:098463de4c5d
Initial commit
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| group-onsemi | 0:098463de4c5d | 1 | /* |
| group-onsemi | 0:098463de4c5d | 2 | * Copyright (c) 2016, ARM Limited, All Rights Reserved |
| group-onsemi | 0:098463de4c5d | 3 | * SPDX-License-Identifier: Apache-2.0 |
| group-onsemi | 0:098463de4c5d | 4 | * |
| group-onsemi | 0:098463de4c5d | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may |
| group-onsemi | 0:098463de4c5d | 6 | * not use this file except in compliance with the License. |
| group-onsemi | 0:098463de4c5d | 7 | * You may obtain a copy of the License at |
| group-onsemi | 0:098463de4c5d | 8 | * |
| group-onsemi | 0:098463de4c5d | 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| group-onsemi | 0:098463de4c5d | 10 | * |
| group-onsemi | 0:098463de4c5d | 11 | * Unless required by applicable law or agreed to in writing, software |
| group-onsemi | 0:098463de4c5d | 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| group-onsemi | 0:098463de4c5d | 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| group-onsemi | 0:098463de4c5d | 14 | * See the License for the specific language governing permissions and |
| group-onsemi | 0:098463de4c5d | 15 | * limitations under the License. |
| group-onsemi | 0:098463de4c5d | 16 | */ |
| group-onsemi | 0:098463de4c5d | 17 | |
| group-onsemi | 0:098463de4c5d | 18 | #include "rt_TypeDef.h" |
| group-onsemi | 0:098463de4c5d | 19 | #include "rt_Memory.h" |
| group-onsemi | 0:098463de4c5d | 20 | |
| group-onsemi | 0:098463de4c5d | 21 | #include "secure_allocator.h" |
| group-onsemi | 0:098463de4c5d | 22 | #include "uvisor-lib/uvisor-lib.h" |
| group-onsemi | 0:098463de4c5d | 23 | |
| group-onsemi | 0:098463de4c5d | 24 | #include <stdio.h> |
| group-onsemi | 0:098463de4c5d | 25 | #include <stdlib.h> |
| group-onsemi | 0:098463de4c5d | 26 | #include <string.h> |
| group-onsemi | 0:098463de4c5d | 27 | |
| group-onsemi | 0:098463de4c5d | 28 | /* Use printf with caution inside malloc: printf may allocate memory itself, |
| group-onsemi | 0:098463de4c5d | 29 | so using printf in malloc may lead to recursive calls! */ |
| group-onsemi | 0:098463de4c5d | 30 | #define DPRINTF(...) {} |
| group-onsemi | 0:098463de4c5d | 31 | |
| group-onsemi | 0:098463de4c5d | 32 | /* offsetof is a gcc built-in function, this is the manual implementation */ |
| group-onsemi | 0:098463de4c5d | 33 | #define OFFSETOF(type, member) ((uint32_t) (&(((type *)(0))->member))) |
| group-onsemi | 0:098463de4c5d | 34 | |
| group-onsemi | 0:098463de4c5d | 35 | /* Internal structure currently only contains the page table. */ |
| group-onsemi | 0:098463de4c5d | 36 | typedef struct { |
| group-onsemi | 0:098463de4c5d | 37 | UvisorPageTable table; |
| group-onsemi | 0:098463de4c5d | 38 | } SecureAllocatorInternal; |
| group-onsemi | 0:098463de4c5d | 39 | |
| group-onsemi | 0:098463de4c5d | 40 | static inline UvisorPageTable * table(SecureAllocator allocator) { |
| group-onsemi | 0:098463de4c5d | 41 | return &(((SecureAllocatorInternal *) allocator)->table); |
| group-onsemi | 0:098463de4c5d | 42 | } |
| group-onsemi | 0:098463de4c5d | 43 | |
| group-onsemi | 0:098463de4c5d | 44 | SecureAllocator secure_allocator_create_with_pool( |
| group-onsemi | 0:098463de4c5d | 45 | void * mem, |
| group-onsemi | 0:098463de4c5d | 46 | size_t bytes) |
| group-onsemi | 0:098463de4c5d | 47 | { |
| group-onsemi | 0:098463de4c5d | 48 | SecureAllocatorInternal * allocator = mem; |
| group-onsemi | 0:098463de4c5d | 49 | /* Signal that this is non-page allocated memory. */ |
| group-onsemi | 0:098463de4c5d | 50 | allocator->table.page_size = bytes; |
| group-onsemi | 0:098463de4c5d | 51 | allocator->table.page_count = 0; |
| group-onsemi | 0:098463de4c5d | 52 | /* The internal rt_Memory MEMP structure must be placed AFTER table.page_origins[0] !!! */ |
| group-onsemi | 0:098463de4c5d | 53 | size_t offset = OFFSETOF(SecureAllocatorInternal, table.page_origins) + sizeof(((UvisorPageTable) {0}).page_origins); |
| group-onsemi | 0:098463de4c5d | 54 | /* Create MEMP structure inside the memory. */ |
| group-onsemi | 0:098463de4c5d | 55 | if (rt_init_mem(mem + offset, bytes - offset)) { |
| group-onsemi | 0:098463de4c5d | 56 | /* Abort if failed. */ |
| group-onsemi | 0:098463de4c5d | 57 | DPRINTF("secure_allocator_create_with_pool: MEMP allocator creation failed\n\n"); |
| group-onsemi | 0:098463de4c5d | 58 | return NULL; |
| group-onsemi | 0:098463de4c5d | 59 | } |
| group-onsemi | 0:098463de4c5d | 60 | /* Remember the MEMP pointer though. */ |
| group-onsemi | 0:098463de4c5d | 61 | allocator->table.page_origins[0] = mem + offset; |
| group-onsemi | 0:098463de4c5d | 62 | DPRINTF("secure_allocator_create_with_pool: Created MEMP allocator %p with offset %d\n\n", mem + offset, offset); |
| group-onsemi | 0:098463de4c5d | 63 | return allocator; |
| group-onsemi | 0:098463de4c5d | 64 | } |
| group-onsemi | 0:098463de4c5d | 65 | |
| group-onsemi | 0:098463de4c5d | 66 | SecureAllocator secure_allocator_create_with_pages( |
| group-onsemi | 0:098463de4c5d | 67 | size_t size, |
| group-onsemi | 0:098463de4c5d | 68 | size_t maximum_malloc_size) |
| group-onsemi | 0:098463de4c5d | 69 | { |
| group-onsemi | 0:098463de4c5d | 70 | const uint32_t page_size = uvisor_get_page_size(); |
| group-onsemi | 0:098463de4c5d | 71 | /* The rt_Memory allocator puts one MEMP structure at both the |
| group-onsemi | 0:098463de4c5d | 72 | * beginning and end of the memory pool. */ |
| group-onsemi | 0:098463de4c5d | 73 | const size_t block_overhead = 2 * sizeof(MEMP); |
| group-onsemi | 0:098463de4c5d | 74 | const size_t page_size_with_overhead = page_size + block_overhead; |
| group-onsemi | 0:098463de4c5d | 75 | /* Calculate the integer part of required the page count. */ |
| group-onsemi | 0:098463de4c5d | 76 | size_t page_count = size / page_size_with_overhead; |
| group-onsemi | 0:098463de4c5d | 77 | /* Add another page if the remainder is not zero. */ |
| group-onsemi | 0:098463de4c5d | 78 | if (size - page_count * page_size_with_overhead) { |
| group-onsemi | 0:098463de4c5d | 79 | page_count++; |
| group-onsemi | 0:098463de4c5d | 80 | } |
| group-onsemi | 0:098463de4c5d | 81 | DPRINTF("secure_allocator_create_with_pages: Requesting %u pages for at least %uB\n", page_count, size); |
| group-onsemi | 0:098463de4c5d | 82 | |
| group-onsemi | 0:098463de4c5d | 83 | /* Compute the maximum allocation within our blocks. */ |
| group-onsemi | 0:098463de4c5d | 84 | size_t maximum_allocation_size = page_size - block_overhead; |
| group-onsemi | 0:098463de4c5d | 85 | /* If the required maximum allocation is larger than we can provide, abort. */ |
| group-onsemi | 0:098463de4c5d | 86 | if (maximum_malloc_size > maximum_allocation_size) { |
| group-onsemi | 0:098463de4c5d | 87 | DPRINTF("secure_allocator_create_with_pages: Maximum allocation request %uB is larger then available %uB\n\n", maximum_malloc_size, maximum_allocation_size); |
| group-onsemi | 0:098463de4c5d | 88 | return NULL; |
| group-onsemi | 0:098463de4c5d | 89 | } |
| group-onsemi | 0:098463de4c5d | 90 | |
| group-onsemi | 0:098463de4c5d | 91 | /* Compute the required memory size for the page table. */ |
| group-onsemi | 0:098463de4c5d | 92 | size_t allocator_type_size = sizeof(SecureAllocatorInternal); |
| group-onsemi | 0:098463de4c5d | 93 | /* Add size for each additional page. */ |
| group-onsemi | 0:098463de4c5d | 94 | allocator_type_size += (page_count - 1) * sizeof(((UvisorPageTable) {0}).page_origins); |
| group-onsemi | 0:098463de4c5d | 95 | /* Allocate this much memory. */ |
| group-onsemi | 0:098463de4c5d | 96 | SecureAllocatorInternal * const allocator = malloc(allocator_type_size); |
| group-onsemi | 0:098463de4c5d | 97 | /* If malloc failed, abort. */ |
| group-onsemi | 0:098463de4c5d | 98 | if (allocator == NULL) { |
| group-onsemi | 0:098463de4c5d | 99 | DPRINTF("secure_allocator_create_with_pages: SecureAllocatorInternal failed to be allocated!\n\n"); |
| group-onsemi | 0:098463de4c5d | 100 | return NULL; |
| group-onsemi | 0:098463de4c5d | 101 | } |
| group-onsemi | 0:098463de4c5d | 102 | |
| group-onsemi | 0:098463de4c5d | 103 | /* Prepare the page table. */ |
| group-onsemi | 0:098463de4c5d | 104 | allocator->table.page_size = page_size; |
| group-onsemi | 0:098463de4c5d | 105 | allocator->table.page_count = page_count; |
| group-onsemi | 0:098463de4c5d | 106 | /* Get me some pages. */ |
| group-onsemi | 0:098463de4c5d | 107 | if (uvisor_page_malloc((UvisorPageTable *) &(allocator->table))) { |
| group-onsemi | 0:098463de4c5d | 108 | free(allocator); |
| group-onsemi | 0:098463de4c5d | 109 | DPRINTF("secure_allocator_create_with_pages: Not enough free pages available!\n\n"); |
| group-onsemi | 0:098463de4c5d | 110 | return NULL; |
| group-onsemi | 0:098463de4c5d | 111 | } |
| group-onsemi | 0:098463de4c5d | 112 | |
| group-onsemi | 0:098463de4c5d | 113 | /* Initialize a MEMP structure in all pages. */ |
| group-onsemi | 0:098463de4c5d | 114 | for(size_t ii = 0; ii < page_count; ii++) { |
| group-onsemi | 0:098463de4c5d | 115 | /* Add each page as a pool. */ |
| group-onsemi | 0:098463de4c5d | 116 | rt_init_mem(allocator->table.page_origins[ii], page_size); |
| group-onsemi | 0:098463de4c5d | 117 | DPRINTF("secure_allocator_create_with_pages: Created MEMP allocator %p with offset %d\n", allocator->table.page_origins[ii], 0); |
| group-onsemi | 0:098463de4c5d | 118 | } |
| group-onsemi | 0:098463de4c5d | 119 | DPRINTF("\n"); |
| group-onsemi | 0:098463de4c5d | 120 | /* Aaaand across the line. */ |
| group-onsemi | 0:098463de4c5d | 121 | return (SecureAllocator) allocator; |
| group-onsemi | 0:098463de4c5d | 122 | } |
| group-onsemi | 0:098463de4c5d | 123 | |
| group-onsemi | 0:098463de4c5d | 124 | int secure_allocator_destroy( |
| group-onsemi | 0:098463de4c5d | 125 | SecureAllocator allocator) |
| group-onsemi | 0:098463de4c5d | 126 | { |
| group-onsemi | 0:098463de4c5d | 127 | DPRINTF("secure_allocator_destroy: Destroying MEMP allocator at %p\n", table(allocator)->page_origins[0]); |
| group-onsemi | 0:098463de4c5d | 128 | |
| group-onsemi | 0:098463de4c5d | 129 | /* Check if we are working on statically allocated memory. */ |
| group-onsemi | 0:098463de4c5d | 130 | SecureAllocatorInternal * alloc = (SecureAllocatorInternal * const) allocator; |
| group-onsemi | 0:098463de4c5d | 131 | if (alloc->table.page_count == 0) { |
| group-onsemi | 0:098463de4c5d | 132 | DPRINTF("secure_allocator_destroy: %p is not page-backed memory, not freeing!\n", allocator); |
| group-onsemi | 0:098463de4c5d | 133 | return -1; |
| group-onsemi | 0:098463de4c5d | 134 | } |
| group-onsemi | 0:098463de4c5d | 135 | |
| group-onsemi | 0:098463de4c5d | 136 | /* Free all pages. */ |
| group-onsemi | 0:098463de4c5d | 137 | if (uvisor_page_free(&(alloc->table))) { |
| group-onsemi | 0:098463de4c5d | 138 | DPRINTF("secure_allocator_destroy: Unable to free pages!\n\n"); |
| group-onsemi | 0:098463de4c5d | 139 | return -1; |
| group-onsemi | 0:098463de4c5d | 140 | } |
| group-onsemi | 0:098463de4c5d | 141 | |
| group-onsemi | 0:098463de4c5d | 142 | /* Free the allocator structure. */ |
| group-onsemi | 0:098463de4c5d | 143 | free(allocator); |
| group-onsemi | 0:098463de4c5d | 144 | |
| group-onsemi | 0:098463de4c5d | 145 | DPRINTF("\n"); |
| group-onsemi | 0:098463de4c5d | 146 | return 0; |
| group-onsemi | 0:098463de4c5d | 147 | } |
| group-onsemi | 0:098463de4c5d | 148 | |
| group-onsemi | 0:098463de4c5d | 149 | void * secure_malloc( |
| group-onsemi | 0:098463de4c5d | 150 | SecureAllocator allocator, |
| group-onsemi | 0:098463de4c5d | 151 | size_t size) |
| group-onsemi | 0:098463de4c5d | 152 | { |
| group-onsemi | 0:098463de4c5d | 153 | size_t index = 0; |
| group-onsemi | 0:098463de4c5d | 154 | do { |
| group-onsemi | 0:098463de4c5d | 155 | /* Search in this page. */ |
| group-onsemi | 0:098463de4c5d | 156 | void * mem = rt_alloc_mem(table(allocator)->page_origins[index], size); |
| group-onsemi | 0:098463de4c5d | 157 | /* Return if we found something. */ |
| group-onsemi | 0:098463de4c5d | 158 | if (mem) { |
| group-onsemi | 0:098463de4c5d | 159 | DPRINTF("secure_malloc: Found %4uB in page %u at %p\n", size, index, mem); |
| group-onsemi | 0:098463de4c5d | 160 | return mem; |
| group-onsemi | 0:098463de4c5d | 161 | } |
| group-onsemi | 0:098463de4c5d | 162 | /* Otherwise, go to the next page. */ |
| group-onsemi | 0:098463de4c5d | 163 | index++; |
| group-onsemi | 0:098463de4c5d | 164 | } /* Continue search if more pages are available. */ |
| group-onsemi | 0:098463de4c5d | 165 | while (index < table(allocator)->page_count); |
| group-onsemi | 0:098463de4c5d | 166 | |
| group-onsemi | 0:098463de4c5d | 167 | DPRINTF("secure_malloc: Out of memory in allocator %p \n", allocator); |
| group-onsemi | 0:098463de4c5d | 168 | /* We found nothing. */ |
| group-onsemi | 0:098463de4c5d | 169 | return NULL; |
| group-onsemi | 0:098463de4c5d | 170 | } |
| group-onsemi | 0:098463de4c5d | 171 | |
| group-onsemi | 0:098463de4c5d | 172 | void * secure_realloc( |
| group-onsemi | 0:098463de4c5d | 173 | SecureAllocator allocator, |
| group-onsemi | 0:098463de4c5d | 174 | void * ptr, |
| group-onsemi | 0:098463de4c5d | 175 | size_t new_size) |
| group-onsemi | 0:098463de4c5d | 176 | { |
| group-onsemi | 0:098463de4c5d | 177 | /* TODO: THIS IS A NAIVE IMPLEMENTATION, which always allocates new |
| group-onsemi | 0:098463de4c5d | 178 | memory, and copies the memory, then frees the old memory. */ |
| group-onsemi | 0:098463de4c5d | 179 | |
| group-onsemi | 0:098463de4c5d | 180 | /* Allocate new memory. */ |
| group-onsemi | 0:098463de4c5d | 181 | void * new_ptr = secure_malloc(allocator, new_size); |
| group-onsemi | 0:098463de4c5d | 182 | /* If memory allocation failed, abort. */ |
| group-onsemi | 0:098463de4c5d | 183 | if (new_ptr == NULL) { |
| group-onsemi | 0:098463de4c5d | 184 | return NULL; |
| group-onsemi | 0:098463de4c5d | 185 | } |
| group-onsemi | 0:098463de4c5d | 186 | |
| group-onsemi | 0:098463de4c5d | 187 | /* Passing NULL as ptr is legal, realloc acts as malloc then. */ |
| group-onsemi | 0:098463de4c5d | 188 | if (ptr) { |
| group-onsemi | 0:098463de4c5d | 189 | /* Get the size of the ptr memory. */ |
| group-onsemi | 0:098463de4c5d | 190 | size_t size = ((MEMP *) ((uint32_t) ptr - sizeof(MEMP)))->len; |
| group-onsemi | 0:098463de4c5d | 191 | /* Copy the memory to the new location, min(new_size, size). */ |
| group-onsemi | 0:098463de4c5d | 192 | memcpy(new_ptr, ptr, new_size < size ? new_size : size); |
| group-onsemi | 0:098463de4c5d | 193 | /* Free the previous memory. */ |
| group-onsemi | 0:098463de4c5d | 194 | secure_free(allocator, ptr); |
| group-onsemi | 0:098463de4c5d | 195 | } |
| group-onsemi | 0:098463de4c5d | 196 | return new_ptr; |
| group-onsemi | 0:098463de4c5d | 197 | } |
| group-onsemi | 0:098463de4c5d | 198 | |
| group-onsemi | 0:098463de4c5d | 199 | void secure_free( |
| group-onsemi | 0:098463de4c5d | 200 | SecureAllocator allocator, |
| group-onsemi | 0:098463de4c5d | 201 | void * ptr) |
| group-onsemi | 0:098463de4c5d | 202 | { |
| group-onsemi | 0:098463de4c5d | 203 | size_t index = 0; |
| group-onsemi | 0:098463de4c5d | 204 | do { |
| group-onsemi | 0:098463de4c5d | 205 | /* Search in this page. */ |
| group-onsemi | 0:098463de4c5d | 206 | int ret = rt_free_mem(table(allocator)->page_origins[index], ptr); |
| group-onsemi | 0:098463de4c5d | 207 | /* Return if free was successful. */ |
| group-onsemi | 0:098463de4c5d | 208 | if (ret == 0) { |
| group-onsemi | 0:098463de4c5d | 209 | DPRINTF("secure_free: Freed %p in page %u.\n", ptr, index); |
| group-onsemi | 0:098463de4c5d | 210 | return; |
| group-onsemi | 0:098463de4c5d | 211 | } |
| group-onsemi | 0:098463de4c5d | 212 | /* Otherwise, go to the next page. */ |
| group-onsemi | 0:098463de4c5d | 213 | index++; |
| group-onsemi | 0:098463de4c5d | 214 | } /* Continue search if more pages are available. */ |
| group-onsemi | 0:098463de4c5d | 215 | while (index < table(allocator)->page_count); |
| group-onsemi | 0:098463de4c5d | 216 | |
| group-onsemi | 0:098463de4c5d | 217 | DPRINTF("secure_free: %p not found in allocator %p!\n", ptr, allocator); |
| group-onsemi | 0:098463de4c5d | 218 | /* We found nothing. */ |
| group-onsemi | 0:098463de4c5d | 219 | return; |
| group-onsemi | 0:098463de4c5d | 220 | } |