cap.c 6.45 KB
Newer Older
Charlie Jacobsen's avatar
Charlie Jacobsen committed
1 2 3 4 5 6 7 8
/* 
 * Author: Anton Burtsev <aburtsev@flux.utah.edu>
 * Copyright: University of Utah
 */
#include <linux/slab.h>
#include "defs.h"
#include "../include/common.h"

9
struct mutex __lcd_cap_lock;
10
EXPORT_SYMBOL(__lcd_cap_lock);
11

Charlie Jacobsen's avatar
Charlie Jacobsen committed
12 13 14 15 16
int lcd_cap_init(void)
{
	mutex_init(&__lcd_cap_lock);
	return 0;
}
17
EXPORT_SYMBOL(lcd_cap_init);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

static void init_cspace_cnodes(struct cspace *cspace)
{
	int i;
	struct cnode *cnode;

	INIT_LIST_HEAD(&cspace->free_list);

	for (i = 0; i < LCD_NUM_CAPS; i++) {
		cnode = &cspace->cnodes[i];

		INIT_LIST_HEAD(&cnode->free_list);
		INIT_LIST_HEAD(&cnode->children);
		INIT_LIST_HEAD(&cnode->child_list);

		list_add(&cnode->free_list, &cspace->free_list);

		cnode->cspace = cspace;
	}

	return;
}

Charlie Jacobsen's avatar
Charlie Jacobsen committed
41
int lcd_mk_cspace(struct cspace **cspace_ptr)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
42 43 44 45 46 47 48
{
	struct cspace *cspace;
	/*
	 * Allocate cspace
	 */
	cspace = kmalloc(sizeof(*cspace), GFP_KERNEL);
	if (!cspace)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
49 50
		return -ENOMEM;
	/* 
Charlie Jacobsen's avatar
Charlie Jacobsen committed
51 52
	 * Zero out all data (including cnodes). Sets cnode types to free with
	 * no rights. Initialize free list and cnodes.
Charlie Jacobsen's avatar
Charlie Jacobsen committed
53
	 */
Charlie Jacobsen's avatar
Charlie Jacobsen committed
54
	memset(cspace, 0, sizeof(*cspace));
Charlie Jacobsen's avatar
Charlie Jacobsen committed
55
	init_cspace_cnodes(cspace);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
56 57 58 59 60
	/*
	 * Done
	 */
	*cspace_ptr = cspace;
	return 0;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
61
}
62
EXPORT_SYMBOL(lcd_mk_cspace);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
63

Charlie Jacobsen's avatar
Charlie Jacobsen committed
64
static int __lcd_cnode_alloc(struct cspace *cspace, cptr_t *cptr)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
65
{
66
	struct cnode *cnode;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
67 68 69 70 71 72
	if (list_empty(&cspace->free_list)) {
		return -ENOMEM;
	} else {
		/*
		 * Get first available cnode, and remove it from the list.
		 */
73
		cnode = list_first_entry(&cspace->free_list, struct cnode,
Charlie Jacobsen's avatar
Charlie Jacobsen committed
74 75 76 77 78 79 80 81
					free_list);
		/*
		 * Remove from free list
		 */
		list_del_init(&cnode->free_list);
		/*
		 * Mark it as unformed
		 */
82
		__lcd_cnode_set_type(cnode, LCD_CAP_TYPE_UNFORMED);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
83 84 85
		/*
		 * Calc index
		 */
86
		*cptr = cnode - (cspace->cnodes);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
87 88 89 90 91 92
		return 0;
	}
}

int lcd_cnode_alloc(struct cspace *cspace, cptr_t *cptr)
{
Charlie Jacobsen's avatar
Charlie Jacobsen committed
93 94
	int ret;
	/*
Charlie Jacobsen's avatar
Charlie Jacobsen committed
95
	 * LOCK cap
Charlie Jacobsen's avatar
Charlie Jacobsen committed
96
	 */
Charlie Jacobsen's avatar
Charlie Jacobsen committed
97 98
	ret = lcd_cap_lock();
	if (ret)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
99
		return ret;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
100
	ret = __lcd_cnode_alloc(cspace, cptr);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
101
	/*
Charlie Jacobsen's avatar
Charlie Jacobsen committed
102
	 * UNLOCK cap
Charlie Jacobsen's avatar
Charlie Jacobsen committed
103
	 */
Charlie Jacobsen's avatar
Charlie Jacobsen committed
104 105 106
	lcd_cap_unlock();
	return ret;
}
107
EXPORT_SYMBOL(lcd_cnode_alloc);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
108 109 110 111 112 113 114 115 116 117

