All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

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.
*/