1/* 2 * Copyright 2018, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13// #define ZF_LOG_LEVEL ZF_LOG_DEBUG 14 15#include <utils/util.h> 16 17#include <sync/mutex.h> 18 19#include <camkes/sync.h> 20#include <camkes/allocator.h> 21#include <camkes/tls.h> 22 23/* Allocates a mutex using camkes_alloc */ 24static void *camkes_mutex_new(void) 25{ 26 ZF_LOGD("called by %p", 27 camkes_get_tls()->thread_index); 28 29 /* The arguments to camkes_alloc need to match what arguements were given when the objects were added 30 * to the allocator by the camkes runtime. It treates notification objects as 0 sized and with Read 31 * Write cap rights. */ 32 seL4_CPtr cap = camkes_alloc(seL4_NotificationObject, 0, seL4_CanRead.words[0] | seL4_CanWrite.words[0]); 33 if (cap == seL4_CapNull) { 34 ZF_LOGE("Failed to allocate notification object"); 35 return NULL; 36 } 37 38 /* Allocate underlying mutex struct. We use the implementation from libsel4sync */ 39 sync_mutex_t *mtx = calloc(1, sizeof(mtx[0])); 40 if (mtx == NULL) { 41 ZF_LOGE("ENOMEM allocating malloc"); 42 camkes_free(cap); 43 return NULL; 44 } 45 46 /* Init the mutex. */ 47 int res = sync_mutex_init(mtx, cap); 48 if (res) { 49 ZF_LOGE("sync_mutex_init failed"); 50 free(mtx); 51 camkes_free(cap); 52 return NULL; 53 } 54 return mtx; 55} 56 57static int camkes_mutex_lock(void *mutex) 58{ 59 ZF_LOGD("called by %p on cap %d", 60 camkes_get_tls()->thread_index, 61 ((sync_mutex_t *)mutex)->notification.cptr); 62 return sync_mutex_lock(mutex); 63} 64 65static int camkes_mutex_unlock(void *mutex) 66{ 67 ZF_LOGD("called by %p on cap %d", 68 camkes_get_tls()->thread_index, 69 ((sync_mutex_t *)mutex)->notification.cptr); 70 return sync_mutex_unlock(mutex); 71} 72 73/* Free a mutex back to the camkes allocator */ 74static int camkes_mutex_free(void *mutex) 75{ 76 ZF_LOGD("called by %p on cap %d", 77 camkes_get_tls()->thread_index, 78 ((sync_mutex_t *)mutex)->notification.cptr); 79 /* There isn't a sync_mutex_free for a preallocated mutex. 80 * We just release the Cap the notification object to the camkes allocator. 81 */ 82 sync_mutex_t *mtx = mutex; 83 camkes_free(mtx->notification.cptr); 84 free(mtx); 85 return 0; 86} 87 88/** 89 * Populates function pointers. Takes a preallocated struct. 90 */ 91int init_camkes_mutex_ops(ps_mutex_ops_t *mutex_ops) 92{ 93 if (mutex_ops == NULL) { 94 ZF_LOGE("Trying to init a NULL mutex_ops"); 95 return -1; 96 } 97 ps_mutex_ops_t mutex_ops_interface = { 98 .mutex_new = camkes_mutex_new, 99 .mutex_lock = camkes_mutex_lock, 100 .mutex_unlock = camkes_mutex_unlock, 101 .mutex_destroy = camkes_mutex_free, 102 }; 103 104 105 *mutex_ops = mutex_ops_interface; 106 return 0; 107} 108 109 110/** 111 * Allocates the allocator struct and then calls init_default_allocator 112 */ 113int init_camkes_mutex_ops_heap(ps_mutex_ops_t **mutex_ops) 114{ 115 if (mutex_ops == NULL) { 116 ZF_LOGE("Trying to init a NULL mutex_ops"); 117 return -1; 118 } 119 *mutex_ops = malloc(sizeof(ps_mutex_ops_t)); 120 if (*mutex_ops == NULL) { 121 ZF_LOGE("Trying to init a NULL allocator"); 122 return -1; 123 } 124 return init_camkes_mutex_ops(*mutex_ops); 125 126} 127 128