Commit 2b829db5 authored by Charlie Jacobsen's avatar Charlie Jacobsen Committed by Vikram Narayanan

Improved capability module.

parent b796391c
......@@ -19,10 +19,11 @@ static int test01(void)
struct cspace *cspace;
if (lcd_mk_cspace(&cspace))
LCD_FAIL("mk cspace");
lcd_rm_cspace(cspace);
lcd_rm_cspace(&cspace);
LCD_PASS();
}
#if 0
static int test02(void)
{
struct cspace *cspace;
......@@ -155,18 +156,20 @@ static int test05(void)
LCD_PASS();
}
#endif
int api_tests(void)
{
if (test01())
return -1;
if (test02())
return -1;
if (test03())
return -1;
if (test04())
return -1;
if (test05())
return -1;
/* if (test02()) */
/* return -1; */
/* if (test03()) */
/* return -1; */
/* if (test04()) */
/* return -1; */
/* if (test05()) */
/* return -1; */
LCD_MSG("all api tests passed!");
return 0;
}
......@@ -6,6 +6,34 @@
#include "defs.h"
#include "../include/common.h"
int lcd_cap_init(void)
{
mutex_init(&__lcd_cap_lock);
return 0;
}
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;
}
int lcd_mk_cspace(struct cspace **cspace_ptr)
{
struct cspace *cspace;
......@@ -16,13 +44,11 @@ int lcd_mk_cspace(struct cspace **cspace_ptr)
if (!cspace)
return -ENOMEM;
/*
* Sets cnode types to unformed, and free_slot to 0
* Zero out all data (including cnodes). Sets cnode types to free with
* no rights. Initialize free list and cnodes.
*/
memset(cspace, 0, sizeof(*cspace));
/*
* Initialize lock
*/
mutex_init(&cspace->lock);
init_cspace_cnodes(cspace);
/*
* Done
*/
......@@ -30,56 +56,267 @@ int lcd_mk_cspace(struct cspace **cspace_ptr)
return 0;
}
int lcd_cap_insert(struct cspace *cspace, cptr_t cptr, void *object,
enum lcd_cap_type type)
static int __lcd_cnode_alloc(struct cspace *cspace, cptr_t *cptr)
{
struct cnode *cnode = NULL;
int ret;
if (list_empty(&cspace->free_list)) {
return -ENOMEM;
} else {
/*
* Get first available cnode, and remove it from the list.
*/
cnode = list_first_entry(&cspace->free_list, struct cspace,
free_list);
/*
* Remove from free list
*/
list_del_init(&cnode->free_list);
/*
* Mark it as unformed
*/
lcd_cnode_set_type(cnode, LCD_CAP_TYPE_UNFORMED);
/*
* Calc index
*/
*cptr = (cnode - (cspace->cnodes)) / sizeof(struct cnode);
return 0;
}
}
int lcd_cnode_alloc(struct cspace *cspace, cptr_t *cptr)
{
struct cnode *cnode;
int ret;
/*
* Lookup cnode
* LOCK cap
*/
ret = lcd_lock_cspace(cspace);
if (!ret) {
cnode = __lcd_cnode_lookup(cspace, cptr);
lcd_unlock_cspace(cspace);
} else {
ret = lcd_cap_lock();
if (ret)
return ret;
}
ret = __lcd_cnode_alloc(cspace, cptr);
/*
* Set vals
* UNLOCK cap
*/
if (cnode && cnode->type == LCD_CAP_TYPE_UNFORMED) {
lcd_cap_unlock();
return ret;
}
int __lcd_cnode_lookup(struct cspace *cspace, cptr_t cptr, struct cnode **out)
{
struct cnode *c;
int ret;
if (cptr >= LCD_NUM_CAPS)
return -EINVAL;
c = &cspace->cnodes[cptr];
*out = c;
return 0;
}
static int __lcd_cnode_insert(struct cnode *cnode, void *object,
enum lcd_cap_type type, int rights)
{
if (!lcd_cnode_is_unformed(cnode))
return -EINVAL;
else {
cnode->object = object;
cnode->type = type;
cnode->type = type;
cnode->rights = rights;
return 0;
} else {
return -EINVAL;
}
}
int lcd_cap_grant(struct cspace *src_cspace, struct cspace *dest_cspace,
cptr_t src_cptr, cptr_t dest_cptr)
int lcd_cnode_insert(struct cspace *cspace, cptr_t cptr,
void *object, enum lcd_cap_type type, int rights)
{
struct cnode *src_cnode;
struct cnode *cnode;
int ret;
/*
* Get source capability data
* LOCK cap
*/
ret = lcd_cnode_lookup(src_cspace, src_cptr, &src_cnode);
ret = lcd_cap_lock();
if (ret)
return ret;
if (!src_cnode)
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;
}
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))
return -EINVAL;
if (!__lcd_cap_can_grant(src_cnode))
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))
return -EINVAL;
dest_rights = lcd_cnode_rights(src_cnode) & rights;
ret = __lcd_insert_for_grant(src_cnode, dest_cnode, dest_rights);
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
*/
ret = lcd_lock_cap();
if (ret)
return ret;
ret = __lcd_cnode_grant(src_cspace, dest_cspace, src_cptr, dest_cptr,
rights);
/*
* UNLOCK cap
*/
lcd_unlock_cap();
return ret;
}
static void __lcd_cnode_do_revoke(struct cnode *parent, int rights)
{
int ret;
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;
/*
* Insert into destination
* LOCK cap
*/
return lcd_cap_insert(dest_cspace, dest_cptr, src_cnode->object,
src_cnode->type);
ret = lcd_lock_cap();
if (ret)
return ret;
ret = __lcd_cnode_revoke(cspace, cptr, rights);
/*
* UNLOCK cap
*/
lcd_unlock_cap();
return ret;
}
void lcd_rm_cspace(struct cspace *cspace)
static void __lcd_cnode_do_free(struct cnode *parent)
{
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
*/
__lcd_cnode_do_free(cspace, child);
/*
* Remove from parent
*/
list_del_init(&child->child_list);
}
/*
* Mark parent as free
*/
__lcd_cnode_set_type(parent, LCD_CAP_TYPE_FREE);
/*
* 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;
}
void __lcd_rm_cnode(struct cnode *cnode)
{
if (lcd_cnode_is_occupied(cnode))
__lcd_cnode_do_free(cnode);
return;
}
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]);
kfree(cspace);
*cspace_ptr = NULL;
return;
}
This diff is collapsed.
/*
* ipc.c
*
* Authors: Anton Burtsev <aburtsev@flux.utah.edu>
* Charles Jacobsen <charlesj@cs.utah.edu>
* Copyright: University of Utah
*/
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <lcd-prototype/lcd.h>
#include "../include/common.h"
#include "defs.h"
int __lcd_send(struct task_struct *from, cptr_t c)
{
return -ENOSYS;
}
int __lcd_recv(struct task_struct *to, cptr_t c)
{
return -ENOSYS;
}
int __lcd_call(struct task_struct *from, cptr_t c)
{
return -ENOSYS;
}
int __lcd_select(struct task_struct *from, cptr_t *cs, int cs_count,
cptr_t *c_out)
{
return -ENOSYS;
}
int lcd_mk_sync_endpoint(struct lcd *lcd, cptr_t c)
{
struct sync_endpoint *e;
struct cnode *cnode;
int ret = -EINVAL;
/*
* Allocate end point
*/
e = kmalloc(sizeof(*e), GFP_KERNEL);
if (!e) {
ret = -ENOMEM;
goto fail1;
}
/*
* Initialize data
*/
INIT_LIST_HEAD(&e->senders);
INIT_LIST_HEAD(&e->receivers);
mutex_init(&e->lock);
/*
* Get the destination node in the cspace
*/
ret = lcd_cnode_lookup(lcd->cspace, c, &cnode);
if (ret) {
LCD_ERR("cnode lookup at %lld", c);
goto fail2;
}
if (!CNODE_UNFORMED(cnode)) {
LCD_ERR("cnode occupied at %lld", c);
ret = -EINVAL;
goto fail3;
}
/*
* Install endpoint
*/
cnode->object = e;
cnode->type = CAP_TYPE_SYNC_EP;
lcd_cnode_release(cnode);
return 0;
fail3:
lcd_cnode_release(cnode);
fail2:
kfree(e);
fail1:
return ret;
}
int lcd_rm_sync_endpoint(struct lcd *lcd, cptr_t c)
{
struct sync_endpoint *e;
struct cnode *cnode;
int ret = -EINVAL;
/*
* Look up cnode
*/
ret = lcd_cnode_lookup(lcd->cspace, c, &cnode);
if (ret) {
LCD_ERR("cnode lookup at %lld", c);
goto fail1;
}
if (!CNODE_SYNC_EP(cnode)) {
LCD_ERR("cnode does not contain sync ep at %lld", c);
ret = -EINVAL;
goto fail2;
}
/*
* Free end point
*
* XXX: For now, we assume no one is in line, and no one has
* the lock.
*/
kfree(cnode->object);
return 0;
fail2:
lcd_cnode_release(cnode);
fail1:
return ret;
}
inline void transfer_msg(struct task_struct *to, struct task_struct *from) {
printk(KERN_INFO "Sending %d registers (recv ready to take %d)\n",
from->utcb->msg_info.valid_regs, to->utcb->msg_info.valid_regs);
// copy the message registers
// XXX: BU: maybe MIN(of valid_regs)?
memcpy(&to->utcb->msg_info.regs,
&from->utcb->msg_info.regs,
sizeof(uint64_t)*to->utcb->msg_info.valid_regs);
// BU: TODO: transfer capabilities
//
// Transfer err code
to->utcb->msg_info.err = from->utcb->msg_info.err;
return;
}
int ipc_reply(capability_t cap, struct message_info *msg)
{
return ipc_send(cap, msg);
}
EXPORT_SYMBOL(ipc_reply);
int ipc_call(capability_t cap, struct message_info *msg)
{
int ret;
// The last capability register is expected to
// have the reply capability
if (msg->valid_cap_regs == 0)
return -EINVAL;
ret = ipc_send(cap, msg);
if (ret)
return ret;
// The last capability register is expected to
// have the reply capability
ret = ipc_recv(msg->cap_regs[msg->valid_cap_regs - 1], msg);
return ret;
}
EXPORT_SYMBOL(ipc_call);
int ipc_send(capability_t rvp_cap, struct message_info *msg)
{
struct task_struct *recv_task;
struct sync_ipc *sync_ipc;
struct cnode *cnode;
unsigned long flags;
printk(KERN_ERR "ipc_send:%s: sending on cap %lld\n", current->comm, rvp_cap);
cnode = lcd_cnode_lookup(&current->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 *) cnode->object;
BUG_ON(!sync_ipc);
// XXX: BU: Maybe I need to do some reference counting for IPC
// objects here (before releasing the lock)
lcd_cnode_release(cnode);
spin_lock_irqsave(&sync_ipc->lock, flags);
if (list_empty(&sync_ipc->receivers)) {
set_current_state(TASK_INTERRUPTIBLE);
list_add_tail(&current->sync_rendezvous, &sync_ipc->senders);
printk(KERN_ERR "ipc_send:%s: putting myself to sleep\n", current->comm);
spin_unlock_irqrestore(&sync_ipc->lock, flags);
schedule();
printk(KERN_ERR "ipc_send: someone woke me up\n");
return 0;
}
recv_task = list_first_entry(&sync_ipc->receivers,
struct task_struct,
sync_rendezvous);
list_del(&recv_task->sync_rendezvous);
spin_unlock_irqrestore(&sync_ipc->lock, flags);
printk(KERN_ERR "ipc_send: found other end %s\n", recv_task->comm);
transfer_msg(recv_task, current);
wake_up_process(recv_task);
printk(KERN_ERR "ipc_send: finished\n");
return 0;
}
EXPORT_SYMBOL(ipc_send);
int ipc_recv(capability_t rvp_cap, struct message_info *msg)
{
struct task_struct *send_task;
struct sync_ipc *sync_ipc;
struct cnode *cnode;
unsigned long flags;
printk(KERN_ERR "ipc_recv:%s: receiving on cap %lld\n", current->comm, rvp_cap);
cnode = lcd_cnode_lookup(&current->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 *) cnode->object;
BUG_ON(!sync_ipc);
// XXX: BU: Maybe I need to do some reference counting for IPC
// objects here (before releasing the lock)
lcd_cnode_release(cnode);
spin_lock_irqsave(&sync_ipc->lock, flags);
if (list_empty(&sync_ipc->senders)) {
set_current_state(TASK_INTERRUPTIBLE);
list_add_tail(&current->sync_rendezvous, &sync_ipc->receivers);
printk(KERN_ERR "ipc_recv:%s: putting myself to sleep\n", current->comm);
spin_unlock_irqrestore(&sync_ipc->lock, flags);
schedule();
printk(KERN_ERR "ipc_recv: someone woke me up\n");
return 0;
}
send_task = list_first_entry(&sync_ipc->senders,
struct task_struct,
sync_rendezvous);
list_del(&send_task->sync_rendezvous);
spin_unlock_irqrestore(&sync_ipc->lock, flags);
printk(KERN_ERR "ipc_send: other end %s\n", send_task->comm);
transfer_msg(current, send_task);
wake_up_process(send_task);
printk(KERN_ERR "ipc_recv: finished\n");
return 0;
}
EXPORT_SYMBOL(ipc_recv);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment