diff --git a/drivers/lcd/ipc-ping-pong/sender.c b/drivers/lcd/ipc-ping-pong/sender.c index c2be5116a489ba8de0084f0fcd120b9fd1215b7a..46b49ad9f4db79ac284a8ac237d7411b85f2c8b1 100644 --- a/drivers/lcd/ipc-ping-pong/sender.c +++ b/drivers/lcd/ipc-ping-pong/sender.c @@ -15,9 +15,10 @@ #include #include #include +#include #include -#include +#include MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("LCD ping-pong IPC test (sender)"); @@ -26,7 +27,8 @@ struct sync_ipc *rvp; int lcd_ping_pong_init_sender(void) { int ret; - capability_t rvp_cap; + capability_t rvp_cap = 0; + struct cnode *cnode; ret = lcd_enter(); if (ret) { @@ -40,13 +42,18 @@ int lcd_ping_pong_init_sender(void) { return -ENOMEM; }; - rvp_cap = lcd_cap_create_capability(¤t->cspace, (void*)rvp, 0); - if(rvp_cap == 0) { + cnode = lcd_cnode_lookup(¤t->cspace, rvp_cap); + if(cnode == 0) { printk(KERN_ERR "Failed to create capability\n"); kfree(rvp); return -ENOMEM; }; + cnode->type = LCD_TYPE_SYNC_EP; + cnode->object = rvp; + + lcd_cnode_release(cnode); + current->utcb->boot_info.boot_rvp = rvp_cap; return 0; }; @@ -54,8 +61,8 @@ int lcd_ping_pong_init_sender(void) { int lcd_ping_pong_init_receiver(void) { int ret; - struct sync_ipc *rvp; - capability_t rvp_cap; + capability_t rvp_cap = 0; + struct cnode *cnode; ret = lcd_enter(); if (ret) { @@ -65,13 +72,18 @@ int lcd_ping_pong_init_receiver(void) BUG_ON(rvp == NULL); - rvp_cap = lcd_cap_create_capability(¤t->cspace, (void*)rvp, 0); - if(rvp_cap == 0) { + cnode = lcd_cnode_lookup(¤t->cspace, rvp_cap); + if(cnode == 0) { printk(KERN_ERR "Failed to create capability\n"); kfree(rvp); return -ENOMEM; }; + cnode->type = LCD_TYPE_SYNC_EP; + cnode->object = rvp; + + lcd_cnode_release(cnode); + current->utcb->boot_info.boot_rvp = rvp_cap; return 0; }; diff --git a/include/lcd/cap-internal.h b/include/lcd/cap-internal.h deleted file mode 100644 index 4696cc0bc73e419d9fa7cc5ece2004c7020ea059..0000000000000000000000000000000000000000 --- a/include/lcd/cap-internal.h +++ /dev/null @@ -1,225 +0,0 @@ -#ifndef __LCD_CAP_INTERNAL_H__ -#define __LCD_CAP_INTERNAL_H__ - -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_SLOTS (PAGE_SIZE/sizeof(struct cte)) -#define CNODE_SLOTS_PER_CNODE 64 -#define CNODE_SLOTS_START (MAX_SLOTS - CNODE_SLOTS_PER_CNODE) -#define CNODE_INDEX_BITS (ilog2(MAX_SLOTS)) -#define CAP_ID_SIZE (sizeof(capability_t) * 8) -#define MAX_DEPTH ((CAP_ID_SIZE + 1)/CNODE_INDEX_BITS) - -#define SAFE_EXIT_IF_ALLOC_FAILED(ptr, label) \ -if (ptr == NULL) \ -{ \ - goto label; \ -} \ - -#define ASSERT(condition, expr) \ -if(!(condition)) \ -{ \ - printk("\nAssertion Failed at: %d\n",__LINE__); \ - panic(#expr); \ -} - -#define LCD_PANIC(expr) \ - panic(#expr); - - - -/* caps with fixed slot potitions in the root CNode */ -enum -{ - LCD_CapNull = 0, /* null cap */ - //LCD_CapInitThreadTCB = 1, /* initial thread's TCB cap */ - //LCD_CapInitThreadPD = 2, /* initial thread' page directory */ - //LCD_CapIRQControl = 3, /* global IRQ controller */ - //LCD_CapInitThreadIPCBuffer = 4, /* initial thread's IPC buffer frame cap */ - LCD_CapFirstFreeSlot -}; - - - -#define CAPRIGHTS_READ (1 << 0) -#define CAPRIGHTS_WRITE (1 << 1) -#define CAPRIGHTS_EXECUTE (1 << 2) -#define CAPRIGHTS_GRANT (1 << 3) -#define CAPRIGHTS_NUM 4 - -#define CAPRIGHTS_ALL ((1 << CAPRIGHTS_NUM) - 1) -#define CAPRIGHTS_RW (CAPRIGHTS_READ | CAPRIGHTS_WRITE) -#define CAPRIGHTS_RWX (CAPRIGHTS_RW | CAPRIGHTS_EXECUTE) -#define CAPRIGHTS_NORIGHTS 0 - -int lcd_cap_init(void); -int lcd_cap_exit(void); - -//////////////////////////////////////////////////////////////////////////////////////////// -/* Helper Functions */ -//////////////////////////////////////////////////////////////////////////////////////////// -static inline int lcd_get_bits_at_level(capability_t id, int level) -{ - int bits = 0; - id = id << ((MAX_DEPTH - level - 1) * CNODE_INDEX_BITS); - id = id >> ((MAX_DEPTH - 1) * CNODE_INDEX_BITS); - bits = (int) id; - return bits; -} - -static inline void lcd_clear_bits_at_level(capability_t *id, int level) -{ - capability_t mask = (~0); - // clear all higher order bits. - mask = mask << ((MAX_DEPTH - 1) * CNODE_INDEX_BITS); - // clear lower order bits - mask = mask >> ((MAX_DEPTH - 1) * CNODE_INDEX_BITS); - // get the mask to appropriate position - mask = mask << (level * CNODE_INDEX_BITS); - mask = ~mask; - *id = (*id) & mask; -} - -static inline void lcd_set_bits_at_level(struct cte *cnode, capability_t *cid, int free_slot) -{ - int level = cnode->cnode.table_level; - capability_t id = free_slot; - - *cid = cnode->cnode.cnode_id; - lcd_clear_bits_at_level(cid, level); - id = id << (level * CNODE_INDEX_BITS); - *cid = *cid | id; -} - -struct cte * lcd_cap_reserve_slot(struct cte *cnode, capability_t *cid, int free_slot); - -bool lcd_cap_initialize_freelist(struct cap_space *cspace, struct cte *cnode, bool bFirstCNode); - -capability_t lcd_cap_lookup_freeslot(struct cap_space *cspace, struct cte **cap); - -void lcd_cap_update_cdt(struct task_struct *tcb); - -bool lcd_cap_delete_internal(struct cte *cap, bool *last_reference); - -bool lcd_cap_delete_internal_lockless(struct cte *cap, bool *last_reference); - - -//////////////////////////////////////////////////////////////////////////////////////////// -/* External Interface */ -//////////////////////////////////////////////////////////////////////////////////////////// -// creates a cspace for a thread. should be called during lcd/thread creation. -// expects the following objects as input with the rights for those objects: -// ****(LCD_CapInitThreadTCB is compulsory) -// Input: -// objects: array of pointers where each pointer is as follows: -// objects[index] Index within input array Comments -// LCD_CapNull 0 Should be a NULL entry in objects array -// ****LCD_CapInitThreadTCB 1 Pointer to task_struct of thread. -// LCD_CapInitThreadPD 2 Pointer to the page directory of process. -// LCD_CapIRQControl 3 ?? will be used later. -// LCD_CapInitThreadIPCBuffer 4 Pointer to the IPC buffer which will be used. -// total number of object pointers expected in array is equal to LCD_CapFirstFreeSlot. -// Put a NULL pointer for entries which the thread is not expected to have. -// e.g. if the thread does not need an IPC buffer then objects[4] should be NULL. -// pointer to the cspace is also added to the TCB of the caller. -// Output: -// pointer to the newly created cspace. -int lcd_cap_init_cspace(struct cap_space *cspace); - -// will be used to access the object on which a method is to be invoked. -// the returned value is a pointer to the entry in the table where the capability -// maps. This contains the handle to the object which can be used by the invoked method. -// Input: -// tcb: pointer to the thread control block of the thread which invokes method. -// cid: capability identifier of the object on which the method is to be invoked. -// keep_locked: whether or not to keep the semaphore protecting cdt locked. -// Output: -// pointer to the capability table entry if the cid is valid else NULL is returned. -struct cte * lcd_cap_lookup_capability(struct cap_space *cspace, capability_t cid, bool keep_locked); - -// creates a new capability, inserts it into cspace of caller and -// returns the capability identifier. -// it is unclear who will have the right to perform this operation. -// Input: -// ptcb: pointer to the task_struct of the thread which intends to create the capability. -// hobject: pointer to the underlying kernel object for which capability is being created. -// crights: the rights associated with the capability for the object. -// Output: -// capability identifier within the cspace of the thread which intended to create this capability. -// 0 = Failure -capability_t lcd_cap_create_capability(struct cap_space *cspace, void * hobject, lcd_cap_rights crights); - -// will be used to grant a capability to another thread -// returns the address of the capability within the cspace of the receiver thread. -// a logical AND of the input parameter crights and the rights on the capability -// being granted will decide the final rights the granted capability will have. -// Input: -// src_tcb: pointer to the task_struct of the thread which internds to grant the capability. -// src_cid: capability identifier of the capability being granted. -// dst_tcb: pointer to the task_struct of the receiver thread. -// crights: the rights on the capability to be granted to the receiver. -capability_t lcd_cap_grant_capability(struct cap_space *src_space, capability_t src_cid, struct cap_space *dst_space, lcd_cap_rights crights); - -// will be called to delete a particular capability in the calling threads -// cspace. threads have right to delete capabilities in their own cspace. -// Input: -// ptcb: pointer to the task_struct of the thread intending to delete a capability. -// cid : capability identifier of the capability to be deleted. -// Output: -// 0 = Success -// Any other value indicates failure. -uint32_t lcd_cap_delete_capability(struct cap_space *cspace, capability_t cid); - -// will be called to delete the capability and all its children. -// the children can be present in cspace belonging to different threads. -// as such the thread owning the parent capability has a right to delete -// a capability which is its child or was derieved from it. -// Input: -// ptcb: pointer to the task_struct of the thread which is invoking this revoke operation. -// cid : the capability identifier of the capability being revoked. -// Ouptput: -// 0 = Success -// Any other value indicates failure. -uint32_t lcd_cap_revoke_capability(struct cap_space *cspace, capability_t cid); - -// should be called when the thread exits. -// this is extremely heavy function which updates the CDT for all capabilities present -// in the cspace of the exiting thread. -// Input: -// ptcb: pointer to the task_struct of the thread which is getting terminated. -void lcd_cap_destroy_cspace(struct cap_space *cspace); - -// will be used to get the rights available with a capability. -// Input: -// ptcb: pointer to the task_struct of the thread in whose cspace the capability resides. -// cid : capability identifier of the capability whose rights are being queried. -// rights: The rights will be saved in this variable. -// Output: -// Return Value: 0 = Success, Any other value indicates failure. -// The rights associated with the capability will be saved in the rights ouput paramter. -uint32_t lcd_cap_get_rights(struct cap_space *cspace, capability_t cid, lcd_cap_rights *rights); - -// will be used to craete a copy of the capability identified by cid within the same cspace -// the rights of the copied capability could be modified using the rights parameter. -// Input: -// tcb: pointer to the thread control block whose cspace has the capability to be copied. -// cid: the capability identifier of the capability to be copied. -// rights: the new rights for the copied capability, the final rights the capability will -// be the Logical AND of the original rights and the parameter rights. -// Output: -// the capability identifier for the copied capability is returned. -// 0 indicates failure. -capability_t lcd_cap_mint_capability(struct cap_space *cspace, capability_t cid, lcd_cap_rights rights); - -#endif // __LCD_CAP_H__ diff --git a/include/lcd/cap.h b/include/lcd/cap.h index df65a1978c41658388b927ec00734b5ab89aaa28..03fcda1e1e68f6245262d883deb161627821ae33 100644 --- a/include/lcd/cap.h +++ b/include/lcd/cap.h @@ -1,80 +1,37 @@ +/* Author: Anton Burtsev + * Copyright: University of Utah */ + #ifndef __LCD_CAP_H__ #define __LCD_CAP_H__ #include -#include #include -typedef uint32_t lcd_cnode; // a pointer to the cnode -typedef uint32_t lcd_cnode_entry; // a pointer to an entry within a cnode -typedef uint64_t lcd_tcb; // a pointer/handle to the thread contrl block -typedef uint16_t lcd_cap_rights; // holds the rights associated with a capability. -typedef uint16_t lcd_cap_type; - - -enum __lcd_cap_type +enum lcd_cap_type { - lcd_type_invalid, - lcd_type_free, - lcd_type_capability, - lcd_type_cnode, - lcd_type_endpoint, - lcd_type_separator + LCD_TYPE_INVALID, + LCD_TYPE_FREE, + LCD_TYPE_SYNC_EP, }; - -struct cap_derivation_tree -{ - struct cte *cap; - struct semaphore *sem_cdt; - struct cap_derivation_tree *next; - struct cap_derivation_tree *prev; - struct cap_derivation_tree *parent_ptr; - struct cap_derivation_tree *child_ptr; +struct cnode { + enum lcd_cap_type type; + void *object; }; -struct capability_internal -{ - void *hobject; // a pointer to a kernel object - struct cap_derivation_tree *cdt_node; // list of domain ids to whom this - //capability is granted - lcd_cap_rights crights; // specifies the rights the domain has over this capability +struct cspace { + spinlock_t lock; + struct cnode *cnode; }; -struct cte; - -struct cap_node -{ - capability_t cnode_id; - struct cte *table; /* points to another cnode table */ - uint16_t table_level; -}; +int lcd_cap_init(void); +int lcd_cap_exit(void); -struct free_slot_t -{ - int next_free_cap_slot; - int next_free_cnode_slot; - struct cap_space *cspace; -}; - -struct cte // capability table entry -{ - union - { - struct cap_node cnode; - struct capability_internal cap; - struct free_slot_t slot; - }; - lcd_cap_type ctetype; - uint16_t index; -}; - -struct cap_space -{ - struct cte root_cnode; - struct semaphore sem_cspace; -}; +void lcd_cnode_release(struct cnode *cnode); +int lcd_init_cspace(struct cspace *cspace); +int lcd_cnode_insert(struct cspace *cspace, capability_t cap, struct cnode *cnode); +struct cnode *lcd_cnode_lookup(struct cspace *cspace, capability_t cap); #endif diff --git a/include/linux/sched.h b/include/linux/sched.h index fb4c0cc438aac60a877f13dd42748542ad9531d5..1be54639d7b185f5ac749d6da19d12e789be01e8 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1469,7 +1469,7 @@ struct task_struct { unsigned int flags; /* per process flags, defined below */ unsigned int ptrace; #ifdef CONFIG_HAVE_LCD - struct cap_space cspace; + struct cspace cspace; struct list_head sync_rendezvous; struct utcb *utcb; #endif diff --git a/virt/lcd-domains/cap.c b/virt/lcd-domains/cap.c index 211de4964e7a2c0e2363910cd9f2355536476476..27d428ebaa9ef36e43907232ee6594c5e2ecdb08 100644 --- a/virt/lcd-domains/cap.c +++ b/virt/lcd-domains/cap.c @@ -1,850 +1,80 @@ +/* + * Author: Anton Burtsev + * Copyright: University of Utah + */ #include -#include +#include -struct kmem_cache *cte_cache; -struct kmem_cache *cdt_cache; +#define LCD_MAX_CAPS 32 + +struct kmem_cache *cnode_cache; +struct kmem_cache *cdtnode_cache; int lcd_cap_init(void){ - cte_cache = KMEM_CACHE(cte, 0); - if(!cte_cache){ - printk(KERN_ERR "Failed to allocate cte slab\n"); + cnode_cache = KMEM_CACHE(cnode, 0); + if(!cnode_cache){ + printk(KERN_ERR "Failed to allocate cnode slab\n"); return -ENOMEM; }; - cdt_cache = KMEM_CACHE(cap_derivation_tree, 0); - if(!cdt_cache){ - printk(KERN_ERR "Failed to allocate cte slab\n"); - return -ENOMEM; - }; + //cdtnode_cache = KMEM_CACHE(cap_derivation_tree, 0); + //if(!cdt_cache){ + // printk(KERN_ERR "Failed to allocate cte slab\n"); + // return -ENOMEM; + //}; return 0; }; int lcd_cap_exit(void) { - if (cte_cache) - kmem_cache_destroy(cte_cache); - if (cdt_cache) - kmem_cache_destroy(cdt_cache); - return 0; -} - - -// this function will not lock any semaphore. -// assumption is that cdt and cspace are already locked. -bool lcd_cap_delete_internal_lockless(struct cte *cap, bool *last_reference) -{ - struct cte *table; - struct cap_derivation_tree *p_cdt, *cdt, *c_cdt, *prev_cdt = NULL; - *last_reference = false; - - - BUG_ON(cap != NULL); - - cdt = cap->cap.cdt_node; - p_cdt = cdt->parent_ptr; - c_cdt = cdt->child_ptr; - if (p_cdt == NULL && c_cdt == NULL && cdt->next == NULL && cdt->prev == NULL) - *last_reference = true; - - // update parent pointer - while (c_cdt != NULL) - { - prev_cdt = c_cdt; - c_cdt->parent_ptr = p_cdt; - c_cdt = c_cdt->next; - } - c_cdt = cdt->child_ptr; - - // update sibling pointers - if (c_cdt == NULL) - { - if (cdt->prev != NULL) - { - cdt->prev->next = cdt->next; - } - if (cdt->next != NULL) - { - cdt->next->prev = cdt->prev; - } - } - else - { - if (cdt->prev != NULL) - { - cdt->prev->next = c_cdt; - c_cdt->prev = cdt->prev; - cdt->prev = NULL; - } - if (cdt->next != NULL) - { - prev_cdt->next = cdt->next; - cdt->next->prev = c_cdt; - cdt->next = NULL; - } - } - - // update child pointer - if (p_cdt->child_ptr == cdt) - { - if (c_cdt != NULL) - { - p_cdt->child_ptr = c_cdt; - } - else - { - p_cdt->child_ptr = cdt->next; - } - } - - // delete the capability - kmem_cache_free(cdt_cache, cdt); - cap->ctetype = lcd_type_free; - table = cap - cap->index; - cap->slot.next_free_cap_slot = table[0].slot.next_free_cap_slot; - table[0].slot.next_free_cap_slot = cap->index; - return true; -} - -bool lcd_cap_delete_internal(struct cte *cap, bool *last_reference) -{ - struct cap_space *cspace; - struct cte *node; - bool done = false; - - BUG_ON(cap == NULL); - - if(last_reference == NULL) - return false; - *last_reference = false; - node = cap - cap->index; - if (node[0].ctetype != lcd_type_free) - return false; - cspace = node[0].slot.cspace; - if (cspace == NULL) - return false; - - while (!done) - { - // lock the cspace - if (down_trylock(&(cspace->sem_cspace)) == 0) - { - lcd_cap_delete_internal_lockless(cap, last_reference); - done = true; - } - else - { - msleep_interruptible(1); - } - } - return true; -} - -uint32_t lcd_cap_delete_capability(struct cap_space *cspace, capability_t cid) -{ - struct cte *cap; - bool last_reference = false; - struct semaphore *sem_cdt_backup; - - BUG_ON(cid == 0); - - cap = lcd_cap_lookup_capability(cspace, cid, true); - if (cap == NULL) - { - LCD_PANIC("lcd_cap_delete_capability: Capability not found\n"); - return -1; - } - sem_cdt_backup = cap->cap.cdt_node->sem_cdt; - lcd_cap_delete_internal(cap, &last_reference); - up(sem_cdt_backup); - if (last_reference == true) - { - // TBD: this is the place where we free the object associated with teh capability. - // for now we just release the sem_cdt semaphore. - kfree(sem_cdt_backup); - } + if (cnode_cache) + kmem_cache_destroy(cnode_cache); + //if (cdt_cache) + // kmem_cache_destroy(cdt_cache); return 0; } -uint32_t lcd_cap_revoke_capability(struct cap_space *cspace, capability_t cid) -{ - struct cte *cap; - struct cap_derivation_tree *cdt, *c_cdt; - struct kfifo cap_q; - struct semaphore *sem_cdt_backup; - int size = sizeof(struct cte); - bool dummy = false, last_reference = false; - - BUG_ON(cid == 0); +int lcd_init_cspace(struct cspace *cspace) { - if (kfifo_alloc(&cap_q, sizeof(struct cte) * 512, GFP_KERNEL) != 0) - { - LCD_PANIC("lcd_cap_revoke_capability: Fifo allocation failed, aborting\n"); - return -1; - } - - cap = lcd_cap_lookup_capability(cspace, cid, true); - if (cap == NULL) - { - LCD_PANIC("lcd_cap_revoke_capability: Capability not found\n"); - return -1; - } - cdt = cap->cap.cdt_node; - sem_cdt_backup = cap->cap.cdt_node->sem_cdt; - if (cdt->parent_ptr == NULL && cdt->next == NULL && cdt->prev == NULL) - last_reference = true; - - kfifo_in(&cap_q, cap, size); - - while (!kfifo_is_empty(&cap_q)) - { - kfifo_out(&cap_q, cap, size); - if (cap == NULL || cap->ctetype != lcd_type_capability) - continue; - cdt = cap->cap.cdt_node; - c_cdt = cdt->child_ptr; - while (c_cdt != NULL) - { - kfifo_in(&cap_q, c_cdt->cap, size); - c_cdt = c_cdt->next; - } - lcd_cap_delete_internal(cap, &dummy); - } - up(sem_cdt_backup); - // with revoke the entire tree is deleted. Now if the root of the tree had not parent, - // or no siblings then this was the true last_reference so we now remove the cdt semaphore. - if (last_reference) - { - kfree(sem_cdt_backup); - } - return 0; -} - - -void lcd_cap_destroy_cspace(struct cap_space *cspace) -{ - struct cte *cnode, *node, level_separator; - struct kfifo cnode_q; - int size = sizeof(struct cte); - int depth_count = 0, i; - struct semaphore *sem_cdt_backup; - bool cspace_locked = false, table_visited = false, last_reference = false; - - BUG_ON(cspace == NULL); - - if (kfifo_alloc(&cnode_q, sizeof(struct cte) * 512, GFP_KERNEL) != 0) - { - printk(KERN_ALERT "lcd_cap_destroy_cspace: Failed to allcoate kfifo, cspace cannot be destroyed\n"); - return; - } - if (cspace->root_cnode.cnode.table != NULL) - kfifo_in(&cnode_q, &(cspace->root_cnode), size); - level_separator.ctetype = lcd_type_separator; - kfifo_in(&cnode_q, &level_separator, size); - - while (!kfifo_is_empty(&cnode_q) && depth_count < MAX_DEPTH) - { - if (cspace_locked || down_trylock(&(cspace->sem_cspace)) == 0) - { - cspace_locked = true; - cspace->root_cnode.ctetype = lcd_type_invalid; - if (!table_visited) - { - kfifo_out(&cnode_q, cnode, size); - if (cnode->ctetype == lcd_type_separator) - { - depth_count++; - - if (kfifo_is_empty(&cnode_q)) - { - up(&(cspace->sem_cspace)); - cspace_locked = false; - break; - } - else - { - kfifo_in(&cnode_q, &level_separator, size); - continue; - } - } - node = cnode->cnode.table; - if (node == NULL) - { - // we may have a cycle or the tables are corrupted - up(&(cspace->sem_cspace)); - cspace_locked = false; - break; - } - // push all its cnode to cnode_q - for (i = CNODE_SLOTS_START; i < MAX_SLOTS; i++) - { - if (node[i].ctetype == lcd_type_cnode) - { - if (node[i].cnode.table != NULL) - kfifo_in(&cnode_q, &(node[i]), size); - } - } - table_visited = true; - i = 1; - } // if (!table_visited) - for (; i < CNODE_SLOTS_START; i++) - { - if (node[i].ctetype == lcd_type_free) - continue; - // try to get the CDT lock ... recipe for deadlock- Revoke, Delete and delete_internal - // access the locks in the order CDT Lock and then CSPACE lock, but this function - // tries to access them in order CSPACE and then CDT. Be very careful while modifying - // this function or the lock access patterns in this and the related functions. - if (down_trylock(node[i].cap.cdt_node->sem_cdt) == 0) - { - sem_cdt_backup = node[i].cap.cdt_node->sem_cdt; - last_reference = false; - lcd_cap_delete_internal_lockless(&(node[i]), &last_reference); - up(sem_cdt_backup); - if (last_reference == true) - { - // TBD: this is the place where we can free the object associated with the cap. - // for now just free sem_cdt. - kfree(node[i].cap.cdt_node->sem_cdt); - } - } - else - { - up(&(cspace->sem_cspace)); - cspace_locked = false; - break; - } - } - if (i == CNODE_SLOTS_START) - { - kmem_cache_free(cte_cache, node); - table_visited = false; - } - else - { - msleep_interruptible(1); - } - if (kfifo_is_empty(&cnode_q) || depth_count >= MAX_DEPTH) - { - up(&(cspace->sem_cspace)); - cspace_locked = false; - } - } // if down_trylock(cspace->sem_cspace) - } // while (!kfifo_is_empty(&cnode_q) && depth_count < MAX_DEPTH) - kfifo_free(&cnode_q); - return; -} - -capability_t lcd_cap_grant_capability(struct cap_space *src_space, capability_t src_cid, struct cap_space *dst_space, lcd_cap_rights crights) -{ - capability_t cid = 0; - struct cte *src_cte = NULL, *dst_cte = NULL; - bool done = false; - struct cap_derivation_tree *dst_cdt_node; - - BUG_ON(src_space == NULL || dst_space == NULL || src_cid == 0); - - dst_cdt_node = kmem_cache_alloc(cdt_cache, GFP_KERNEL); - if(!dst_cdt_node) { - LCD_PANIC("Allocation failed\n"); - return 0; + cspace->cnode = kmalloc(sizeof(struct cnode) * LCD_MAX_CAPS, GFP_KERNEL); + if(!cspace->cnode){ + printk(KERN_ERR "Failed to allocate memory for cnodes\n"); + return -ENOMEM; }; - while (!done) - { - struct cap_derivation_tree *src_cdt_node; - struct cap_derivation_tree *cdtnode; - - // Lookup the source TCB to get a pointer to capability and keep the cdt locked. - src_cte = lcd_cap_lookup_capability(src_space, src_cid, true); - if (src_cte == NULL || src_cte->ctetype != lcd_type_capability) - { - LCD_PANIC("lcd_cap_grant_capability: Invalid Capability\n"); - if (src_cte != NULL) - up(src_cte->cap.cdt_node->sem_cdt); - kmem_cache_free(cdt_cache, dst_cdt_node); - return 0; - } - - if ((src_cte->cap.crights & CAPRIGHTS_GRANT) == 0) - { - LCD_PANIC("lcd_cap_grant_capability: Source does not have grant permissions\n"); - up(src_cte->cap.cdt_node->sem_cdt); - kmem_cache_free(cdt_cache, dst_cdt_node); - return 0; - } - - src_cdt_node = src_cte->cap.cdt_node; - cdtnode = src_cdt_node->child_ptr; - // lock the destination cspace - if (down_trylock(&(dst_space->sem_cspace)) == 0) - { - if (dst_space->root_cnode.ctetype == lcd_type_invalid) - { - LCD_PANIC("lcd_cap_grant_capability: Destroy may be in progress, aborting operation\n"); - up(&(dst_space->sem_cspace)); - up(src_cte->cap.cdt_node->sem_cdt); - kmem_cache_free(cdt_cache, dst_cdt_node); - return 0; - } - - // get a free slot in destination. - if (cid == 0) - { - cid = lcd_cap_lookup_freeslot(dst_space, &dst_cte); - } - if (dst_cte == NULL || dst_cte->ctetype != lcd_type_free) - { - LCD_PANIC("lcd_cap_grant_capability: No free slot\n"); - up(&(dst_space->sem_cspace)); - up(src_cte->cap.cdt_node->sem_cdt); - kmem_cache_free(cdt_cache, dst_cdt_node); - return 0; - } - - // add the capability to destination. - dst_cte->cap.crights = (crights & src_cte->cap.crights); - dst_cte->cap.hobject = src_cte->cap.hobject; - dst_cdt_node->sem_cdt = src_cte->cap.cdt_node->sem_cdt; - dst_cte->cap.cdt_node = dst_cdt_node; - - src_cdt_node->child_ptr = dst_cdt_node; - dst_cdt_node->parent_ptr = src_cdt_node; - dst_cdt_node->child_ptr = NULL; - dst_cdt_node->next = cdtnode; - dst_cdt_node->prev = NULL; - - if (cdtnode) - { - cdtnode->prev = dst_cdt_node; - } - dst_cte->ctetype = lcd_type_capability; - done = true; - up(&(dst_space->sem_cspace)); - up(src_cte->cap.cdt_node->sem_cdt); - break; - } - up(src_cte->cap.cdt_node->sem_cdt); - if (!done) - msleep_interruptible(1); - } - return cid; -} - -uint32_t lcd_cap_get_rights(struct cap_space *cspace, capability_t cid, lcd_cap_rights *rights) -{ - struct cte *cap; - - BUG_ON(cspace == NULL || cid == 0 || rights == NULL); - - cap = lcd_cap_lookup_capability(cspace, cid, false); - if (cap == NULL || cap->ctetype != lcd_type_capability) - { - printk(KERN_ALERT "lcd_get_cap_rights: Invalid capability identifier\n"); - return -1; - } - *rights = cap->cap.crights; + spin_lock_init(&cspace->lock); return 0; -} - -// does not lock the cspace caller responsbile for the same. -// Given a task_struct and a capability identifier, will return the pointer to the -// capability table entry associated with that identifier within the cspace of the thread. -struct cte * lcd_cap_lookup_capability(struct cap_space *cspace, capability_t cid, bool keep_locked) -{ - struct cte *cap = NULL, *node = NULL; - capability_t id = cid; - int index = 0; - int mask = (~0); - - BUG_ON(cspace == NULL || cid == 0); - - mask = mask << (CNODE_INDEX_BITS); - mask = ~mask; - - BUG_ON(cspace->root_cnode.cnode.table == NULL); - - node = cspace->root_cnode.cnode.table; - - while (id > 0) - { - index = (int)(id) & mask; - id = id >> (CNODE_INDEX_BITS); - if (node[index].ctetype == lcd_type_capability && id == 0) - { - // delete/revoke could be accessing the same node - // try to lock it and confirm if still valid. - if (down_interruptible(node[index].cap.cdt_node->sem_cdt) == 0) - { - if (node[index].ctetype == lcd_type_capability) - { - cap = &node[index]; - } - else - { - up(node[index].cap.cdt_node->sem_cdt); - } - if (!keep_locked) - up(node[index].cap.cdt_node->sem_cdt); - } - break; - } - else if (node[index].ctetype == lcd_type_cnode && id != 0) - { - node = node[index].cnode.table; - } - else - { - printk(KERN_ALERT "lcd_lookup_capability: Invalid Capability Identifier\n"); - break; - } - } - - return cap; -} - -capability_t lcd_cap_create_capability(struct cap_space *cspace, void * hobject, lcd_cap_rights crights) -{ - struct cte *cap; - capability_t cid; - struct cap_derivation_tree *cdtnode; - - BUG_ON(cspace == NULL || cspace->root_cnode.cnode.table == NULL); - - cdtnode = kmem_cache_alloc(cdt_cache, GFP_KERNEL); - if (cdtnode == NULL) - { - LCD_PANIC("lcd_cap_create_capability: CDT Node allocation failed\n"); - return 0; - } - - cdtnode->sem_cdt = kmalloc(sizeof(struct semaphore), GFP_KERNEL); - if (cdtnode == NULL) - { - LCD_PANIC("lcd_cap_create_capability: CDT Semaphore allocation failed\n"); - kmem_cache_free(cdt_cache, cdtnode); - return 0; - } - - if (down_interruptible(&(cspace->sem_cspace)) == 0) - { - if (cspace->root_cnode.ctetype == lcd_type_invalid) - { - LCD_PANIC("lcd_cap_create_capability: Destroy may be in progress, operation aborted\n"); - up(&(cspace->sem_cspace)); - kfree(cdtnode->sem_cdt); - kmem_cache_free(cdt_cache, cdtnode); - return 0; - } - cid = lcd_cap_lookup_freeslot(cspace, &cap); - if (cid == 0) - { - LCD_PANIC("lcd_cap_create_capability: No Free Slot found\n"); - kfree(cdtnode->sem_cdt); - kmem_cache_free(cdt_cache, cdtnode); - up(&(cspace->sem_cspace)); - return 0; - } - - cap->ctetype = lcd_type_capability; - cap->cap.crights = crights; - cap->cap.hobject = hobject; - sema_init(cdtnode->sem_cdt, 1); - cap->cap.cdt_node = cdtnode; - cap->cap.cdt_node->cap = cap; - cap->cap.cdt_node->child_ptr = NULL; - cap->cap.cdt_node->parent_ptr = NULL; - cap->cap.cdt_node->prev = NULL; - cap->cap.cdt_node->next = NULL; - up(&(cspace->sem_cspace)); - } - else - { - LCD_PANIC("lcd_cap_create_capability: Signal interrupted cspace lock acquire\n"); - kfree(cdtnode->sem_cdt); - kmem_cache_free(cdt_cache, cdtnode); - } - return cid; -} -EXPORT_SYMBOL(lcd_cap_create_capability); - -int lcd_cap_init_cspace(struct cap_space *cspace) -{ - int ret; - struct cte *table; - - cspace->root_cnode.cnode.table = NULL; - - // initialize semaphore - sema_init(&cspace->sem_cspace, 1); - - // allocate memory for the first cnode. - cspace->root_cnode.ctetype = lcd_type_cnode; - cspace->root_cnode.cnode.cnode_id = 0; - cspace->root_cnode.cnode.table_level = 0; - cspace->root_cnode.cnode.table = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (cspace->root_cnode.cnode.table == NULL) { - LCD_PANIC("lcd_cap_create_cspace: Failed to allocate cnode table\n"); - return -ENOMEM; - } - - table = cspace->root_cnode.cnode.table; - table[0].ctetype = lcd_type_free; +}; +EXPORT_SYMBOL(lcd_init_cspace); - // initialize the free list - ret = lcd_cap_initialize_freelist(cspace, cspace->root_cnode.cnode.table, true); - if (!ret) { - LCD_PANIC("lcd_cap_create_cspace: Failed to initialize free list\n"); - goto out; - } - +int lcd_cnode_insert(struct cspace *cspace, capability_t cap, struct cnode *cnode) { + /* XXX: not clear */ return 0; - -out: - if (cspace->root_cnode.cnode.table) { - kfree(cspace->root_cnode.cnode.table); - cspace->root_cnode.cnode.table = NULL; - } - return ret; -} -EXPORT_SYMBOL(lcd_cap_init_cspace); - -// does not lock the cspace. -// First entry of every cnode table will be the head of the free slots available -// in the table. This function will just populate the free list. -bool lcd_cap_initialize_freelist(struct cap_space *cspace, struct cte *cnode, bool bFirstCNode) -{ - int startid = 1; - int i; - - BUG_ON(cnode == NULL || cspace == NULL); - - if (bFirstCNode) - { - startid = LCD_CapFirstFreeSlot; - } - - cnode[0].ctetype = lcd_type_invalid; - cnode[0].slot.cspace = cspace; - cnode[0].ctetype = lcd_type_free; - cnode[0].index = 0; - cnode[0].slot.next_free_cap_slot = startid; - cnode[startid].ctetype = lcd_type_free; - for (i = startid; i < CNODE_SLOTS_START - 1; i++) - { - cnode[i].slot.next_free_cap_slot = i + 1; - cnode[i+1].ctetype = lcd_type_free; - cnode[i].index = i; - } - cnode[i].slot.next_free_cap_slot = 0; - cnode[i].index = i; - - startid = CNODE_SLOTS_START; - cnode[0].slot.next_free_cnode_slot = startid; - cnode[startid].ctetype = lcd_type_free; - for (i = CNODE_SLOTS_START; i < MAX_SLOTS - 1; i++) - { - cnode[i].slot.next_free_cnode_slot = i + 1; - cnode[i].index = i; - cnode[i+1].ctetype = lcd_type_free; - } - cnode[i].slot.next_free_cnode_slot = 0; - cnode[i].index = i; - return true; -} - -// Removes the free_slot from free list. -struct cte * lcd_cap_reserve_slot(struct cte *cnode, capability_t *cid, int free_slot) -{ - struct cte *node = cnode->cnode.table; - BUG_ON(node[free_slot].ctetype != lcd_type_free); - // a valid empty slot - node[0].slot.next_free_cap_slot = node[free_slot].slot.next_free_cap_slot; - lcd_set_bits_at_level(cnode, cid, free_slot); - return &node[free_slot]; -} - - -// free slot will be booked for the caller. -// ie. it will not longer be free once this function returns it. -// naming convention: -// cnode = struct cte entry in the table, which points to another table. -// node = pointer the the array of struct cte entries/capability table i.e. cnode->cnode.table -capability_t lcd_cap_lookup_freeslot(struct cap_space *cspace, struct cte **cap) -{ - capability_t cid = 0, cnode_id; - bool found = false; - int i = 0; - struct kfifo cnode_q; - - BUG_ON(cspace == NULL || cspace->root_cnode.cnode.table == NULL || cap == NULL); +}; - if (kfifo_alloc(&cnode_q, sizeof(struct cte *) * 512, GFP_KERNEL) != 0) - { - LCD_PANIC("lcd_cap_lookup_freeslot: Failed to allocate FIFO buffer\n"); - return 0; - } +static inline void lcd_cnode_lock(struct cnode *cnode) { + /* XXX: not clear what to do yet */ + return; +}; - kfifo_in(&cnode_q, &cspace->root_cnode, sizeof(struct cte *)); - - while (!found && !kfifo_is_empty(&cnode_q)) - { - int free_cap_slot = 0, free_cnode_slot = 0; - struct cte *node = NULL, *cnode; - - printk(KERN_INFO "Looking up free slot\n"); +void lcd_cnode_release(struct cnode *cnode) { + /* XXX: not clear what to do yet */ + return; +}; +EXPORT_SYMBOL(lcd_cnode_release); - kfifo_out(&cnode_q, &cnode, sizeof(struct cte *)); - if (cnode == NULL) - { - break; - } - - node = cnode->cnode.table; +struct cnode *lcd_cnode_lookup(struct cspace *cspace, capability_t cap) { - - free_cap_slot = node[0].slot.next_free_cap_slot; - free_cnode_slot = node[0].slot.next_free_cnode_slot; - - printk(KERN_INFO "Next free cap slot:%d, cnode slot:%d\n", free_cap_slot, free_cnode_slot); + unsigned long flags; + + if(cap >= LCD_MAX_CAPS) + return NULL; - if (free_cap_slot != 0 && free_cap_slot < CNODE_SLOTS_START) - { - *cap = lcd_cap_reserve_slot(cnode, &cid, free_cap_slot); - break; - } - - if (free_cnode_slot != 0 && free_cnode_slot >= CNODE_SLOTS_START && free_cnode_slot < MAX_SLOTS) - { - // there is no slot free for capability - // 1. Check if free slots are available at next level - for (i = CNODE_SLOTS_START; i < free_cnode_slot; i++) - { - struct cte * next_cnode = &node[i]; - struct cte *next_node = node[i].cnode.table; - free_cap_slot = next_node[0].slot.next_free_cap_slot; - if (free_cap_slot != 0 && free_cap_slot < CNODE_SLOTS_START) - { - *cap = lcd_cap_reserve_slot(next_cnode, &cid, free_cap_slot); - found = true; - break; - } - } - if (found) - break; - - // we will have to allocate a new cnode - node[free_cnode_slot].cnode.table = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (node[free_cnode_slot].cnode.table == NULL) - { - LCD_PANIC("lcd_cap_lookup_freeslot: Not able to allocate cnode\n"); - break; - } - node[0].slot.next_free_cnode_slot = node[free_cnode_slot].slot.next_free_cnode_slot; - node[free_cnode_slot].ctetype = lcd_type_cnode; - lcd_cap_initialize_freelist(cspace, node[free_cnode_slot].cnode.table, false); - node[free_cnode_slot].cnode.table_level = cnode->cnode.table_level + 1; - lcd_set_bits_at_level(cnode, &cnode_id, free_cnode_slot); - node[free_cnode_slot].cnode.cnode_id = cnode_id; - - cnode = &node[free_cnode_slot]; - node = node[free_cnode_slot].cnode.table; - free_cap_slot = node[0].slot.next_free_cap_slot; - if (free_cap_slot != 0 && free_cap_slot < CNODE_SLOTS_START) - { - *cap = lcd_cap_reserve_slot(cnode, &cid, free_cap_slot); - } - break; - } // found a free cnode slot - else - { - // nothing is free in this cnode - // keep lookin at all its children - for (i = CNODE_SLOTS_START; i < MAX_SLOTS; i++) - { - kfifo_in(&cnode_q, &node[i], sizeof(struct cte *)); - } - } - } // while (!kfifo_is_empty()) - kfifo_free(&cnode_q); - return cid; -} + spin_lock_irqsave(&cspace->lock, flags); + lcd_cnode_lock(&cspace->cnode[cap]); + spin_unlock_irqrestore(&cspace->lock, flags); -capability_t lcd_cap_mint_capability(struct cap_space *cspace, capability_t cid, lcd_cap_rights rights) -{ - capability_t id = 0; - struct cte *src_cte = NULL, *dst_cte = NULL; - struct cap_derivation_tree *cdt; - struct cap_derivation_tree *dst_cdt; - bool done = false; - - BUG_ON(cid == 0); + return &cspace->cnode[cap]; +}; +EXPORT_SYMBOL(lcd_cnode_lookup); - dst_cdt = kmem_cache_alloc(cdt_cache, GFP_KERNEL); - if (dst_cdt == NULL) - { - LCD_PANIC("lcd_cap_mint_capability: Failed to allocate memory for cdt node\n"); - return 0; - } - while (!done) - { - // keep the source cdt locked. - src_cte = lcd_cap_lookup_capability(cspace, cid, true); - if (src_cte == NULL || src_cte->ctetype != lcd_type_capability) - { - LCD_PANIC("lcd_cap_mint_capability: Invalid Capability\n"); - if (src_cte != NULL) - up(src_cte->cap.cdt_node->sem_cdt); - kmem_cache_free(cdt_cache, dst_cdt); - return 0; - } - cdt = src_cte->cap.cdt_node; - if (down_trylock(&(cspace->sem_cspace)) == 0) - { - if (cspace->root_cnode.ctetype == lcd_type_invalid) - { - LCD_PANIC("lcd_cap_mint_capability: Destroy may be in progress, aborting operation\n"); - up(&(cspace->sem_cspace)); - up(cdt->sem_cdt); - kmem_cache_free(cdt_cache, dst_cdt); - return 0; - } - - // get a free slot in destination. - if (id == 0) - { - id = lcd_cap_lookup_freeslot(cspace, &dst_cte); - } - if (dst_cte == NULL || dst_cte->ctetype != lcd_type_free) - { - LCD_PANIC("lcd_cap_mint_capability: No free slot\n"); - up(&(cspace->sem_cspace)); - up(cdt->sem_cdt); - kmem_cache_free(cdt_cache, dst_cdt); - return 0; - } - - // add the capability in cspace and cdt node as a sibling. - dst_cte->cap.crights = (rights & src_cte->cap.crights); - dst_cte->cap.hobject = src_cte->cap.hobject; - dst_cdt->sem_cdt = cdt->sem_cdt; - dst_cte->cap.cdt_node = dst_cdt; - - dst_cdt->next = cdt->next; - if (cdt->next != NULL) - cdt->next->prev = dst_cdt; - cdt->next = dst_cdt; - dst_cdt->prev = cdt; - dst_cdt->child_ptr = NULL; - dst_cdt->parent_ptr = cdt->parent_ptr; - - dst_cte->ctetype = lcd_type_capability; - done = true; - up(&(cspace->sem_cspace)); - } - up(cdt->sem_cdt); - if (!done) - msleep_interruptible(1); - } - - return id; -} diff --git a/virt/lcd-domains/ipc.c b/virt/lcd-domains/ipc.c index e24e9641c6be54b82e32f7819d5e1e91ff0deaef..fbb233e56ac42d5f4ed95020b4d5e41020bcd537 100644 --- a/virt/lcd-domains/ipc.c +++ b/virt/lcd-domains/ipc.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include struct kmem_cache *sync_ipc_cache; @@ -49,24 +49,24 @@ int ipc_send(capability_t rvp_cap, struct message_info *msg) { struct task_struct *recv_task; struct sync_ipc *sync_ipc; - struct cte *rvp_cte; + struct cnode *cnode; unsigned long flags; printk(KERN_ERR "ipc_send:%s: sending on cap %lld\n", current->comm, rvp_cap); - rvp_cte = lcd_cap_lookup_capability(¤t->cspace, rvp_cap, true); - if (rvp_cte == NULL) { + cnode = lcd_cnode_lookup(¤t->cspace, rvp_cap); + if (cnode == NULL || cnode->type != LCD_TYPE_SYNC_EP) { printk(KERN_ERR "ipc_send: can't resolve rendezvous capabilty: %lld\n", rvp_cap); return -EINVAL; } - sync_ipc = (struct sync_ipc *) rvp_cte->cap.hobject; + sync_ipc = (struct sync_ipc *) cnode->object; BUG_ON(!sync_ipc); // XXX: BU: Maybe I need to do some reference counting for IPC // objects here (before releasing the lock) - up(rvp_cte->cap.cdt_node->sem_cdt); + lcd_cnode_release(&cnode); spin_lock_irqsave(&sync_ipc->lock, flags); if (list_empty(&sync_ipc->receivers)) { @@ -111,24 +111,24 @@ int ipc_recv(capability_t rvp_cap, struct message_info *msg) { struct task_struct *send_task; struct sync_ipc *sync_ipc; - struct cte *rvp_cte; + struct cnode *cnode; unsigned long flags; printk(KERN_ERR "ipc_recv:%s: receiving on cap %lld\n", current->comm, rvp_cap); - rvp_cte = lcd_cap_lookup_capability(¤t->cspace, rvp_cap, true); - if (rvp_cte == NULL) { + cnode = lcd_cnode_lookup(¤t->cspace, rvp_cap); + if (cnode == NULL || cnode->type != LCD_TYPE_SYNC_EP) { printk(KERN_ERR "ipc_recv: can't resolve capability: %lld\n", rvp_cap); return -EINVAL; } - sync_ipc = (struct sync_ipc *) rvp_cte->cap.hobject; + sync_ipc = (struct sync_ipc *) cnode->object; BUG_ON(!sync_ipc); // XXX: BU: Maybe I need to do some reference counting for IPC // objects here (before releasing the lock) - up(rvp_cte->cap.cdt_node->sem_cdt); + lcd_cnode_release(cnode); spin_lock_irqsave(&sync_ipc->lock, flags); if (list_empty(&sync_ipc->senders)) {