libcap.h 13.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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
/* 
 * libcap primary header file and interface.
 *
 * Author: Charles Jacobsen <charlesj@cs.utah.edu>
 * Copyright: University of Utah
 *
 * This is the non-isolated code interface to the microkernel. The
 * implementation is in virt/lcd-domains/kliblcd.c.
 *
 * An LCD that runs in non-isolated code is called a klcd.
 */
#ifndef __LIBCAP_H__
#define __LIBCAP_H__

#include "libcap_types.h"

struct cnode;
struct cspace;

struct cap_type_ops {
	char *name;
	int (*delete)(struct cspace *cspace, struct cnode *cnode, void *object);
	int (*revoke)(struct cspace *cspace, struct cnode *cnode, void *object);
};

/*
 * Add some macros to generate built-in capability object type.  Not
 * ideal to put this here, but don't want to expose internal headers,
 * and have to give per-platform a chance to change them.
 */
#define CAP_BUILD_CORE_TYPES(PT)				\
	typedef enum cap_type {					\
		CAP_TYPE_ERR = -1,				\
		CAP_TYPE_NONE = 0,				\
		CAP_TYPE_INVALID,				\
		CAP_TYPE_FREE,					\
		CAP_TYPE_CNODE,					\
		PT,						\
		CAP_TYPE_FIRST_NONBUILTIN			\
	} cap_type_t
#define CAP_BUILD_CORE_TYPES_NOBUILTIN()			\
	typedef enum cap_type {					\
		CAP_TYPE_NONE = 0,				\
		CAP_TYPE_INVALID,				\
		CAP_TYPE_FREE,					\
		CAP_TYPE_CNODE,					\
		CAP_TYPE_FIRST_NONBUILTIN			\
	} cap_type_t

#ifdef __KERNEL__
#include "libcap_kernel.h"
#else
#include "libcap_user.h"
#endif

#ifndef CAP_TYPE_MAX
#define CAP_TYPE_MAX 256
#endif

60 61
#define CAP_BUG() __cap_bug()

62
/**
63
 * For now, put debug macros in the user-accessible part; convenient.
64
 */
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
extern int cap_debug_level;

#define CAP_ERR __cap_err
#define CAP_WARN __cap_warn
#define CAP_MSG __cap_msg

#define CAP_DEBUG_ERR  1
#define CAP_DEBUG_WARN 2
#define CAP_DEBUG_MSG  3

#define CAP_DEBUG(lvl, msg, ...) {					\
	if (lvl <= cap_debug_level)					\
	    __cap_debug(msg,## __VA_ARGS__);				\
	}

/* CPTRs -------------------------------------------------- */

82 83 84
#include "libcap_internal.h" /* temporary hack */


85
/**
86 87 88 89 90
 * __cptr -- Construct a cptr from an unsigned long
 * @cptr: the unsigned long to use
 *
 * This is a low-level function. You need to know how to pack
 * the bits into the unsigned long.
91
 */
92 93 94 95
static inline cptr_t __cptr(unsigned long cptr)
{
	return (cptr_t) {cptr};
}
96
/**
97 98 99 100 101
 * cptr_val -- Extract the unsigned long (bits) in the cptr
 * @c: the ctpr to extract
 *
 * This can be useful if you want to pass a cptr in a register,
 * as a scalar.
102
 */
103 104 105 106
static inline unsigned long cptr_val(cptr_t c)
{
	return c.cptr;
}
107
/**
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 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 190 191
 * cap_cptr_slot -- Returns the slot index into the final cnode table
 * @c: the cptr
 *
 * Once you have arrived at the correct cnode table in the cspace
 * radix tree, this is the index into that table to get the
 * capability that @c refers to.
 */
static inline unsigned long cap_cptr_slot(cptr_t c)
{
	/*
	 * Mask off low bits
	 */
	return cptr_val(c) & ((1 << (CAP_CSPACE_CNODE_TABLE_BITS - 1)) - 1);
}
/**
 * cap_cptr_fanout -- Gives fanout index for going *from* @lvl to @lvl + 1
 * @c: the cptr
 * @lvl: the level in the cspace radix tree, where 0 <= lvl < CAP_CSPACE_DEPTH
 *
 * Each node in the cspace radix tree is a cnode table. Each cnode
 * table is split in half: the first half are capability slots, and
 * the other half are pointers to further nodes in the tree. If a
 * cptr refers to a slot in a deeper level in the tree, you need to
 * follow these pointers. The fanout index tells you which pointers
 * to follow at each level.
 */
static inline unsigned long cap_cptr_fanout(cptr_t c, int lvl)
{
	unsigned long i;

	if (lvl >= CAP_CSPACE_DEPTH - 1)
		CAP_BUG();

	i = cptr_val(c);
	/*
	 * Shift and mask off bits at correct section
	 */
	i >>= ((lvl + 1) * (CAP_CSPACE_CNODE_TABLE_BITS - 1));
	i &= ((1 << (CAP_CSPACE_CNODE_TABLE_BITS - 1)) - 1);

	return i;
}
/**
 * cap_cptr_level -- The zero-indexed level in the cspace radix tree
 * @c: the cptr
 *
 * Returns the level of the slot which @c refers to. 0 means the root 
 * cnode table.
 */
static inline unsigned long cap_cptr_level(cptr_t c)
{
	unsigned long i;

	i = cptr_val(c);
	/*
	 * Shift and mask
	 */
	i >>= (CAP_CSPACE_DEPTH * (CAP_CSPACE_CNODE_TABLE_BITS - 1));
	i &= ((1 << CAP_CSPACE_DEPTH_BITS) - 1);

	return i;
}
/**
 * cap_cptr_set_level -- Sets the level for @c
 * @c: the cptr
 * @lvl: the level in the cspace radix tree, 0 <= lvl < CAP_CSPACE_DEPTH
 */
static inline void cap_cptr_set_level(cptr_t *c, int lvl)
{
	/* Shift and OR to store lvl */
	c->cptr |= (lvl << 
		(CAP_CSPACE_DEPTH * (CAP_CSPACE_CNODE_TABLE_BITS - 1)));
}
/**
 * cptr_is_null -- Returns non-zero if cptr is the special null cptr
 * @c: cptr to test
 */
static inline int cptr_is_null(cptr_t c)
{
	return cptr_val(c) == cptr_val(CAP_CPTR_NULL);
}

/* CPTR CACHEs -------------------------------------------------- */

192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
#if (CAP_CSPACE_DEPTH == 4)

struct cptr_cache {
	/* lock */
	cap_mutex_t lock;
	/* level 0 bitmap */
	unsigned long bmap0[CAP_BITS_TO_LONGS(CAP_CSPACE_SLOTS_IN_LEVEL(0))];
	/* level 1 bitmap */
	unsigned long bmap1[CAP_BITS_TO_LONGS(CAP_CSPACE_SLOTS_IN_LEVEL(1))];
	/* level 2 bitmap */
	unsigned long bmap2[CAP_BITS_TO_LONGS(CAP_CSPACE_SLOTS_IN_LEVEL(2))];
	/* level 3 bitmap */
	unsigned long bmap3[CAP_BITS_TO_LONGS(CAP_CSPACE_SLOTS_IN_LEVEL(3))];
};

#else
#error "You need to adjust the cptr cache def."
#endif

211 212 213 214 215 216 217 218 219 220 221 222 223 224 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
/**
 * cptr_init -- Initalize the cptr cache subsystem
 */
int cptr_init(void);
/**
 * cptr_fini -- Tear down the cptr cache subsystem.
 */
void cptr_fini(void);
/**
 * cptr_cache_alloc -- Allocate a cptr cache data structure (not initialized)
 * @out: out param, pointer to newly alloc'd cache
 *
 * You should call cptr_cache_free when done with the cache. Returns
 * non-zero on error.
 */
int cptr_cache_alloc(struct cptr_cache **out);
/**
 * cptr_cache_free -- Free a cptr cache alloc'd via cptr_cache_alloc
 * @cache: the cptr cache to free
 */
void cptr_cache_free(struct cptr_cache *cache);
/**
 * cptr_cache_init -- Initialize the data in a cptr cache
 * @cache: the cptr cache to initialize
 *
 * Zeros out things, and sets some initial values. You *must* call this
 * function before using the cptr cache.
 */
int cptr_cache_init(struct cptr_cache *cache);
/**
 * cptr_cache_destroy -- Destroys internals of cptr cache
 * @cache: cache to destroy
 *
 * For now, this is a no-op. You *must* call this before freeing the
 * cache. (Yes, for now it is a no-op, but perhaps it won't be in the
 * future.)
 */
