Commit 6ee9a51f authored by Charlie Jacobsen's avatar Charlie Jacobsen Committed by Vikram Narayanan

Muktesh's capabilities fully incorporated. Capsicum-style enter/exit.

Builds, but not fully tested. Good tests for capability subsystem, some tests
for kliblcd.

Non-isolated kernel threads can "enter" the lcd system by doing
klcd_enter / klcd_exit. They can create other lcd's, set them up, etc. They
use the same interface that regular lcd's will use, so such code could be
moved to an lcd, as we had planned. Will document this in Documentation folder
tomorrow ( == today ).

Capability system does checks now when a capability is deleted/revoked: for
example, if it's for a page, the microkernel checks if the page is mapped, and
unmaps it. If the last capability goes away, the page is freed. Documentation
is in Documentation/lcd-domains/cap.txt.

IPC code is in place, but not tested yet (pray for me).

Debug is taking some time. Sometimes requires a power cycle which adds an
extra 5 - 10 minutes. Build is slow the first time after reboot. Give me a user
level program and I'll debug it in 30 seconds! argc

Main arch-independent files:

    include/lcd-domains/kliblcd.h, types.h

       This is what non-isolated kernel code should include to use the
       kliblcd interface to the microkernel.

    virt/lcd-domains/main.c, kliblcd.c, cap.c, ipc.c, internal.h

       The microkernel, broken up into pieces.

    virt/lcd-domains/tests/

       The tests, in progress.

Some old files are still hanging around in virt/lcd-domains and will be
incorprated/cleaned up soon.

I couldn't squash over the merge from the decomposition branch, so there's a
bunch of junk commits coming over. (I should've just copied Muktesh's files.)

Conflicts:
	drivers/Kconfig
	drivers/lcd-cspace/test.h
	include/lcd-domains/cap.h
	include/lcd-prototype/lcd.h
	include/lcd/console.h
	include/lcd/elfnote.h
	include/linux/init_task.h
	include/linux/module.h
	include/linux/sched.h
	virt/lcd-domains/cap.c
	virt/lcd-domains/ipc.c
	virt/lcd-domains/lcd-cspace-tests2.c
