diff --git a/include/aos/paging_types.h b/include/aos/paging_types.h index fae9254..f1a927e 100644 --- a/include/aos/paging_types.h +++ b/include/aos/paging_types.h @@ -40,8 +40,6 @@ typedef int paging_flags_t; // NOTE rueegges: page table metadata used to create child mappings and unmap struct pt_t { - // the level of the page table. since we abuse this struct also to track l3 entries we set it to 4 there. - size_t level; // capref that holds this page table struct capref cap_pt; // capref that maps this page table in the higher level page table @@ -67,7 +65,9 @@ struct paging_state { // NOTE rueegges: remember if we are refilling so we can skip the checks uint8_t refilling; - // TODO rueegges: use to track an allocated slot in failure conditions + // NOTE rueegges: use to track an already allocated page table in failure conditions + struct capref free_l1_vnode; + struct capref free_l2_vnode; struct capref free_l3_vnode; // TODO rueegges: implement more precisely? diff --git a/lib/aos/paging.c b/lib/aos/paging.c index 837c997..760af07 100644 --- a/lib/aos/paging.c +++ b/lib/aos/paging.c @@ -29,7 +29,6 @@ static struct paging_state current; #define PT_PT_SLAB_INITIAL_SPACE SLAB_STATIC_SIZE(PT_PT_SLAB_MIN_SPACE, sizeof(struct pt_t)) #define PT_CHILDREN_SLAB_INITIAL_SPACE SLAB_STATIC_SIZE(PT_CHILDREN_SLAB_MIN_SPACE, BASE_PAGE_SIZE) -// NOTE rueegges: temporary (?) solution for initial slab space char pt_pt_slab_buf[PT_PT_SLAB_INITIAL_SPACE]; char pt_children_slab_buf[PT_CHILDREN_SLAB_INITIAL_SPACE]; @@ -102,20 +101,20 @@ void pt_print_state(struct paging_state *st) { // - this slab // - child slab // - mm slab -static errval_t pt_ensure_slots_and_slabs(struct paging_state *st) { +static errval_t pt_ensure_slabs(struct paging_state *st) { errval_t err; // ensure there is enough space to refill the page tables at any time if(slab_freecount(&st->pt_slabs) <= PT_PT_SLAB_MIN_SPACE && !st->refilling) { // ASSESSMENT M1: show refilling - // debug_printf("DEBUG rueegges: pt_ensure_slots_and_slabs - refilling pt_slab\n"); + // debug_printf("DEBUG rueegges: pt_ensure_slabs - refilling pt_slab\n"); st->refilling = 1; err = slab_default_refill(&st->pt_slabs); st->refilling = 0; - // debug_printf("DEBUG rueegges: pt_ensure_slots_and_slabs - refilling pt_slab DONE\n"); + // debug_printf("DEBUG rueegges: pt_ensure_slabs - refilling pt_slab DONE\n"); if(err_is_fail(err)) { return err_push(err, LIB_ERR_SLAB_REFILL); @@ -124,7 +123,7 @@ static errval_t pt_ensure_slots_and_slabs(struct paging_state *st) { if(slab_freecount(&st->pt_children_slabs) <= PT_CHILDREN_SLAB_MIN_SPACE && !st->refilling) { // ASSESSMENT M1: show refilling - // debug_printf("DEBUG rueegges: pt_ensure_slots_and_slabs - refilling pt_children_slabs\n"); + // debug_printf("DEBUG rueegges: pt_ensure_slabs - refilling pt_children_slabs\n"); st->refilling = 1; @@ -137,7 +136,7 @@ static errval_t pt_ensure_slots_and_slabs(struct paging_state *st) { err = slab_refill_no_pagefault(&st->pt_children_slabs, frame_cap, 10 * 4096); st->refilling = 0; - // debug_printf("DEBUG rueegges: pt_ensure_slots_and_slabs - refilling pt_children_slabs DONE\n"); + // debug_printf("DEBUG rueegges: pt_ensure_slabs - refilling pt_children_slabs DONE\n"); if(err_is_fail(err)) { return err_push(err, LIB_ERR_SLAB_REFILL); @@ -147,53 +146,83 @@ static errval_t pt_ensure_slots_and_slabs(struct paging_state *st) { return SYS_ERR_OK; } -// NOTE rueegges: ensures that a page table exists at the specified index in the parent page table and return it -static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_t pt_index, struct pt_t **pt_ret){ - // debug_printf("DEBUG rueegges: pt_ensure l%u\n", pt_parent->level+1); - +static errval_t pt_alloc_level(struct paging_state *st, struct capref *pt_cap, uint8_t level) { errval_t err; - // If this fails we got an l3 pt as the parent - assert(pt_parent->children != NULL); - assert(pt_parent->level < 3); - - // MUST DO before check if table already exists since it might create it - // make sure slot and slab refilling is performed in time - err = pt_ensure_slots_and_slabs(st); - if(err_is_fail(err)) { - DEBUG_ERR(err, "Could not restock slots and slabs"); - return err; - } - - // check if the page table already exists - struct pt_t *res = (pt_parent->children)[pt_index]; - if (res != NULL) { - *pt_ret = res; - return SYS_ERR_OK; - } - - // create the page table - struct capref pt_cap; - switch(pt_parent->level){ - case 0: - err = pt_alloc_l1(st, &pt_cap); - break; + switch(level){ case 1: - err = pt_alloc_l2(st, &pt_cap); + if(!capref_is_null(st->free_l1_vnode)){ + *pt_cap = st->free_l1_vnode; + st->free_l1_vnode = NULL_CAP; + err = SYS_ERR_OK; + } else { + err = pt_alloc_l1(st, pt_cap); + } break; case 2: - err = pt_alloc_l3(st, &pt_cap); + if(!capref_is_null(st->free_l2_vnode)){ + *pt_cap = st->free_l2_vnode; + st->free_l2_vnode = NULL_CAP; + err = SYS_ERR_OK; + } else { + err = pt_alloc_l2(st, pt_cap); + } + break; + case 3: + if(!capref_is_null(st->free_l3_vnode)){ + *pt_cap = st->free_l3_vnode; + st->free_l3_vnode = NULL_CAP; + err = SYS_ERR_OK; + } else { + err = pt_alloc_l3(st, pt_cap); + } break; default: err = ERR_INVALID_ARGS; break; } - if (err_is_fail(err)) { - DEBUG_ERR(err, "Failed pt_alloc l%u", pt_parent->level + 1); + + return err; +} + +static void pt_save_allocation(struct paging_state *st, struct capref cap, uint8_t level) { + switch(level){ + case 1: + assert(capref_is_null(st->free_l1_vnode)); + st->free_l1_vnode = cap; + break; + case 2: + assert(capref_is_null(st->free_l2_vnode)); + st->free_l2_vnode = cap; + break; + case 3: + assert(capref_is_null(st->free_l3_vnode)); + st->free_l3_vnode = cap; + break; + default: + assert(false); + break; + } +} + +// NOTE rueegges: ensures that a page table exists at the specified index in the parent page table and return it +static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_t pt_index, uint8_t level, struct pt_t **pt_ret){ + errval_t err; + struct pt_t *res; + + // debug_printf("DEBUG rueegges: pt_ensure l%u\n", pt_parent->level+1); + + // If this fails we got an l3 pt as the parent + assert(pt_parent->children != NULL); + assert(level > 0 && level <= 3); + + // MUST DO before check if table already exists since it might create it + // make sure slot and slab refilling is performed in time + err = pt_ensure_slabs(st); + if(err_is_fail(err)) { return err; } - // TODO rueegges: store the allocated pt // check if the page table already exists res = (pt_parent->children)[pt_index]; if (res != NULL) { @@ -201,77 +230,61 @@ static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_ return SYS_ERR_OK; } - // debug_printf("DEBUG rueegges: allocated pt l%u\n", pt_parent->level+1); - - // create new mapping - struct capref pt_mapping; - err = st->slot_alloc->alloc(st->slot_alloc, &pt_mapping); - if (err_is_fail(err)) - { - // NOTE rueegges: cannot free the pt allocated above since we do not have the ram cap - - DEBUG_ERR(err, "Failed slot alloc for new pt mapping"); + // create the page table + struct capref pt_cap; + err = pt_alloc_level(st, &pt_cap, level); + if (err_is_fail(err)) { + DEBUG_ERR(err, "Failed pt_alloc l%u", level); return err; } - err = vnode_map(pt_parent->cap_pt, pt_cap, pt_index, 0, 0, 1, pt_mapping); - if (err_is_fail(err)) - { - // free the already allocated capref - errval_t err_err = st->slot_alloc->free(st->slot_alloc, pt_mapping); - if (err_is_fail(err_err)) { - DEBUG_ERR(err_err, "Failed to free capability slot during error handling"); - } - // NOTE rueegges: cannot free the pt allocated above since we do not have the ram cap - - DEBUG_ERR(err, "Failed vnode_map for pt l%u", pt_parent->level + 1); - return err_push(err, LIB_ERR_VNODE_MAP); + // check if the page table already exists + res = (pt_parent->children)[pt_index]; + if (res != NULL) { + *pt_ret = res; + return SYS_ERR_OK; } - // debug_printf("DEBUG rueegges: inserted mapping for pt l%u\n", pt_parent->level+1); - // allocate shadow page table space struct pt_t *pt_meta = (struct pt_t *) slab_alloc(&st->pt_slabs); if(pt_meta == NULL) { - err = vnode_unmap(pt_cap, pt_mapping); - if (err_is_fail(err)) { - DEBUG_ERR(err, "Failed to unmap pt during error handling"); - } - - err = st->slot_alloc->free(st->slot_alloc, pt_mapping); - if (err_is_fail(err)) { - DEBUG_ERR(err, "Failed to free capability slot during error handling"); - } - - // NOTE rueegges: cannot free the pt allocated above since we do not have the ram cap - + pt_save_allocation(st, pt_cap, level); return LIB_ERR_SLAB_ALLOC_FAIL; } struct pt_t **pt_children = (struct pt_t **) slab_alloc(&st->pt_children_slabs); if(pt_children == NULL) { - err = vnode_unmap(pt_cap, pt_mapping); - if (err_is_fail(err)) { - DEBUG_ERR(err, "Failed to unmap pt during error handling"); - } + slab_free(&st->pt_slabs, pt_meta); + pt_save_allocation(st, pt_cap, level); + return LIB_ERR_SLAB_ALLOC_FAIL; + } - err = st->slot_alloc->free(st->slot_alloc, pt_mapping); - if (err_is_fail(err)) { - DEBUG_ERR(err, "Failed to free capability slot during error handling"); + // create new mapping + struct capref pt_mapping; + err = st->slot_alloc->alloc(st->slot_alloc, &pt_mapping); + if (err_is_fail(err)) { + slab_free(&st->pt_slabs, pt_meta); + slab_free(&st->pt_children_slabs, pt_children); + pt_save_allocation(st, pt_cap, level); + return err_push(err, LIB_ERR_SLOT_ALLOC); + } + err = vnode_map(pt_parent->cap_pt, pt_cap, pt_index, 0, 0, 1, pt_mapping); + if (err_is_fail(err)) { + errval_t err_err = st->slot_alloc->free(st->slot_alloc, pt_mapping); + 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); - - // NOTE rueegges: cannot free the pt allocated above since we do not have the ram cap - - return LIB_ERR_SLAB_ALLOC_FAIL; + slab_free(&st->pt_children_slabs, pt_children); + pt_save_allocation(st, pt_cap, level); + DEBUG_ERR(err, "Failed vnode_map for pt l%u", level); + return err_push(err, LIB_ERR_VNODE_MAP); } + + // save metadata // make sure all child pointers are initialized to NULL memset(pt_children, 0, st->pt_children_slabs.blocksize); - - // debug_printf("DEBUG rueegges: completed shadow allocation for pt l%u\n", pt_parent->level+1); - - pt_meta->level = pt_parent->level + 1; pt_meta->cap_pt = pt_cap; pt_meta->cap_mapping = pt_mapping; pt_meta->children = pt_children; @@ -306,9 +319,6 @@ errval_t paging_init_state(struct paging_state *st, lvaddr_t start_vaddr, assert(ca != NULL); - st->slot_alloc = ca; - st->refilling = 0; - // initialize slab allocators // TODO rueegges: is this how we should initialize the slab allocators? slab_init(&st->pt_slabs, sizeof(struct pt_t), NULL); @@ -331,11 +341,18 @@ errval_t paging_init_state(struct paging_state *st, lvaddr_t start_vaddr, // make sure all child pointers are initialized to NULL memset(l0_children, 0, st->pt_children_slabs.blocksize); - l0_pt->level = 0; l0_pt->cap_pt = pdir; + l0_pt->cap_mapping = NULL_CAP; l0_pt->children = l0_children; + 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->next_vaddr = start_vaddr; return SYS_ERR_OK; @@ -488,15 +505,13 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr, lvaddr_t end_vaddr = vaddr + bytes; assert(VADDR_OFFSET <= vaddr && vaddr < end_vaddr && end_vaddr <= VADDR_OFFSET + PTABLE_ENTRIES * PTABLE_ENTRIES *PTABLE_ENTRIES * PTABLE_ENTRIES * BASE_PAGE_SIZE); - - // consistentcy checks assert(st != NULL); assert(st->slot_alloc != NULL); - assert(st->l0_pt->level == 0); // debug_printf("DEBUG rueegges: paging_map_fixed_attr(%p, 0x%lx, cap, %lu, %d)\n", st, vaddr, bytes, flags); - // simple fix for now + // TODO rueegges: nicefy simple fix for mapping over multiple l3? + // TODO rueegges: cleanup partially completed mapping? for(lvaddr_t current_vaddr = vaddr; current_vaddr < vaddr + bytes; current_vaddr += BASE_PAGE_SIZE) { capaddr_t l0_index = VMSAv8_64_L0_INDEX(current_vaddr); capaddr_t l1_index = VMSAv8_64_L1_INDEX(current_vaddr); @@ -508,36 +523,32 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr, // get l1 page table struct pt_t *l1_pt; - err = pt_ensure(st, st->l0_pt, l0_index, &l1_pt); + err = pt_ensure(st, st->l0_pt, l0_index, 1, &l1_pt); if(err_is_fail(err)) { return err; } - assert(l1_pt->level == 1); assert(l1_pt->children != NULL); // get l2 page table struct pt_t *l2_pt; - err = pt_ensure(st, l1_pt, l1_index, &l2_pt); + err = pt_ensure(st, l1_pt, l1_index, 2, &l2_pt); if(err_is_fail(err)) { return err; } - assert(l2_pt->level == 2); assert(l2_pt->children != NULL); // get l3 page table struct pt_t *l3_pt; - err = pt_ensure(st, l2_pt, l2_index, &l3_pt); + err = pt_ensure(st, l2_pt, l2_index, 3, &l3_pt); if(err_is_fail(err)) { return err; } - assert(l3_pt->level == 3); assert(l3_pt->children != NULL); // make sure we have enough slot and slab space left - err = pt_ensure_slots_and_slabs(st); + err = pt_ensure_slabs(st); if(err_is_fail(err)) { - DEBUG_ERR(err, "Could not ensure presence of sufficient slabs and slots"); - return err; + return err_push(err, LIB_ERR_SLAB_REFILL); } // debug_printf("DEBUG rueegges: paging_map_fixed_attr - allocate mapping meta\n"); @@ -550,9 +561,6 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr, // set to null to indicate it is a frame mapping and not a page table mapping pt_entry->children = NULL; - // NOTE rueegges: we set this to 4 to indicate its an entry not a map to another - // table even though for superpages the level would be 3 - pt_entry->level = 4; // allocate the new mapping err = st->slot_alloc->alloc(st->slot_alloc, &pt_entry->cap_mapping); if (err_is_fail(err)) {