Commit 33293c86 authored by root's avatar root

Added cspace related files

parent 181c1cc2
#ifndef LCD_DOMAINS_INTERNAL_H
#define LCD_DOMAINS_INTERNAL_H
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <asm/lcd-domains/lcd-domains.h>
#include <lcd-domains/types.h>
#include <lcd-domains/utcb.h>
#include <lcd-domains/syscall.h>
/* --------------------------------------------------
* DEBUG
* --------------------------------------------------
*/
#define LCD_DEBUG_LVL 0
#define LCD_ERR(msg...) __lcd_err(__FILE__, __LINE__, msg)
static inline void __lcd_err(char *file, int lineno, char *fmt, ...)
{
va_list args;
printk(KERN_ERR "lcd-domains: %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;
printk(KERN_ERR "lcd-domains: %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;
printk(KERN_ERR "lcd-domains: %s:%d: warning: ", file, lineno);
va_start(args, fmt);
vprintk(fmt, args);
va_end(args);
}
#define LCD_DEBUG_ERR 1
#define LCD_DEBUG_WARN 2
#define LCD_DEBUG_MSG 3
#define LCD_DEBUG(lvl, msg...) { \
if (lvl <= LCD_DEBUG_LVL) \
__lcd_debug(__FILE__, __LINE__, msg); \
}
static inline void __lcd_debug(char *file, int lineno, char *fmt, ...)
{
va_list args;
printk(KERN_ERR "lcd-domains: %s:%d: debug: ", file, lineno);
va_start(args, fmt);
vprintk(fmt, args);
va_end(args);
}
/*
* --------------------------------------------------
* CAPABILITIES
* --------------------------------------------------
*
* See Documentation/lcd-domains/cap.txt.
*/
/*
* --------------------------------------------------
*
* CNODES
*
*/
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_CNODE,
};
enum allocation_state {
ALLOCATION_INVALID,
ALLOCATION_VALID,
ALLOCATION_MARKED_FOR_DELETE,
ALLOCATION_REMOVED,
};
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;
};
/**
* 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.
*
* 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.
*/
void __lcd_cap_delete(struct cspace *cspace, cptr_t c);
/**
* 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.
*/
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);
/**
* Equivalent to calling lcd_cap_delete on all of the cnode's children.
*
* ** Does not delete the cnode itself. **
*/
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.
*/
void __lcd_cap_destroy_cspace(struct cspace *cspace);
/**
* Looks up and locks cnode at c in cspace.
*
* ** Must match with lcd_cnode_put. **
*
* ** Interrupts and preemption *are not* disabled. **
* (so we can easily get out of deadlocks while debugging)
*/
int __lcd_cnode_get(struct cspace *cspace, cptr_t cap, struct cnode **cnode);
/**
* Unlocks cnode.
*/
void __lcd_cnode_put(struct cnode *c);
/*
* --------------------------------------------------
*
* LCDs - lightweight capability domain
*
* See Documentation/lcd-domains/lcd.txt
*/
#define LCD_STATUS_EMBRYO 0
#define LCD_STATUS_CONFIGED 1
#define LCD_STATUS_RUNNING 2
#define LCD_STATUS_DEAD 4
enum lcd_xmit_status {
LCD_XMIT_INVALID = 0, /* when lcd is not in queue */
LCD_XMIT_SUCCESS = 1, /* when send/recv succeeded */
LCD_XMIT_FAILED = 2, /* when send/recv failed */
};
#define LCD_CONSOLE_BUFF_SIZE 512
struct lcd {
/*
* Lock
*
* Protects all fields except the cspace and endpoint_queue.
*
* (Pray for me that I will not get deadlocks)
*/
struct mutex lock;
/*
* Status
*/
atomic_t status;
/*
* My corresponding kthread
*/
struct task_struct *kthread;
/*
* The arch-dependent parts of the lcd (e.g., the ept). (This needs
* to be aligned properly, so we use a pointer instead of embedding
* it.)
*/
struct lcd_arch *lcd_arch;
/*
* The LCD's cspace
*/
struct cspace cspace;
/*
* Message Passing
* ===============
*
* Thread control block, accessible by lcd_thread while running inside
* lcd (mapped in the bottom of its stack). Contains message
* registers, etc.
*/
struct lcd_utcb *utcb;
/*
* Transmission status. When a send/recv is completed, set to
* success/fail.
*/
atomic_t xmit_flag;
/*
* Non-zero if we are making an ipc call (so microkernel knows
* it needs to do a grant on the sender's call endpoint)
*/
int making_call;
/*
* Non-zero if we are doing a reply (so microkernel knows it
* needs to delete capability for reply endpoint)
*/
int doing_reply;
/*
* Send/recv queue we are on.
*
* This is protected by the endpoint's lock. The only time we need
* to access this field from the lcd side (rather than the endpoint
* side) is when we're tearing down the lcd. The proper way to do that
* is to first look up the capability for the endpoint, lock it, and
* then check if the lcd is in the queue.
*/
struct list_head endpoint_queue;
/*
* Console
*/
char console_buff[LCD_CONSOLE_BUFF_SIZE];
unsigned console_cursor;
};
/* similar to task structs */
#define set_lcd_status(lcd, status_value) \
do { \
atomic_set(&(lcd)->status, (status_value)); \
smp_mb(); \
} while(0);
#define get_lcd_status(lcd) (atomic_read(&(lcd)->status))
#define lcd_status_embryo(lcd) \
(get_lcd_status(lcd) == LCD_STATUS_EMBRYO)
#define lcd_status_configed(lcd) \
(get_lcd_status(lcd) == LCD_STATUS_CONFIGED)
#define lcd_status_running(lcd) \
(get_lcd_status(lcd) == LCD_STATUS_RUNNING)
#define lcd_status_dead(lcd) \
(get_lcd_status(lcd) == LCD_STATUS_DEAD)
#define set_lcd_xmit(lcd, xmit_val) \
do { \
atomic_set(&(lcd)->xmit_flag, (xmit_val)); \
smp_mb(); \
} while(0);
#define get_lcd_xmit(lcd) (atomic_read(&(lcd)->xmit_flag))
/*
* --------------------------------------------------
*
* MESSAGE PASSING
*
* Synchronous endpoints contain a send/receive queue for lcd's
* (similar to an seL4 endpoint). Also known as `rendezvous point'.
*/
struct lcd_sync_endpoint {
struct list_head senders;
struct list_head receivers;
struct mutex lock;
};
/* KLCD STUFF -------------------------------------------------- */
int __kliblcd_init(void);
void __kliblcd_exit(void);
int __klcd_enter(void);
void __klcd_exit(void);
int __klcd_page_zalloc(struct lcd *klcd, cptr_t c, hpa_t *hpa_out,
hva_t *hva_out);
int __klcd_pages_zalloc(struct lcd *klcd, cptr_t *slots,
hpa_t *hp_base_out, hva_t *hv_base_out,
unsigned order);
int __lcd_create(struct lcd *caller, cptr_t slot, gpa_t stack);
int __lcd_create__(struct lcd **out);
int __lcd_config(struct lcd *caller, cptr_t lcd, gva_t pc, gva_t sp,
gpa_t gva_root);
int __lcd_run(struct lcd *caller, cptr_t lcd);
int __lcd_cap_grant_cheat(struct lcd *caller, cptr_t lcd, cptr_t src,
cptr_t dest);
int __lcd_cap_page_grant_map_cheat(struct lcd *caller, cptr_t lcd,
cptr_t page, cptr_t dest, gpa_t gpa);
/* IPC -------------------------------------------------- */
int __lcd_ipc_init(void);
void __lcd_ipc_exit(void);
int __lcd_create_sync_endpoint(struct lcd *caller, cptr_t slot);
int __lcd_send(struct lcd *caller, cptr_t endpoint);
int __lcd_recv(struct lcd *caller, cptr_t endpoint);
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_check(struct lcd *owning_lcd, struct lcd *owned_lcd);
/*
* 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_destroy(struct lcd *owned_lcd);
void __lcd_destroy__(struct lcd *owned_lcd);
#endif /* LCD_DOMAINS_INTERNAL_H */
/*
* kliblcd.h - header for kliblcd.ko
*
* Author: Charles Jacobsen <charlesj@cs.utah.edu>
* Copyright: University of Utah
*
* This is the non-isolated code interface to the microkernel. The
* implementation is in virt/lcd-domains/kliblcd.c.
*
* An LCD that runs in non-isolated code is called a klcd.
*/
#ifndef LCD_DOMAINS_KLIBLCD_H
#define LCD_DOMAINS_KLIBLCD_H
#include <lcd-domains/types.h>
#include <lcd-domains/utcb.h>
#include <linux/sched.h>
/* KLIBLCD INTERNALS -------------------------------------------------- */
struct lcd_info;
int __klcd_alloc_cptr(struct cptr_cache *cptr_cache, cptr_t *free_cptr);
void __klcd_free_cptr(struct cptr_cache *cptr_cache, cptr_t c);
int klcd_init_cptr(struct cptr_cache **c_out);
void klcd_destroy_cptr(struct cptr_cache *c);
int klcd_alloc_cptr(cptr_t *free_slot);
void klcd_free_cptr(cptr_t c);
int klcd_add_page(struct page *p, cptr_t *slot_out);
void klcd_rm_page(cptr_t slot);
int klcd_enter(void);
void klcd_exit(int retval);
int klcd_page_alloc(cptr_t *slot_out, gpa_t gpa);
int klcd_pages_alloc(cptr_t *slots_out, hpa_t *hp_base_out,
hva_t *hv_base_out, unsigned order);
int klcd_gfp(cptr_t *slot_out, gpa_t *gpa_out, gva_t *gva_out);
int klcd_create_sync_endpoint(cptr_t *slot_out);
int klcd_send(cptr_t endpoint);
int klcd_recv(cptr_t endpoint);
int klcd_call(cptr_t endpoint);
int klcd_reply(void);
int klcd_create(cptr_t *slot_out, gpa_t stack);
int klcd_config(cptr_t lcd, gva_t pc, gva_t sp, gpa_t gva_root);
int klcd_run(cptr_t lcd);
int klcd_cap_grant(cptr_t lcd, cptr_t src, cptr_t dest);
int klcd_cap_page_grant_map(cptr_t lcd, cptr_t page, cptr_t dest, gpa_t gpa);
void klcd_cap_delete(cptr_t slot);
int klcd_cap_revoke(cptr_t slot);
int klcd_load_module(char *mname, cptr_t mloader_endpoint,
struct lcd_info **mi);
void klcd_unload_module(struct lcd_info *mi, cptr_t mloader_endpoint);
int klcd_create_module_lcd(cptr_t *slot_out, char *mname,
cptr_t mloader_endpoint, struct lcd_info **mi);
void klcd_destroy_module_lcd(cptr_t lcd, struct lcd_info *mi,
cptr_t mloader_endpoint);
int klcd_dump_boot_info(struct lcd_info *mi);
/* DEBUG ------------------------------------------------------------ */
#define LIBLCD_ERR(msg...) __kliblcd_err(__FILE__, __LINE__, msg)
static inline void __kliblcd_err(char *file, int lineno, char *fmt, ...)
{
va_list args;
printk(KERN_ERR "error in klcd (kthread 0x%p): %s:%d: error: ",
current, file, lineno);
va_start(args, fmt);
vprintk(fmt, args);
va_end(args);
}
#define LIBLCD_MSG(msg...) __kliblcd_msg(__FILE__, __LINE__, msg)
static inline void __kliblcd_msg(char *file, int lineno, char *fmt, ...)
{
va_list args;
printk(KERN_ERR "msg in klcd (kthread 0x%p): %s:%d: note: ",
current, file, lineno);
va_start(args, fmt);
vprintk(fmt, args);
va_end(args);
}
#define LIBLCD_WARN(msg...) __kliblcd_warn(__FILE__, __LINE__, msg)
static inline void __kliblcd_warn(char *file, int lineno, char *fmt, ...)
{
va_list args;
printk(KERN_ERR "warn in klcd (kthread 0x%p): %s:%d: warning: ",
current, file, lineno);
va_start(args, fmt);
vprintk(fmt, args);
va_end(args);
}
/* KLCD-SPECIFIC STUFF -------------------------------------------------- */
struct lcd;
#define KLCD_MK_REG_ACCESS(idx) \
extern u64 __klcd_r##idx(struct lcd *lcd); \
extern void __klcd_set_r##idx(struct lcd *lcd, u64 val); \
extern cptr_t __klcd_cr##idx(struct lcd *lcd); \
extern void __klcd_set_cr##idx(struct lcd *lcd, cptr_t val); \
static inline u64 lcd_r##idx(void) \
{ \
return __klcd_r##idx(current->lcd); \
} \
static inline void lcd_set_r##idx(u64 val) \
{ \
__klcd_set_r##idx(current->lcd, val); \
} \
static inline cptr_t lcd_cr##idx(void) \
{ \
return __klcd_cr##idx(current->lcd); \
} \
static inline void lcd_set_cr##idx(cptr_t val) \
{ \
__klcd_set_cr##idx(current->lcd, val); \
}
KLCD_MK_REG_ACCESS(0)
KLCD_MK_REG_ACCESS(1)
KLCD_MK_REG_ACCESS(2)
KLCD_MK_REG_ACCESS(3)
KLCD_MK_REG_ACCESS(4)
KLCD_MK_REG_ACCESS(5)
KLCD_MK_REG_ACCESS(6)
KLCD_MK_REG_ACCESS(7)
/* KLCD SPECIFICS -------------------------------------------------- */
/**
* Put a kernel page in the caller's cspace at slot_out. The microkernel will
* not free such pages when the last capability to them goes away - the caller
* is responsible for freeing them.
*
* (This is used for adding module pages.)
*/
int klcd_add_page(struct page *p, cptr_t *slot_out);
/**
* Remove a kernel page from the caller's cspace at slot. This will
* automatically revoke any capabilities that were derived. Doesn't free page.
*/
void klcd_rm_page(cptr_t slot);
/* LCD ENTER / EXIT -------------------------------------------------- */
/**
* Thread enter lcd mode. This is required before invoking anything.
*/
static inline int lcd_enter(void)
{
return klcd_enter();
}
/**
* Thread exit lcd mode. This will tear down the thread's cspace, etc.
*
* For klcd's, the kernel thread won't die, and retval is ignored (for now).
*/
static inline void lcd_exit(int retval)
{
return klcd_exit(retval);
}
/* LOW LEVEL PAGE ALLOC -------------------------------------------------- */
/**
* Allocate a zero'd out page, and put the capability in slot_out. Map it
* at gpa in the guest physical address space.
*/
static inline int lcd_page_alloc(cptr_t *slot_out, gpa_t gpa)
{
return klcd_page_alloc(slot_out, gpa);
}
/**
* Allocate 2**order zero'd out pages, and put capabilities in slots_out.
* slots_out should be an array with at least 2**order slots. Returns
* guest physical and virtual addresses of first page. (For KLCDs, the
* guest physical and virtual will be == to the host physical and virtual.)
*/
static inline int lcd_pages_alloc(cptr_t *slots_out, gpa_t *gp_base_out,
gva_t *gv_base_out, unsigned order)
{
hpa_t hp_base_out;
hva_t hv_base_out;
int ret;
ret = klcd_pages_alloc(slots_out, &hp_base_out, &hv_base_out, order);
if (ret)
return ret;
/*
* For KLCDs, gpa = hpa, gva = hva.
*/
*gp_base_out = __gpa(hpa_val(hp_base_out));
*gv_base_out = __gva(hva_val(hv_base_out));
return ret;
}
/**
* Higher level routine to get a free page. Maps it in guest physical
* and virtual address spaces. Returns slot and addresses.
*/
static inline int lcd_gfp(cptr_t *slot_out, gpa_t *gpa_out, gva_t *gva_out)
{
return klcd_gfp(slot_out, gpa_out, gva_out);
}
/* IPC -------------------------------------------------- */
/**
* Create a synchronous endpoint, capability stored in slot_out.
*/
static inline int lcd_create_sync_endpoint(cptr_t *slot_out)
{
return klcd_create_sync_endpoint(slot_out);
}
/**
* Synchronous send. Set message registers using lcd_set_r0(), lcd_set_r1(),
* etc. before calling.
*/
static inline int lcd_send(cptr_t endpoint)
{
return klcd_send(endpoint);
}
/**
* Synchronous recv. Set cptr registers (for receiving granted caps) using
* lcd_set_cr0(), lcd_set_cr1(), etc. before calling.
*/
static inline int lcd_recv(cptr_t endpoint)
{
return klcd_recv(endpoint);
}
/**
* Synchronous call. Blocks until callee replies on lcd's reply
* endpoint.
*
* (Internally, this is a send followed by a receive.)
*/
static inline int lcd_call(cptr_t endpoint)
{
return klcd_call(endpoint);
}
/**
* Reply to a synchronous call.
*/
static inline int lcd_reply(void)
{
return klcd_reply();
}
/* LCD CREATE / SETUP -------------------------------------------------- */
/**
* Allocates lcd and does minimal initialization of hardware virtual
* machine and lcd's cspace. Returns non-zero on error. Stack should be
* the guest physical address where stack/utcb should be mapped (the
* microkernel will allocate a page for the stack/utcb - it can't trust
* the caller, and the microkernel needs safe access to the utcb during
* ipc).
*/
static inline int lcd_create(cptr_t *slot_out, gpa_t stack)
{
return klcd_create(slot_out, stack);
}
/**
* Configure lcd environment.
*
* For now, we assume lcd will boot with a guest virtual address space.