diff --git a/include/aos/paging_types.h b/include/aos/paging_types.h index e96431d..717cf20 100644 --- a/include/aos/paging_types.h +++ b/include/aos/paging_types.h @@ -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; }; diff --git a/lib/aos/paging.c b/lib/aos/paging.c index 76efae7..a831d45 100644 --- a/lib/aos/paging.c +++ b/lib/aos/paging.c @@ -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,8 +208,8 @@ 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); assert(level > 0 && level <= 3); @@ -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(¤t, 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(¤t.pt_slabs, pt_pt_slab_buf, PT_PT_SLAB_INITIAL_SPACE); + slab_grow(¤t.pt_children_slabs, pt_children_slab_buf, PT_CHILDREN_SLAB_INITIAL_SPACE); + set_current_paging_state(¤t); 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) { @@ -653,9 +657,6 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr, if (vaddr_reg == NULL) { 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; @@ -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; } diff --git a/lib/grading/test_paging.c b/lib/grading/test_paging.c index e50ca2e..cf9e38a 100644 --- a/lib/grading/test_paging.c +++ b/lib/grading/test_paging.c @@ -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; + } }