Commit 48ee0d11 authored by Charlie Jacobsen's avatar Charlie Jacobsen

static-cptr-cache: Changes cptr cache defs to use statically alloc'd bmaps.

That is, the bitmaps are now arrays inside the cptr cache, rather
than pointers. We need this for LCDs because the cptr cache needs
to be up and running before we even initialize the page allocator
and malloc.

I need to tweak the code slightly next.

Note: I considered using a packed struct for cptr's, with char
fields. But I realized the allocation algorithm would become a little
less efficient, due to extra required calculations. The advantage of
the current algorithm is that, because the cnode table size is
a power of 2 *and* the bits are packed (they would no longer be
packed if we used chars, unless the cnode table size was 512), translating
a bitmap index to a path in the cspace radix tree is really simple.
If we switched to a struct with char's, such as:

    struct cptr {
       char level;
       char path[CAP_CSPACE_DEPTH];
       char slot;
    };

we would need to do a handful of bit shifts and masks to set up
these fields properly. (For the current algorithm, there's just
one bitwise OR to set the level bits.)

I also realized the bit-level ops we currently use are not that
bad/obscure. We just sacrifice a slight amount of clarity.
parent 96adabf2
Pipeline #390 skipped
......@@ -37,6 +37,9 @@ AC_TYPE_UINT8_T
AC_FUNC_MALLOC
AC_CHECK_FUNCS([memset strdup])
# Check size of unsigned long (determines cspace sizing, cptr ABI, and so on)
AC_CHECK_SIZEOF([unsigned long])
#
# Check glib.
#
......
......@@ -8,6 +8,89 @@
#ifndef __LIBCAP_TYPES_H__
#define __LIBCAP_TYPES_H__
#include <config.h>
/* HELPERS -------------------------------------------------- */
/* Stolen from the Linux kernel */
#define CAP_DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define CAP_BITS_TO_LONGS(nr) CAP_DIV_ROUND_UP(nr, 8 * sizeof(long))
/* CSPACE CONFIGURATION ---------------------------------------- */
/*
* Controls how many levels can be in the cspace radix tree.
*
* The depth must be at least 1 and a power of 2, since there is always at
* least one root level.
*/
#define CAP_CSPACE_DEPTH_BITS 2
#define CAP_CSPACE_DEPTH (1 << CAP_CSPACE_DEPTH_BITS)
#if (CAP_CSPACE_DEPTH < 1)
#error "cspace depth must be at least 1"
#endif
/*
* Controls the size of each node in the cspace radix tree, and the
* degree of fanout. Each node in the radix tree contains
* CAP_CSPACE_CNODE_TABLE_SIZE slots; the first half store capabilities,
* and the second half store pointers to further nodes in the tree.
*
* The table size must be a power of 2 and at least 2, (1) because of how the
* cptr allocation algorithm works, and (2) because a cnode table needs at
* least one capability slot and one pointer slot.
*/
#define CAP_CSPACE_CNODE_TABLE_BITS 8
#define CAP_CSPACE_CNODE_TABLE_SIZE (1 << CAP_CSPACE_CNODE_TABLE_BITS)
#if (CAP_CSPACE_CNODE_TABLE_SIZE < 2)
#error "cnode table size must be at least 2"
#endif
/*
* All of the data - the level, fanout sections, and slot - must fit
* inside an unsigned long. The current configuration was chosen so
* that this works on 32- and 64-bit. The cspace size is fairly
* significant - over 200 million slot capacity.
*/
#if ((CAP_CSPACE_DEPTH * (CAP_CSPACE_CNODE_TABLE_BITS - 1) + \
CAP_CSPACE_DEPTH_BITS) > SIZEOF_UNSIGNED_LONG)
#error "Adjust cspace sizing, otherwise cptrs won't work."
#endif
/* CONVENIENCE CALCULATIONS ---------------------------------------- */
/*
* To avoid serious CPP hacking, this is hard-coded for cspace depths. This
* is still pretty fugly anyway.
*
* lvl must be a compile-time constant. Use the static inline function
* below instead otherwise.
*
* IMPORTANT: lvl should be zero-indexed (the first level is lvl = 0, ...).
* If you use a bad value, the error may not show up till link time.
*/
#if (CAP_CSPACE_DEPTH == 4)
#define CAP_EXP_0(a) (a)
#define CAP_EXP_1(a) ((a) * CAP_EXP_0(a))
#define CAP_EXP_2(a) ((a) * CAP_EXP_1(a))
#define CAP_EXP_3(a) ((a) * CAP_EXP_2(a))
#define CAP_CSPACE_SLOTS_IN_LEVEL(lvl) \
CAP_EXP_ ## lvl(CAP_CSPACE_CNODE_TABLE_SIZE/2)
#else
#error "cspace depth not 4, you need to update this"
#endif
static inline int cap_cspace_slots_in_level(int lvl)
{
int out = CAP_CSPACE_CNODE_TABLE_SIZE/2;
if (lvl < 0 || lvl >= CAP_CSPACE_DEPTH)
BUG();
for ( ; lvl > 0; lvl-- )
out *= CAP_CSPACE_CNODE_TABLE_SIZE/2;
return out;
}
/* CPTRs -------------------------------------------------- */
typedef struct {
......@@ -24,50 +107,31 @@ static inline unsigned long cptr_val(cptr_t c)
return c.cptr;
}
/*
* Reserved cnodes:
*
* cptr = 0 is always null
*/
#define CAP_CPTR_NULL __cptr(0)
static inline int cptr_is_null(cptr_t c)
{
return cptr_val(c) == cptr_val(CAP_CPTR_NULL);
}
#define CAP_CPTR_DEPTH_BITS 3 /* max depth of 3, zero indexed */
#define CAP_CPTR_FANOUT_BITS 3 /* each level fans out by a factor of 4 */
#define CAP_CPTR_SLOT_BITS 3 /* each node contains 4 cap slots */
#define CAP_CNODE_TABLE_NUM_SLOTS ((1 << CAP_CPTR_SLOT_BITS) + \
(1 << CAP_CPTR_FANOUT_BITS))
#define CAP_CPTR_LEVEL_SHIFT (((1 << CAP_CPTR_DEPTH_BITS) - 1) * \
CAP_CPTR_FANOUT_BITS + CAP_CPTR_SLOT_BITS)
static inline unsigned long cap_cptr_slot(cptr_t c)
{
/*
* Mask off low bits
*/
return cptr_val(c) & ((1 << CAP_CPTR_SLOT_BITS) - 1);
return cptr_val(c) & ((1 << (CAP_CSPACE_CNODE_TABLE_BITS - 1)) - 1);
}
/*
* Gives fanout index for going *from* lvl to lvl + 1, where
* 0 <= lvl < 2^CAP_CPTR_DEPTH_BITS - 1 (i.e., we can't go anywhere
* if lvl = 2^CAP_CPTR_DEPTH_BITS - 1, because we are at the deepest
* level).
* 0 <= lvl < CAP_CSPACE_DEPTH.
*/
static inline unsigned long cap_cptr_fanout(cptr_t c, int lvl)
{
unsigned long i;
if (unlikely(lvl >= 3))
BUG();
i = cptr_val(c);
/*
* Shift and mask off bits at correct section
*/
i >>= (lvl * CAP_CPTR_FANOUT_BITS + CAP_CPTR_SLOT_BITS);
i &= ((1 << CAP_CPTR_FANOUT_BITS) - 1);
i >>= ((lvl + 1) * (CAP_CSPACE_CNODE_TABLE_BITS - 1));
i &= ((1 << (CAP_CSPACE_CNODE_TABLE_BITS - 1)) - 1);
return i;
}
......@@ -83,16 +147,58 @@ static inline unsigned long cap_cptr_level(cptr_t c)
/*
* Shift and mask
*/
i >>= CAP_CPTR_LEVEL_SHIFT;
i &= ((1 << CAP_CPTR_DEPTH_BITS) - 1);
i >>= (CAP_CSPACE_DEPTH * (CAP_CSPACE_CNODE_TABLE_BITS - 1));
i &= ((1 << CAP_CSPACE_DEPTH_BITS) - 1);
return i;
}
/*
* Reserved cnodes:
*
* cptr = 0 is always null
*/
#define CAP_CPTR_NULL __cptr(0)
static inline int cptr_is_null(cptr_t c)
{
return cptr_val(c) == cptr_val(CAP_CPTR_NULL);
}
/* CPTR CACHE -------------------------------------------------- */
#if (CAP_CSPACE_DEPTH == 4)
struct cptr_cache {
unsigned long *bmaps[1 << CAP_CPTR_DEPTH_BITS];
/* level 0 bitmap */
unsigned long bmap0[CAP_BITS_TO_LONGS(CAP_CSPACE_SLOTS_IN_LEVEL(0))];
/* level 1 bitmap */
unsigned long bmap1[CAP_BITS_TO_LONGS(CAP_CSPACE_SLOTS_IN_LEVEL(1))];
/* level 2 bitmap */
unsigned long bmap2[CAP_BITS_TO_LONGS(CAP_CSPACE_SLOTS_IN_LEVEL(2))];
/* level 3 bitmap */
unsigned long bmap3[CAP_BITS_TO_LONGS(CAP_CSPACE_SLOTS_IN_LEVEL(3))];
};
static inline unsigned long*
cap_cptr_cache_bmap_for_level(struct cptr_cache *c, int lvl)
{
switch (lvl) {
case 0:
return c->bmap0;
case 1:
return c->bmap1;
case 2:
return c->bmap2;
case 3:
return c->bmap3;
default:
BUG();
}
}
#else
#error "You need to adjust the cptr cache def."
#endif
#endif /* __LIBCAP_TYPES_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