Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers rtx_malloc_wrapper.c Source File

rtx_malloc_wrapper.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 "cmsis_os2.h"
00019 #include "uvisor-lib/uvisor-lib.h"
00020 
00021 #include <stdint.h>
00022 #include <stddef.h>
00023 #include <stdio.h>
00024 #include <reent.h>
00025 
00026 /*
00027  * These are the C standard memory functions:
00028  * - void *calloc(size_t nmemb, size_t size);
00029  * - void free(void *ptr);
00030  * - void *malloc(size_t size);
00031  * - void *realloc(void *ptr, size_t size);
00032 */
00033 
00034 /* Use printf with caution inside malloc: printf may allocate memory itself,
00035    so using printf in malloc may lead to recursive calls! */
00036 #define DPRINTF(...) {};
00037 
00038 extern RtxBoxIndex * const __uvisor_ps;
00039 
00040 /** @retval 0 The kernel is not initialized.
00041  *  @retval 1 The kernel is initialized.. */
00042 static int is_kernel_initialized()
00043 {
00044     /* TODO: Bare-bone boxes must not call any RTX2 functions for now.
00045      * Each box should instead provide `heap_lock` and `heap_unlock` functions
00046      * as part of the box context. These would just be empty for boxes without
00047      * the need for heap locking. */
00048     if (__uvisor_ps->index.box_id_self != 0) {
00049         return 0;
00050     }
00051 
00052     static uint8_t kernel_running = 0;
00053     if (kernel_running) {
00054         return 1;
00055     }
00056     if (osKernelGetState() == osKernelRunning) {
00057         kernel_running = 1;
00058         return 1;
00059     }
00060     return 0;
00061 }
00062 
00063 static int init_allocator()
00064 {
00065     int ret = 0;
00066     if (__uvisor_ps == NULL) {
00067 #if defined(UVISOR_PRESENT) && (UVISOR_PRESENT == 1)
00068         return -1;
00069 #else
00070         extern void secure_malloc_init(void);
00071         secure_malloc_init();
00072 #endif
00073     }
00074 
00075     if ((__uvisor_ps->mutex_id == NULL) && is_kernel_initialized()) {
00076         /* Point the mutex attr to the data. */
00077         __uvisor_ps->mutex_attr.name = "uvisor_malloc_mutex";
00078         __uvisor_ps->mutex_attr.attr_bits = 0; /* Non-recursive */
00079         __uvisor_ps->mutex_attr.cb_mem = &__uvisor_ps->mutex_data;
00080         __uvisor_ps->mutex_attr.cb_size = sizeof(__uvisor_ps->mutex_data);
00081 
00082         /* Create mutex if not already done. */
00083         __uvisor_ps->mutex_id = osMutexNew(&__uvisor_ps->mutex_attr);
00084         /* Mutex failed to be created. */
00085         if (__uvisor_ps->mutex_id == NULL) {
00086             return -1;
00087         }
00088     }
00089 
00090     if (__uvisor_ps->index.active_heap == NULL) {
00091         /* We need to initialize the process heap. */
00092         if ((void *) __uvisor_ps->index.bss.address_of.heap != NULL) {
00093             /* Lock the mutex during initialization. */
00094             int kernel_initialized = is_kernel_initialized();
00095             if (kernel_initialized) {
00096                 osMutexAcquire(__uvisor_ps->mutex_id, osWaitForever);
00097             }
00098             /* Initialize the process heap. */
00099             SecureAllocator allocator = secure_allocator_create_with_pool(
00100                 (void *) __uvisor_ps->index.bss.address_of.heap,
00101                 __uvisor_ps->index.box_heap_size);
00102             /* Set the allocator. */
00103             ret = allocator ? 0 : -1;
00104             __uvisor_ps->index.active_heap = allocator;
00105             /* Release the mutex. */
00106             if (kernel_initialized) {
00107                 osMutexRelease(__uvisor_ps->mutex_id);
00108             }
00109         }
00110         else {
00111             DPRINTF("uvisor_allocator: No process heap available!\n");
00112             ret = -1;
00113         }
00114     }
00115     return ret;
00116 }
00117 
00118 typedef enum {
00119     MEMOP_MALLOC,
00120     MEMOP_MEMALIGN,
00121     MEMOP_CALLOC,
00122     MEMOP_REALLOC,
00123     MEMOP_FREE
00124 } MemoryOperation;
00125 
00126 
00127 static void * memory(MemoryOperation operation, uint32_t * args)
00128 {
00129     /* Buffer the return value. */
00130     void * ret = NULL;
00131     /* Initialize allocator. */
00132     if (init_allocator()) {
00133         return NULL;
00134     }
00135     /* Check if we need to aquire the mutex. */
00136     int mutexed = is_kernel_initialized();
00137     void * allocator = __uvisor_ps->index.active_heap;
00138 
00139     /* Aquire the mutex if required.
00140      * TODO: Mutex use is very coarse here. It may be sufficient to guard
00141      * the `rt_alloc_mem` and `rt_free_mem` functions in `uvisor_allocator.c`.
00142      * However, it is simpler to do it here for now. */
00143     if (mutexed) {
00144         osMutexAcquire(__uvisor_ps->mutex_id, osWaitForever);
00145     }
00146     /* Perform the required operation. */
00147     switch(operation)
00148     {
00149         case MEMOP_MALLOC:
00150             ret = secure_malloc(allocator, (size_t) args[0]);
00151             break;
00152         case MEMOP_MEMALIGN:
00153             ret = secure_aligned_alloc(allocator, (size_t) args[0], (size_t) args[1]);
00154             break;
00155         case MEMOP_CALLOC:
00156             ret = secure_calloc(allocator, (size_t) args[0], (size_t) args[1]);
00157             break;
00158         case MEMOP_REALLOC:
00159             ret = secure_realloc(allocator, (void *) args[0], (size_t) args[1]);
00160             break;
00161         case MEMOP_FREE:
00162             secure_free(allocator, (void *) args[0]);
00163             break;
00164         default:
00165             break;
00166     }
00167     /* Release the mutex if required. */
00168     if (mutexed) {
00169         osMutexRelease(__uvisor_ps->mutex_id);
00170     }
00171     return ret;
00172 }
00173 
00174 /* Wrapped memory management functions. */
00175 #if defined (__GNUC__)
00176 
00177 void * __wrap__malloc_r(struct _reent * r, size_t size) {
00178     (void) r;
00179     return memory(MEMOP_MALLOC, (uint32_t *) &size);
00180 }
00181 void * __wrap__memalign_r(struct _reent * r, size_t alignment, size_t bytes) {
00182     (void) r;
00183     uint32_t args[2] = {(uint32_t) alignment, (uint32_t) bytes};
00184     return memory(MEMOP_MEMALIGN, args);
00185 }
00186 void * __wrap__calloc_r(struct _reent * r, size_t nmemb, size_t size) {
00187     (void) r;
00188     uint32_t args[2] = {(uint32_t) nmemb, (uint32_t) size};
00189     return memory(MEMOP_CALLOC, args);
00190 }
00191 void * __wrap__realloc_r(struct _reent * r, void * ptr, size_t size) {
00192     (void) r;
00193     uint32_t args[2] = {(uint32_t) ptr, (uint32_t) size};
00194     return memory(MEMOP_REALLOC, args);
00195 }
00196 void __wrap__free_r(struct _reent * r, void * ptr) {
00197     (void) r;
00198     memory(MEMOP_FREE, (uint32_t *) &ptr);
00199 }
00200 
00201 #elif defined (__CC_ARM)
00202 /* TODO: Find out how to do function wrapping for ARMCC. See microlib libc. */
00203 #   warning "Using uVisor allocator is not available for ARMCC. Falling back to default allocator."
00204 #elif defined (__ICCARM__)
00205 /* TODO: Find out how to do function wrapping for IARCC. */
00206 #   warning "Using uVisor allocator is not available for IARCC. Falling back to default allocator."
00207 #endif