[7e3826d9] | 1 | /*
|
---|
| 2 | * Copyright (c) 2017 Jakub Jermar
|
---|
| 3 | * All rights reserved.
|
---|
| 4 | *
|
---|
| 5 | * Redistribution and use in source and binary forms, with or without
|
---|
| 6 | * modification, are permitted provided that the following conditions
|
---|
| 7 | * are met:
|
---|
| 8 | *
|
---|
| 9 | * - Redistributions of source code must retain the above copyright
|
---|
| 10 | * notice, this list of conditions and the following disclaimer.
|
---|
| 11 | * - Redistributions in binary form must reproduce the above copyright
|
---|
| 12 | * notice, this list of conditions and the following disclaimer in the
|
---|
| 13 | * documentation and/or other materials provided with the distribution.
|
---|
| 14 | * - The name of the author may not be used to endorse or promote products
|
---|
| 15 | * derived from this software without specific prior written permission.
|
---|
| 16 | *
|
---|
| 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
---|
| 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
---|
| 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
---|
| 20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
---|
| 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
---|
| 22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
---|
| 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
---|
| 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
---|
| 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
---|
| 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
| 27 | */
|
---|
| 28 |
|
---|
| 29 | /** @addtogroup generic
|
---|
| 30 | * @{
|
---|
| 31 | */
|
---|
| 32 | /** @file
|
---|
| 33 | */
|
---|
| 34 |
|
---|
[3f74275] | 35 | #include <cap/cap.h>
|
---|
[7e3826d9] | 36 | #include <proc/task.h>
|
---|
[9e87562] | 37 | #include <synch/mutex.h>
|
---|
[e9d15d9] | 38 | #include <abi/errno.h>
|
---|
[e7ac23d0] | 39 | #include <mm/slab.h>
|
---|
[9e87562] | 40 | #include <adt/list.h>
|
---|
[7e3826d9] | 41 |
|
---|
[48bcf49] | 42 | static kobject_t *cap_unpublish_locked(task_t *, cap_handle_t, kobject_type_t);
|
---|
| 43 |
|
---|
| 44 | void cap_initialize(cap_t *cap, cap_handle_t handle)
|
---|
[05ffb41] | 45 | {
|
---|
[48bcf49] | 46 | cap->state = CAP_STATE_FREE;
|
---|
[e68765e] | 47 | cap->handle = handle;
|
---|
[9e87562] | 48 | link_initialize(&cap->link);
|
---|
[05ffb41] | 49 | }
|
---|
| 50 |
|
---|
[3f74275] | 51 | void caps_task_alloc(task_t *task)
|
---|
[e7ac23d0] | 52 | {
|
---|
[9e87562] | 53 | task->cap_info = (cap_info_t *) malloc(sizeof(cap_info_t), 0);
|
---|
| 54 | task->cap_info->caps = malloc(sizeof(cap_t) * MAX_CAPS, 0);
|
---|
[e7ac23d0] | 55 | }
|
---|
| 56 |
|
---|
[3f74275] | 57 | void caps_task_init(task_t *task)
|
---|
[e7ac23d0] | 58 | {
|
---|
[9e87562] | 59 | mutex_initialize(&task->cap_info->lock, MUTEX_PASSIVE);
|
---|
| 60 |
|
---|
[48bcf49] | 61 | for (kobject_type_t t = 0; t < KOBJECT_TYPE_MAX; t++)
|
---|
| 62 | list_initialize(&task->cap_info->type_list[t]);
|
---|
[9e87562] | 63 |
|
---|
[48bcf49] | 64 | for (cap_handle_t h = 0; h < MAX_CAPS; h++)
|
---|
| 65 | cap_initialize(&task->cap_info->caps[h], h);
|
---|
[e7ac23d0] | 66 | }
|
---|
| 67 |
|
---|
[3f74275] | 68 | void caps_task_free(task_t *task)
|
---|
[e7ac23d0] | 69 | {
|
---|
[9e87562] | 70 | free(task->cap_info->caps);
|
---|
| 71 | free(task->cap_info);
|
---|
| 72 | }
|
---|
| 73 |
|
---|
[48bcf49] | 74 | bool caps_apply_to_kobject_type(task_t *task, kobject_type_t type,
|
---|
[9e87562] | 75 | bool (*cb)(cap_t *, void *), void *arg)
|
---|
| 76 | {
|
---|
| 77 | bool done = true;
|
---|
| 78 |
|
---|
| 79 | mutex_lock(&task->cap_info->lock);
|
---|
| 80 | list_foreach_safe(task->cap_info->type_list[type], cur, next) {
|
---|
| 81 | cap_t *cap = list_get_instance(cur, cap_t, link);
|
---|
| 82 | done = cb(cap, arg);
|
---|
| 83 | if (!done)
|
---|
| 84 | break;
|
---|
| 85 | }
|
---|
| 86 | mutex_unlock(&task->cap_info->lock);
|
---|
| 87 |
|
---|
| 88 | return done;
|
---|
| 89 | }
|
---|
| 90 |
|
---|
[48bcf49] | 91 | static cap_t *cap_get(task_t *task, cap_handle_t handle, cap_state_t state)
|
---|
[7e3826d9] | 92 | {
|
---|
[9e87562] | 93 | assert(mutex_locked(&task->cap_info->lock));
|
---|
| 94 |
|
---|
[3f74275] | 95 | if ((handle < 0) || (handle >= MAX_CAPS))
|
---|
[7e3826d9] | 96 | return NULL;
|
---|
[48bcf49] | 97 | if (task->cap_info->caps[handle].state != state)
|
---|
[7e3826d9] | 98 | return NULL;
|
---|
[9e87562] | 99 | return &task->cap_info->caps[handle];
|
---|
[7e3826d9] | 100 | }
|
---|
| 101 |
|
---|
[48bcf49] | 102 | cap_handle_t cap_alloc(task_t *task)
|
---|
[7e3826d9] | 103 | {
|
---|
[9e87562] | 104 | mutex_lock(&task->cap_info->lock);
|
---|
[48bcf49] | 105 | for (cap_handle_t handle = 0; handle < MAX_CAPS; handle++) {
|
---|
[9e87562] | 106 | cap_t *cap = &task->cap_info->caps[handle];
|
---|
[48bcf49] | 107 | /* See if the capability should be garbage-collected */
|
---|
| 108 | if (cap->state == CAP_STATE_PUBLISHED &&
|
---|
| 109 | cap->kobject->ops->reclaim &&
|
---|
| 110 | cap->kobject->ops->reclaim(cap->kobject)) {
|
---|
| 111 | kobject_t *kobj = cap_unpublish_locked(task, handle,
|
---|
| 112 | cap->kobject->type);
|
---|
| 113 | kobject_put(kobj);
|
---|
| 114 | cap_initialize(&task->cap_info->caps[handle], handle);
|
---|
[05ffb41] | 115 | }
|
---|
[48bcf49] | 116 | if (cap->state == CAP_STATE_FREE) {
|
---|
| 117 | cap->state = CAP_STATE_ALLOCATED;
|
---|
[9e87562] | 118 | mutex_unlock(&task->cap_info->lock);
|
---|
[3f74275] | 119 | return handle;
|
---|
[7e3826d9] | 120 | }
|
---|
| 121 | }
|
---|
[9e87562] | 122 | mutex_unlock(&task->cap_info->lock);
|
---|
[7e3826d9] | 123 |
|
---|
[e9d15d9] | 124 | return ELIMIT;
|
---|
[7e3826d9] | 125 | }
|
---|
| 126 |
|
---|
[48bcf49] | 127 | void
|
---|
| 128 | cap_publish(task_t *task, cap_handle_t handle, kobject_t *kobj)
|
---|
[9e87562] | 129 | {
|
---|
| 130 | mutex_lock(&task->cap_info->lock);
|
---|
[48bcf49] | 131 | cap_t *cap = cap_get(task, handle, CAP_STATE_ALLOCATED);
|
---|
[9e87562] | 132 | assert(cap);
|
---|
[48bcf49] | 133 | cap->state = CAP_STATE_PUBLISHED;
|
---|
| 134 | /* Hand over kobj's reference to cap */
|
---|
| 135 | cap->kobject = kobj;
|
---|
| 136 | list_append(&cap->link, &task->cap_info->type_list[kobj->type]);
|
---|
[9e87562] | 137 | mutex_unlock(&task->cap_info->lock);
|
---|
| 138 | }
|
---|
| 139 |
|
---|
[48bcf49] | 140 | static kobject_t *
|
---|
| 141 | cap_unpublish_locked(task_t *task, cap_handle_t handle, kobject_type_t type)
|
---|
[9e87562] | 142 | {
|
---|
[48bcf49] | 143 | kobject_t *kobj = NULL;
|
---|
[9e87562] | 144 |
|
---|
[48bcf49] | 145 | cap_t *cap = cap_get(task, handle, CAP_STATE_PUBLISHED);
|
---|
[9e87562] | 146 | if (cap) {
|
---|
[48bcf49] | 147 | if (cap->kobject->type == type) {
|
---|
| 148 | /* Hand over cap's reference to kobj */
|
---|
| 149 | kobj = cap->kobject;
|
---|
| 150 | cap->kobject = NULL;
|
---|
| 151 | list_remove(&cap->link);
|
---|
| 152 | cap->state = CAP_STATE_ALLOCATED;
|
---|
| 153 | }
|
---|
[9e87562] | 154 | }
|
---|
[48bcf49] | 155 |
|
---|
| 156 | return kobj;
|
---|
| 157 | }
|
---|
| 158 | kobject_t *cap_unpublish(task_t *task, cap_handle_t handle, kobject_type_t type)
|
---|
| 159 | {
|
---|
| 160 |
|
---|
| 161 | mutex_lock(&task->cap_info->lock);
|
---|
| 162 | kobject_t *kobj = cap_unpublish_locked(task, handle, type);
|
---|
[9e87562] | 163 | mutex_unlock(&task->cap_info->lock);
|
---|
| 164 |
|
---|
[48bcf49] | 165 | return kobj;
|
---|
[9e87562] | 166 | }
|
---|
| 167 |
|
---|
[48bcf49] | 168 | void cap_free(task_t *task, cap_handle_t handle)
|
---|
[7e3826d9] | 169 | {
|
---|
[3f74275] | 170 | assert(handle >= 0);
|
---|
| 171 | assert(handle < MAX_CAPS);
|
---|
[48bcf49] | 172 | assert(task->cap_info->caps[handle].state == CAP_STATE_ALLOCATED);
|
---|
[7e3826d9] | 173 |
|
---|
[9e87562] | 174 | mutex_lock(&task->cap_info->lock);
|
---|
| 175 | cap_initialize(&task->cap_info->caps[handle], handle);
|
---|
| 176 | mutex_unlock(&task->cap_info->lock);
|
---|
[7e3826d9] | 177 | }
|
---|
| 178 |
|
---|
[48bcf49] | 179 | void kobject_initialize(kobject_t *kobj, kobject_type_t type, void *raw,
|
---|
| 180 | kobject_ops_t *ops)
|
---|
| 181 | {
|
---|
| 182 | atomic_set(&kobj->refcnt, 1);
|
---|
| 183 | kobj->type = type;
|
---|
| 184 | kobj->raw = raw;
|
---|
| 185 | kobj->ops = ops;
|
---|
| 186 | }
|
---|
| 187 |
|
---|
| 188 | kobject_t *
|
---|
| 189 | kobject_get(struct task *task, cap_handle_t handle, kobject_type_t type)
|
---|
| 190 | {
|
---|
| 191 | kobject_t *kobj = NULL;
|
---|
| 192 |
|
---|
| 193 | mutex_lock(&task->cap_info->lock);
|
---|
| 194 | cap_t *cap = cap_get(task, handle, CAP_STATE_PUBLISHED);
|
---|
| 195 | if (cap) {
|
---|
| 196 | if (cap->kobject->type == type) {
|
---|
| 197 | kobj = cap->kobject;
|
---|
| 198 | atomic_inc(&kobj->refcnt);
|
---|
| 199 | }
|
---|
| 200 | }
|
---|
| 201 | mutex_unlock(&task->cap_info->lock);
|
---|
| 202 |
|
---|
| 203 | return kobj;
|
---|
| 204 | }
|
---|
| 205 |
|
---|
| 206 | void kobject_put(kobject_t *kobj)
|
---|
| 207 | {
|
---|
| 208 | if (atomic_postdec(&kobj->refcnt) == 1) {
|
---|
| 209 | kobj->ops->destroy(kobj->raw);
|
---|
| 210 | free(kobj);
|
---|
| 211 | }
|
---|
| 212 | }
|
---|
| 213 |
|
---|
[7e3826d9] | 214 | /** @}
|
---|
| 215 | */
|
---|