Commit ef040dc7 authored by Charlie Jacobsen's avatar Charlie Jacobsen Committed by Vikram Narayanan

Basic 'data store' code added to libkernel.

Just the capability code adapted for use inside the libkernel.

Basic tests passing. Coalesced a lot of the liblcd tests into
one spot (in liblcd/lcd/test.c).
parent 91a3e4ab
========================================
EXPERIENCES
RANDOM EXPERIENCES
========================================
-- If your code fails, but e.g. modprobe or insmod hangs, the cpu may
......@@ -36,3 +36,15 @@ be the source of the bad hang, but I'm not sure.
-- See also some of the tips in liblcd.txt: Notes & Suggestions when debugging
page faults, etc. inside an LCD.
-- If you get linking errors or redefined symbol errors, you might be using
a different configuration than what I used when I set up liblcd. You will
need to either change your configuration, or modify liblcd to resolve the
symbol errors. (This is one reason why we should build liblcd in a separate
tree, in the future.)
-- If you have lock dep turned on with `proving correctness', you will
get some warnings when you load the LCD module. This is because the code
in main.c and cap.c uses some wild locking that could possibly lead to
deadlocks (it hasn't yet). So lockdep dumps warnings. I haven't bothered
inserting the code to prevent lock dep from complaining.
......@@ -49,6 +49,7 @@ 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 ------------------------------------------------------------ */
......@@ -428,6 +429,11 @@ struct lcd_info {
struct list_head free_mem_list;
};
static inline struct lcd_boot_info * to_boot_info(struct lcd_info *mi)
{
return (struct lcd_boot_info *)mi->boot_page_base;
}
static inline int lcd_load_module(char *mname, cptr_t mloader_endpoint,
struct lcd_info **mi)
{
......@@ -563,5 +569,9 @@ static inline void lcd_destroy_module_lcd(cptr_t lcd, struct lcd_info *mi,
return klcd_destroy_module_lcd(lcd, mi, mloader_endpoint);
}
static inline int lcd_dump_boot_info(struct lcd_info *mi)
{
return klcd_dump_boot_info(mi);
}
#endif /* LCD_DOMAINS_KLIBLCD_H */
......@@ -148,12 +148,21 @@
#undef put_online_cpus
#define put_online_cpus() do { } while(0)
#undef mutex_init
#define mutex_init(x) do { } while(0)
#undef mutex_lock
#define mutex_lock(x) do { } while(0)
#undef mutex_trylock
#define mutex_trylock(x) 1
#undef mutex_unlock
#define mutex_unlock(x) do { } while(0)
#undef mutex_lock_interruptible
#define mutex_lock_interruptible(x) 0
#undef spin_lock_init
#define spin_lock_init(x) do { } while(0)
......@@ -225,6 +234,9 @@ static inline void force_up_write(void *x)
#undef might_fault
#define might_fault() do { } while(0)
#undef msleep
#define msleep(x) do { } while(0)
/*
* Copy to/from user
*/
......
......@@ -121,7 +121,7 @@ void __noreturn lcd_exit(int retval);
*
* This should be called when the lcd boots.
*/
void lcd_mem_init(void);
int lcd_mem_init(void);
/**
* Allocate a zero'd out page, and put the capability in slot_out.
*/
......@@ -238,7 +238,7 @@ void lcd_cap_delete(cptr_t slot);
*
* This should be called when an lcd boots.
*/
void lcd_init_cptr(void);
int lcd_init_cptr(void);
/**
* Find an unused cptr in the lcd's cptr cache (a cptr that refers to an
* unused cnode).
......@@ -257,4 +257,215 @@ void lcd_free_cptr(cptr_t c);
*/
void lcd_printk(char *fmt, ...);
#define LIBLCD_ERR(msg...) do { \
lcd_printk("error @ %s:%d: ", __FILE__, __LINE__); \
lcd_printk(msg); \
lcd_printk("end of error"); \
} while (0)
#define LIBLCD_MSG(msg...) do { \
lcd_printk("msg @ %s:%d: ", __FILE__, __LINE__); \
lcd_printk(msg); \
lcd_printk("end of msg"); \
} while (0)
#define LIBLCD_WARN(msg...) do { \
lcd_printk("warn @ %s:%d: ", __FILE__, __LINE__); \
lcd_printk(msg); \
lcd_printk("end of warn"); \
} while (0)
/* BOOT INFO -------------------------------------------------- */
static inline struct lcd_boot_info * lcd_get_boot_info(void)
{
return (struct lcd_boot_info *)gva_val(LCD_BOOT_PAGES_GVA);
}
/* DATA STORE -------------------------------------------------- */
/*
* Adapted from cptrs / capabilities. I'm leaving in some of the
* locks, though they are elided for now, in case we decide to make
* this multithreaded in the future.
*/
typedef struct { unsigned long dptr; } dptr_t;
static inline dptr_t __dptr(unsigned long dptr)
{
return (dptr_t){ dptr };
}
static inline unsigned long dptr_val(dptr_t d)
{
return d.dptr;
}
#define LCD_DPTR_NULL (__dptr(0))
static inline int dptr_is_null(dptr_t d)
{
return dptr_val(d) == dptr_val(LCD_DPTR_NULL);
}
#define LCD_DPTR_DEPTH_BITS 2 /* max depth of 3, zero indexed */
#define LCD_DPTR_FANOUT_BITS 2 /* each level fans out by a factor of 4 */
#define LCD_DPTR_SLOT_BITS 2 /* each node contains 4 slots */
#define LCD_DSTORE_NODE_TABLE_NUM_SLOTS ((1 << LCD_DPTR_SLOT_BITS) + \
(1 << LCD_DPTR_FANOUT_BITS))
#define LCD_DPTR_LEVEL_SHIFT (((1 << LCD_DPTR_DEPTH_BITS) - 1) * \
LCD_DPTR_FANOUT_BITS + LCD_DPTR_SLOT_BITS)
static inline unsigned long lcd_dptr_slot(dptr_t d)
{
/*
* Mask off low bits
*/
return dptr_val(d) & ((1 << LCD_DPTR_SLOT_BITS) - 1);
}
/*
* Gives fanout index for going *from* lvl to lvl + 1, where
* 0 <= lvl < 2^LCD_DPTR_DEPTH_BITS - 1 (i.e., we can't go anywhere
* if lvl = 2^LCD_DPTR_DEPTH_BITS - 1, because we are at the deepest
* level).
*/
static inline unsigned long lcd_dptr_fanout(dptr_t d, int lvl)
{
unsigned long i;
i = dptr_val(d);
/*
* Shift and mask off bits at correct section
*/
i >>= (lvl * LCD_DPTR_FANOUT_BITS + LCD_DPTR_SLOT_BITS);
i &= ((1 << LCD_DPTR_FANOUT_BITS) - 1);
return i;
}
/*
* Gives depth/level of cptr, zero indexed (0 means the root cnode table)
*/
static inline unsigned long lcd_dptr_level(dptr_t d)
{
unsigned long i;
i = dptr_val(d);
/*
* Shift and mask
*/
i >>= LCD_DPTR_LEVEL_SHIFT;
i &= ((1 << LCD_DPTR_DEPTH_BITS) - 1);
return i;
}
/*
* DPTR CACHE
*/
struct dptr_cache {
unsigned long *bmaps[1 << LCD_DPTR_DEPTH_BITS];
};
/*
* Data store
*/
enum allocation_state {
ALLOCATION_INVALID,
ALLOCATION_VALID,
ALLOCATION_MARKED_FOR_DELETE,
ALLOCATION_REMOVED,
};
struct dstore_node;
/*
* (The dstore derivation tree, the analogue of the cdt, may be pointless
* right now since we don't allow grant, etc. with data stores. But maybe
* in the future ...)
*/
struct ddt_root_node {
struct mutex lock;
struct dstore_node *root_node;
enum allocation_state state;
};
#define LCD_DSTORE_TAG_NULL 0
#define LCD_DSTORE_TAG_DSTORE_NODE 1
struct dstore;
struct dstore_node {
struct mutex lock;
/*
* dstore node data
*/
void *object;
int tag;
struct dstore *dstore;
/*
* ddt data
*/
struct ddt_root_node *ddt_root;
struct list_head children;
struct list_head siblings;
};
struct dstore_node_table {
struct dstore_node dstore_node[LCD_DSTORE_NODE_TABLE_NUM_SLOTS];
uint8_t table_level;
struct list_head table_list;
};
struct dstore {
struct mutex lock;
enum allocation_state state;
struct dstore_node_table *root_table;
struct kmem_cache *dstore_node_table_cache;
struct dptr_cache *dptr_cache;
struct list_head table_list;
};
/**
* Initializes caches, etc. in data store subsystem. Should be called when
* LCD boots, but after the slab allocator is initialized.
*/
int lcd_dstore_init(void);
/**
* Tears down caches, etc. in data store subsystem. Should be called before
* LCD exits (not critical right now).
*/
void lcd_dstore_exit(void);
/**
* Sets up data store.
*/
int lcd_dstore_init_dstore(struct dstore **out);
/**
* Inserts object into data store. The caller can associate
* an arbitrary integer tag with the object so that it can do basic
* type checking. Tags 0 and 1 are reserved.
*
* Returns dptr where object is stored in out.
*/
int lcd_dstore_insert(struct dstore *dstore, void *object, int tag,
dptr_t *out);
/**
* Removes object from data store. Unlike capabilities, does not free object
* or do anything else; the caller is responsible for tracking that.
*
* Silently fails if no object is stored at d, or if d is invalid.
*/
void lcd_dstore_delete(struct dstore *dstore, dptr_t d);
/**
* Tears down data store.
*/
void lcd_dstore_destroy(struct dstore *dstore);
/**
* Look up object in dstore at d. Ensure it has tag.
*/
int lcd_dstore_lookup(struct dstore *dstore, dptr_t d, int tag, void **out);
/* TESTING -------------------------------------------------- */
/**
* Runs liblcd regression tests (in liblcd/lcd/test.c).
*/
int lcd_run_tests(void);
#endif /* LCD_DOMAINS_LIBLCD_H */
......@@ -8,7 +8,7 @@
#ifndef LCD_DOMAINS_TYPES_H
#define LCD_DOMAINS_TYPES_H
/* todo: need to eliminate this host header : */
#include <linux/kernel.h>
#include <asm/page.h>
/* CPTRs -------------------------------------------------- */
......@@ -104,7 +104,6 @@ struct cptr_cache {
unsigned long *bmaps[1 << LCD_CPTR_DEPTH_BITS];
};
/* ADDRESS SPACE TYPES ---------------------------------------- */
/* XXX: Assumes host and guest run in 64-bit mode */
......@@ -207,7 +206,7 @@ static inline hpa_t hva2hpa(hva_t hva)
return (hpa_t){ (unsigned long)__pa(hva2va(hva)) };
}
/* BOOT INFO -------------------------------------------------- */
/* BOOT ADDRESS SPACE & INFO ------------------------------------------- */
#define LCD_BOOT_PAGES_ORDER 2
......@@ -223,17 +222,27 @@ static inline hpa_t hva2hpa(hva_t hva)
#define LCD_BOOT_PAGES_GVA __gva(gpa_val(LCD_BOOT_PAGES_GPA))
#define LCD_STACK_GVA __gva(gpa_val(LCD_STACK_GPA))
/* Hack for now to make boot easier */
#define LCD_NUM_BOOT_CPTRS 8
struct lcd_boot_info_for_page {
cptr_t my_cptr;
gpa_t page_gpa;
};
/*
* Hack for now to make boot easier, used in liblcd/lcd/cap.c for cptr
* cache.
*/
#define LCD_BMAP0_SIZE (1 << (LCD_CPTR_SLOT_BITS + 0 * LCD_CPTR_FANOUT_BITS))
#define LCD_BMAP1_SIZE (1 << (LCD_CPTR_SLOT_BITS + 1 * LCD_CPTR_FANOUT_BITS))
#define LCD_BMAP2_SIZE (1 << (LCD_CPTR_SLOT_BITS + 2 * LCD_CPTR_FANOUT_BITS))
#define LCD_BMAP3_SIZE (1 << (LCD_CPTR_SLOT_BITS + 3 * LCD_CPTR_FANOUT_BITS))
struct lcd_boot_info_for_page {
cptr_t my_cptr;
gpa_t page_gpa;
};
#define LCD_BMAP0_NUM_LONGS BITS_TO_LONGS(LCD_BMAP0_SIZE)
#define LCD_BMAP1_NUM_LONGS BITS_TO_LONGS(LCD_BMAP1_SIZE)
#define LCD_BMAP2_NUM_LONGS BITS_TO_LONGS(LCD_BMAP2_SIZE)
#define LCD_BMAP3_NUM_LONGS BITS_TO_LONGS(LCD_BMAP3_SIZE)
struct lcd_boot_info {
/*
......@@ -241,13 +250,13 @@ struct lcd_boot_info {
*
* level 0
*/
unsigned long bmap0[LCD_BMAP0_SIZE];
unsigned long bmap0[LCD_BMAP0_NUM_LONGS];
/* level 1 */
unsigned long bmap1[LCD_BMAP1_SIZE];
unsigned long bmap1[LCD_BMAP1_NUM_LONGS];
/* level 2 */
unsigned long bmap2[LCD_BMAP2_SIZE];
unsigned long bmap2[LCD_BMAP2_NUM_LONGS];
/* level 3 */
unsigned long bmap3[LCD_BMAP3_SIZE];
unsigned long bmap3[LCD_BMAP3_NUM_LONGS];
/*
* Bootstrap page info --------------------
*/
......@@ -257,6 +266,10 @@ struct lcd_boot_info {
struct lcd_boot_info_for_page *boot_mem_pi_start;
struct lcd_boot_info_for_page *paging_mem_pi_start;
struct lcd_boot_info_for_page *free_mem_pi_start;
/*
* Other capabilities (e.g., endpoints)
*/
cptr_t cptrs[LCD_NUM_BOOT_CPTRS];
};
#endif /* LCD_DOMAINS_TYPES_H */
lib-y += $(addprefix lcd/, cap.o enterexit.o ipc.o page_alloc.o printk.o)
lib-y += $(addprefix lcd/, cap.o enterexit.o ipc.o page_alloc.o printk.o \
dstore.o tests.o)
lib-y += $(addprefix lib/, find_next_bit.o kstrtox.o string.o \
vsprintf.o ctype.o hexdump.o \
......
......@@ -9,7 +9,8 @@
/*
* XXX: This is hardwired for a depth of 3 (4 levels) so that we
* don't depend kmalloc. If you change the cspace depth, table size,
* don't depend kmalloc (we need the cptr cache before kmalloc is
* up and running). If you change the cspace depth, table size,
* etc., you will need to change this.
*
* XXX: We don't use a lock because this is only used by one thread, for now.
......@@ -33,39 +34,20 @@ struct cptr_cache_2 {
static struct cptr_cache_2 cptr_cache;
void lcd_init_cptr(void)
int lcd_init_cptr(void)
{
cptr_t test;
struct lcd_boot_info *bi;
int r;
/*
* Read from boot param page
*/
bi = (struct lcd_boot_info *)gva_val(LCD_BOOT_PAGES_GVA);
lcd_printk("bi is 0x%lx", (unsigned long)bi);
lcd_printk("cptr cache is 0x%lx", (unsigned long)&cptr_cache);
bi = lcd_get_boot_info();
memcpy(cptr_cache.bmap0, bi->bmap0, sizeof(bi->bmap0));
memcpy(cptr_cache.bmap1, bi->bmap1, sizeof(bi->bmap1));
memcpy(cptr_cache.bmap2, bi->bmap2, sizeof(bi->bmap2));
memcpy(cptr_cache.bmap3, bi->bmap3, sizeof(bi->bmap3));
lcd_printk("done with memcpy");
/*
* Test
*/
r = lcd_alloc_cptr(&test);
if (r) {
lcd_printk("cptr alloc err ret = %d", r);
return;
}
lcd_printk("got cptr 0x%lx", cptr_val(test));
lcd_free_cptr(test);
lcd_printk("ctpr init done");
return;
return 0;
}
static int __lcd_alloc_cptr_from_bmap(unsigned long *bmap, int size,
......@@ -96,22 +78,26 @@ static int __lcd_alloc_cptr(struct cptr_cache_2 *cache, cptr_t *free_cptr)
/*
* Can't use a loop since we didn't kmalloc the bitmaps
*/
done = __lcd_alloc_cptr_from_bmap(cache->bmap0, LCD_BMAP0_SIZE, &idx);
done = __lcd_alloc_cptr_from_bmap(cache->bmap0,
LCD_BMAP0_SIZE, &idx);
if (done) {
depth = 0;
goto found;
}
done = __lcd_alloc_cptr_from_bmap(cache->bmap1, LCD_BMAP1_SIZE, &idx);
done = __lcd_alloc_cptr_from_bmap(cache->bmap1,
LCD_BMAP1_SIZE, &idx);
if (done) {
depth = 1;
goto found;
}
done = __lcd_alloc_cptr_from_bmap(cache->bmap2, LCD_BMAP2_SIZE, &idx);
done = __lcd_alloc_cptr_from_bmap(cache->bmap2,
LCD_BMAP2_SIZE, &idx);
if (done) {
depth = 2;
goto found;
}
done = __lcd_alloc_cptr_from_bmap(cache->bmap3, LCD_BMAP3_SIZE, &idx);
done = __lcd_alloc_cptr_from_bmap(cache->bmap3,
LCD_BMAP3_SIZE, &idx);
if (done) {
depth = 3;
goto found;
......
This diff is collapsed.
......@@ -6,14 +6,51 @@
int lcd_enter(void)
{
int ret;
/*
* For now, we don't do anything.
* Order is important ...
*
* ------------------------------
*
* Set up cptr cache
*/
ret = lcd_init_cptr();
if (ret) {
LIBLCD_ERR("lcd_init_cptr error");
goto fail;
}
LIBLCD_MSG("cptr cache ready");
/*
* Set up page alloc and kmalloc
*/
ret = lcd_mem_init();
if (ret) {
LIBLCD_ERR("lcd_mem_init error");
goto fail;
}
LIBLCD_MSG("memory subsystem ready");
/*
* Set up dstore subsystem
*/
ret = lcd_dstore_init();
if (ret) {
LIBLCD_ERR("lcd_dstore_init error");
goto fail;
}
LIBLCD_MSG("data store subystem ready");
return 0;
fail:
return ret;
}
void __noreturn lcd_exit(int retval)
{
/*
* For now, don't tear anything down, just exit.
*/
LIBLCD_MSG("exiting");
lcd_set_r0(retval);
for(;;)
LCD_DO_SYSCALL(LCD_SYSCALL_EXIT); /* doesn't return */
......
......@@ -53,7 +53,6 @@ int lcd_page_alloc(cptr_t *slot_out)
lcd_printk("lcd_page_alloc: no cptrs left");
goto fail1;
}
lcd_printk("lcd_alloc_page: cptr is 0x%lx", cptr_val(page));
/*
* Do sys call
*/
......@@ -916,7 +915,7 @@ static void get_mem_boot_info(void)
* The boot info is in the boot info page, mapped when the lcd
* is built.
*/
bi = (struct lcd_boot_info *)gva_val(LCD_BOOT_PAGES_GVA);
bi = lcd_get_boot_info();
/*
* Extract the page info data, store in globals (declared in this
* file).
......@@ -959,7 +958,6 @@ static void init_page_alloc_data(void)
idx = gpa_val(boot_mem_pi_start[i].page_gpa);
idx -= gpa_val(LCD_BOOT_PAGES_GPA);
idx >>= PAGE_SHIFT;
lcd_printk("boot mem idx is %d", idx);
boot_cptrs[idx] = boot_mem_pi_start[i].my_cptr;
}
/*
......@@ -986,67 +984,6 @@ static void init_page_alloc_data(void)
}
}
static void page_alloc_test(void)
{
int ret;
gva_t pages[10];
int i;
int j;
int *loc;
/*
* Allocate ten pages
*/
for (i = 0; i < 10; i++) {
ret = lcd_alloc_page(&pages[i]);
if (ret) {
lcd_printk("mem_test: failed to alloc page");
goto fail1;
}
}
/*
* Write and read each one, make sure we don't fault.
*/
for (i = 0; i < 10; i++) {
loc = (int *)gva_val(pages[i]);
*loc = i;
}
for (i = 0; i < 10; i++) {
loc = (int *)gva_val(pages[i]);
if (*loc != i) {
lcd_printk("mem_test: unexpected val %d != %d",
*loc, i);
i = 10;
goto fail1;
}
}
/*
* Free the pages
*/
i = 10;
lcd_printk("mem test passed!");
goto out;
out:
fail1:
for (j = 0; j < i; j++)
lcd_free_page(pages[j]);
return;
}
static void kmalloc_test(void)
{
struct page *p;
p = kmalloc(sizeof(*p), GFP_KERNEL);
if (!p) {
lcd_printk("kmalloc_test: got null");
return;
}
kfree(p);
}
void cpucache_init(void);
static void __init_refok kmalloc_init(void)
......@@ -1056,7 +993,7 @@ static void __init_refok kmalloc_init(void)
cpucache_init();
}
void lcd_mem_init(void)
int lcd_mem_init(void)
{
/*
* Extract page info from boot info page
......@@ -1066,22 +1003,14 @@ void lcd_mem_init(void)
* Initialize bitmap and page2cptr globals
*/
init_page_alloc_data();
lcd_printk("lcd_mem_init: done with init_page_alloc_data");
/*
* Set up the pgd pointer
*/
setup_pgd();
/*
* Run page alloc tests
*/
page_alloc_test();
lcd_printk("lcd_mem_init: done with page alloc tests");
/*
* Init kmalloc
*/
kmalloc_init();
lcd_printk("lcd_mem_init: done with kmalloc_init");
kmalloc_test();
lcd_printk("lcd_mem_init: done with kmalloc tests");
return 0;
}
#include <lcd-domains/liblcd-config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <lcd-domains/liblcd.h>
#include <lcd-domains/liblcd-hacks.h>
static int cptr_test(void)
{
cptr_t cptrs[10];
int i, j;
int ret;
for (i = 0; i < 10; i++) {
ret = lcd_alloc_cptr(&cptrs[i]);
if (ret) {
LIBLCD_ERR("failed at i = %d", i);
goto fail;
}
if (cptr_is_null(cptrs[i])) {
LIBLCD_ERR("got null cptr");
i++;
goto fail;
}
}
ret = 0;
goto out;
out:
fail:
for (j = 0; j < i; j++)
lcd_free_cptr(cptrs[j]);
return ret;
}
static int page_alloc_test(void)
{
int ret;
gva_t pages[10];
int i;
int j;
int *loc;
/*
* Allocate ten pages
*/
for (i = 0; i < 10; i++) {
ret = lcd_alloc_page(&pages[i]);
if (ret) {
LIBLCD_ERR("failed to alloc page");
goto fail1;
}
}
/*
* Write and read each one, make sure we don't fault.
*/
for (i = 0; i < 10; i++) {
loc = (int *)gva_val(pages[i]);
*loc = i;
}
for (i = 0; i < 10; i++) {
loc = (int *)gva_val(pages[i]);
if (*loc != i) {
LIBLCD_ERR("unexpected val %d != %d",
*loc, i);