Commit a5d6ea85 authored by root's avatar root Committed by Vikram Narayanan

Working lookup, insert, and delete

parent 8753687b
......@@ -204,4 +204,6 @@ source "drivers/fpga/Kconfig"
source "drivers/lcd-prototype/Kconfig"
source "drivers/lcd-cspace/Kconfig"
endmenu
......@@ -40,6 +40,7 @@ obj-$(CONFIG_VIRTIO) += virtio/
obj-$(CONFIG_XEN) += xen/
obj-$(CONFIG_LCD_PROTOTYPE) += lcd-prototype/
obj-$(CONFIG_LCD_CSPACE) += lcd-cspace/
# regulators early, since some subsystems rely on them to initialize
obj-$(CONFIG_REGULATOR) += regulator/
......
#
# LCD cspace
#
config LCD_CSPACE
bool "LCD CSPACE"
default y
---help---
LCD Cspace implementation
obj-$(CONFIG_LCD_CSPACE) += lcd-cspace.o
lcd-cspace-y := test.o main.o cap.o cap-cache.o
#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)
{
printk(KERN_ERR "lcd_cap Failed to allocate memory for capabilities");
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;
spin_lock_init(&list_cache->lock);
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;
};
EXPORT_SYMBOL(lcd_alloc_cap);
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;
}
EXPORT_SYMBOL(lcd_free_cap);
/*
* Author: Anton Burtsev <aburtsev@flux.utah.edu>
* Copyright: University of Utah
*/
#include <linux/slab.h>
#include <linux/delay.h>
#include <lcd/cap.h>
int lcd_init_cspace(struct cspace *cspace) {
int i = 0;
spin_lock_init(&cspace->lock);
lcd_init_list_cache(&(cspace->cap_cache), LCD_MAX_CAPS);
if (!cspace->cap_cache.cap) {
printk(KERN_ERR "lcd_cap Failed to allocate cap_cache\n");
return -ENOMEM;
}
cspace->cnode_table_cache = KMEM_CACHE(cnode_table, 0);
if(!cspace->cnode_table_cache){
printk(KERN_ERR "lcd_cap Failed to allocate cnode_table slab\n");
return -ENOMEM;
};
cspace->cdt_root_cache = KMEM_CACHE(cdt_root_node, 0);
if(!cspace->cdt_root_cache){
printk(KERN_ERR "lcd_cap Failed to allocate cdt_root slab\n");
return -ENOMEM;
};
cspace->cnode_table = kmem_cache_alloc(cspace->cnode_table_cache, 0);
for (i = 0; i < MAX_SLOTS_PER_TABLE; i++)
{
cspace->cnode_table->cnode[i].type = LCD_CAP_TYPE_FREE;
cspace->cnode_table->table_level = 0;
}
cspace->state = ALLOCATION_VALID;
return 0;
};
EXPORT_SYMBOL(lcd_init_cspace);
// expects the cspace to be locked by the caller.
struct cnode *lcd_cnode_lookup(struct cspace *cspace, capability_t cap, bool alloc) {
bool more_levels;
capability_t levelId;
struct cnode *cnode;
struct cnode_table *table, *newtable;
int i = 0;
if(cap >= LCD_MAX_CAPS)
return NULL;
// spin_lock_irqsave(&cspace->lock, flags);
table = cspace->cnode_table;
do {
more_levels = _get_level_bits(table->table_level, cap, &levelId);
if (more_levels) {
capability_t index = levelId + MAX_CAP_SLOTS;
if (table->cnode[index].type != LCD_CAP_TYPE_CNODE) {
if (alloc) {
table->cnode[index].type = LCD_CAP_TYPE_CNODE;
newtable = kmem_cache_alloc(cspace->cnode_table_cache, 0);
table->cnode[index].object = (void*)newtable;
newtable->table_level = table->table_level + 1;
printk(KERN_ERR "lcd_cap Created a new table with level: %u", newtable->table_level);
for (i = 0; i < MAX_SLOTS_PER_TABLE; i++)
{
newtable->cnode[i].type = LCD_CAP_TYPE_FREE;
}
table->cnode[index].cspace = cspace;
table = newtable;
} else {
cnode = NULL;
break;
}
} else {
table = (struct cnode_table *)table->cnode[index].object;
}
} else {
if ((alloc && table->cnode[levelId].type == LCD_CAP_TYPE_FREE) ||
(!alloc && table->cnode[levelId].type != LCD_CAP_TYPE_FREE)) {
printk(KERN_ERR "lcd_cap Lookup got a cnode");
cnode = &(table->cnode[levelId]);
} else {
printk(KERN_ERR "lcd_cap Lookup failed to get a cnode");
cnode = NULL;
break;
}
}
} while (more_levels == true);
// lcd_cnode_lock(&cspace->cnode[cap]);
//spin_unlock_irqrestore(&cspace->lock, flags);
return cnode;
};
EXPORT_SYMBOL(lcd_cnode_lookup);
int lcd_cap_insert(struct cspace *cspace, capability_t cap,
void *object, enum lcd_cap_type type)
{
unsigned long flags, flags_cnode_lock;
struct cnode *cnode;
spin_lock_irqsave(&cspace->lock, flags);
if (cspace->state != ALLOCATION_VALID)
{
spin_unlock_irqrestore(&cspace->lock, flags);
return -EIDRM;
}
cnode = lcd_cnode_lookup(cspace, cap, true);
if(cnode == NULL) {
spin_unlock_irqrestore(&cspace->lock, flags);
printk(KERN_ERR "Failed to create capability\n");
return -ENOMEM;
};
cnode->object = object;
spin_lock_init(&cnode->lock);
spin_lock_irqsave(&cnode->lock, flags_cnode_lock);
spin_unlock_irqrestore(&cspace->lock, flags);
cnode->cspace = cspace;
cnode->parent = NULL;
cnode->next = NULL;
cnode->prev = NULL;
cnode->child = NULL;
cnode->type = type;
cnode->cdt_root = kmem_cache_alloc(cspace->cdt_root_cache, 0);
spin_lock_init(&(cnode->cdt_root->lock));
cnode->cdt_root->cnode = cnode;
cnode->cdt_root->node_count = 1;
cnode->cdt_root->state = ALLOCATION_VALID;
//lcd_cnode_release(cnode);
spin_unlock_irqrestore(&cnode->lock, flags_cnode_lock);
return 0;
}
EXPORT_SYMBOL(lcd_cap_insert);
void lcd_cap_delete(struct cspace *cspace, capability_t cap) {
struct cnode *cnode;
unsigned long flags, flags_cnode_lock;
bool done = false;
do {
spin_lock_irqsave(&cspace->lock, flags);
if (cspace->state != ALLOCATION_VALID) {
spin_unlock_irqrestore(&cspace->lock, flags);
return;
}
cnode = lcd_cnode_lookup(cspace, cap, false);
if(cnode == NULL)
{
spin_unlock_irqrestore(&cspace->lock, flags);
return;
}
spin_lock_irqsave(&cnode->lock, flags_cnode_lock);
spin_unlock_irqrestore(&cspace->lock, flags);
if (cnode->type == LCD_CAP_TYPE_FREE) {
spin_unlock_irqrestore(&cnode->lock, flags_cnode_lock);
return;
}
if (spin_trylock(&cnode->cdt_root->lock)) {
_lcd_delete_node(cspace, cnode);
if (cnode->cdt_root) {
spin_unlock(&cnode->cdt_root->lock);
cnode->cdt_root = NULL;
}
lcd_free_cap(&(cspace->cap_cache), cap);
done = true;
}
spin_unlock_irqrestore(&cnode->lock, flags_cnode_lock);
if (!done) {
// someone is using CDT root
// wait for him to finish
msleep(5);
}
} while (!done);
};
EXPORT_SYMBOL(lcd_cap_delete);
int lcd_cnode_insert(struct cspace *cspace, capability_t cap, struct cnode *cnode) {
/* XXX: not clear */
return 0;
};
static inline void lcd_cnode_lock(struct cnode *cnode) {
/* XXX: not clear what to do yet */
return;
};
void lcd_cnode_release(struct cnode *cnode) {
/* XXX: not clear what to do yet */
return;
};
EXPORT_SYMBOL(lcd_cnode_release);
//////////////////////////////////////////////////////////////////
// Helper functions
//////////////////////////////////////////////////////////////////
bool _get_level_bits(int table_level, capability_t cap, capability_t *levelId)
{
bool more_levels;
// Get rid of capability identifer bits
capability_t c = ((uint64_t)cap >> CAP_IDENTIFIER_BITS) >> (table_level * TABLE_IDENTIFIER_BITS);
printk(KERN_ERR "lcd_cap cap: %llu", (uint64_t)cap);
printk(KERN_ERR "lcd_cap c = : %llu", (uint64_t)c);
if (c)
{
int level_mask = (MAX_TABLE_ID_SLOTS - 1);
*levelId = c & level_mask;
more_levels = true;
}
else
{
capability_t mask = MAX_CAP_SLOTS - 1;
*levelId = cap & mask;
more_levels = false;
}
return more_levels;
}
// assumes cnode and cdt root is locked (in that order)
void _lcd_delete_node (struct cspace *cspace, struct cnode *cnode){
cnode->object = NULL;
cnode->type = LCD_CAP_TYPE_FREE;
cnode->cdt_root->node_count--;
if (cnode->cdt_root->node_count > 0) {
// get cnode out of CDT
if (cnode->child) {
struct cnode *childnode = cnode->child;
cnode->child = NULL;
childnode->parent = cnode->parent;
if (cnode->parent) {
if (cnode->parent->child == cnode) {
cnode->parent->child = childnode;
}
}
childnode->prev = cnode->prev;
if (cnode->prev) {
cnode->prev->next = childnode;
}
while (childnode->next) {
childnode = childnode->next;
childnode->parent = cnode->parent;
}
cnode->parent = NULL;
childnode->next = cnode->next;
if (cnode->next) {
cnode->next->prev = childnode;
}
cnode->next = NULL;
cnode->prev = NULL;
} else {
if (cnode->parent) {
if (cnode->parent->child == cnode) {
cnode->parent->child = cnode->next;
}
}
if (cnode->prev) {
cnode->prev->next = cnode->next;
}
if (cnode->next) {
cnode->next->prev = cnode->prev;
}
cnode->parent = NULL;
cnode->prev = NULL;
cnode->next = NULL;
}
} else {
// this was the last node
spin_unlock(&cnode->cdt_root->lock);
kmem_cache_free(cspace->cdt_root_cache, cnode->cdt_root);
cnode->cdt_root = NULL;
}
}
\ No newline at end of file
/*
* main.c
*
* Authors: Anton Burtsev <aburtsev@flux.utah.edu>
* Muktesh Khole <muktesh.khole@utah.edu>
* Copyright: University of Utah
*/
#include <linux/init.h>
#include <linux/module.h>
#include "test.h"
int __init api_init(void)
{
bool res = true;
printk(KERN_ERR "lcd cspace entering module");
res = test_insert();
if (res == false) {
printk(KERN_ERR "lcd_cap_insert failed");
} else {
printk(KERN_ERR "lcd_cap_insert succeeded");
test_delete();
}
return 0;
}
void __exit api_exit(void)
{
printk(KERN_ERR "lcd cspace exiting module");
return;
}
module_init(api_init);
module_exit(api_exit);
#include "test.h"
int test_cap_count = 0;
struct cspace test_cspace;
int test_max_cap = 4 * MAX_CAP_SLOTS;
capability_t arr[4 * MAX_CAP_SLOTS] = {0};
bool test_insert(void) {
capability_t cap;
int i = 0;
int res = 0;
lcd_init_cspace(&test_cspace);
for (; i < test_max_cap; i++) {
if (lcd_alloc_cap(&(test_cspace.cap_cache), &cap) == 0) {
printk(KERN_ERR "lcd_cap_test got capability %llu", cap);
arr[test_cap_count++] = cap;
res = lcd_cap_insert(&test_cspace, cap, &test_max_cap, LCD_CAP_TYPE_SYNC_EP);
if (res != 0) {
break;
}
}
}
return (res==0);
}
void test_delete(void) {
int i = 0;
for (; i < test_cap_count; i++) {
lcd_cap_delete(&test_cspace, arr[i]);
}
test_cap_count = 0;
}
\ No newline at end of file
#include <lcd/cap.h>
extern int lcd_init_cspace(struct cspace *cspace);
extern int lcd_cap_insert(struct cspace *cspace, capability_t cap,
void *object, enum lcd_cap_type type);
extern void lcd_cap_delete(struct cspace *cspace, capability_t cap);
bool test_insert(void);
void test_delete(void);
\ No newline at end of file
......@@ -6,8 +6,8 @@
#ifndef _LCD_CAP_CACHE_H_
#define _LCD_CAP_CACHE_H_
#include <lcd/cap.h>
#include <linux/spinlock.h>
#include <uapi/linux/lcd-cap.h>
struct cap_cache {
uint32_t *cap;
......@@ -20,5 +20,4 @@ void lcd_free_list_cache(struct cap_cache *list_cache);
int lcd_alloc_cap(struct cap_cache *cap_cache, capability_t *free_cap);
void lcd_free_cap(struct cap_cache *cap_cache, capability_t free_cap);
#endif
......@@ -6,42 +6,79 @@
#include <linux/types.h>
#include <linux/spinlock.h>
#include "cap-cache.h"
#include <uapi/linux/lcd-cap.h>
#define LCD_MAX_CAPS 32
#define CAP_IDENTIFIER_BITS 2
#define TABLE_IDENTIFIER_BITS 1
// should always be 2^CAP_IDENTIFIER_BITS
#define MAX_CAP_SLOTS 4
// should always be 2^TABLE_IDENTIFIER_BITS
#define MAX_TABLE_ID_SLOTS 2
// should always be 2^CAP_IDENTIFIER_BITS + 2^TABLE_IDENTIFIER_BITS
#define MAX_SLOTS_PER_TABLE 6
struct cnode;
struct cspace;
enum lcd_cap_type
{
LCD_TYPE_INVALID,
LCD_TYPE_FREE,
LCD_TYPE_SYNC_EP,
LCD_CAP_TYPE_INVALID,
LCD_CAP_TYPE_FREE,
LCD_CAP_TYPE_SYNC_EP,
LCD_CAP_TYPE_CNODE
};
enum allocation_state {
ALLOCATION_INVALID,
ALLOCATION_VALID,
ALLOCATION_MARKED_FOR_DELETE,
ALLOCATION_REMOVED
};
struct cdt_root_node {
spinlock_t lock;
struct cnode *cnode;
unsigned long node_count;
enum allocation_state state;
};
struct cnode {
enum lcd_cap_type type;
void *object;
spinlock_t lock;
struct cdt_root_node *cdt_root;
struct cnode *parent, *child, *prev, *next;
struct cspace *cspace;
};
struct cnode_table {
struct cnode cnode[MAX_SLOTS_PER_TABLE];
uint8_t table_Id;
uint8_t table_level;
};
struct cspace {
spinlock_t lock;
struct cnode *cnode;
enum allocation_state state;
struct cnode_table *cnode_table;
struct kmem_cache *cdt_root_cache;
struct kmem_cache *cnode_table_cache;
struct cap_cache cap_cache;
};
int lcd_cap_init(void);
int lcd_cap_exit(void);
int lcd_cap_insert_object(struct cspace *cspace, capability_t cap,
void *object, enum ... type);
bool _get_level_bits(int table_level, capability_t cap, capability_t *levelId);
void _lcd_delete_node (struct cspace *cspace, struct cnode *cnode);
struct sync_ipc *lcd_cap_make_sync_endpoint(struct cspace *cspace,
struct cap_cache *cache, capability_t *cap);
void lcd_cnode_release(struct cnode *cnode);
int lcd_init_cspace(struct cspace *cspace);
int lcd_cnode_insert(struct cspace *cspace, capability_t cap, struct cnode *cnode);
struct cnode *lcd_cnode_lookup(struct cspace *cspace, capability_t cap);
void lcd_cap_drop(struct cspace *cspace, capability_t cap);
#define LCD_MAX_CAPS 32
int lcd_cap_init_cspace(struct cspace *cspace);
struct cnode *lcd_cnode_lookup(struct cspace *cspace, capability_t cap, bool alloc);
int lcd_cap_insert(struct cspace *cspace, capability_t cap,
void *object, enum lcd_cap_type type);
void lcd_cap_delete(struct cspace *cspace, capability_t cap);
//int lcd_cap_grant(struct cspace *cspacesrc, capability_t capsrc, struct cspace *cspacedst, capability_t capdst);
#endif
/*
* Author: Charles Jacobsen <charlesj@cs.utah.edu>
* Copyright: University of Utah
*/
#ifndef LCD_LCD_H
#define LCD_LCD_H
#define LCD_NUM_REGS 8
#define LCD_NUM_OUT_CAP_REGS 8
#define LCD_NUM_IN_CAP_REGS LCD_NUM_OUT_CAP_REGS
#define LCD_NUM_BOOT_CPTRS 8
struct cspace;
typedef u64 cptr_t;
struct lcd {
/*
* Not accessible in lcd
*/
struct task_struct *parent;
u64 badge;
struct cspace *cspace;
struct list_head senders;
struct list_head receivers;
int making_call;
/*
* Accessible in lcd
*/
struct {
cptr_t boot_cptrs[LCD_NUM_BOOT_CPTRS];
u64 regs[LCD_NUM_REGS];
cptr_t out_cap_regs[LCD_NUM_OUT_CAP_REGS];
cptr_t in_cap_regs[LCD_NUM_IN_CAP_REGS];
u8 max_valid_reg_idx;
u8 max_valid_out_cap_reg_idx;
u8 max_valid_in_cap_reg_idx;
cptr_t call_endpoint_cap;
cptr_t reply_endpoint_cap;
} utcb;
};
#endif /* LCD_LCD_H */
......@@ -1467,7 +1467,7 @@ struct task_struct {
atomic_t usage;
unsigned int flags; /* per process flags, defined below */
unsigned int ptrace;
#ifdef CONFIG_LCD_PROTOTYPE
#ifdef CONFIG_LCD_CSPACE
struct lcd *lcd;
#endif
#ifdef CONFIG_SMP
......
......@@ -72,13 +72,22 @@ struct sync_ipc * lcd_cap_make_sync_endpoint(struct cspace *cspace,
int lcd_init_cspace(struct cspace *cspace) {
cspace->cnode = kmalloc(sizeof(struct cnode) * LCD_MAX_CAPS, GFP_KERNEL);
if(!cspace->cnode){
printk(KERN_ERR "Failed to allocate memory for cnodes\n");
spin_lock_init(&cspace->lock);
cnode_table_cache = KMEM_CACHE(cnode_table, 0);
if(!cnode_table_cache){
printk(KERN_ERR "Failed to allocate cnode_table slab\n");
return -ENOMEM;
};
spin_lock_init(&cspace->lock);
cdt_root_cache = KMEM_CACHE(cdt_root_node, 0);
if(!cdt_root_cache){
printk(KERN_ERR "Failed to allocate cdt_root slab\n");
return -ENOMEM;
};
cspace->cnode_table = kmem_cache_alloc(cnode_table_cache, 0);
cspace->state = ALLOCATION_VALID;
return 0;
};
EXPORT_SYMBOL(lcd_init_cspace);
......
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