diff --git a/include/aos/paging_types.h b/include/aos/paging_types.h index f1a927e..273f9f6 100644 --- a/include/aos/paging_types.h +++ b/include/aos/paging_types.h @@ -18,6 +18,7 @@ #include #define VADDR_OFFSET ((lvaddr_t)512UL*1024*1024*1024) // 1GB +#define VADDR_SIZE (1UL << 48) #define VREGION_FLAGS_READ 0x01 // Reading allowed #define VREGION_FLAGS_WRITE 0x02 // Writing allowed #define VREGION_FLAGS_EXECUTE 0x04 // Execute allowed @@ -51,6 +52,14 @@ struct pt_t { struct pt_t **children; }; +// NOTE rueegges: store information about a region of virtual address space +struct pt_vaddr_reg_t { + lvaddr_t base; + size_t size; + uint8_t free; + struct pt_vaddr_reg_t *next; +}; + // struct to store the paging status of a process struct paging_state { struct slot_allocator *slot_alloc; @@ -71,7 +80,7 @@ struct paging_state { struct capref free_l3_vnode; // TODO rueegges: implement more precisely? - lvaddr_t next_vaddr; + struct pt_vaddr_reg_t *vaddr_head; }; diff --git a/lib/aos/paging.c b/lib/aos/paging.c index 760af07..1eb0703 100644 --- a/lib/aos/paging.c +++ b/lib/aos/paging.c @@ -23,12 +23,14 @@ static struct paging_state current; -#define PT_PT_SLAB_MIN_SPACE 16 +#define PT_PT_SLAB_MIN_SPACE 18 #define PT_CHILDREN_SLAB_MIN_SPACE 12 -#define PT_PT_SLAB_INITIAL_SPACE SLAB_STATIC_SIZE(PT_PT_SLAB_MIN_SPACE, sizeof(struct pt_t)) +#define PT_META_MAX_SIZE MAX(sizeof(struct pt_t), sizeof(struct pt_vaddr_reg_t)) +#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]; @@ -321,12 +323,12 @@ errval_t paging_init_state(struct paging_state *st, lvaddr_t start_vaddr, // initialize slab allocators // TODO rueegges: is this how we should initialize the slab allocators? - slab_init(&st->pt_slabs, sizeof(struct pt_t), NULL); + 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 pages + // 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"); @@ -345,6 +347,19 @@ errval_t paging_init_state(struct paging_state *st, lvaddr_t start_vaddr, l0_pt->cap_mapping = NULL_CAP; l0_pt->children = l0_children; + // 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->slot_alloc = ca; st->l0_pt = l0_pt; st->refilling = 0; @@ -353,7 +368,7 @@ errval_t paging_init_state(struct paging_state *st, lvaddr_t start_vaddr, st->free_l2_vnode = NULL_CAP; st->free_l3_vnode = NULL_CAP; - st->next_vaddr = start_vaddr; + st->vaddr_head = vaddr_reg; return SYS_ERR_OK; } @@ -421,6 +436,70 @@ errval_t paging_init_onthread(struct thread *t) } +static errval_t paging_insert_vaddr_reg(struct paging_state *st, struct pt_vaddr_reg_t *target_region, size_t prefix_size, size_t alloc_size) +{ + assert(target_region->free); + assert(target_region->size >= prefix_size + alloc_size); + + // calculate the number of bytes that are left overafter the region + size_t postfix_size = target_region->size - prefix_size - alloc_size; + + struct pt_vaddr_reg_t *prefix_reg = NULL; + struct pt_vaddr_reg_t *main_reg = NULL; + struct pt_vaddr_reg_t *postfix_reg = NULL; + + if (prefix_size > 0) { + prefix_reg = target_region; + main_reg = slab_alloc(&st->pt_slabs); + if (main_reg == NULL) { + return LIB_ERR_SLAB_ALLOC_FAIL; + } + } else { + main_reg = target_region; + } + if (postfix_size > 0) { + postfix_reg = slab_alloc(&st->pt_slabs); + if (postfix_reg == NULL) { + if (prefix_size > 0) { + slab_free(&st->pt_slabs, main_reg); + } + return LIB_ERR_SLAB_ALLOC_FAIL; + } + } + + size_t base = target_region->base; + + // update vaddr metadata structure + if (prefix_size > 0) { + prefix_reg->base = base; + prefix_reg->size = prefix_size; + prefix_reg->free = true; + + main_reg->next = prefix_reg->next; + prefix_reg->next = main_reg; + + base += prefix_size; + } + + main_reg->base = base; + main_reg->size = alloc_size; + main_reg->free = false; + + base += alloc_size; + + if (postfix_size > 0) { + postfix_reg->base = base; + postfix_reg->size = postfix_size; + postfix_reg->free = true; + + postfix_reg->next = main_reg->next; + main_reg->next = postfix_reg; + } + + return SYS_ERR_OK; + +} + /** * @brief Find a free region of virtual address space that is large enough to accomodate a @@ -435,14 +514,49 @@ errval_t paging_init_onthread(struct thread *t) */ errval_t paging_alloc(struct paging_state *st, void **buf, size_t bytes, size_t alignment) { + errval_t err; + /** * TODO(M2): Implement this function * - Find a region of free virtual address space that is large enough to * accomodate a buffer of size `bytes`. */ + + assert(buf != NULL); + if ((alignment & (alignment - 1)) != 0) { + return LIB_ERR_VREGION_BAD_ALIGNMENT; + } + *buf = NULL; - return LIB_ERR_NOT_IMPLEMENTED; + // start by allocating the new metadata space so we don't have to after checking the state + err = pt_ensure_slabs(st); + if (err_is_fail(err)) { + return err; + } + + 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; + + // check if it is a free region of sufficient size + if (vaddr_reg->free && vaddr_reg->size >= prefix_size + bytes) { + + // allocate the new region, potentially splitting off a prefix and postfix from the region + err = paging_insert_vaddr_reg(st, vaddr_reg, prefix_size, bytes); + if (err_is_fail(err)) { + return err; + } + + *buf = (void *) (vaddr_reg->base + prefix_size); + + return SYS_ERR_OK; + } + vaddr_reg = vaddr_reg -> next; + } + + return LIB_ERR_OUT_OF_VIRTUAL_ADDR; } @@ -461,6 +575,7 @@ errval_t paging_alloc(struct paging_state *st, void **buf, size_t bytes, size_t errval_t paging_map_frame_attr(struct paging_state *st, void **buf, size_t bytes, struct capref frame, int flags) { + errval_t err; // TODO(M2): // - Find and allocate free region of virtual address space of at least bytes in size. // - Map the user provided frame at the free virtual address @@ -469,7 +584,17 @@ errval_t paging_map_frame_attr(struct paging_state *st, void **buf, size_t bytes // Hint: // - think about what mapping configurations are actually possible - return LIB_ERR_NOT_IMPLEMENTED; + // we can only map full pages + assert(bytes % BASE_PAGE_SIZE == 0); + + // get address space to map to + err = paging_alloc(st, buf, bytes, BASE_PAGE_SIZE); + if (err_is_fail(err)) { + return err; + } + + // map the virtual space to the given frame + return paging_map_fixed_attr(st, (lvaddr_t) *buf, frame, bytes, flags); } @@ -508,16 +633,46 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr, assert(st != NULL); assert(st->slot_alloc != 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; + while(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) { + if (vaddr_reg->size >= bytes && vaddr_reg->free == 0) { + // this region was probably allocated with paging_alloc beforehand and that is ok + } else { + // make sure the virtual memory is not used by anyone else + err = paging_insert_vaddr_reg(st, vaddr_reg, vaddr - vaddr_reg->base, bytes); + if (err_is_fail(err)) { + return err; + } + } + break; + } + } + 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: 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) { + + size_t mapping_size; + for(lvaddr_t current_vaddr = vaddr; current_vaddr < vaddr + bytes; current_vaddr += mapping_size * BASE_PAGE_SIZE) { capaddr_t l0_index = VMSAv8_64_L0_INDEX(current_vaddr); capaddr_t l1_index = VMSAv8_64_L1_INDEX(current_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); @@ -556,6 +711,7 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr, // 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; } @@ -569,8 +725,6 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr, // debug_printf("DEBUG rueegges: paging_map_fixed_attr - add new mapping\n"); // create the new mapping - size_t mapping_size = 1; - // if (mapping_size * BASE_PAGE_SIZE < bytes) ++mapping_size; // debug_printf("DEBUG rueegges: vnode_map(ll_pt, frame, %u, %d, %lu, %lu, cap_mapping)\n", l3_index, flags, 0, mapping_size); 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)) { diff --git a/lib/aos/slab.c b/lib/aos/slab.c index 2e5d0e7..16dbc04 100644 --- a/lib/aos/slab.c +++ b/lib/aos/slab.c @@ -222,19 +222,17 @@ errval_t slab_refill_no_pagefault(struct slab_allocator *slabs, struct capref fr if (err_is_fail(err)) return err_push(err, LIB_ERR_FRAME_ALLOC); struct paging_state *paging_state = get_current_paging_state(); - lvaddr_t vaddr = paging_state->next_vaddr; - paging_state->next_vaddr += alloc_bytes; - - err = paging_map_fixed_attr( - paging_state, vaddr, - frame, alloc_bytes, VREGION_FLAGS_READ_WRITE + void *vaddr = NULL; + err = paging_map_frame_attr( + paging_state, &vaddr, + alloc_bytes, frame, VREGION_FLAGS_READ_WRITE ); if (err_is_fail(err)) { cap_delete(frame); return err; } - slab_grow(slabs, (void *)vaddr, alloc_bytes); + slab_grow(slabs, vaddr, alloc_bytes); return SYS_ERR_OK; } diff --git a/lib/grading/grading.c b/lib/grading/grading.c index 6bd5572..6f86014 100644 --- a/lib/grading/grading.c +++ b/lib/grading/grading.c @@ -45,13 +45,12 @@ static void *alloc_frame(size_t bytes, size_t alignment, check_err(cap_retype(*frame_cap_ret, *ram_cap_ret, 0, ObjType_Frame, bytes, 1)); struct paging_state *paging_state = get_current_paging_state(); - lvaddr_t vaddr = paging_state->next_vaddr; - paging_state->next_vaddr += bytes; - check_err(paging_map_fixed_attr( - paging_state, vaddr, - *frame_cap_ret, bytes, VREGION_FLAGS_READ_WRITE + void *vaddr; + check_err(paging_map_frame_attr( + paging_state, &vaddr, + bytes, *frame_cap_ret, VREGION_FLAGS_READ_WRITE )); - return (void *)vaddr; + return vaddr; } void diff --git a/lib/mm/mm.c b/lib/mm/mm.c index 882ba7a..26948da 100644 --- a/lib/mm/mm.c +++ b/lib/mm/mm.c @@ -133,7 +133,7 @@ errval_t mm_alloc_aligned(struct mm *mm, size_t size, size_t alignment, struct c return MM_ERR_OUT_OF_RAM; } - err = slot_alloc(retcap); + err = slot_alloc(retcap);/* condition */ if (err_is_fail(err)) return err_push(err, LIB_ERR_SLOT_ALLOC); // Find a suitable range of free RAM