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