Commit c17ae9f6 authored by Charlie Jacobsen's avatar Charlie Jacobsen Committed by Vikram Narayanan
Browse files

libcap-integration: Re-factor libcap callbacks for revoke and delete.

Moved to a new file, cap_types.c.

The microkernel will use one shared type system for all LCD cspaces.
This is initialized in cap_types.c when the microkernel initializes.
parent 99755e27
......@@ -6,7 +6,7 @@
obj-m += lcd_domains.o
# Arch independent code
lcd_domains-y += main.o ipc.o cap.o
lcd_domains-y += main.o ipc.o cap_types.o
# Arch dependent code
lcd_domains-y += arch/$(ARCH)/main.o
......
/*
* cap_types.c -- Capability types the microkernel uses
*
* Copyright: University of Utah
*/
#include <linux/gfp.h>
#include <linux/list.h>
#include <linux/bitops.h>
#include <libcap.h>
#include "internal.h"
struct cap_type_system *lcd_libcap_type_system;
/* ------------------------------------------------------------ */
/* struct for internal use to store all information about a type. */
struct type_ops_id {
struct cap_type_ops ops;
cap_type_t libcap_type;
};
/* REVOCATION CALLBACKS ---------------------------------------- */
static void page_revoke(struct cspace *cspace, struct cnode *cnode,
void *object)
{
struct lcd_mapping_metadata *m;
struct lcd_memory_object *mo = (struct lcd_memory_object *)object;
/*
* Check if page is mapped; if not, nothing to do.
*/
m = cap_cnode_metadata(cnode);
if (!m->is_mapped)
goto out;
/*
* Unmap it
*/
__lcd_unmap(cap_cspace_getowner(cspace), m->where_mapped,
mo->order);
out:
kfree(m);
}
static void volunteered_page_revoke(struct cspace *cspace, struct cnode *cnode,
void *object)
{
page_revoke(cspace, cnode, object);
}
static void dev_mem_revoke(struct cspace *cspace, struct cnode *cnode,
void *object)
{
page_revoke(cspace, cnode, object);
}
static void sync_endpoint_revoke(struct cspace *cspace, struct cnode *cnode,
void *object)
{
int ret;
struct list_head *cursor, *next;
struct lcd_sync_endpoint *e;
struct lcd *lcd;
lcd = cap_cspace_getowner(cspace);
e = (struct lcd_sync_endpoint *)object;
/*
* Lock the endpoint, and see if lcd is in its queues
*/
ret = mutex_lock_interruptible(&e->lock);
if (ret) {
LCD_ERR("interrupted");
goto out1;
}
list_for_each_safe(cursor, next, &e->senders) {
if (cursor == &lcd->endpoint_queue) {
/*
* Set xmit flag to fail so lcd knows
*/
atomic_set(&lcd->xmit_flag, LCD_XMIT_FAILED);
list_del_init(cursor);
goto out2;
}
}
list_for_each_safe(cursor, next, &e->receivers) {
if (cursor == &lcd->endpoint_queue) {
/*
* Set xmit flag to fail so lcd knows
*/
atomic_set(&lcd->xmit_flag, LCD_XMIT_FAILED);
list_del_init(cursor);
goto out2;
}
}
out2:
mutex_unlock(&e->lock);
out1:
return;
}
static void lcd_revoke(struct cspace *cspace, struct cnode *cnode,
void *object)
{
/* no-op for now */
return;
}
static void klcd_revoke(struct cspace *cspace, struct cnode *cnode,
void *object)
{
/* no-op for now */
return;
}
/* DELETE CALLBACKS ---------------------------------------- */
static void page_delete(struct cspace *cspace, struct cnode *cnode,
void *object)
{
struct lcd_memory_object *mo = (struct lcd_memory_object *)object;
/*
* Pages should be unmapped from all LCDs and not in use
* by any code. Free them.
*/
__free_pages(mo->object, mo->order);
/*
* Free mo, no one else should have a reference.
*/
kfree(mo);
}
static void volunteered_page_delete(struct cspace *cspace, struct cnode *cnode,
void *object)
{
/*
* Do not free the actual pages. The thread that "volunteered"
* the pages is responsible for freeing them after they are removed
* from the capability system.
*
* Free the struct memory_object though (this is what is actually
* stored in the cspace, and contains a further pointer to the
* struct page).
*/
kfree(object);
}
static void dev_mem_delete(struct cspace *cspace, struct cnode *cnode,
void *object)
{
/*
* The device memory itself (e.g., high memory, ISA memory) shouldn't
* need to be "freed".
*
* XXX: Correct? There might be more sophisticated tear-down
* required in the future.
*
* Free the struct memory_object.
*/
kfree(object);
}
static void lcd_delete(struct cspace *cspace, struct cnode *cnode,
void *object)
{
__lcd_destroy(object);
}
static void klcd_delete(struct cspace *cspace, struct cnode *cnode,
void *object)
{
__lcd_destroy(object);
}
/* INTERNAL DATA -------------------------------------------------- */
static struct type_ops_id mk_type_ops_id[LCD_MICROKERNEL_NUM_CAP_TYPES] = {
{
{
.name = "page",
.delete = page_delete,
.revoke = page_revoke,
}
},
{
{
.name = "volunteered page",
.delete = volunteered_page_delete,
.revoke = volunteered_page_revoke,
}
},
{
{
.name = "device memory",
.delete = dev_mem_delete,
.revoke = dev_mem_revoke,
}
},
{
{
.name = "lcd",
.delete = lcd_delete,
.revoke = lcd_revoke,
}
},
{
{
.name = "klcd",
.delete = klcd_delete,
.revoke = klcd_revoke,
}
},
{
{
.name = "sync ipc endpoint",
.delete = sync_endpoint_delete,
.revoke = sync_endpoint_revoke,
}
},
};
/* MISC -------------------------------------------------- */
inline cap_type_t __lcd_get_libcap_type(enum lcd_microkernel_type_id t_id)
{
return mk_type_ops_id[t_id].libcap_type;
}
/* INIT/EXIT -------------------------------------------------- */
int __lcd_init_cap_types(void)
{
int ret;
cap_type_t type_id;
/*
* Alloc and init microkernel type system
*/
ret = cap_type_system_alloc(&lcd_libcap_type_system);
if (ret) {
LCD_ERR("alloc microkernel type system failed");
goto fail1;
}
ret = cap_type_system_init(lcd_libcap_type_system)
if (ret) {
LCD_ERR("init microkernel type system failed");
goto fail2;
}
/*
* Add types
*/
for (i = 0; i < LCD_MICROKERNEL_NUM_CAP_TYPES; i++) {
libcap_type = cap_register_private_type(
lcd_libcap_type_system,
0,
&mk_type_ops_id[i].ops);
if (libcap_type == CAP_TYPE_ERR) {
LCD_ERR("failed to register microkernel cap type %s",
mk_type_ops_id[i].ops.name);
ret = -EIO;
goto fail3;
}
mk_type_ops_id[i].libcap_type = libcap_type;
}
return 0;
fail3:
cap_type_system_destroy(lcd_libcap_type_system);
fail2:
cap_type_system_free(lcd_libcap_type_system);
lcd_libcap_type_system = NULL;
fail1:
return ret;
}
void __lcd_exit_cap_types(void)
{
/*
* Destroy and free type system if necessary
*/
if (lcd_libcap_type_system) {
cap_type_system_destroy(lcd_libcap_type_system);
cap_type_system_free(lcd_libcap_type_system);
lcd_libcap_type_system = NULL;
}
}
......@@ -65,162 +65,84 @@ static inline void __lcd_debug(char *file, int lineno, char *fmt, ...)
va_end(args);
}
/*
* --------------------------------------------------
* CAPABILITIES
* --------------------------------------------------
*
* See Documentation/lcd-domains/cap.txt.
*/
/*
/* --------------------------------------------------
* LCD MICROKERNEL CAPABILITY TYPES
* --------------------------------------------------
*
* CNODES
*
* cap_types.c
*/
enum lcd_cap_type {
LCD_CAP_TYPE_INVALID,
LCD_CAP_TYPE_FREE,
LCD_CAP_TYPE_SYNC_EP,
LCD_CAP_TYPE_PAGE,
LCD_CAP_TYPE_KPAGE,
LCD_CAP_TYPE_LCD,
LCD_CAP_TYPE_KLCD,
LCD_CAP_TYPE_CNODE,
};
enum allocation_state {
ALLOCATION_INVALID,
ALLOCATION_VALID,
ALLOCATION_MARKED_FOR_DELETE,
ALLOCATION_REMOVED,
enum lcd_microkernel_type_id {
LCD_MICROKERNEL_TYPE_ID_PAGE,
LCD_MICROKERNEL_TYPE_ID_VOLUNTEERED_PAGE,
LCD_MICROKERNEL_TYPE_ID_DEV_MEM,
LCD_MICROKERNEL_TYPE_ID_SYNC_EP,
LCD_MICROKERNEL_TYPE_ID_LCD,
LCD_MICROKERNEL_TYPE_ID_KLCD,
LCD_MICROKERNEL_NUM_CAP_TYPES,
};
struct cnode;
struct cdt_root_node {
struct mutex lock;
struct cnode *cnode;
enum allocation_state state;
};
struct cspace;
struct cnode {
struct mutex lock;
/*
* cnode data
*/
enum lcd_cap_type type;
void *object;
struct cspace *cspace;
/*
* cdt data
*/
struct cdt_root_node *cdt_root;
struct list_head children;
struct list_head siblings;
/*
* Page-specific cnodes (temporary!)
* =================================
*
* We need to keep track of if and where the page is mapped so we
* know how to unmap it when the lcd deletes/loses this capability.
*
* We impose the constraint that pages can only be mapped *once* in an
* lcd's ept, so we only need one gpa.
*/
int is_mapped;
gpa_t where_mapped;
};
struct cnode_table {
struct cnode cnode[LCD_CNODE_TABLE_NUM_SLOTS];
uint8_t table_level;
struct list_head table_list;
};
struct cspace {
struct mutex lock;
enum allocation_state state;
struct cnode_table *cnode_table;
struct kmem_cache *cnode_table_cache;
struct list_head table_list;
};
extern struct cap_type_system *lcd_libcap_type_system;
/**
* Initializes caches, etc. in capability subsystem. Called when microkernel
* intializes.
*/
int __lcd_cap_init(void);
/**
* Tears down caches, etc. in capability subsystem. Called when microkernel
* is exiting.
*/
void __lcd_cap_exit(void);
/**
* Sets up cspace - initializes lock, root cnode table, etc.
*/
int __lcd_cap_init_cspace(struct cspace *cspace);
/**
* Inserts object data into cspace at cnode pointed at by c.
*/
int __lcd_cap_insert(struct cspace *cspace, cptr_t c, void *object,
enum lcd_cap_type type);
/**
* Deletes object data from cspace at cnode pointed at by c.
* __lcd_init_cap_types -- Initialize data structures for libcap type system
*
* Updates the state of the microkernel to reflect rights change (e.g., if
* a cnode for a page is deleted, and the page is mapped, the page will be
* unmapped).
*
* If this is the last cnode that refers to the object, the object is
* destroyed.
* Initializes the cap_type_system that is shared by all LCD cspaces. Should
* be invoked when the microkernel initializes. Returns non-zero if init
* fails.
*/
void __lcd_cap_delete(struct cspace *cspace, cptr_t c);
int __lcd_init_cap_types(void);
/**
* Copies cnode data in src cnode at c_src to dest cnode at c_dst. The dest
* cnode will be a child of the src cnode in the cdt containing src cnode.
* __lcd_exit_cap_types -- Destroy/tear down data structures for type system
*
* Should be invoked before microkernel module is uninstalled from host.
*/
int __lcd_cap_grant(struct cspace *cspacesrc, cptr_t c_src,
struct cspace *cspacedst, cptr_t c_dst);
int __lcd_cap_grant_page(struct cspace *cspacesrc, cptr_t c_src,
struct cspace *cspacedst, cptr_t c_dst, gpa_t gpa);
void __lcd_exit_cap_types(void);
/**
* Equivalent to calling lcd_cap_delete on all of the cnode's children.
* __lcd_get_libcap_type -- Translate our type id to libcap's type id
* @t_id: one of the type id enum values
*
* ** Does not delete the cnode itself. **
* Motivation: You need to know the libcap type id in order to insert
* an object in a cspace.
*/
int __lcd_cap_revoke(struct cspace *cspace, cptr_t c);
/**
* Equivalent to calling lcd_cap_delete on all cnodes in cspace. Frees up
* all cnode tables, etc.
cap_type_t __lcd_get_libcap_type(enum lcd_microkernel_type_id t_id);
/* --------------------------------------------------
* MEMORY
* --------------------------------------------------
*/
void __lcd_cap_destroy_cspace(struct cspace *cspace);
/**
* Looks up and locks cnode at c in cspace.
* struct lcd_mapping_metadata
*
* ** Must match with lcd_cnode_put. **
*
* ** Interrupts and preemption *are not* disabled. **
* (so we can easily get out of deadlocks while debugging)
* This is used as cnode metadata in cspaces to record whether
* a page capability has been mapped in an LCD's address
* space, and if so, where. This information is needed when
* the capability is revoked or deleted, so that we can
* unmap the pages from the LCD's guest physical address space.
*/
int __lcd_cnode_get(struct cspace *cspace, cptr_t cap, struct cnode **cnode);
struct lcd_mapping_metadata {
int is_mapped;
gpa_t where_mapped;
};
/**
* Unlocks cnode.
* struct lcd_memory_object
*
* This is used as a wrapper around struct page and arbitrary
* host physical addresses, so that we can track the size of the
* memory region. This is the object that is inserted into an LCD's
* cspace (rather than a struct page, say). We don't store an extra
* type field because this information is stored in the cspace.
*/
void __lcd_cnode_put(struct cnode *c);
struct lcd_memory_object {
void *object;
unsigned int order;
};
/*
* --------------------------------------------------
*
* LCDs - lightweight capability domain
*
* See Documentation/lcd-domains/lcd.txt
*/
......@@ -273,7 +195,7 @@ struct lcd {
/*
* The LCD's cspace
*/
struct cspace cspace;
struct cspace *cspace;
/*
* Message Passing
* ===============
......@@ -397,37 +319,4 @@ int __lcd_call(struct lcd *caller, cptr_t endpoint);
int __lcd_reply(struct lcd *caller);
/* CHECK & DESTROY -------------------------------------------------- */
/*
* These are executed by code in cap.c when a capability to an object
* is revoked. It gives the microkernel a chance to update any state (like
* removing an lcd from an endpoint queue, unmapping a page, etc.). If the
* final capability is revoked, these are called, followed by the appropriate
* destroy routine below.
*/
void __lcd_sync_endpoint_check(struct lcd *lcd, struct lcd_sync_endpoint *e);
void __lcd_page_check(struct lcd *lcd, struct page *p, int is_mapped,
gpa_t where_mapped);
void __lcd_kpage_check(struct lcd *lcd, struct page *p, int is_mapped,
gpa_t where_mapped);
void __lcd_hpa_check(struct lcd *lcd, unsigned long hpa, int is_mapped,
gpa_t where_mapped);
void __lcd_check(struct lcd *owning_lcd, struct lcd *owned_lcd);
void __lcd_check_klcd(struct lcd *owning_lcd, struct lcd *owned_klcd);
/*
* These are called by code in cap.c when the last capability goes
* away.
*/
void __lcd_sync_endpoint_destroy(struct lcd_sync_endpoint *e);
void __lcd_page_destroy(struct page *p);
void __lcd_kpage_destroy(struct page *p);
void __lcd_hpa_destroy(unsigned long hpa);
void __lcd_destroy(struct lcd *owned_lcd);
void __lcd_destroy__(struct lcd *owned_lcd);
void __lcd_destroy_klcd(struct lcd *owned_klcd);
#endif /* LCD_DOMAINS_INTERNAL_H */
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