int __lcd_cnode_lookup(struct cspace *cspace, cptr_t cptr, struct cnode **out)
{
	struct cnode *c;
	if (cptr >= LCD_NUM_CAPS)
		return -EINVAL;
	c = &cspace->cnodes[cptr];
	*out = c;
	return 0;
}
118
EXPORT_SYMBOL(__lcd_cnode_lookup);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
119 120 121 122

static int __lcd_cnode_insert(struct cnode *cnode, void *object, 
			enum lcd_cap_type type, int rights)
{
123
	if (!__lcd_cnode_is_unformed(cnode))
Charlie Jacobsen's avatar
Charlie Jacobsen committed
124 125
		return -EINVAL;
	else {
Charlie Jacobsen's avatar
Charlie Jacobsen committed
126
		cnode->object = object;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
127 128
		cnode->type   = type;
		cnode->rights = rights;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
129 130
		return 0;
	}
Charlie Jacobsen's avatar
Charlie Jacobsen committed
131 132
}

Charlie Jacobsen's avatar
Charlie Jacobsen committed
133 134
int lcd_cnode_insert(struct cspace *cspace, cptr_t cptr, 
		void *object, enum lcd_cap_type type, int rights)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
135
{
Charlie Jacobsen's avatar
Charlie Jacobsen committed
136
	struct cnode *cnode;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
137 138
	int ret;
	/*
Charlie Jacobsen's avatar
Charlie Jacobsen committed
139
	 * LOCK cap
Charlie Jacobsen's avatar
Charlie Jacobsen committed
140
	 */
Charlie Jacobsen's avatar
Charlie Jacobsen committed
141
	ret = lcd_cap_lock();
Charlie Jacobsen's avatar
Charlie Jacobsen committed
142 143
	if (ret)
		return ret;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
144 145 146 147 148 149 150 151 152 153 154
	ret = __lcd_cnode_lookup(cspace, cptr, &cnode);
	if (ret)
		goto out;
	ret = __lcd_cnode_insert(cnode, object, type, rights);
out:
	/*
	 * UNLOCK cap
	 */
	lcd_cap_unlock();
	return ret;
}
155
EXPORT_SYMBOL(lcd_cnode_insert);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189

static int __lcd_cnode_insert_for_grant(struct cnode *src_cnode, 
					struct cnode *dest_cnode, int rights)
{
	int ret;

	ret = __lcd_cnode_insert(dest_cnode, src_cnode->object,
				src_cnode->type, rights);
	if (ret)
		return ret;
	/*
	 * Add dest_cnode to src_cnode's children.
	 */
	list_add(&dest_cnode->child_list, &src_cnode->children);
	return 0;
}

static int __lcd_cnode_grant(struct cspace *src_cspace, 
			struct cspace *dest_cspace, cptr_t src_cptr, 
			cptr_t dest_cptr, int rights)

{
	struct cnode *src_cnode;
	struct cnode *dest_cnode;
	int dest_rights;
	int ret;

	if (src_cspace == dest_cspace)
		return -EINVAL;

	ret = __lcd_cnode_lookup(src_cspace, src_cptr, &src_cnode);
	if (ret)
		return ret;
	if (!__lcd_cnode_can_grant(src_cnode))
Charlie Jacobsen's avatar
Charlie Jacobsen committed
190
		return -EINVAL;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
191 192 193 194 195 196
	ret = __lcd_cnode_lookup(dest_cspace, dest_cptr, &dest_cnode);
	if (ret)
		return ret;

	if (!__lcd_cnode_is_occupied(src_cnode) ||
		!__lcd_cnode_is_unformed(dest_cnode))
Charlie Jacobsen's avatar
Charlie Jacobsen committed
197
		return -EINVAL;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
198

199
	dest_rights = __lcd_cnode_rights(src_cnode) & rights;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
200

201
	ret = __lcd_cnode_insert_for_grant(src_cnode, dest_cnode, dest_rights);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
202 203 204 205 206 207 208 209 210 211 212

	return ret;
}

int lcd_cnode_grant(struct cspace *src_cspace, struct cspace *dest_cspace,
		cptr_t src_cptr, cptr_t dest_cptr, int rights)
{
	int ret;
	/*
	 * LOCK cap
	 */
213
	ret = lcd_cap_lock();
Charlie Jacobsen's avatar
Charlie Jacobsen committed
214 215 216 217 218 219 220
	if (ret)
		return ret;
	ret = __lcd_cnode_grant(src_cspace, dest_cspace, src_cptr, dest_cptr,
				rights);
	/*
	 * UNLOCK cap
	 */
221
	lcd_cap_unlock();
Charlie Jacobsen's avatar
Charlie Jacobsen committed
222 223
	return ret;
}
224
EXPORT_SYMBOL(lcd_cnode_grant);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261

