defs.h 8.26 KB
Newer Older
Charlie Jacobsen's avatar
Charlie Jacobsen committed
1 2 3 4 5 6 7 8 9
/*
 * Authors: Anton Burtsev <aburtsev@flux.utah.edu>
 *          Charles Jacobsen <charlesj@cs.utah.edu>
 * Copyright: University of Utah
 */

#ifndef LCD_PROTOTYPE_API_DEFS_H
#define LCD_PROTOTYPE_API_DEFS_H

Charlie Jacobsen's avatar
Charlie Jacobsen committed
10
#include <linux/mutex.h>
11
#include <linux/sched.h>
Charlie Jacobsen's avatar
Charlie Jacobsen committed
12
#include <lcd-prototype/lcd.h>
Charlie Jacobsen's avatar
Charlie Jacobsen committed
13
#include "../include/api-internal.h"
Charlie Jacobsen's avatar
Charlie Jacobsen committed
14 15 16

/* CAPABILITIES -------------------------------------------------- */

Charlie Jacobsen's avatar
Charlie Jacobsen committed
17
/*
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
 * A cspace is a simple static array of cnodes. Each cnode can have 0 or more
 * derived children, in a linked list. This simple prototype uses a global 
 * mutex for the entire capability module. All routines marked as unsafe
 * should be executed with the lock held. 
 *
 * Unlike seL4, objects are not deallocated automatically when no one has a 
 * capability to it. Here is a typical sequence that exhibits the current 
 * features:
 *
 *   // Create cspaces for two lcds.
 *   lcd_mk_cspace(&cspace1);
 *   lcd_mk_cspace(&cspace2);
 *
 *   // Create a rendezvous point.
 *   rvp = mk_rvp();
 *
 *   // Put rvp in cspace1, give lcd1 all rights (lcd1 is the owner). The 
 *   // corresponding cnode will be parentless.
 *   lcd_cnode_alloc(cspace1, &cptr1);
 *   lcd_cnode_insert(cspace1, cptr1, rvp, LCD_CAP_RIGHT_ALL);
 *
 *   // lcd1 grants write rights to lcd2. Internally, lcd1's cnode
 *   // will be the parent of lcd2's cnode.
 *   lcd_cnode_grant(cspace1, cptr1, cspace2, cptr2, rvp, 
 *                 LCD_CAP_RIGHT_WRITE);
 *
 *   // lcd2 tries to send on rvp
 *   lcd_cap_lock();
 *   cnode2 = __lcd_cnode_lookup(cspace2, cptr2);
 *   if (__lcd_cnode_can_write(cnode2) && __lcd_cnode_sync_ep(cnode2))
 *      ... do send ...
 *   else
 *      ... fail ...
 *   lcd_cap_unlock();
 *
 *   // lcd1 revokes write rights to all derived children (lcd2)
 *   lcd_cnode_revoke(cspace1, cptr1, LCD_CAP_RIGHT_WRITE);
 *
 *   // lcd1 destroys the rvp. This revokes all rights given to lcd1,
 *   // and transitively, all rights to lcd2 (if they hadn't been
 *   // revoked already). Since the hypervisor created the object, it
 *   // will free the allocated memory for the rvp.
 *   lcd_cap_lock();
 *   ret = __lcd_cnode_lookup(cspace1, cptr1, &cnode1);
 *   if (ret)
 *       ... look up error ...
 *   if (__lcd_cnode_is_owner(cnode1) && __lcd_cnode_sync_ep(cnode1))
 *       rvp = cnode->object;
 *       free_rvp(rvp);
 *       __lcd_cnode_free(cspace1, cnode1);
 *   else
 *       ... fail ...
 *   lcd_cap_unlock();
 *   
 *   // lcd1 and lcd2 are torn down
 *   lcd_cap_lock();
 *   __lcd_rm_cspace(cspace1);
 *   __lcd_rm_cspace(cspace2);
 *   lcd_cap_unlock();
 *
 * All routines must exec in process context (no interrupt context,
 * since processes will sleep when trying to acquire the mutex).
Charlie Jacobsen's avatar
Charlie Jacobsen committed
80 81
 */

Charlie Jacobsen's avatar
Charlie Jacobsen committed
82
enum lcd_cap_type {
83 84 85
	LCD_CAP_TYPE_FREE     = 0,
	LCD_CAP_TYPE_UNFORMED = 1,
	LCD_CAP_TYPE_SYNC_EP  = 2,
Charlie Jacobsen's avatar
Charlie Jacobsen committed
86 87
};

