diff --git a/include/aos/core_state.h b/include/aos/core_state.h index d1ece50..be76c7e 100644 --- a/include/aos/core_state.h +++ b/include/aos/core_state.h @@ -41,6 +41,7 @@ struct ram_alloc_state { errval_t mem_connect_err; struct thread_mutex ram_alloc_lock; ram_alloc_func_t ram_alloc_func; + ram_free_func_t ram_free_func; uint64_t default_minbase; uint64_t default_maxlimit; int base_capnum; diff --git a/include/aos/paging_types.h b/include/aos/paging_types.h index 171a982..ad35644 100644 --- a/include/aos/paging_types.h +++ b/include/aos/paging_types.h @@ -77,11 +77,6 @@ struct paging_state { // NOTE rueegges: remember if we are refilling so we can skip the checks uint8_t refilling; - // 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; - struct pt_vaddr_reg_t vaddr_head; }; diff --git a/include/aos/ram_alloc.h b/include/aos/ram_alloc.h index 623422e..d7b9702 100644 --- a/include/aos/ram_alloc.h +++ b/include/aos/ram_alloc.h @@ -25,12 +25,14 @@ __BEGIN_DECLS struct capref; typedef errval_t (* ram_alloc_func_t)(struct capref *ret, size_t size, size_t alignment); +typedef errval_t (* ram_free_func_t)(struct capref cap); errval_t ram_alloc_fixed(struct capref *ret, size_t size, size_t alignment); errval_t ram_alloc_aligned(struct capref *ret, size_t size, size_t alignment); errval_t ram_alloc(struct capref *retcap, size_t size); +errval_t ram_free(struct capref cap); errval_t ram_available(genpaddr_t *available, genpaddr_t *total); -errval_t ram_alloc_set(ram_alloc_func_t local_allocator); +errval_t ram_alloc_set(ram_alloc_func_t local_allocator, ram_free_func_t local_free); void ram_set_affinity(uint64_t minbase, uint64_t maxlimit); void ram_get_affinity(uint64_t *minbase, uint64_t *maxlimit); void ram_alloc_init(void); diff --git a/lib/aos/init.c b/lib/aos/init.c index 7f3d2cb..afd03b4 100644 --- a/lib/aos/init.c +++ b/lib/aos/init.c @@ -123,7 +123,7 @@ errval_t barrelfish_init_onthread(struct spawn_domain_params *params) // Initialize ram_alloc state ram_alloc_init(); /* All domains use smallcn to initialize */ - err = ram_alloc_set(ram_alloc_fixed); + err = ram_alloc_set(ram_alloc_fixed, NULL); if (err_is_fail(err)) { return err_push(err, LIB_ERR_RAM_ALLOC_SET); } diff --git a/lib/aos/paging.c b/lib/aos/paging.c index e1dbf2e..2f4e7bf 100644 --- a/lib/aos/paging.c +++ b/lib/aos/paging.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "threads_priv.h" #include @@ -34,8 +35,8 @@ static struct paging_state current; * \brief Helper function that allocates a slot and * creates a aarch64 page table capability for a certain level */ -static errval_t pt_alloc(struct paging_state * st, enum objtype type, - struct capref *ret) +static errval_t pt_alloc(struct paging_state * st, enum objtype type, + struct capref *ret) { errval_t err; err = st->slot_alloc->alloc(st->slot_alloc, ret); @@ -61,11 +62,24 @@ __attribute__((unused)) static errval_t pt_alloc_l2(struct paging_state * st, st return pt_alloc(st, ObjType_VNode_AARCH64_l2, ret); } -__attribute__((unused)) static errval_t pt_alloc_l3(struct paging_state * st, struct capref *ret) +__attribute__((unused)) static errval_t pt_alloc_l3(struct paging_state * st, struct capref *ret) { return pt_alloc(st, ObjType_VNode_AARCH64_l3, ret); } +static errval_t pt_alloc_level(struct paging_state *st, struct capref *pt_cap, uint8_t level) { + switch(level){ + case 1: + return pt_alloc_l1(st, pt_cap); + case 2: + return pt_alloc_l2(st, pt_cap); + case 3: + return pt_alloc_l3(st, pt_cap); + default: + return ERR_INVALID_ARGS; + } +} + void pt_print_state(struct paging_state *st) { // iterates over all the page table entries and prints them debug_printf("L0\n"); @@ -88,11 +102,18 @@ void pt_print_state(struct paging_state *st) { for(size_t i3 = 0; i3 < PTABLE_ENTRIES; ++i3) { struct pt_t *l4_pt = l3_pt->children[i3]; if (l4_pt == NULL) continue; - debug_printf(" %lu -> Map\n", i3); + debug_printf(" %lu -> Map, size: %lu\n", i3, l4_pt->mapping_size); } } } } + + debug_printf("ranges:\n"); + struct pt_vaddr_reg_t *reg = &st->vaddr_head; + while (reg != NULL) { + debug_printf("- base=%lu, size=%lu, %s\n", reg->base, reg->size, reg->free ? "free" : "in use"); + reg = reg->next; + } } // NOTE rueegges: each paging fixed call can use up to 4 pt slabs, up to 3 children slabs and up to 7 slots @@ -107,7 +128,7 @@ static errval_t pt_ensure_slabs(struct paging_state *st) { if(slab_freecount(&st->pt_slabs) <= PT_PT_SLAB_MIN_SPACE && !st->refilling) { // ASSESSMENT M1: show refilling // debug_printf("DEBUG rueegges: pt_ensure_slabs - refilling pt_slab\n"); - + st->refilling = 1; err = slab_default_refill(&st->pt_slabs); @@ -119,19 +140,14 @@ static errval_t pt_ensure_slabs(struct paging_state *st) { return err_push(err, LIB_ERR_SLAB_REFILL); } } - + if(slab_freecount(&st->pt_children_slabs) <= PT_CHILDREN_SLAB_MIN_SPACE && !st->refilling) { // ASSESSMENT M1: show refilling // debug_printf("DEBUG rueegges: pt_ensure_slabs - refilling pt_children_slabs\n"); st->refilling = 1; - struct capref frame_cap; - err = st->slot_alloc->alloc(st->slot_alloc, &frame_cap); - if (err_is_fail(err)) { - return err_push(err, LIB_ERR_SLOT_ALLOC); - } - err = slab_refill_no_pagefault(&st->pt_children_slabs, frame_cap, LARGE_PAGE_SIZE); + err = slab_refill_pages(&st->pt_children_slabs, LARGE_PAGE_SIZE); st->refilling = 0; // debug_printf("DEBUG rueegges: pt_ensure_slabs - refilling pt_children_slabs DONE\n"); @@ -144,90 +160,27 @@ static errval_t pt_ensure_slabs(struct paging_state *st) { return SYS_ERR_OK; } -static errval_t pt_alloc_level(struct paging_state *st, struct capref *pt_cap, uint8_t level) { +// NOTE rueegges: ensures that a page table exists at the specified index in the parent page table +static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_t pt_index, uint8_t level){ errval_t err; - - switch(level){ - case 1: - 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: - 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; - } - - 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", level); - + // 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 + // check if the page table already exists + if (pt_parent->children[pt_index] != NULL) { + return SYS_ERR_OK; + } + // make sure slot and slab refilling is performed in time err = pt_ensure_slabs(st); if(err_is_fail(err)) { return err; } - // check if the page table already exists - res = pt_parent->children[pt_index]; - if (res != NULL) { - *pt_ret = res; - return SYS_ERR_OK; - } - // create the page table struct capref pt_cap; err = pt_alloc_level(st, &pt_cap, level); @@ -236,24 +189,17 @@ static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_ return err; } - // check again if the page table already exists - res = pt_parent->children[pt_index]; - if (res != NULL) { - *pt_ret = res; - return SYS_ERR_OK; - } - // allocate shadow page table space struct pt_t *pt_meta = (struct pt_t *) slab_alloc(&st->pt_slabs); if(pt_meta == NULL) { - pt_save_allocation(st, pt_cap, level); + ram_free(pt_cap); return LIB_ERR_SLAB_ALLOC_FAIL; } struct pt_t **pt_children = (struct pt_t **) slab_alloc(&st->pt_children_slabs); if(pt_children == NULL) { slab_free(&st->pt_slabs, pt_meta); - pt_save_allocation(st, pt_cap, level); + ram_free(pt_cap); return LIB_ERR_SLAB_ALLOC_FAIL; } @@ -263,9 +209,22 @@ static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_ 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); + ram_free(pt_cap); return err_push(err, LIB_ERR_SLOT_ALLOC); } + + // check again if the page table already exists + if (pt_parent->children[pt_index] != NULL) { + 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); + slab_free(&st->pt_children_slabs, pt_children); + ram_free(pt_cap); + return SYS_ERR_OK; + } + 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); @@ -274,7 +233,7 @@ static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_ } slab_free(&st->pt_slabs, pt_meta); slab_free(&st->pt_children_slabs, pt_children); - pt_save_allocation(st, pt_cap, level); + ram_free(pt_cap); DEBUG_ERR(err, "Failed vnode_map for pt l%u", level); return err_push(err, LIB_ERR_VNODE_MAP); } @@ -288,17 +247,15 @@ static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_ pt_parent->children[pt_index] = pt_meta; - *pt_ret = pt_meta; - return SYS_ERR_OK; } /** - * TODO(M2): Implement this function. + * (M2): Implement this function. * TODO(M4): Improve this function. * \brief Initialize the paging_state struct for the paging * state of the calling process. - * + * * \param st The struct to be initialized, must not be NULL. * \param start_vaddr Virtual address allocation should start at * this address. @@ -310,7 +267,7 @@ static errval_t pt_ensure(struct paging_state *st, struct pt_t *pt_parent, size_ errval_t paging_init_state(struct paging_state *st, lvaddr_t start_vaddr, struct capref pdir, struct slot_allocator *ca) { - // TODO (M2): Implement state struct initialization + // (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. @@ -330,23 +287,19 @@ errval_t paging_init_state(struct paging_state *st, lvaddr_t 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->refilling = 0; - - st->free_l1_vnode = NULL_CAP; - st->free_l2_vnode = NULL_CAP; - st->free_l3_vnode = NULL_CAP; return SYS_ERR_OK; } /** - * TODO(M2): Implement this function. + * (M2): Implement this function. * TODO(M4): Improve this function. * \brief Initialize the paging_state struct for the paging state * of a child process. - * + * * \param st The struct to be initialized, must not be NULL. * \param start_vaddr Virtual address allocation should start at * this address. @@ -359,7 +312,7 @@ 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 + // (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. struct capref pt_cap; @@ -384,7 +337,7 @@ errval_t paging_init(void) { errval_t err; debug_printf("paging_init\n"); - // TODO (M2): Call paging_init_state for ¤t + // (M2): Call paging_init_state for ¤t // TODO (M4): initialize self-paging handler // TIP: use thread_set_exception_handler() to setup a page fault handler // TIP: Think about the fact that later on, you'll have to make sure that @@ -425,7 +378,7 @@ static errval_t paging_insert_vaddr_reg(struct paging_state *st, struct pt_vaddr assert(target_region->free); assert(target_region->size >= prefix_size + alloc_size); - // calculate the number of bytes that are left overafter the region + // calculate the number of bytes that are left over after the region size_t postfix_size = target_region->size - prefix_size - alloc_size; struct pt_vaddr_reg_t *prefix_reg = NULL; @@ -481,7 +434,6 @@ static errval_t paging_insert_vaddr_reg(struct paging_state *st, struct pt_vaddr } return SYS_ERR_OK; - } @@ -501,7 +453,7 @@ errval_t paging_alloc(struct paging_state *st, void **buf, size_t bytes, size_t errval_t err; /** - * TODO(M2): Implement this function + * (M2): Implement this function * - Find a region of free virtual address space that is large enough to * accomodate a buffer of size `bytes`. */ @@ -523,7 +475,7 @@ errval_t paging_alloc(struct paging_state *st, void **buf, size_t bytes, size_t 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) { @@ -534,7 +486,7 @@ errval_t paging_alloc(struct paging_state *st, void **buf, size_t bytes, size_t } *buf = (void *) (vaddr_reg->base + prefix_size); - + return SYS_ERR_OK; } vaddr_reg = vaddr_reg -> next; @@ -560,7 +512,7 @@ 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): + // (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 // - return the virtual address in the buf parameter @@ -599,9 +551,9 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr, { errval_t err; /* - * TODO(M1): + * (M1): * - Map a frame assuming all mappings will fit into one leaf page table (L3) - * TODO(M2): + * (M2): * - General case: you will need to handle mappings spanning multiple leaf page tables. * - Make sure to update your paging state to reflect the newly mapped region * @@ -610,9 +562,10 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr, */ // preconditions + assert(vaddr % BASE_PAGE_SIZE == 0); assert(bytes % BASE_PAGE_SIZE == 0); lvaddr_t end_vaddr = vaddr + bytes; - assert(end_vaddr <= VADDR_OFFSET + PTABLE_ENTRIES * PTABLE_ENTRIES *PTABLE_ENTRIES * PTABLE_ENTRIES * BASE_PAGE_SIZE); + assert(end_vaddr <= PTABLE_ENTRIES * PTABLE_ENTRIES *PTABLE_ENTRIES * PTABLE_ENTRIES * BASE_PAGE_SIZE); assert(st != NULL); assert(st->slot_alloc != NULL); @@ -641,13 +594,15 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr, 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) { + if(vaddr_reg->base <= vaddr && end_vaddr <= vaddr_reg->base + vaddr_reg->size) { if (vaddr_reg->free == true) { // 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; } + } else if (!(vaddr_reg->base == vaddr && end_vaddr == vaddr_reg->base + vaddr_reg->size)) { + return LIB_ERR_PMAP_ADDR_NOT_FREE; } break; } @@ -658,39 +613,41 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr, // 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) { + for(lvaddr_t current_vaddr = vaddr; current_vaddr < end_vaddr; 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); + mapping_size = MIN(PTABLE_ENTRIES - l3_index, (end_vaddr - current_vaddr) / BASE_PAGE_SIZE); // get l1 page table - struct pt_t *l1_pt; - err = pt_ensure(st, l0_pt, l0_index, 1, &l1_pt); + err = pt_ensure(st, l0_pt, l0_index, 1); if(err_is_fail(err)) { return err; } + struct pt_t *l1_pt = l0_pt->children[l0_index]; assert(l1_pt->children != NULL); // get l2 page table - struct pt_t *l2_pt; - err = pt_ensure(st, l1_pt, l1_index, 2, &l2_pt); + err = pt_ensure(st, l1_pt, l1_index, 2); if(err_is_fail(err)) { return err; } + struct pt_t *l2_pt = l1_pt->children[l1_index]; assert(l2_pt->children != NULL); // get l3 page table - struct pt_t *l3_pt; - err = pt_ensure(st, l2_pt, l2_index, 3, &l3_pt); + err = pt_ensure(st, l2_pt, l2_index, 3); if(err_is_fail(err)) { return err; } + struct pt_t *l3_pt = l2_pt->children[l2_index]; assert(l3_pt->children != NULL); + assert(l3_pt->children[l3_index] == NULL); + // debug_printf("DEBUG rueegges: paging_map_fixed_attr - allocate mapping meta\n"); // make sure we have enough slot and slab space left @@ -731,8 +688,8 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr, // add the new page table metadata to the shadow tables l3_pt->children[l3_index] = pt_entry; } - - // debug_printf("DEBUG rueegges: paging_map_fixed_attr - success\n"); + + // debug_printf("DEBUG rueegges: paging_map_fixed_attr - success\n"); return SYS_ERR_OK; } @@ -752,5 +709,73 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr, */ errval_t paging_unmap(struct paging_state *st, const void *region) { - return LIB_ERR_NOT_IMPLEMENTED; + errval_t err; + lvaddr_t vaddr = (lvaddr_t)region; + assert(vaddr % BASE_PAGE_SIZE == 0); + + struct pt_vaddr_reg_t *prev_reg = NULL; + struct pt_vaddr_reg_t *vaddr_reg = &st->vaddr_head; + for (; vaddr_reg != NULL; vaddr_reg = vaddr_reg->next) { + if (vaddr_reg->base == vaddr && !vaddr_reg->free) { + break; + } + prev_reg = vaddr_reg; + } + if (vaddr_reg == NULL) { + return LIB_ERR_PMAP_NOT_MAPPED; + } + + struct pt_t *l0_pt = &st->l0_pt; + assert(l0_pt->children != NULL); + + lvaddr_t end_vaddr = vaddr + vaddr_reg->size; + size_t mapping_size; + for (lvaddr_t current_vaddr = vaddr; current_vaddr < end_vaddr; 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); + + mapping_size = MIN(PTABLE_ENTRIES - l3_index, (end_vaddr - current_vaddr) / BASE_PAGE_SIZE); + + struct pt_t *l1_pt = l0_pt->children[l0_index]; + assert(l1_pt->children != NULL); + + struct pt_t *l2_pt = l1_pt->children[l1_index]; + assert(l2_pt->children != NULL); + + struct pt_t *l3_pt = l2_pt->children[l2_index]; + assert(l3_pt->children != NULL); + + struct pt_t *pt_entry = l3_pt->children[l3_index]; + assert(pt_entry != NULL); + + err = cap_delete(pt_entry->cap_mapping); + if (err_is_fail(err)) return err_push(err, LIB_ERR_VNODE_UNMAP); + + err = st->slot_alloc->free(st->slot_alloc, pt_entry->cap_mapping); + if (err_is_fail(err)) return err_push(err, LIB_ERR_SLOT_FREE); + + l3_pt->children[l3_index] = NULL; + slab_free(&st->pt_slabs, pt_entry); + } + + vaddr_reg->free = true; + + // Merge free regions + if (prev_reg != NULL && prev_reg->free && prev_reg->base + prev_reg->size == vaddr_reg->base) { + prev_reg->size += vaddr_reg->size; + prev_reg->next = vaddr_reg->next; + slab_free(&st->pt_slabs, vaddr_reg); + vaddr_reg = prev_reg; + } + + struct pt_vaddr_reg_t *next_reg = vaddr_reg->next; + if (next_reg != NULL && next_reg->free && vaddr_reg->base + vaddr_reg->size == next_reg->base) { + vaddr_reg->size += next_reg->size; + vaddr_reg->next = next_reg->next; + slab_free(&st->pt_slabs, next_reg); + } + + return SYS_ERR_OK; } diff --git a/lib/aos/ram_alloc.c b/lib/aos/ram_alloc.c index 9aac225..abfa4cc 100644 --- a/lib/aos/ram_alloc.c +++ b/lib/aos/ram_alloc.c @@ -97,6 +97,22 @@ errval_t ram_alloc(struct capref *ret, size_t size) return ram_alloc_aligned(ret, size, BASE_PAGE_SIZE); } +/** + * \brief Frees allocated memory + * + * \param cap A capability whose memory was allocated with ram_alloc. + * It will be destroyed by this function. + */ +errval_t ram_free(struct capref cap) +{ + struct ram_alloc_state *ram_alloc_state = get_ram_alloc_state(); + if (ram_alloc_state->ram_free_func == NULL) { + debug_printf("WARN: cannot free RAM, not supported by current allocator\n"); + return SYS_ERR_OK; + } + return ram_alloc_state->ram_free_func(cap); +} + errval_t ram_available(genpaddr_t *available, genpaddr_t *total) { // TODO: Implement protocol to check amount of ram available with memserv @@ -114,6 +130,7 @@ void ram_alloc_init(void) ram_alloc_state->mem_connect_err = 0; thread_mutex_init(&ram_alloc_state->ram_alloc_lock); ram_alloc_state->ram_alloc_func = NULL; + ram_alloc_state->ram_free_func = NULL; ram_alloc_state->default_minbase = 0; ram_alloc_state->default_maxlimit = 0; ram_alloc_state->base_capnum = 0; @@ -125,16 +142,18 @@ void ram_alloc_init(void) * If local_allocator is NULL, it will be initialized to the default * remote allocator. */ -errval_t ram_alloc_set(ram_alloc_func_t local_allocator) +errval_t ram_alloc_set(ram_alloc_func_t local_allocator, ram_free_func_t local_free) { struct ram_alloc_state *ram_alloc_state = get_ram_alloc_state(); /* Special case */ if (local_allocator != NULL) { ram_alloc_state->ram_alloc_func = local_allocator; + ram_alloc_state->ram_free_func = local_free; return SYS_ERR_OK; } ram_alloc_state->ram_alloc_func = ram_alloc_remote; + ram_alloc_state->ram_free_func = NULL; return SYS_ERR_OK; } diff --git a/lib/aos/slab.c b/lib/aos/slab.c index 16dbc04..51dc7c3 100644 --- a/lib/aos/slab.c +++ b/lib/aos/slab.c @@ -228,6 +228,7 @@ errval_t slab_refill_no_pagefault(struct slab_allocator *slabs, struct capref fr alloc_bytes, frame, VREGION_FLAGS_READ_WRITE ); if (err_is_fail(err)) { + // TODO: free the RAM, but without freeing the frame slot cap_delete(frame); return err; } diff --git a/lib/mm/mm.c b/lib/mm/mm.c index 26948da..d470880 100644 --- a/lib/mm/mm.c +++ b/lib/mm/mm.c @@ -232,7 +232,6 @@ errval_t mm_free(struct mm *mm, struct capref cap) struct capability c; err = cap_direct_identify(cap, &c); if (err_is_fail(err)) return err; - assert(c.type == mm->objtype); genpaddr_t base = get_address(&c); assert(base != 0 && base % BASE_PAGE_SIZE == 0); gensize_t size = get_size(&c); diff --git a/lib/spawn/spawn.c b/lib/spawn/spawn.c index 72a775f..3a3f287 100644 --- a/lib/spawn/spawn.c +++ b/lib/spawn/spawn.c @@ -49,10 +49,14 @@ static void armv8_set_registers(void *arch_load_info, +struct temp_mapping { + struct temp_mapping *next; + void *addr; +}; struct allocate_state { - // TODO: add fields struct paging_state *paging_state; + struct temp_mapping *temp_mapping_head; }; static errval_t elf_allocate( @@ -86,7 +90,6 @@ static errval_t elf_allocate( alloc_bytes, frame, VREGION_FLAGS_READ_WRITE ); if (err_is_fail(err)) return err; - *ret += base - sv; // translate elf flags to paging flags uint32_t paging_flags = 0; @@ -104,7 +107,14 @@ static errval_t elf_allocate( if (err_is_fail(err)) return err; - // TODO: Keep track of the mapped regions, so you can unmap them later. + // Keep track of the mapped regions, so you can unmap them later. + struct temp_mapping *tm = malloc(sizeof(struct temp_mapping)); + if (tm == NULL) return LIB_ERR_MALLOC_FAIL; + tm->next = st->temp_mapping_head; + tm->addr = *ret; + st->temp_mapping_head = tm; + + *ret += base - sv; return SYS_ERR_OK; } @@ -238,6 +248,7 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si, // - Load the ELF binary struct allocate_state st = { .paging_state = &child_paging_state, + .temp_mapping_head = NULL, }; genvaddr_t entry; err = elf_load(EM_AARCH64, elf_allocate, &st, (lvaddr_t)elf_base, elf_bytes, &entry); @@ -250,6 +261,22 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si, got_addr = got_shdr->sh_addr; } + debug_printf("SPAWN: self paging state after loading:\n"); + pt_print_state(get_current_paging_state()); + + err = paging_unmap(get_current_paging_state(), elf_base); + if (err_is_fail(err)) return err_push(err, LIB_ERR_PMAP_UNMAP); + while (st.temp_mapping_head != NULL) { + struct temp_mapping *tm = st.temp_mapping_head; + err = paging_unmap(get_current_paging_state(), tm->addr); + if (err_is_fail(err)) return err_push(err, LIB_ERR_PMAP_UNMAP); + st.temp_mapping_head = tm->next; + free(tm); + } + + debug_printf("SPAWN: self paging state after unmapping:\n"); + pt_print_state(get_current_paging_state()); + // - Setup the dispatcher err = frame_create(si->cspace_cap_dispframe, DISPATCHER_FRAME_SIZE, NULL); if (err_is_fail(err)) { @@ -353,6 +380,12 @@ errval_t spawn_load_argv(int argc, char *argv[], struct spawninfo *si, // afeer: script page 104: set the first register registers_set_param(enabled_area, (uint64_t) arguments_page_in_child); + err = paging_unmap(get_current_paging_state(), (void *)handle); + if (err_is_fail(err)) return err_push(err, LIB_ERR_PMAP_UNMAP); + + err = paging_unmap(get_current_paging_state(), arguments_page_in_self); + if (err_is_fail(err)) return err_push(err, LIB_ERR_PMAP_UNMAP); + // - Make the new dispatcher runnable err = invoke_dispatcher( si->dispatcher, cap_dispatcher, diff --git a/usr/init/mem_alloc.c b/usr/init/mem_alloc.c index cd8b01c..53f2827 100644 --- a/usr/init/mem_alloc.c +++ b/usr/init/mem_alloc.c @@ -71,7 +71,7 @@ errval_t initialize_ram_alloc(void) // Initialize the generic RAM allocator to use our local allocator. // We do this here, because mm_add allocates memory for the slab allocator, // and that uses ram_alloc. - err = ram_alloc_set(aos_ram_alloc_aligned); + err = ram_alloc_set(aos_ram_alloc_aligned, aos_ram_free); if (err_is_fail(err)) { return err_push(err, LIB_ERR_RAM_ALLOC_SET); }