void cptr_cache_destroy(struct cptr_cache *cache);
/**
 * cptr_alloc -- Allocate a new cptr from the cache
 * @cache: the cptr cache to allocate from
 * @free_cptr: out param, points to the allocated cptr
 *
 * Returns non-zero if there are no more slots left.
255 256 257
 */
int cptr_alloc(struct cptr_cache *cptr_cache, cptr_t *free_cptr);
/**
258 259 260 261 262
 * cptr_free -- Return a cptr to the cache
 * @cache: the cptr cache to return the cptr to
 * @c: the cptr to return
 *
 * Fails silently if the cptr is free already.
263 264
 */
void cptr_free(struct cptr_cache *cptr_cache, cptr_t c);
265

266 267 268

/* CSPACES -------------------------------------------------- */

269 270 271 272 273 274 275 276 277 278
/**
 * Initializes caches, etc. in capability subsystem. Called when microkernel
 * intializes.
 */
int cap_init(void);
/**
 * Tears down caches, etc. in capability subsystem. Called when microkernel
 * is exiting.
 */
void cap_fini(void);
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

/**
 * cap_cspace_slots_in_level -- Return total number of slots in cspace at lvl
 * @lvl: the level to query
 *
 * Returns the total number of *capability* slots in all of the
 * cnode tables at a given @lvl of the cspace radix tree.
 */
static inline int cap_cspace_slots_in_level(int lvl)
{
	int out = CAP_CSPACE_CNODE_TABLE_SIZE/2;
	if (lvl < 0 || lvl >= CAP_CSPACE_DEPTH)
		CAP_BUG();
	for ( ; lvl > 0; lvl-- )
		out *= CAP_CSPACE_CNODE_TABLE_SIZE/2;
	return out;
}

297 298 299 300 301 302 303 304
/**
 * Register a new capability object type.  If you pass type == 0, the
 * system will select the next available identifier and return it.  You
 * should use the returned value as your object identifier.  If you
 * attempt to use a type that is already in use, this returns
 * -EADDRINUSE.  If there are no types remaining or you exceed
 * CAP_TYPE_MAX, this returns -ENOMEM .
 */
305
cap_type_t cap_register_type(cap_type_t type, const struct cap_type_ops *ops);
306
/**
307
 * Allocates a new cspace. If no memory could be allocated, returns NULL.
308 309 310 311
 */
struct cspace * cap_alloc_cspace(void);

/**
312
 * Frees a cspace allocated with `cap_alloc_cspace`.
313 314 315
 */
void cap_free_cspace(struct cspace *cspace);

316 317 318 319
/**
 * Sets up cspace - initializes lock, root cnode table, etc.
 */
int cap_init_cspace(struct cspace *cspace);
320 321 322 323 324 325 326 327
/**
 * Set the "owner" field of the given cspace
 */
void cap_cspace_setowner(struct cspace *cspace, void * owner);
/**
 * Get the "owner" field of the given cspace
 */
void* cap_cspace_getowner(struct cspace *cspace);
328 329 330 331 332
/**
 * Inserts object data into cspace at cnode pointed at by c.
 */
int cap_insert(struct cspace *cspace, cptr_t c, void *object, cap_type_t type);
/**
333 334 335 336 337 338 339
 * cap_delete -- Deletes object data from cspace at cnode pointed at by c
 * @cspace: the cspace to delete capability from
 * @c: the cptr to the capability in the cspace
 *
 * The revoke callback for the capability's type will be invoked. This
 * gives the libcap user a chance to update any external state to reflect
 * the rights change.
340
 *
341 342 343
 * Note: After the revoke callback is invoked, libcap will NULL out the
 * slot's metadata (so when you re-use the slot in the future, the metadata
 * will start out as NULL).
344
 *
345 346
 * If this is the last cnode that refers to the object, the
 * delete callback for the capability's type will be invoked.
347 348 349
 */
