Commit d4a334cb authored by Charlie Jacobsen's avatar Charlie Jacobsen Committed by Vikram Narayanan

Starting tests for api.

parent 3206be73
obj-$(CONFIG_LCD_PROTOTYPE_API) += api.o cap.o
/*
* api-tests.c
*
* Authors: Anton Burtsev <aburtsev@flux.utah.edu>
* Charles Jacobsen <charlesj@cs.utah.edu>
* Copyright: University of Utah
*/
static int test01(void)
{
return 0;
}
static int api_tests(void)
{
if (test01())
return -1;
LCD_MSG("all api tests passed!");
}
/*
* api.c
*
* Authors: Anton Burtsev <aburtsev@flux.utah.edu>
* Charles Jacobsen <charlesj@cs.utah.edu>
* Copyright: University of Utah
*/
int lcd_mk_sync_endpoint(cptr_t dest)
{
int ret;
struct sync_ipc *rvp;
capability_t rvp_cap;
struct cnode *cnode;
struct message_info *msg = &current->utcb->msg_info;
rvp = lcd_create_sync_ep();
if(!rvp) {
printk(KERN_ERR "Failed to allocate memory\n");
ret = -ENOMEM;
goto err;
};
ret = lcd_alloc_cap(&current->cap_cache, &rvp_cap);
if(ret) {
printk(KERN_ERR "Failed to allocate free capability\n");
ret = -ENOSPC;
kfree(rvp);
goto err;
};
ret = lcd_cap_insert_object(&current->cspace, rvp_cap, rvp, LCD_TYPE_SYNC_EP);
if(cnode == 0) {
lcd_destroy_rvp(rvp);
goto err;
};
msg->cap_regs[0] = rvp_cap;
msg->valid_cap_regs = 1;
ipc_reply(reply_cap, msg);
lcd_cap_drop(&current->cspace, rvp_cap);
lcd_free_cap(&current->cap_cache, rvp_cap);
return 0;
err:
msg->err = ret;
ipc_reply(reply_cap, msg);
return ret;
};
int lcd_api_create_lcd(struct message_info *msg, struct lcd_api *api, capability_t reply_cap) {
int ret;
int i;
capability_t lcd_cap;
struct cnode *cnode;
char *module_name;
module_name = lcd_cap_marshal_string(&msg->regs[1], LCD_MAX_REGS - 1);
if (!module_name) {
printk(KERN_ERR "Failed to unmarshal LCD name\n");
ret = -EINVAL;
goto err;
};
lcd_task = lcd_create_as_module(module_name);
if(!lcd_task) {
printk(KERN_ERR "Failed to create LCD from a module:%s\n", module_name);
ret = -ENOMEM;
goto err;
};
ret = lcd_alloc_cap(&current->cap_cache, &lcd_cap);
if(ret) {
printk(KERN_ERR "Failed to allocate free capability\n");
ret = -ENOSPC;
lcd_destroy(lcd_task);
goto err;
};
ret = lcd_cap_insert_object(&current->cspace, lcd_cap, lcd_task, LCD_TYPE_LCD);
if(cnode == 0) {
lcd_destroy(lcd_task);
goto err;
};
for (int i = 0; i < cap_regs - 2; i++) {
capability_t boot_cap;
ret = lcd_alloc_cap(&lcd_task->cap_cache, &boot_cap);
if(ret) {
printk(KERN_ERR "Failed to allocate free capability\n");
ret = -ENOSPC;
lcd_destroy(lcd_task);
goto err;
};
ret = lcd_cap_move_object(&lcd_task->cspace, boot_cap, &current->cspace, msg->cap_regs[i]);
if(ret) {
printk(KERN_ERR "Failed to move boot capability number:d\n", i);
ret = -ENOSPC;
lcd_destroy(lcd_task);
goto err;
};
lcd_task->utcb->boot_info.boot_caps[i] = boot_cap;
lcd_drop_cap(&current->cspace, msg->cap_regs[i]);
};
msg->cap_regs[0] = lcd_cap;
msg->valid_cap_regs = 1;
ipc_reply(reply_cap, msg);
lcd_cap_drop(&current->cspace, lcd_cap);
lcd_free_cap(&current->cap_cache, lcd_cap);
return 0;
err:
msg->err = ret;
ipc_reply(reply_cap, msg);
return ret;
};
int lcd_api_execution_loop(struct lcd_api *lcd_api) {
struct message_info *msg = &current->utcb->msg_info;
capability_t reply_cap;
enum lcd_api_calls call;
int ret;
int i;
#include <linux/kernel.h>
#include <linux/module.h>
#include "../include/common.h"
#include "defs.h"
for (i = 0; i < LCD_MAX_CAP_REGS; i++) {
static int api_tests(void);
ret = lcd_alloc_cap(&current->cap_cache,
&msg->cap_regs[i]);
if(ret) {
printk(KERN_ERR "Failed to allocate free capability\n");
return -ENOSPC;
};
};
while (!lcd_api->exit_flag)
{
msg->valid_regs = sizeof(msg->regs)/sizeof(msg->regs[0]);
ret = ipc_recv(lcd_api->rvp, msg);
if (ret) {
printk(KERN_ERR "lcd_api: recv failed:%d\n", ret);
continue;
}
reply_cap = msg->cap_regs[msg->valid_cap_regs];
// We know we're serving a call invocation, reply cap is
// verified by the ipc_call()
if(msg->valid_regs == 0) {
printk(KERN_ERR "lcd_api: invalid invocation\n");
msg->valid_regs = 0;
msg->valid_cap_regs = 0;
ipc_reply(reply_cap, msg);
lcd_cap_drop(&current->cspace, reply_cap);
continue;
};
call = msg->regs[0];
switch (call) {
case LCD_CREATE_SYNC_ENDPOINT:
ret = lcd_api_create_sync_endpoint(msg, lcd_api, reply_cap);
break;
case LCD_CREATE_LCD:
ret = lcd_api_create_lcd(msg, lcd_api, reply_cap);
break;
default:
printk(KERN_ERR "lcd_api: invalid call number:%d\n", call);
msg->valid_regs = 0;
msg->valid_cap_regs = 0;
ipc_reply(reply_cap, msg);
lcd_cap_drop(&current->cspace, reply_cap);
};
};
for (i = 0; i < LCD_MAX_CAP_REGS; i++) {
static int __init api_init(void)
{
LCD_MSG("api starting");
ret = lcd_free_cap(&current->cap_cache, msg->cap_regs[i]);
};
/*
* Run regression tests
*/
if (api_tests()) {
return -1;
}
return 0;
};
int lcd_api_thread(void *p) {
int ret;
struct lcd_api *api = (struct lcd_api*) p;
ret = lcd_enter();
if(ret) {
printk(KERN_ERR "Failed to enter LCD:%d\n", ret);
return ret;
};
api->ep = lcd_make_sync_endpoint(&current->cspace, &current->cap_cache, &api->ep_cap);
if(api->ep) {
printk(KERN_ERR "Failed to create API endpoint:%d\n", ret);
return -EINVAL;
};
ret = lcd_api_execution_loop(api);
return ret;
};
int lcd_api_init(struct lcd_api *api) {
int ret;
struct task_struct *t;
t = kthread_create(lcd_api_thread, api, "lcd-api");
if (!t) {
printk(KERN_ERR "Failed to create LCD API thread\n");
return -EINVAL;
};
}
wake_up_process(t);
return 0;
static void __exit api_exit(void)
{
return;
}
int lcd_api_exit(struct lcd_api *api) {
api->exit_flag = 1;
};
module_init(api_init);
module_exit(api_exit);
/* DEBUG -------------------------------------------------- */
#include "api-tests.c"
/*
* Authors: Anton Burtsev <aburtsev@flux.utah.edu>
* Charles Jacobsen <charlesj@cs.utah.edu>
* Copyright: University of Utah
*/
#include <linux/slab.h>
#include <lcd/cap-cache.h>
#include <lcd/cap.h>
int lcd_init_list_cache(struct cap_cache *list_cache, uint64_t size) {
uint32_t i;
list_cache->cap = kmalloc(sizeof(*list_cache->cap)*size, GFP_KERNEL);
if(!list_cache->cap)
return -ENOMEM;
list_cache->head = 0;
for(i = 0; i < size; i++) {
list_cache->cap[i] = i + 1;
}
list_cache->cap[size - 2] = size - 2;
return 0;
}
void lcd_free_list_cache(struct cap_cache *list_cache) {
kfree(list_cache->cap);
return;
};
int lcd_alloc_cap(struct cap_cache *cap_cache, capability_t *free_cap) {
unsigned long flags;
uint32_t head;
spin_lock_irqsave(&cap_cache->lock, flags);
if(cap_cache->head == cap_cache->cap[cap_cache->head]) {
spin_unlock_irqrestore(&cap_cache->lock, flags);
return -ENOMEM;
};
head = cap_cache->head;
*free_cap = (capability_t)head;
cap_cache->head = cap_cache->cap[head];
spin_unlock_irqrestore(&cap_cache->lock, flags);
return 0;
};
void lcd_free_cap(struct cap_cache *cap_cache, capability_t free_cap) {
unsigned long flags;
spin_lock_irqsave(&cap_cache->lock, flags);
cap_cache->cap[(uint32_t)free_cap] = cap_cache->head;
cap_cache->head = (uint32_t)free_cap;
spin_unlock_irqrestore(&cap_cache->lock, flags);
return 0;
}
......@@ -6,7 +6,7 @@
#include "defs.h"
#include "../include/common.h"
struct cspace * lcd_mk_cspace(void)
int lcd_mk_cspace(struct cspace **cspace_ptr)
{
struct cspace *cspace;
int i;
......@@ -15,90 +15,72 @@ struct cspace * lcd_mk_cspace(void)
*/
cspace = kmalloc(sizeof(*cspace), GFP_KERNEL);
if (!cspace)
return NULL;
memset(cspace, 0, sizeof(*cspace)); /* sets cnode types to invalid */
/*
* Initialize free list
return -ENOMEM;
/*
* Sets cnode types to unformed, and free_slot to 0
*/
for (i = 0; i < LCD_NUM_CAPS; i++)
list_add(&cspace->free_list, &cspace->cnodes[i].free_list);
memset(cspace, 0, sizeof(*cspace));
/*
* Initialize lock
*/
mutex_init(&cspace->lock);
return cspace;
/*
* Done
*/
*cspace_ptr = cspace;
return 0;
}
int lcd_cap_insert(struct cspace *cspace, cptr_t cptr, void *object,
enum lcd_cap_type type)
{
struct cnode *cnode;
cnode = lcd_cnode_lookup(cspace, cap);
if(cnode == 0) {
printk(KERN_ERR "Failed to create capability\n");
return -ENOMEM;
};
cnode->type = type;
cnode->object = object;
lcd_cnode_release(cnode);
return 0;
struct cnode *cnode = NULL;
int ret;
/*
* Lookup cnode
*/
ret = lcd_lock_cspace(cspace);
if (!ret) {
cnode = __lcd_cnode_lookup(cspace, cptr);
lcd_unlock_cspace(cspace);
} else {
return ret;
}
/*
* Set vals
*/
if (cnode && cnode->type == LCD_CAP_TYPE_UNFORMED) {
cnode->object = object;
cnode->type = type;
return 0;
} else {
return -EINVAL;
}
}
struct sync_ipc * lcd_cap_make_sync_endpoint(struct cspace *cspace,
struct cap_cache *cache, capability_t *cap) {
struct sync_ipc *rvp;
rvp = alloc_sync_ipc();
if(!rvp) {
printk(KERN_ERR "Failed to allocate memory\n");
return NULL;
};
ret = lcd_alloc_cap(cache, cap);
if(ret) {
printk(KERN_ERR "Failed to allocate free capability\n");
kfree(rvp);
return NULL;
};
ret = lcd_cap_insert_object(cspace, *cap, rvp, LCD_TYPE_SYNC_EP);
if(ret) {
printk(KERN_ERR "Failed to insert endpoint into the cspace:%d\n", ret);
kfree(rvp);
return NULL;
};
return rvp;
};
struct cnode *lcd_cnode_lookup(struct cspace *cspace, capability_t cap) {
unsigned long flags;
if(cap >= LCD_MAX_CAPS)
return NULL;
spin_lock_irqsave(&cspace->lock, flags);
lcd_cnode_lock(&cspace->cnode[cap]);
spin_unlock_irqrestore(&cspace->lock, flags);
return &cspace->cnode[cap];
};
EXPORT_SYMBOL(lcd_cnode_lookup);
void lcd_cap_drop(struct cspace *cspace, capability_t cap) {
struct cnode *cnode;
cnode = lcd_cnode_lookup(cspace, cap);
if(!cnode)
return;
cnode->type = LCD_TYPE_FREE;
cnode->object = NULL;
lcd_cnode_release(cnode);
return;
};
int lcd_cap_grant(struct cspace *src_cspace, struct cspace *dest_cspace,
cptr_t src_cptr, cptr_t dest_cptr)
{
struct cnode *src_cnode;
int ret;
/*
* Get source capability data
*/
ret = lcd_cnode_lookup(src_cspace, src_cptr, &src_cnode);
if (ret)
return ret;
if (!src_cnode)
return -EINVAL;
if (!__lcd_cap_can_grant(src_cnode))
return -EINVAL;
/*
* Insert into destination
*/
return lcd_cap_insert(dest_cspace, dest_cptr, src_cnode->object,
src_cnode->type);
}
void lcd_rm_cspace(struct cspace *cspace)
{
kfree(cspace);
}
......@@ -3,41 +3,37 @@
* Charles Jacobsen <charlesj@cs.utah.edu>
* Copyright: University of Utah
*
* This simple prototype uses a global lock on an lcd's cspace.
* This simple prototype uses a global lock on an lcd's cspace. No
* rights checking. The lcd need only have a valid cnode mapped by
* the cptr. Capability grants just copy cnode data from one cspace
* to another. Capabilities cannot be revoked, so if a cnode is valid,
* it can be used freely. Cnodes are allocated in a linear order, so
* no need to do fancy free lists, etc.
*/
#ifndef LCD_PROTOTYPE_API_DEFS_H
#define LCD_PROTOTYPE_API_DEFS_H
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <lcd-prototype/lcd.h>
/* CAPABILITIES -------------------------------------------------- */
enum lcd_cap_type {
LCD_CAP_TYPE_INVALID = 0,
LCD_CAP_TYPE_SYNC_EP = 1,
LCD_CAP_TYPE_UNFORMED = 0,
LCD_CAP_TYPE_SYNC_EP = 1,
};
enum lcd_cap_right {
LCD_CAP_RIGHT_READ = 0x01,
LCD_CAP_RIGHT_WRITE = 0x02,
LCD_CAP_RIGHT_GRANT = 0x04,
};
#define LCD_CAP_RIGHT_ALL = (LCD_CAP_RIGHT_READ | LCD_CAP_RIGHT_WRITE | LCD_CAP_RIGHT_GRANT)
struct cnode {
enum lcd_cap_type type;
int rights;
void *object;
struct listhead free_list;
};
#define LCD_NUM_CAPS 32
struct cspace {
struct mutex lock;
struct cnode cnodes[LCD_NUM_CAPS];
struct listhead free_list;
int free_slot;
};
/**
......@@ -47,56 +43,79 @@ static inline struct cspace * lcd_cspace(void)
{
return current->lcd->cspace;
}
/**
* Set current's cspace
*/
static inline void lcd_store_cspace(struct cspace *cspace)
{
current->lcd->cspace = cspace;
}
/**
* Allocates memory and initializes the contents of a cspace.
*/
struct cspace * lcd_mk_cspace(void);
int lcd_mk_cspace(struct cspace **cspace_ptr);
/**
* Acquires/releases global cspace lock. Must wrap calls to unsafe
* insert, lookup, etc. with lock/unlock.
* insert, lookup, etc. with lock/unlock. Lock returns zero if
* lock successfully taken (no signals).
*/
void lcd_lock_cspace(struct cspace *cspace);
void lcd_unlock_cspace(struct cspace *cspace);
static inline int lcd_lock_cspace(struct cspace *cspace)
{
return mutex_lock_interruptible(cspace->lock);
}
static inline void lcd_unlock_cspace(struct cspace *cspace)
{
mutex_unlock(cspace->lock);
}
/**
* (UNSAFE) Insert object into cspace at cptr with type and rights.
* (SAFE) Allocates an empty cnode slot, and returns a cptr to it. Returns
* non-zero if no free slots available.
*/
int __lcd_cap_insert(struct cspace *cspace, cptr_t cptr, void *object,
enum lcd_cap_type type, int rights);
static inline int lcd_cap_alloc(struct cspace *cspace, cptr_t *cptr)
{
int ret = lcd_lock_cspace(cspace);
if (!ret) {
if (cspace->free_slot < LCD_NUM_CAPS)
*cptr = ++cspace->free_slot;
else
ret = -ENOMEM;
lcd_unlock_cspace(cspace);
}
return ret;
}
/**
* (SAFE) Insert object into cspace.
*/
static inline int lcd_cap_insert(struct cspace *cspace, cptr_t cptr,
void *object, enum lcd_cap_type type,
int rights)
{
lcd_lock_cspace(cspace);
__lcd_cap_insert(cspace, cptr, object, type, rights);
lcd_unlock_cspace(cspace);
}
void *object, enum lcd_cap_type type);
/**
* (UNSAFE) Look up cnode in cspace at cptr.
*/
struct cnode *__lcd_cnode_lookup(struct cspace *cspace, cptr_t cptr);
/**
* (UNSAFE) Free cnode at cptr in cspace.
*/
void __lcd_cap_drop(struct cspace *cspace, cptr_t cptr);
static inline struct cnode *__lcd_cnode_lookup(struct cspace *cspace,
cptr_t cptr)
{
BUG_ON(cspace->free_slot > LCD_NUM_CAPS);
if (cptr < cspace->free_slot)
return cspace->cnodes[cptr];
else
return NULL;
}
/**
* (SAFE) Free cnode at cptr in cspace.
* (SAFE) Look up cnode in cspace at cptr. Returns non-zero if lock
* failed. out set to null if cnode is marked as unformed.
*/
static inline void lcd_cap_drop(struct cspace *cspace, cptr_t cptr)
static inline int lcd_cnode_lookup(struct cspace *cspace, cptr_t cptr,
struct cnode **out)
{
lcd_lock_cspace(cspace);
__lcd_cap_drop(cspace, cptr);
lcd_unlock_cspace(cspace);
struct cnode *c = NULL;
int ret = lcd_lock_cspace(cspace);
if (!ret) {
c = __lcd_cnode_lookup(cspace, cptr);
if (c && c->type == LCD_CAP_TYPE_UNFORMED)
c = NULL;
lcd_unlock_cspace(cspace);
}
*out = c;
return ret;
}
/**
* (SAFE) Transfer capability from one cspace to another.
*/
int lcd_cap_grant(struct cspace *src_cspace, struct cspace *dest_cspace,
cptr_t src_cptr, cptr_t dest_cptr);
/**
* (SAFE) Get capability type.
*/
......@@ -104,36 +123,34 @@ static inline enum lcd_cap_type lcd_cap_type(struct cspace *cspace, cptr_t cptr)
{
struct cnode *cnode;
enum lcd_cap_type type;
lcd_lock_cspace(cspace);
cnode = __lcd_lookup_cnode(cspace, cptr);
type = cnode->type;
lcd_unlock_cspace(cspace);
return type;
if (lcd_cnode_lookup(cspace, cptr, &cnode) || !cnode)
return LCD_CAP_TYPE_INVALID;
else
return cnode->type;
}
/**
* (SAFE) Get capability rights.
*/
static inline int lcd_cap_rights(struct cspace *cspace, cptr_t cptr)
static inline int __lcd_cap_can_read(struct cnode *cnode)
{
struct cnode *cnode;
int rights;
lcd_lock_cspace(cspace); <