ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Committer:
group-onsemi
Date:
Wed Jan 25 20:34:15 2017 +0000
Revision:
0:098463de4c5d
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew 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 }