void cap_delete(struct cspace *cspace, cptr_t c);
/**
350 351 352 353 354 355
 * cap_grant -- Grant capability from source to destination cspace
 * @cspacesrc: the source cspace
 * @c_src: the cptr to the slot/capability in the source cspace
 * @cspacedst: the destination cspace
 * @c_dst: the cptr to the slot in the destination cspace to grant to
 *
356 357
 * Copies cnode data in src cnode at c_src to dest cnode at c_dst. The dest
 * cnode will be a child of the src cnode in the cdt containing src cnode.
358 359 360
 *
 * Note: Metadata pointers *are not* carried over to the destination slot (the
 * destination slot will start out with NULL metadata).
361 362 363 364
 */
int cap_grant(struct cspace *cspacesrc, cptr_t c_src,
	      struct cspace *cspacedst, cptr_t c_dst);
/**
365 366 367 368 369 370 371 372 373 374
 * cap_revoke -- Equivalent to calling cap_delete on all of the capability's 
 *               children
 * @cspace: the cspace that contains the parent capability
 * @c: the cptr to the capability/slot in @cspace that contains parent
 *
 * The revoke callback will be invoked for every child capability. This gives
 * the libcap user a chance to update external state to reflect the
 * rights change.
 *
 * ** Does not delete the parent capability itself. **
375
 *
376 377 378
 * Note: After the revoke callback completes, each child's metadata field
 * will be NULL'd out (so that when the slot is re-used in the future,
 * the metadata field will start out as NULL).
379 380 381 382 383 384 385 386
 */
int cap_revoke(struct cspace *cspace, cptr_t c);
/**
 * Equivalent to calling lcd_cap_delete on all cnodes in cspace. Frees up
 * all cnode tables, etc.
 */
void cap_destroy_cspace(struct cspace *cspace);
/**
387
 * Looks up cnode at cap in cspace.
388
 *
389
 * ** Frees the cnode lock itself without relying on user.
390 391 392 393
 *
 * ** Interrupts and preemption *are not* disabled. **
 *    (so we can easily get out of deadlocks while debugging)
 */
394
int cap_cnode_verify(struct cspace *cspace, cptr_t cap);
395 396 397 398 399
/**
 * Return the cptr that points to this cnode.
 */
cptr_t cap_cnode_cptr(struct cnode *cnode);

400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
/**
 * Return the cnode that this cptr points to in the given cspace. Acquires
 * a lock to the cnode. Returns zero on success. Make sure to call
 * cap_cnode_put after every cap_cnode_get.
 */
int cap_cnode_get(struct cspace *cspace, cptr_t cptr, struct cnode **cnode);

/**
 * Unlock the cnode. Call this on every cnode you've called
 * cap_cnode_get on.
 */
void cap_cnode_put(struct cnode *cnode);

/**
 * Get the object stored at this cnode.
 */
void* cap_cnode_object(struct cnode *cnode);
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
/**
 * cap_cnode_metadata -- Get the metadata stored in the cnode
 * @cnode: the cnode to get metadata from
 *
 * Note: If you never called cap_cnode_set_metadata on the @cnode
 * since it became occupied, this will be NULL.
 */
void* cap_cnode_metadata(struct cnode *cnode);
/**
 * cap_cnode_set_metadata -- Store metadata in cnode
 * @cnode: the cnode to store metadata into
 * @metadata: the metadata pointer to store
 *
 * IMPORTANT: As mentioned in cap_delete/cap_revoke, a cnode's metadata
 * will be NULL'd out after the callbacks are called when a capability is 
 * deleted (a cnode becomes free). The libcap user is responsible for
 * doing the right thing in the delete/revoke callbacks.
 *
 * libcap *will not* copy metadata pointers during grant. The destination
 * cnode/capability will not be given the same metadata pointer that the
 * source capability had. (Of course, the libcap user is free to set
 * the metadata pointers of the source and destination cnodes/capabilities
 * to point to the same object.)
 *
 * Motivation: The libcap user may want to associate some contextual
 * information for each capability (rather than with the object). For
 * example, the LCD microkernel uses metadata to track whether a page 
 * referred to by a page capability has been mapped and where.
 */
void cap_cnode_set_metadata(struct cnode *cnode, void *metadata);
Josh Kunz's avatar
Josh Kunz committed
447 448 449 450 451
/**
 * Get the type of this cnode
 */
cap_type_t cap_cnode_type(struct cnode *cnode);

452 453 454 455 456
/**
 * Get the cspace this cnode is in.
 */
struct cspace * cap_cnode_cspace(struct cnode *cnode);

457 458

#endif /* __LIBCAP_H__ */