Commit 25949c4a authored by Charlie Jacobsen's avatar Charlie Jacobsen Committed by Vikram Narayanan

Starting api code.

parent 963eb782
/*
* 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;
for (i = 0; i < LCD_MAX_CAP_REGS; i++) {
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++) {
ret = lcd_free_cap(&current->cap_cache, msg->cap_regs[i]);
};
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;
}
int lcd_api_exit(struct lcd_api *api) {
api->exit_flag = 1;
};
/*
* 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;
}
/*
* Author: Anton Burtsev <aburtsev@flux.utah.edu>
* Copyright: University of Utah
*/
#include <linux/slab.h>
#include "defs.h"
#include "../include/common.h"
struct cspace * lcd_mk_cspace(void)
{
struct cspace *cspace;
int i;
/*
* Allocate cspace
*/
cspace = kmalloc(sizeof(*cspace), GFP_KERNEL);
if (!cspace)
return NULL;
memset(cspace, 0, sizeof(*cspace)); /* sets cnode types to invalid */
/*
* Initialize free list
*/
for (i = 0; i < LCD_NUM_CAPS; i++)
list_add(&cspace->free_list, &cspace->cnodes[i].free_list);
/*
* Initialize lock
*/
mutex_init(&cspace->lock);
return cspace;
}
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 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;
};
/*
* Authors: Anton Burtsev <aburtsev@flux.utah.edu>
* Charles Jacobsen <charlesj@cs.utah.edu>
* Copyright: University of Utah
*
* This simple prototype uses a global lock on an lcd's cspace.
*/
#ifndef LCD_PROTOTYPE_API_DEFS_H
#define LCD_PROTOTYPE_API_DEFS_H
#include <linux/spinlock.h>
#include <lcd-prototype/lcd.h>
/* CAPABILITIES -------------------------------------------------- */
enum lcd_cap_type {
LCD_CAP_TYPE_INVALID = 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;
};
/**
* Return current's cspace
*/
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);
/**
* Acquires/releases global cspace lock. Must wrap calls to unsafe
* insert, lookup, etc. with lock/unlock.
*/
void lcd_lock_cspace(struct cspace *cspace);
void lcd_unlock_cspace(struct cspace *cspace);
/**
* (UNSAFE) Insert object into cspace at cptr with type and rights.
*/
int __lcd_cap_insert(struct cspace *cspace, cptr_t cptr, void *object,
enum lcd_cap_type type, int rights);
/**
* (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);
}
/**
* (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);
/**
* (SAFE) Free cnode at cptr in cspace.
*/
static inline void lcd_cap_drop(struct cspace *cspace, cptr_t cptr)
{
lcd_lock_cspace(cspace);
__lcd_cap_drop(cspace, cptr);
lcd_unlock_cspace(cspace);
}
/**
* (SAFE) Get capability type.
*/
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;
}
/**
* (SAFE) Get capability rights.
*/
static inline int lcd_cap_rights(struct cspace *cspace, cptr_t cptr)
{
struct cnode *cnode;
int rights;
lcd_lock_cspace(cspace);
cnode = __lcd_lookup_cnode(cspace, cptr);
rights = cnode->rights;
lcd_unlock_cspace(cspace);
return rights;
}
static inline int lcd_cap_can_read()
{
return rights & LCD_CAP_RIGHT_READ;
}
static inline int lcd_cap_can_write(int rights)
{
return rights & LCD_CAP_RIGHT_WRITE;
}
static inline int lcd_cap_can_grant(int rights)
{
return rights & LCD_CAP_RIGHT_GRANT;
}
/**
* Deallocates cspace. Caller should ensure no one is trying to
* use the cspace (e.g., is waiting on the lock).
*/
void lcd_rm_cspace(struct cspace *cspace);
#endif /* LCD_PROTOTYPE_API_DEFS_H */
/*
* api-internal.h - direct access to hypervisor routines
*
* Author: Charles Jacobsen <charlesj@cs.utah.edu>
* Copyright: University of Utah
*
* Use the higher-level calls in ipc.h. In the future,
* these won't be directly callable.
*/
#ifndef LCD_PROTOTYPE_API_INTERNAL_H
#define LCD_PROTOTYPE_API_INTERNAL_H
#include <lcd-prototype/lcd.h>
struct lcd_handler {
cptr_t c;
int (*handler)(void);
};
int __lcd_send(cptr_t c);
int __lcd_call(cptr_t c);
int __lcd_select(struct lcd_handlers *hs, int hs_count);
#endif /* LCD_PROTOTYPE_API_INTERNAL_H */
/*
* api.h - wrappers for calls into api code, via ipc
*
* Author: Charles Jacobsen <charlesj@cs.utah.edu>
* Copyright: University of Utah
*
* Implemented by liblcd. Sets up and performs calls
* into api code, via ipc. See api code for more info.
*/
#ifndef LCD_PROTOTYPE_API_H
#define LCD_PROTOTYPE_API_H
#include <lcd-prototype/lcd.h>
int lcd_mk_sync_endpoint(cptr_t c);
int lcd_rm_sync_endpoint(cptr_t c);
#endif /* LCD_PROTOTYPE_API_H */
/*
* Author: Charles Jacobsen <charlesj@cs.utah.edu>
* Copyright: University of Utah
*
*/
#ifndef LCD_PROTOTYPE_COMMON_H
#define LCD_PROTOTYPE_COMMON_H
#define LCD_ERR(msg...) __lcd_err(__FILE__, __LINE__, msg)
static inline void __lcd_err(char *file, int lineno, char *fmt, ...)
{
va_list args;
pr_err("lcd-proto: %s:%d: error: ", file, lineno);
va_start(args, fmt);
vprintk(fmt, args);
va_end(args);
}
#define LCD_MSG(msg...) __lcd_msg(__FILE__, __LINE__, msg)
static inline void __lcd_msg(char *file, int lineno, char *fmt, ...)
{
va_list args;
pr_info("lcd-proto: %s:%d: note: ", file, lineno);
va_start(args, fmt);
vprintk(fmt, args);
va_end(args);
}
#define LCD_WARN(msg...) __lcd_warn(__FILE__, __LINE__, msg)
static inline void __lcd_warn(char *file, int lineno, char *fmt, ...)
{
va_list args;
pr_warn("lcd-proto: %s:%d: warning: ", file, lineno);
va_start(args, fmt);
vprintk(fmt, args);
va_end(args);
}
#endif /* LCD_PROTOTYPE_COMMON_H */
/*
* dstore.h - routines for creating and manipulating a data store
*
* Author: Charles Jacobsen <charlesj@cs.utah.edu>
* Copyright: University of Utah
*
* Implemented by liblcd.
*/
#ifndef LCD_PROTOTYPE_DSTORE_H
#define LCD_PROTOTYPE_DSTORE_H
#include <lcd-prototype/lcd.h>
typedef u64 dsptr_t;
enum dstore_rights {
DSTORE_READ_RIGHTS = 0x01,