diff --git a/drivers/lcd-prototype/api/Makefile b/drivers/lcd-prototype/api/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e9b24de9254aa6cdaf8d8b20b1758ad38129567d --- /dev/null +++ b/drivers/lcd-prototype/api/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_LCD_PROTOTYPE_API) += api.o cap.o + + diff --git a/drivers/lcd-prototype/api/api-tests.c b/drivers/lcd-prototype/api/api-tests.c new file mode 100644 index 0000000000000000000000000000000000000000..7ef7118fb0cfe4735defe010cac3f24c8353d3eb --- /dev/null +++ b/drivers/lcd-prototype/api/api-tests.c @@ -0,0 +1,19 @@ +/* + * api-tests.c + * + * Authors: Anton Burtsev + * Charles Jacobsen + * 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!"); +} diff --git a/drivers/lcd-prototype/api/api.c b/drivers/lcd-prototype/api/api.c index caf9efed6d506973c46c6dc666061e06d75ef2e3..4464a36b16177df3da7045ace207b26c8ee3dd21 100644 --- a/drivers/lcd-prototype/api/api.c +++ b/drivers/lcd-prototype/api/api.c @@ -1,232 +1,40 @@ /* + * api.c + * * Authors: Anton Burtsev * Charles Jacobsen * 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 = ¤t->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(¤t->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(¤t->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(¤t->cspace, rvp_cap); - - lcd_free_cap(¤t->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(¤t->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(¤t->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, ¤t->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(¤t->cspace, msg->cap_regs[i]); - - }; - - msg->cap_regs[0] = lcd_cap; - msg->valid_cap_regs = 1; - ipc_reply(reply_cap, msg); - - lcd_cap_drop(¤t->cspace, lcd_cap); - - lcd_free_cap(¤t->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 = ¤t->utcb->msg_info; - capability_t reply_cap; - enum lcd_api_calls call; - int ret; - int i; +#include +#include +#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(¤t->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(¤t->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(¤t->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(¤t->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(¤t->cspace, ¤t->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" diff --git a/drivers/lcd-prototype/api/cap-cache.c b/drivers/lcd-prototype/api/cap-cache.c deleted file mode 100644 index 6141bd16e8058d0e6d0de0d7eeca34aeb65c11b2..0000000000000000000000000000000000000000 --- a/drivers/lcd-prototype/api/cap-cache.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Authors: Anton Burtsev - * Charles Jacobsen - * Copyright: University of Utah - */ -#include -#include -#include - -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; -} - diff --git a/drivers/lcd-prototype/api/cap.c b/drivers/lcd-prototype/api/cap.c index 7eec390dd60c6b00de522fe058216ff886026f17..ff75e634d7a852dd2589c144e0e8ab43abba41ba 100644 --- a/drivers/lcd-prototype/api/cap.c +++ b/drivers/lcd-prototype/api/cap.c @@ -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); +} diff --git a/drivers/lcd-prototype/api/defs.h b/drivers/lcd-prototype/api/defs.h index 9bbc669239b1276c72fcd4deaefbe4a7c831c859..4111b0d43e4279bf054b25f34810ef86281ae6ab 100644 --- a/drivers/lcd-prototype/api/defs.h +++ b/drivers/lcd-prototype/api/defs.h @@ -3,41 +3,37 @@ * Charles Jacobsen * 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 +#include #include /* 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); - cnode = __lcd_lookup_cnode(cspace, cptr); - rights = cnode->rights; - lcd_unlock_cspace(cspace); - return rights; + return 1; +} +static inline int __lcd_cap_can_write(struct cnode *cnode) +{ + return 1; +} +static inline int __lcd_cap_can_grant(struct cnode *cnode) +{ + return 1; } -static inline int lcd_cap_can_read() +static inline int lcd_cap_can_read(struct cspace *cspace, cptr_t cptr) { - return rights & LCD_CAP_RIGHT_READ; + return 1; } -static inline int lcd_cap_can_write(int rights) +static inline int lcd_cap_can_write(struct cspace *cspace, cptr_t cptr) { - return rights & LCD_CAP_RIGHT_WRITE; + return 1; } -static inline int lcd_cap_can_grant(int rights) +static inline int lcd_cap_can_grant(struct cspace *cspace, cptr_t cptr) { - return rights & LCD_CAP_RIGHT_GRANT; + return 1; } /** * Deallocates cspace. Caller should ensure no one is trying to