Resolved-by: Vikram Narayanan's avatarVikram Narayanan <vikram186@gmail.com>
parent 3365b018
This diff is collapsed.
......@@ -97,7 +97,7 @@ and do the following:
[ 1 ] aclocal -I m4 && automake --add-missing --copy && autoconf
[ 2 ] ./configure --prefix=/ --program-prefx=lcd-
[ 2 ] ./configure --prefix=/ --program-prefix=lcd-
[ 3 ] make
......
This diff is collapsed.
......@@ -24,8 +24,8 @@ static int test02(void)
char *buf;
int ret = -1;
lcd = lcd_arch_create();
if (!lcd) {
ret = lcd_arch_create(&lcd);
if (ret) {
LCD_ARCH_ERR("failed to alloc lcd");
goto fail_alloc;
}
......@@ -73,8 +73,8 @@ static int test03(void)
gpa_t base;
int ret = -1;
lcd = lcd_arch_create();
if (!lcd) {
ret = lcd_arch_create(&lcd);
if (ret) {
LCD_ARCH_ERR("failed to alloc lcd");
goto fail1;
}
......@@ -137,96 +137,72 @@ fail1:
static int test04(void)
{
struct lcd_arch *lcd;
struct lcd_arch_thread *t;
hva_t pgd;
int ret = -1;
/*
* Init lcd
*/
lcd = lcd_arch_create();
if (!lcd) {
ret = lcd_arch_create(&lcd);
if (ret) {
LCD_ARCH_ERR("failed to create lcd");
goto fail1;
}
if (lcd->vpid == 0) {
LCD_ARCH_ERR("bad vpid");
goto fail2;
}
/*
* Map a dummy page in the lcd's guest physical address space
*/
pgd = __hva(__get_free_page(GFP_KERNEL));
if (!hva_val(pgd)) {
LCD_ARCH_ERR("failed to alloc page");
goto fail2;
goto fail3;
}
ret = lcd_arch_ept_map(lcd, __gpa(0), hva2hpa(pgd), 1, 0);
if (ret) {
LCD_ARCH_ERR("error mapping pgd");
goto fail3;
}
/*
* Set up an lcd_thread, added to lcd
*/
t = lcd_arch_add_thread(lcd);
if (!t) {
LCD_ARCH_ERR("error setting up lcd_thread");
goto fail4;
}
/*
* Check fields
*/
if (t->vpid == 0) {
LCD_ARCH_ERR("bad vpid");
goto fail5;
}
if (t->lcd_arch != lcd) {
LCD_ARCH_ERR("wrong lcd");
goto fail6;
}
if (list_empty(&t->lcd_arch_threads)) {
LCD_ARCH_ERR("not in lcd arch thread list?");
goto fail7;
}
/*
* Set up its runtime environment
*/
ret = lcd_arch_set_gva_root(t, __gpa(0));
ret = lcd_arch_set_gva_root(lcd, __gpa(0));
if (ret) {
LCD_ARCH_ERR("error setting gva root");
goto fail8;
goto fail5;
}
ret = lcd_arch_set_pc(t, __gva(0));
ret = lcd_arch_set_pc(lcd, __gva(0));
if (ret) {
LCD_ARCH_ERR("error setting pc");
goto fail9;
goto fail6;
}
ret = lcd_arch_set_sp(t, __gva(0));
ret = lcd_arch_set_sp(lcd, __gva(0));
if (ret) {
LCD_ARCH_ERR("error setting sp");
goto fail10;
goto fail7;
}
if (lcd_arch_check(t)) {
if (lcd_arch_check(lcd)) {
LCD_ARCH_ERR("failed a check\n");
goto fail11;
goto fail8;
}
ret = 0;
goto done;
done:
fail11:
fail10:
fail9:
fail8:
fail7:
fail6:
fail5:
lcd_arch_destroy_thread(t);
fail4:
lcd_arch_ept_unmap(lcd, __gpa(0));
fail3:
fail4:
free_page(hva_val(pgd));
fail2:
fail3:
lcd_arch_destroy(lcd);
fail2:
fail1:
return ret;
}
......
This diff is collapsed.
......@@ -202,8 +202,4 @@ source "drivers/hwtracing/intel_th/Kconfig"
source "drivers/fpga/Kconfig"
source "drivers/lcd-prototype/Kconfig"
source "drivers/lcd-cspace/Kconfig"
endmenu
......@@ -39,9 +39,6 @@ obj-y += soc/
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
This diff is collapsed.
/*
* 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 <linux/slab.h>
#include <linux/spinlock.h>
#include <lcd/cap.h>
#include "test.h"
struct cdt_cache_t {
spinlock_t lock;
struct kmem_cache *cdt_root_cache;
};
struct cdt_cache_t cdt_cache;
int __init api_init(void)
{
bool res = true;
printk(KERN_ERR "lcd_cap entering module");
spin_lock_init(&(cdt_cache.lock));
cdt_cache.cdt_root_cache = KMEM_CACHE(cdt_root_node, 0);
if(!cdt_cache.cdt_root_cache){
printk(KERN_ERR "lcd_cap Failed to initialize cdt_root_node allocator\n");
return -ENOMEM;
};
res = begintests();
if (res == false) {
printk(KERN_ERR "tests failed");
} else {
printk(KERN_ERR "tests succeeded");
}
return 0;
}
void __exit api_exit(void)
{
printk(KERN_ERR "lcd cspace exiting module");
return;
}
struct cdt_root_node * get_cdt_root(void) {
unsigned long flags;
struct cdt_root_node *cdt_node;
spin_lock_irqsave(&cdt_cache.lock, flags);
cdt_node = kmem_cache_alloc(cdt_cache.cdt_root_cache, 0);
cdt_node->state = ALLOCATION_VALID;
spin_lock_init(&(cdt_node->lock));
cdt_node->node_count = 0;
spin_unlock_irqrestore(&cdt_cache.lock, flags);
return cdt_node;
}
void free_cdt_root(struct cdt_root_node *cdt_node) {
unsigned long flags;
spin_lock_irqsave(&cdt_cache.lock, flags);
cdt_node->state = ALLOCATION_REMOVED;
cdt_node->node_count = 0;
kmem_cache_free(cdt_cache.cdt_root_cache, cdt_node);
spin_unlock_irqrestore(&cdt_cache.lock, flags);
}
module_init(api_init);
module_exit(api_exit);
#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);
extern int lcd_cap_destroy_cspace(struct cspace *cspace);
bool test_insert(void);
bool test_grant(void);
void test_delete(void);
bool test_revoke(void);
bool test_cspace_destroy(void);
bool begintests(void);
\ No newline at end of file
#
# LCD prototype
#
config LCD_PROTOTYPE
bool "LCD Prototype"
default y
---help---
Prototype for Lightweight Capability Domains system.
config LCD_PROTOTYPE_API
tristate "LCD Prototype API"
default m
depends on LCD_PROTOTYPE
---help---
The kernel prototype for the LCD system.
config LCD_PROTOTYPE_LIBLCD
tristate "LCD Prototype LibLCD"
default m
depends on LCD_PROTOTYPE
---help---
Routines used by test modules.
config LCD_PROTOTYPE_TEST
tristate "LCD Prototype Test"
default m
depends on LCD_PROTOTYPE_API
depends on LCD_PROTOTYPE_LIBLCD
select LCD_PROTOTYPE_TEST_BOOT
select LCD_PROTOTYPE_TEST_CUSTOMER
select LCD_PROTOTYPE_TEST_DEALER
select LCD_PROTOTYPE_TEST_MANUFACTURER
config LCD_PROTOTYPE_TEST_CUSTOMER
tristate
depends on LCD_PROTOTYPE_TEST
default m
config LCD_PROTOTYPE_TEST_DEALER
tristate
depends on LCD_PROTOTYPE_TEST
default m
config LCD_PROTOTYPE_TEST_MANUFACTURER
tristate
depends on LCD_PROTOTYPE_TEST
default m
config LCD_PROTOTYPE_TEST_BOOT
tristate
depends on LCD_PROTOTYPE_TEST
depends on LCD_PROTOTYPE_TEST_CUSTOMER
depends on LCD_PROTOTYPE_TEST_MANUFACTURER
depends on LCD_PROTOTYPE_TEST_DEALER
default m
config LCD_PROTOTYPE_TEST_IN_LCD
bool "LCD Prototype run tests in LCD"
depends on LCD_PROTOTYPE_TEST
default false
obj-$(CONFIG_LCD_PROTOTYPE_API) += api/
obj-$(CONFIG_LCD_PROTOTYPE_LIBLCD) += liblcd/
obj-$(CONFIG_LCD_PROTOTYPE_TEST) += test/
This documents the first draft of the prototype.
Introduction
------------
This is a simple prototype (with a small test) for the LCD architecture. It
consists of:
[ 1 ] an API module (in api dir) that implements a simplified capability
subsystem and ipc subsystem
[ 2 ] a `library' module (in liblcd dir) that is intended to contain
high-level routines that lcd's can call directly into that carry
out low-level tasks (for now, it just contains a simple implementation
of a data store, more below).
[ 3 ] a group of 4 test modules (in test dir)
Building and Running
--------------------
In the kernel menuconfig, under the drivers submenu, select:
-- LCD Prototype
-- LCD Prototype API
-- LCD Prototype LibLCD
-- LCD Prototype Test (for 4 test modules)
-- LCD Prototype run tests in LCD (yes/no)
Then:
make
sudo make modules_install install
To run, insert the modules in this order:
-- api/lcd-prototype-api.ko (runs basic regression tests)
-- liblcd/lcd-prototype-liblcd.ko (does nothing on init)
-- test/lcd-prototype-test-dealer.ko (does nothing on init)
-- test/lcd-prototype-test-manufacturer.ko (does nothing on init)
-- test/lcd-prototype-test-customer.ko (does nothing on init)
-- test/lcd-prototype-test-boot.ko (inits lcd's and runs modules)
Code Layout
-----------
api/defs.h
-- api-private header for definitions (capability subsystem and ipc);
for simplicity, I ended up using this header in the liblcd module
api/main.c
-- contains init/exit for api module
api/cap.c
-- simple capability system, with one global lock
api/ipc.c
-- simple ipc primitives using synchronous endpoints
include/...
-- definitions used by test modules, and some used by all code (LCD_ERR
macros)
liblcd/dstore.c
-- simple `data store' implementation (the `multiple internal cspaces'
component of our design)
test/...
-- test modules
Design
------
Each test module (e.g., dealer.ko) has the original source file (dealer.c)
and the idl glue code (dealer-idl.c and dealer-idl.h).
IPC calls and api calls go into a header or liblcd, providing *code-level*
isolation, for simplicity. For example, a thread in dealer-idl.c calling
lcd_send eventually calls __lcd_send inside the api module.
For simplicity, the api code does not run in its own kernel thread, nor
does it interact with the lcds via any ipc.
This tests some of the decomposition patterns, but not isolation.
Test Modules
------------
The test modules consist of:
-- a customer
-- a (car) dealer
-- a (car) manufacturer
-- a boot module
The test consists of building a simple data structure and passing it between
the three test lcds:
struct automobile
|
--- int doors
|
--- struct engine
|
--- int cylinders
The boot sequence is roughly as follows:
[ 1 ] boot.ko builds the lcd's and initializes kernel threads to run the
three modules; it also creates a sync endpoint for the dealer for its
interface, provided to all three modules at boot
[ 2 ] dealer.ko listens on its endpoint; customer.ko waits until
dealer.ko says the manufacturer is ready
[ 3 ] manufacturer.ko registers its interface with dealer, and dealer
signals to customer.ko (via a struct completion) that it's ready
[ 4 ] customer.ko buys a car from dealer.ko
[ 5 ] dealer.ko creates an engine and automobile using manufacturer's
interface, and allocates a shadow copy of the data; passes a
capability back to the customer for the data
[ 6 ] customer.ko frees the data, by using the capability provided by
the dealer; in the process, the customer and dealer deallocate their
shadow copies of the data
[ 7 ] customer.ko tells dealer.ko to die, which in turn tells
manufacturer.ko to die, and all three kthreads exit back to boot.ko
\ No newline at end of file
obj-$(CONFIG_LCD_PROTOTYPE_API) += lcd-prototype-api.o
lcd-prototype-api-y := main.o cap.o ipc.o api-tests.o
This diff is collapsed.
/*
* Author: Anton Burtsev <aburtsev@flux.utah.edu>
* Copyright: University of Utah
*/
#include <linux/slab.h>
#include "defs.h"
#include "../include/common.h"
struct mutex __lcd_cap_lock;
EXPORT_SYMBOL(__lcd_cap_lock);
int lcd_cap_init(void)
{
mutex_init(&__lcd_cap_lock);
return 0;
}
EXPORT_SYMBOL(lcd_cap_init);
static void init_cspace_cnodes(struct cspace *cspace)
{
int i;
struct cnode *cnode;
INIT_LIST_HEAD(&cspace->free_list);
for (i = 0; i < LCD_NUM_CAPS; i++) {
cnode = &cspace->cnodes[i];
INIT_LIST_HEAD(&cnode->free_list);
INIT_LIST_HEAD(&cnode->children);
INIT_LIST_HEAD(&cnode->child_list);
list_add(&cnode->free_list, &cspace->free_list);
cnode->cspace = cspace;
}
return;
}
int lcd_mk_cspace(struct cspace **cspace_ptr)
{
struct cspace *cspace;
/*
* Allocate cspace
*/
cspace = kmalloc(sizeof(*cspace), GFP_KERNEL);
if (!cspace)
return -ENOMEM;
/*
* Zero out all data (including cnodes). Sets cnode types to free with
* no rights. Initialize free list and cnodes.
*/
memset(cspace, 0, sizeof(*cspace));
init_cspace_cnodes(cspace);
/*
* Done
*/
*cspace_ptr = cspace;
return 0;
}
EXPORT_SYMBOL(lcd_mk_cspace);
static int __lcd_cnode_alloc(struct cspace *cspace, cptr_t *cptr)
{
struct cnode *cnode;
if (list_empty(&cspace->free_list)) {
return -ENOMEM;
} else {
/*
* Get first available cnode, and remove it from the list.
*/
cnode = list_first_entry(&cspace->free_list, struct cnode,
free_list);
/*
* Remove from free list
*/
list_del_init(&cnode->free_list);
/*
* Mark it as unformed
*/
__lcd_cnode_set_type(cnode, LCD_CAP_TYPE_UNFORMED);
/*
* Calc index
*/
*cptr = cnode - (cspace->cnodes);
return 0;
}
}
int lcd_cnode_alloc(struct cspace *cspace, cptr_t *cptr)
{
int ret;
/*
* LOCK cap
*/
ret = lcd_cap_lock();
if (ret)
return ret;
ret = __lcd_cnode_alloc(cspace, cptr);
/*
* UNLOCK cap
*/
lcd_cap_unlock();
return ret;
}
EXPORT_SYMBOL(lcd_cnode_alloc);
int __lcd_cnode_lookup(struct cspace *cspace, cptr_t cptr, struct cnode **out)
{
struct cnode *c;
if (cptr >= LCD_NUM_CAPS)
return -EINVAL;
c = &cspace->cnodes[cptr];
*out = c;
return 0;
}
EXPORT_SYMBOL(__lcd_cnode_lookup);
static int __lcd_cnode_insert(struct cnode *cnode, void *object,
enum lcd_cap_type type, int rights)
{
if (!__lcd_cnode_is_unformed(cnode))
return -EINVAL;
else {
cnode->object = object;
cnode->type = type;
cnode->rights = rights;
return 0;
}
}
int lcd_cnode_insert(struct cspace *cspace, cptr_t cptr,
void *object, enum lcd_cap_type type, int rights)
{
struct cnode *cnode;
int ret;
/*
* LOCK cap
*/
ret = lcd_cap_lock();
if (ret)
return ret;
ret = __lcd_cnode_lookup(cspace, cptr, &cnode);
if (ret)
goto out;
ret = __lcd_cnode_insert(cnode, object, type, rights);
out:
/*
* UNLOCK cap
*/
lcd_cap_unlock();
return ret;
}
EXPORT_SYMBOL(lcd_cnode_insert);
static int __lcd_cnode_insert_for_grant(struct cnode *src_cnode,
struct cnode *dest_cnode, int rights)
{
int ret;
ret = __lcd_cnode_insert(dest_cnode, src_cnode->object,
src_cnode->type, rights);
if (ret)
return ret;
/*
* Add dest_cnode to src_cnode's children.
*/
list_add(&dest_cnode->child_list, &src_cnode->children);
return 0;
}
static int __lcd_cnode_grant(struct cspace *src_cspace,
struct cspace *dest_cspace, cptr_t src_cptr,
cptr_t dest_cptr, int rights)
{
struct cnode *src_cnode;
struct cnode *dest_cnode;
int dest_rights;
int ret;
if (src_cspace == dest_cspace)
return -EINVAL;
ret = __lcd_cnode_lookup(src_cspace, src_cptr, &src_cnode);
if (ret)
return ret;
if (!__lcd_cnode_can_grant(src_cnode))
return -EINVAL;
ret = __lcd_cnode_lookup(dest_cspace, dest_cptr, &dest_cnode);
if (ret)
return ret;
if (!__lcd_cnode_is_occupied(src_cnode) ||
!__lcd_cnode_is_unformed(dest_cnode))
return -EINVAL;
dest_rights = __lcd_cnode_rights(src_cnode) & rights;
ret = __lcd_cnode_insert_for_grant(src_cnode, dest_cnode, dest_rights);
return ret;
}
int lcd_cnode_grant(struct cspace *src_cspace, struct cspace *dest_cspace,
cptr_t src_cptr, cptr_t dest_cptr, int rights)
{
int ret;
/*
* LOCK cap
*/
ret = lcd_cap_lock();
if (ret)
return ret;
ret = __lcd_cnode_grant(src_cspace, dest_cspace, src_cptr, dest_cptr,
rights);
/*
* UNLOCK cap
*/
lcd_cap_unlock();
return ret;
}
EXPORT_SYMBOL(lcd_cnode_grant);
static void __lcd_cnode_do_revoke(struct cnode *parent, int rights)
{