static void __lcd_cnode_do_revoke(struct cnode *parent, int rights)
{
	struct cnode *child;
	struct list_head *ptr;

	list_for_each(ptr, &parent->children) {
		child = list_entry(ptr, struct cnode, child_list);
		/*
		 * Revoke child's rights
		 */
		child->rights &= ~rights;
		/*
		 * Recur on its children
		 *
		 * XXX: Be aware of stack overflow
		 */
		__lcd_cnode_do_revoke(child, rights);
	}
	return;
}

static int __lcd_cnode_revoke(struct cspace *cspace, cptr_t cptr, int rights)
{
	int ret;
	struct cnode *parent;

	ret = __lcd_cnode_lookup(cspace, cptr, &parent);
	if (ret)
		return ret;
	__lcd_cnode_do_revoke(parent, rights);
	return 0;
}

int lcd_cnode_revoke(struct cspace *cspace, cptr_t cptr, int rights)
{
	int ret;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
262
	/*
Charlie Jacobsen's avatar
Charlie Jacobsen committed
263
	 * LOCK cap
Charlie Jacobsen's avatar
Charlie Jacobsen committed
264
	 */
265
	ret = lcd_cap_lock();
Charlie Jacobsen's avatar
Charlie Jacobsen committed
266 267 268 269 270 271
	if (ret)
		return ret;
	ret = __lcd_cnode_revoke(cspace, cptr, rights);
	/*
	 * UNLOCK cap
	 */
272
	lcd_cap_unlock();
Charlie Jacobsen's avatar
Charlie Jacobsen committed
273
	return ret;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
274
}
275
EXPORT_SYMBOL(lcd_cnode_revoke);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
276

Charlie Jacobsen's avatar
Charlie Jacobsen committed
277
static void __lcd_cnode_do_free(struct cnode *parent)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
278
{
Charlie Jacobsen's avatar
Charlie Jacobsen committed
279 280 281 282 283 284 285 286 287 288 289
	struct cnode *child;
	struct list_head *ptr;
	struct list_head *n;

	list_for_each_safe(ptr, n, &parent->children) {
		child = list_entry(ptr, struct cnode, child_list);
		/*
		 * Recur on child's children
		 *
		 * XXX: Be aware of stack overflow
		 */
290
		__lcd_cnode_do_free(child);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
291 292 293 294 295 296
		/*
		 * Remove from parent
		 */
		list_del_init(&child->child_list);
	}
	/*
Charlie Jacobsen's avatar
Charlie Jacobsen committed
297
	 * Mark parent as free, and remove all rights
Charlie Jacobsen's avatar
Charlie Jacobsen committed
298 299
	 */
	__lcd_cnode_set_type(parent, LCD_CAP_TYPE_FREE);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
300
	__lcd_cnode_set_rights(parent, LCD_CAP_RIGHT_NONE);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
301 302 303 304 305 306 307 308 309 310 311 312
	/*
	 * Add to containing cspace free list
	 */
	list_add(&parent->free_list, &parent->cspace->free_list);
	return;
}

void __lcd_cnode_free(struct cnode *cnode)
{
	__lcd_cnode_do_free(cnode);
	return;
}
313
EXPORT_SYMBOL(__lcd_cnode_free);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
314 315 316

void __lcd_rm_cnode(struct cnode *cnode)
{
317
	if (__lcd_cnode_is_occupied(cnode))
Charlie Jacobsen's avatar
Charlie Jacobsen committed
318 319 320
		__lcd_cnode_do_free(cnode);
	return;
}
321 322
EXPORT_SYMBOL(__lcd_rm_cnode);

Charlie Jacobsen's avatar
Charlie Jacobsen committed
323 324 325 326 327 328 329
void __lcd_rm_cspace(struct cspace **cspace_ptr)
{
	int i;
	struct cspace *cspace;
	cspace = *cspace_ptr;
	for (i = 0; i < LCD_NUM_CAPS; i++)
		__lcd_rm_cnode(&cspace->cnodes[i]);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
330
	kfree(cspace);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
331 332
	*cspace_ptr = NULL;
	return;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
333
}
334
EXPORT_SYMBOL(__lcd_rm_cspace);