88 89 90 91 92 93 94
enum lcd_cap_right {
	LCD_CAP_RIGHT_READ    = (1 << 0),
	LCD_CAP_RIGHT_WRITE   = (1 << 1),
	LCD_CAP_RIGHT_GRANT   = (1 << 2),
	LCD_CAP_RIGHT_OWNER   = (1 << 3),
};
#define LCD_CAP_RIGHT_ALL ((1 << 4) - 1)
95
#define LCD_CAP_RIGHT_NONE 0
96 97 98

struct cspace;

Charlie Jacobsen's avatar
Charlie Jacobsen committed
99 100
struct cnode {
	enum lcd_cap_type type;
101 102 103 104 105 106 107 108 109 110
	int rights;
	/* Pointer to containing cspace */
	struct cspace *cspace;
	/* Linked list of free cnodes */
	struct list_head free_list;
	/* Pointer to linked list of my children */
	struct list_head children;
	/* Linked list of siblings */
	struct list_head child_list;
	/* The contained object */
Charlie Jacobsen's avatar
Charlie Jacobsen committed
111 112 113 114 115 116
	void *object;
};

#define LCD_NUM_CAPS 32
struct cspace {
	struct cnode cnodes[LCD_NUM_CAPS];
117
	struct list_head free_list;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
118 119
};

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
extern struct mutex __lcd_cap_lock;

/**
 * Initializes capability module.
 */
int lcd_cap_init(void);
/**
 * Lock entire capability module (all cspaces)
 */
static inline int lcd_cap_lock(void)
{
	return mutex_lock_interruptible(&__lcd_cap_lock);
}
/**
 * Unlock entire capability module (all cspaces)
 */
static inline void lcd_cap_unlock(void)
{
	return mutex_unlock(&__lcd_cap_lock);
}
Charlie Jacobsen's avatar
Charlie Jacobsen committed
140 141 142 143 144 145 146 147
/**
 * Return current's cspace
 */
static inline struct cspace * lcd_cspace(void)
{
	return current->lcd->cspace;
}
/**
148
 * [SAFE]
Charlie Jacobsen's avatar
Charlie Jacobsen committed
149 150
 * Allocates memory and initializes the contents of a cspace.
 */
Charlie Jacobsen's avatar
Charlie Jacobsen committed
151
int lcd_mk_cspace(struct cspace **cspace_ptr);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
152
/**
153 154 155 156 157 158
 * [SAFE, USES LOCK]
 * Allocates an empty cnode slot, and returns a cptr to it. Returns
 * non-zero if no free slots available, or couldn't get lock.
 *
 * (It is necessary to separate allocation and insertion since an lcd
 * can specify where it wants incoming capabilities inserted, via ipc.)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
159
 */
160
int lcd_cnode_alloc(struct cspace *cspace, cptr_t *cptr);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
161
/**
162 163
 * [UNSAFE]
 * Look up cnode in cspace at cptr. Returns non-zero if cptr is out of range. 
Charlie Jacobsen's avatar
Charlie Jacobsen committed
164
 */
165
int __lcd_cnode_lookup(struct cspace *cspace, cptr_t cptr, struct cnode **out);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
166
/**
167 168 169 170 171 172 173
 * [SAFE, USES LOCK]
 * Insert object into cspace with type and rights. Fails if the type of
 * the cnode is not unformed (cnode is free or occupied), or if it fails to 
 * get the lock (interrupted).
 *
 * (Use lcd_cnode_grant to transfer a capability from one cspace to another,
 * and update the parent's children.)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
174
 */
175 176
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
177
/**
178 179 180 181 182
 * [SAFE, USES LOCK]
 * Transfer capability from one cspace to another. Fails if we can't get
 * the lock; if source is not occupied, or dest is not unformed; if source 
 * doesn't have grant rights; or if the source and destination cspaces are the 
 * same.
Charlie Jacobsen's avatar
Charlie Jacobsen committed
183
 */
184 185
int lcd_cnode_grant(struct cspace *src_cspace, struct cspace *dest_cspace,
		cptr_t src_cptr, cptr_t dest_cptr, int rights);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
186
/**
187 188 189
 * [SAFE, USES LOCK]
 * Revoke rights from all derived cnodes. Fails if we can't lock. A cnode
 * is not freed if its rights drop to nothing.
Charlie Jacobsen's avatar
Charlie Jacobsen committed
190
 */
191
int lcd_cnode_revoke(struct cspace *cspace, cptr_t cptr, int rights);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
192
/**
193
 * [UNSAFE]
194 195 196
 * Frees the slot containing cnode in its containing cspace, and recursively 
 * frees derived children in other cspaces (so this also acts as a total 
 * revoke).
197
 */
198
void __lcd_cnode_free(struct cnode *cnode);
199 200 201 202 203
/**
 * [UNSAFE]
 * Deallocates cspace. Caller should ensure no one is trying to
 * use the cspace (e.g., via grant, insert, etc.). This will revoke all
 * cnodes derived from this cspace.
Charlie Jacobsen's avatar
Charlie Jacobsen committed
204
 */
205
void __lcd_rm_cspace(struct cspace **cspace_ptr);
Charlie Jacobsen's avatar
Charlie Jacobsen committed
206
/**
207 208 209
 * [UNSAFE]
 * Quick inlines for determining rights and type. These should be wrapped
 * in a lookup/release.
Charlie Jacobsen's avatar
Charlie Jacobsen committed
210
 */
211
static inline int __lcd_cnode_rights(struct cnode *cnode)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
212
{
213
	return cnode->rights;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
214
}
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
static inline void __lcd_cnode_set_rights(struct cnode *cnode, int rights)
{
	cnode->rights = rights;
}
static inline int __lcd_cnode_type(struct cnode *cnode)
{
	return cnode->type;
}
static inline void __lcd_cnode_set_type(struct cnode *cnode, 
				enum lcd_cap_type t)
{
	cnode->type = t;
}
static inline void * __lcd_cnode_object(struct cnode *cnode)
{
	return cnode->object;
}
232
static inline int __lcd_cnode_can_read(struct cnode *cnode)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
233
{
234
	return cnode->rights & LCD_CAP_RIGHT_READ;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
235
}
236
static inline int __lcd_cnode_can_write(struct cnode *cnode)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
237
{
238
	return cnode->rights & LCD_CAP_RIGHT_WRITE;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
239
}
240
static inline int __lcd_cnode_can_grant(struct cnode *cnode)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
241
{
242
	return cnode->rights & LCD_CAP_RIGHT_GRANT;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
243
}
244
static inline int __lcd_cnode_is_owner(struct cnode *cnode)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
245
{
246
	return cnode->rights & LCD_CAP_RIGHT_OWNER;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
247
}
248
static inline int __lcd_cnode_is_free(struct cnode *cnode)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
249
{
250
	return cnode->type == LCD_CAP_TYPE_FREE;
Charlie Jacobsen's avatar
Charlie Jacobsen committed
251
}
252
static inline int __lcd_cnode_is_unformed(struct cnode *cnode)
Charlie Jacobsen's avatar
Charlie Jacobsen committed
253
{
254 255 256 257 258 259 260 261 262 263
	return cnode->type == LCD_CAP_TYPE_UNFORMED;
}
static inline int __lcd_cnode_is_occupied(struct cnode *cnode)
{
	return !(__lcd_cnode_is_unformed(cnode) || __lcd_cnode_is_free(cnode));
}
static inline int __lcd_cnode_is_sync_ep(struct cnode *cnode)
{
	return cnode->type == LCD_CAP_TYPE_SYNC_EP;
}
Charlie Jacobsen's avatar
Charlie Jacobsen committed
264

Charlie Jacobsen's avatar
Charlie Jacobsen committed
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
/* IPC -------------------------------------------------- */

/* 
 * There is no low-level interface to the api code, so we need
 * to make the ipc routines directly callable for now, in
 * include/api-internal.h. All other api code is directly or
 * indirectly accessed via ipc.
 */

struct sync_endpoint {
	struct list_head senders;
        struct list_head receivers;
        struct mutex lock;
};

/**
 * Create a synchronous end point, and install it in t's cspace
 * at location c.
 */
int lcd_mk_sync_endpoint(struct task_struct *t, cptr_t c);
/**
 * Remove synchronous end point identified by c in t's cspace.
 */
int lcd_rm_sync_endpoint(struct task_struct *t, cptr_t c);


Charlie Jacobsen's avatar
Charlie Jacobsen committed
291
#endif /* LCD_PROTOTYPE_API_DEFS_H */