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> * Authors: Anton Burtsev <aburtsev@flux.utah.edu>
* Charles Jacobsen <charlesj@cs.utah.edu> * Charles Jacobsen <charlesj@cs.utah.edu>
* Copyright: University of Utah * Copyright: University of Utah
*/ */
int lcd_mk_sync_endpoint(cptr_t dest) #include <linux/kernel.h>
{ #include <linux/module.h>
int ret; #include "../include/common.h"
struct sync_ipc *rvp; #include "defs.h"
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;
for (i = 0; i < LCD_MAX_CAP_REGS; i++) { static int api_tests(void);
ret = lcd_alloc_cap(&current->cap_cache, static int __init api_init(void)
&msg->cap_regs[i]); {
if(ret) { LCD_MSG("api starting");
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++) {
ret = lcd_free_cap(&current->cap_cache, msg->cap_regs[i]); /*
}; * Run regression tests
*/
if (api_tests()) {
return -1;
}
return 0; 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); static void __exit api_exit(void)
return 0; {
return;
} }
int lcd_api_exit(struct lcd_api *api) { module_init(api_init);
api->exit_flag = 1; 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 @@ ...@@ -6,7 +6,7 @@
#include "defs.h" #include "defs.h"
#include "../include/common.h" #include "../include/common.h"
struct cspace * lcd_mk_cspace(void) int lcd_mk_cspace(struct cspace **cspace_ptr)
{ {
struct cspace *cspace; struct cspace *cspace;
int i; int i;
...@@ -15,90 +15,72 @@ struct cspace * lcd_mk_cspace(void) ...@@ -15,90 +15,72 @@ struct cspace * lcd_mk_cspace(void)
*/ */
cspace = kmalloc(sizeof(*cspace), GFP_KERNEL); cspace = kmalloc(sizeof(*cspace), GFP_KERNEL);
if (!cspace) if (!cspace)
return NULL; return -ENOMEM;
memset(cspace, 0, sizeof(*cspace)); /* sets cnode types to invalid */ /*
/* * Sets cnode types to unformed, and free_slot to 0
* Initialize free list
*/ */
for (i = 0; i < LCD_NUM_CAPS; i++) memset(cspace, 0, sizeof(*cspace));
list_add(&cspace->free_list, &cspace->cnodes[i].free_list);
/* /*
* Initialize lock * Initialize lock
*/ */
mutex_init(&cspace->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, int lcd_cap_insert(struct cspace *cspace, cptr_t cptr, void *object,
enum lcd_cap_type type) enum lcd_cap_type type)
{ {
struct cnode *cnode; struct cnode *cnode = NULL;
int ret;
cnode = lcd_cnode_lookup(cspace, cap); /*
if(cnode == 0) { * Lookup cnode
printk(KERN_ERR "Failed to create capability\n"); */
return -ENOMEM; ret = lcd_lock_cspace(cspace);
}; if (!ret) {
cnode = __lcd_cnode_lookup(cspace, cptr);
cnode->type = type; lcd_unlock_cspace(cspace);
cnode->object = object; } else {
return ret;
lcd_cnode_release(cnode); }
return 0; /*
* 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, int lcd_cap_grant(struct cspace *src_cspace, struct cspace *dest_cspace,
struct cap_cache *cache, capability_t *cap) { cptr_t src_cptr, cptr_t dest_cptr)
struct sync_ipc *rvp; {
struct cnode *src_cnode;
rvp = alloc_sync_ipc(); int ret;
if(!rvp) { /*
printk(KERN_ERR "Failed to allocate memory\n"); * Get source capability data
return NULL; */
}; ret = lcd_cnode_lookup(src_cspace, src_cptr, &src_cnode);
if (ret)
ret = lcd_alloc_cap(cache, cap); return ret;
if(ret) { if (!src_cnode)
printk(KERN_ERR "Failed to allocate free capability\n"); return -EINVAL;
kfree(rvp); if (!__lcd_cap_can_grant(src_cnode))
return NULL; return -EINVAL;
}; /*
* Insert into destination
ret = lcd_cap_insert_object(cspace, *cap, rvp, LCD_TYPE_SYNC_EP); */
if(ret) { return lcd_cap_insert(dest_cspace, dest_cptr, src_cnode->object,
printk(KERN_ERR "Failed to insert endpoint into the cspace:%d\n", ret); src_cnode->type);
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;
};
void lcd_rm_cspace(struct cspace *cspace)
{
kfree(cspace);
}
...@@ -3,41 +3,37 @@ ...@@ -3,41 +3,37 @@
* Charles Jacobsen <charlesj@cs.utah.edu> * Charles Jacobsen <charlesj@cs.utah.edu>
* Copyright: University of Utah * 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 #ifndef LCD_PROTOTYPE_API_DEFS_H
#define LCD_PROTOTYPE_API_DEFS_H #define LCD_PROTOTYPE_API_DEFS_H
#include <linux/spinlock.h> #include <linux/mutex.h>
#include <lcd-prototype/lcd.h> #include <lcd-prototype/lcd.h>
/* CAPABILITIES -------------------------------------------------- */ /* CAPABILITIES -------------------------------------------------- */
enum lcd_cap_type { enum lcd_cap_type {
LCD_CAP_TYPE_INVALID = 0, LCD_CAP_TYPE_UNFORMED = 0,
LCD_CAP_TYPE_SYNC_EP = 1, 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 { struct cnode {
enum lcd_cap_type type; enum lcd_cap_type type;
int rights;
void *object; void *object;
struct listhead free_list;
}; };
#define LCD_NUM_CAPS 32 #define LCD_NUM_CAPS 32
struct cspace { struct cspace {
struct mutex lock; struct mutex lock;
struct cnode cnodes[LCD_NUM_CAPS]; struct cnode cnodes[LCD_NUM_CAPS];
struct listhead free_list; int free_slot;
}; };
/** /**
...@@ -47,56 +43,79 @@ static inline struct cspace * lcd_cspace(void) ...@@ -47,56 +43,79 @@ static inline struct cspace * lcd_cspace(void)
{ {
return current->lcd->cspace; 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. * 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 * 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); static inline int lcd_lock_cspace(struct cspace *cspace)
void lcd_unlock_cspace(struct cspace *cspace); {
return mutex_lock_interruptible(cspace->lock);