Add foreign state init

This commit is contained in:
Sparchatus 2022-03-23 08:29:02 +00:00
parent c83edbb696
commit fdf72890f1
3 changed files with 119 additions and 75 deletions

View File

@ -49,8 +49,9 @@ struct pt_t {
size_t mapping_size;
// NOTE rueegges: points to an array with pointers for every potential next level page table
// it is NULL for mapping a frame instead of a page table
// entries are NULL if the corresponding mapping does not yet exist
// the entries are NULL if the corresponding mapping does not yet exist
// l0_pt children will initially be NULL and initialized in first mapping call
// lower pt children arrays are immediately allocated.
struct pt_t **children;
};
@ -67,7 +68,7 @@ struct paging_state {
struct slot_allocator *slot_alloc;
// NOTE rueegges: added to keep track of pt metadata
struct pt_t *l0_pt;
struct pt_t l0_pt;
// NOTE rueegges: added to allocate shadow page table metadata
struct slab_allocator pt_slabs;
@ -82,7 +83,7 @@ struct paging_state {
struct capref free_l3_vnode;
// TODO rueegges: implement more precisely?
struct pt_vaddr_reg_t *vaddr_head;
struct pt_vaddr_reg_t vaddr_head;
};

View File

@ -30,10 +30,6 @@ static struct paging_state current;
#define PT_PT_SLAB_INITIAL_SPACE SLAB_STATIC_SIZE(PT_PT_SLAB_MIN_SPACE, PT_META_MAX_SIZE)
#define PT_CHILDREN_SLAB_INITIAL_SPACE SLAB_STATIC_SIZE(PT_CHILDREN_SLAB_MIN_SPACE, BASE_PAGE_SIZE)
char pt_pt_slab_buf[PT_PT_SLAB_INITIAL_SPACE];
char pt_children_slab_buf[PT_CHILDREN_SLAB_INITIAL_SPACE];
/**
* \brief Helper function that allocates a slot and
* creates a aarch64 page table capability for a certain level
@ -73,8 +69,9 @@ __attribute__((unused)) static errval_t pt_alloc_l3(struct paging_state * st, st
void pt_print_state(struct paging_state *st) {
// iterates over all the page table entries and prints them
debug_printf("L0\n");
if(st->l0_pt.children == NULL) return;
for(size_t i0 = 0; i0 < PTABLE_ENTRIES; ++i0) {
struct pt_t *l1_pt = st->l0_pt->children[i0];
struct pt_t *l1_pt = st->l0_pt.children[i0];
if (l1_pt == NULL) continue;
debug_printf(" %lu -> L1\n", i0);
@ -134,8 +131,7 @@ static errval_t pt_ensure_slabs(struct paging_state *st) {
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_SLOT_ALLOC);
}
// TODO rueegges: use fuctions for refill size
err = slab_refill_no_pagefault(&st->pt_children_slabs, frame_cap, 10 * 4096);
err = slab_refill_no_pagefault(&st->pt_children_slabs, frame_cap, LARGE_PAGE_SIZE);
st->refilling = 0;
// debug_printf("DEBUG rueegges: pt_ensure_slabs - refilling pt_children_slabs DONE\n");
@ -212,7 +208,7 @@ static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_
errval_t err;
struct pt_t *res;
// debug_printf("DEBUG rueegges: pt_ensure l%u\n", pt_parent->level+1);
// debug_printf("DEBUG rueegges: pt_ensure l%u\n", level);
// If this fails we got an l3 pt as the parent
assert(pt_parent->children != NULL);
@ -226,7 +222,7 @@ static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_
}
// check if the page table already exists
res = (pt_parent->children)[pt_index];
res = pt_parent->children[pt_index];
if (res != NULL) {
*pt_ret = res;
return SYS_ERR_OK;
@ -240,8 +236,8 @@ static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_
return err;
}
// check if the page table already exists
res = (pt_parent->children)[pt_index];
// check again if the page table already exists
res = pt_parent->children[pt_index];
if (res != NULL) {
*pt_ret = res;
return SYS_ERR_OK;
@ -276,7 +272,6 @@ static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_
if (err_is_fail(err_err)) {
DEBUG_ERR(err_err, "Failed to free capability slot during error handling");
}
slab_free(&st->pt_slabs, pt_meta);
slab_free(&st->pt_children_slabs, pt_children);
pt_save_allocation(st, pt_cap, level);
@ -325,51 +320,25 @@ errval_t paging_init_state(struct paging_state *st, lvaddr_t start_vaddr,
// TODO rueegges: is this how we should initialize the slab allocators?
slab_init(&st->pt_slabs, PT_META_MAX_SIZE, NULL);
slab_init(&st->pt_children_slabs, BASE_PAGE_SIZE, NULL);
slab_grow(&st->pt_slabs, pt_pt_slab_buf, PT_PT_SLAB_INITIAL_SPACE);
slab_grow(&st->pt_children_slabs, pt_children_slab_buf, PT_CHILDREN_SLAB_INITIAL_SPACE);
// initialize shadow page tables
struct pt_t *l0_pt = slab_alloc(&st->pt_slabs);
if(l0_pt == NULL) {
debug_printf("Failed to alloc l0 meta\n");
return LIB_ERR_SLAB_ALLOC_FAIL;
}
struct pt_t **l0_children = (struct pt_t **) slab_alloc(&st->pt_children_slabs);
if(l0_children == NULL) {
debug_printf("Failed to alloc l0 children\n");
slab_free(&st->pt_slabs, l0_pt);
return LIB_ERR_SLAB_ALLOC_FAIL;
}
// make sure all child pointers are initialized to NULL
memset(l0_children, 0, st->pt_children_slabs.blocksize);
l0_pt->cap_pt = pdir;
l0_pt->cap_mapping = NULL_CAP;
l0_pt->children = l0_children;
st->l0_pt.cap_pt = pdir;
st->l0_pt.cap_mapping = NULL_CAP;
st->l0_pt.children = NULL;
// initialize virtual address space
struct pt_vaddr_reg_t *vaddr_reg = (struct pt_vaddr_reg_t *) slab_alloc(&st->pt_slabs);
if (vaddr_reg == NULL) {
debug_printf("Failed to alloc l0 children\n");
slab_free(&st->pt_slabs, l0_pt);
slab_free(&st->pt_children_slabs, l0_children);
return LIB_ERR_SLAB_ALLOC_FAIL;
}
vaddr_reg->base = start_vaddr;
vaddr_reg->size = VADDR_SIZE - start_vaddr;
vaddr_reg->free = true;
vaddr_reg->next = NULL;
st->vaddr_head.base = start_vaddr;
st->vaddr_head.size = VADDR_SIZE - start_vaddr;
st->vaddr_head.free = true;
st->vaddr_head.next = NULL;
st->slot_alloc = ca;
st->l0_pt = l0_pt;
st->refilling = 0;
st->free_l1_vnode = NULL_CAP;
st->free_l2_vnode = NULL_CAP;
st->free_l3_vnode = NULL_CAP;
st->vaddr_head = vaddr_reg;
return SYS_ERR_OK;
}
@ -390,10 +359,21 @@ errval_t paging_init_state(struct paging_state *st, lvaddr_t start_vaddr,
errval_t paging_init_state_foreign(struct paging_state *st, lvaddr_t start_vaddr,
struct capref pdir, struct slot_allocator *ca)
{
errval_t err;
// TODO (M2): Implement state struct initialization
// TODO (M4): Implement page fault handler that installs frames when a page fault
// occurs and keeps track of the virtual address space.
return LIB_ERR_NOT_IMPLEMENTED;
struct capref pt_cap;
err = ca->alloc(ca, &pt_cap);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_SLOT_ALLOC);
}
err = cap_copy(pt_cap, pdir);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_CAP_COPY_FAIL);
}
return paging_init_state(st, start_vaddr, pt_cap, ca);
}
/**
@ -416,6 +396,11 @@ errval_t paging_init(void)
err = paging_init_state(&current, VADDR_OFFSET, cap_vroot, get_default_slot_allocator());
if (err_is_fail(err)) return err;
static char pt_pt_slab_buf[PT_PT_SLAB_INITIAL_SPACE];
static char pt_children_slab_buf[PT_CHILDREN_SLAB_INITIAL_SPACE];
slab_grow(&current.pt_slabs, pt_pt_slab_buf, PT_PT_SLAB_INITIAL_SPACE);
slab_grow(&current.pt_children_slabs, pt_children_slab_buf, PT_CHILDREN_SLAB_INITIAL_SPACE);
set_current_paging_state(&current);
return SYS_ERR_OK;
}
@ -535,7 +520,7 @@ errval_t paging_alloc(struct paging_state *st, void **buf, size_t bytes, size_t
return err;
}
struct pt_vaddr_reg_t *vaddr_reg = st->vaddr_head;
struct pt_vaddr_reg_t *vaddr_reg = &st->vaddr_head;
while(vaddr_reg != NULL) {
// calculate the number of bytes to skip to achieve alignment
size_t prefix_size = (alignment - (vaddr_reg->base & (alignment - 1))) % alignment;
@ -633,10 +618,29 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr,
assert(st != NULL);
assert(st->slot_alloc != NULL);
// debug_printf("DEBUG rueegges: paging_map_fixed_attr(%p, 0x%lx, cap, %lu, %d)\n", st, vaddr, bytes, flags);
// make sure we have enough slot and slab space left
err = pt_ensure_slabs(st);
if(err_is_fail(err)) {
return err_push(err, LIB_ERR_SLAB_REFILL);
}
// get the l0 page table and make sure late init is completed
struct pt_t *l0_pt = &st->l0_pt;
if (l0_pt->children == NULL) {
l0_pt->children = (struct pt_t **) slab_alloc(&st->pt_children_slabs);
if(l0_pt->children == NULL) {
return LIB_ERR_SLAB_ALLOC_FAIL;
}
memset(l0_pt->children, 0, st->pt_children_slabs.blocksize);
}
assert(l0_pt->children != NULL);
// make sure the virtual address space is reserved for this mapping. For this we require either an allocated vaddr reg to
// precisely exist as required or not at all, i.e. it is not overlapping multiple existing regions
// TODO rueegges: not sure this is the best way to do this
struct pt_vaddr_reg_t *vaddr_reg = st->vaddr_head;
struct pt_vaddr_reg_t *vaddr_reg = &st->vaddr_head;
for(;vaddr_reg != NULL; vaddr_reg = vaddr_reg->next) {
// we have found the region it belongs to
if(vaddr_reg->base <= vaddr && vaddr + bytes <= vaddr_reg->base + vaddr_reg->size) {
@ -654,9 +658,6 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr,
return LIB_ERR_PMAP_ADDR_NOT_FREE;
}
// debug_printf("DEBUG rueegges: paging_map_fixed_attr(%p, 0x%lx, cap, %lu, %d)\n", st, vaddr, bytes, flags);
// TODO rueegges: cleanup partially completed mapping?
size_t mapping_size;
for(lvaddr_t current_vaddr = vaddr; current_vaddr < vaddr + bytes; current_vaddr += mapping_size * BASE_PAGE_SIZE) {
@ -665,15 +666,15 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr,
capaddr_t l2_index = VMSAv8_64_L2_INDEX(current_vaddr);
capaddr_t l3_index = VMSAv8_64_L3_INDEX(current_vaddr);
// get the size of the mapping
mapping_size = MIN(PTABLE_ENTRIES - l3_index, (vaddr + bytes - current_vaddr) / BASE_PAGE_SIZE);
// Cannot map anything with l0_index = 0 since this part of the page table was created by the kernel for us
assert(l0_index != 0);
// get the size of the mapping
mapping_size = MIN(PTABLE_ENTRIES - l3_index, (vaddr + bytes - current_vaddr) / BASE_PAGE_SIZE);
// get l1 page table
struct pt_t *l1_pt;
err = pt_ensure(st, st->l0_pt, l0_index, 1, &l1_pt);
err = pt_ensure(st, l0_pt, l0_index, 1, &l1_pt);
if(err_is_fail(err)) {
return err;
}
@ -695,27 +696,26 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr,
}
assert(l3_pt->children != NULL);
// debug_printf("DEBUG rueegges: paging_map_fixed_attr - allocate mapping meta\n");
// make sure we have enough slot and slab space left
err = pt_ensure_slabs(st);
if(err_is_fail(err)) {
return err_push(err, LIB_ERR_SLAB_REFILL);
}
// debug_printf("DEBUG rueegges: paging_map_fixed_attr - allocate mapping meta\n");
// create structures for the new metadata
struct pt_t *pt_entry = (struct pt_t *) slab_alloc(&st->pt_slabs);
if (pt_entry == NULL) {
DEBUG_ERR(err, "Failed to refill slabs before adding page mapping.");
return LIB_ERR_SLAB_ALLOC_FAIL;
}
// set to null to indicate it is a frame mapping and not a page table mapping
pt_entry->children = NULL;
pt_entry->mapping_size = mapping_size;
// allocate the new mapping
err = st->slot_alloc->alloc(st->slot_alloc, &pt_entry->cap_mapping);
if (err_is_fail(err)) {
slab_free(&st->pt_slabs, pt_entry);
return err;
}
@ -725,6 +725,11 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr,
err = vnode_map(l3_pt->cap_pt, frame, l3_index, flags, current_vaddr - vaddr, mapping_size, pt_entry->cap_mapping);
if (err_is_fail(err)) {
debug_printf("Failed to map vnode at vaddr 0x%lx\n", current_vaddr);
slab_free(&st->pt_slabs, pt_entry);
errval_t err_err = st->slot_alloc->free(st->slot_alloc, pt_entry->cap_mapping);
if (err_is_fail(err_err)) {
DEBUG_ERR(err, "Failed to free slot during error handling");
}
return err;
}

View File

@ -7,11 +7,11 @@
// used to avoid conflicts between tests
static lvaddr_t vaddr = 0x0000100000000000L;
static void test_paging_run(errval_t func(void), char *name) {
static void test_paging_run(errval_t func(struct paging_state *paging_state), char *name, struct paging_state *paging_state) {
errval_t err;
// debug_printf("TEST_PAGING %19s: start\n", name);
err = func();
err = func(paging_state);
if (err_is_ok(err)) {
debug_printf("TEST_PAGING %23s: OK\n", name);
@ -21,7 +21,7 @@ static void test_paging_run(errval_t func(void), char *name) {
}
}
static errval_t test_paging_full_l3(void) {
static errval_t test_paging_full_l3(struct paging_state *paging_state) {
errval_t err;
size_t mapping_size = BASE_PAGE_SIZE;
@ -33,7 +33,7 @@ static errval_t test_paging_full_l3(void) {
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_FRAME_ALLOC);
}
err = paging_map_fixed_attr(get_current_paging_state(), vaddr, frame, mapping_size, VREGION_FLAGS_READ_WRITE);
err = paging_map_fixed_attr(paging_state, vaddr, frame, mapping_size, VREGION_FLAGS_READ_WRITE);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_PMAP_NOT_MAPPED);
}
@ -51,7 +51,7 @@ static errval_t test_paging_full_l3(void) {
return SYS_ERR_OK;
}
static errval_t test_paging_full_l2(void) {
static errval_t test_paging_full_l2(struct paging_state *paging_state) {
errval_t err;
size_t mapping_size = BASE_PAGE_SIZE;
@ -63,7 +63,7 @@ static errval_t test_paging_full_l2(void) {
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_FRAME_ALLOC);
}
err = paging_map_fixed_attr(get_current_paging_state(), vaddr, frame, mapping_size, VREGION_FLAGS_READ_WRITE);
err = paging_map_fixed_attr(paging_state, vaddr, frame, mapping_size, VREGION_FLAGS_READ_WRITE);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_PMAP_NOT_MAPPED);
}
@ -81,7 +81,7 @@ static errval_t test_paging_full_l2(void) {
return SYS_ERR_OK;
}
static errval_t test_paging_big_regions(void) {
static errval_t test_paging_big_regions(struct paging_state *paging_state) {
errval_t err;
size_t mapping_size;
@ -95,7 +95,7 @@ static errval_t test_paging_big_regions(void) {
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_FRAME_ALLOC);
}
err = paging_map_fixed_attr(get_current_paging_state(), vaddr, frame, mapping_size, VREGION_FLAGS_READ_WRITE);
err = paging_map_fixed_attr(paging_state, vaddr, frame, mapping_size, VREGION_FLAGS_READ_WRITE);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_PMAP_NOT_MAPPED);
}
@ -114,9 +114,9 @@ static errval_t test_paging_big_regions(void) {
}
void do_test_paging(void) {
test_paging_run(test_paging_full_l3, "test_paging_full_l3");
test_paging_run(test_paging_full_l2, "test_paging_full_l2");
test_paging_run(test_paging_big_regions, "test_paging_big_regions");
test_paging_run(test_paging_full_l3, "test_paging_full_l3", get_current_paging_state());
test_paging_run(test_paging_full_l2, "test_paging_full_l2", get_current_paging_state());
test_paging_run(test_paging_big_regions, "test_paging_big_regions", get_current_paging_state());
// Test paging
for (int i = 0; i < 40; i++) {
@ -124,4 +124,42 @@ void do_test_paging(void) {
char *data = alloc_frame(5176*4096, 16, NULL, NULL);
memset(data, 33, 5176*4096);
}
debug_printf("TEST: do foreign test\n");
// Tet foreign init
errval_t err;
struct capref rootcn_cap;
struct cnoderef rootcn;
struct cnoderef pagecn;
struct paging_state st;
err = cnode_create_l1(&rootcn_cap, &rootcn);
assert(err_is_ok(err));
err = cnode_create_foreign_l2(rootcn_cap, ROOTCN_SLOT_PAGECN, &pagecn);
assert(err_is_ok(err));
struct capref l0 = {
.cnode = pagecn,
.slot = PAGECN_SLOT_VROOT,
};
err = vnode_create(l0, ObjType_VNode_AARCH64_l0);
assert(err_is_ok(err));
err = paging_init_state_foreign(&st, VADDR_OFFSET, l0, get_default_slot_allocator());
assert(err_is_ok(err));
debug_printf("TEST: map foreign l3\n");
size_t mapping_size = BASE_PAGE_SIZE;
// map all entries of a single l3 table
for(size_t i = 0; i < VMSAv8_64_PTABLE_NUM_ENTRIES; ++i) {
struct capref frame;
err = frame_alloc(&frame, mapping_size, NULL);
if (err_is_fail(err)) {
USER_PANIC_ERR(err, "Failed frame alloc");
}
err = paging_map_fixed_attr(&st, vaddr, frame, mapping_size, VREGION_FLAGS_READ_WRITE);
if (err_is_fail(err)) {
USER_PANIC_ERR(err, "Failed page mapping");
}
vaddr += mapping_size;
}
}