Merge rueegges paging into jschaer code
This commit is contained in:
parent
070111da22
commit
292ca0b63b
@ -126,4 +126,7 @@ static inline lvaddr_t paging_genvaddr_to_lvaddr(genvaddr_t genvaddr) {
|
|||||||
return (lvaddr_t) genvaddr;
|
return (lvaddr_t) genvaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE rueegges: added debug helper
|
||||||
|
void pt_print_state(struct paging_state *st);
|
||||||
|
|
||||||
#endif // LIBBARRELFISH_PAGING_H
|
#endif // LIBBARRELFISH_PAGING_H
|
||||||
|
|||||||
@ -38,15 +38,39 @@
|
|||||||
typedef int paging_flags_t;
|
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
|
||||||
|
struct capref cap_mapping;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
struct pt_t **children;
|
||||||
|
};
|
||||||
|
|
||||||
// struct to store the paging status of a process
|
// struct to store the paging status of a process
|
||||||
struct paging_state {
|
struct paging_state {
|
||||||
struct slot_allocator *slot_alloc;
|
struct slot_allocator *slot_alloc;
|
||||||
struct capref l0_vnode;
|
|
||||||
struct capref l2_vnode;
|
// NOTE rueegges: added to keep track of pt metadata
|
||||||
struct capref l3_vnodes[PTABLE_ENTRIES];
|
struct pt_t *l0_pt;
|
||||||
|
|
||||||
|
// NOTE rueegges: added to allocate shadow page table metadata
|
||||||
|
struct slab_allocator pt_slabs;
|
||||||
|
struct slab_allocator pt_children_slabs;
|
||||||
|
|
||||||
|
// 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
|
||||||
struct capref free_l3_vnode;
|
struct capref free_l3_vnode;
|
||||||
|
|
||||||
|
// TODO rueegges: implement more precisely?
|
||||||
lvaddr_t next_vaddr;
|
lvaddr_t next_vaddr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
15
include/test_mm.h
Normal file
15
include/test_mm.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef __TEST_MM_H
|
||||||
|
#define __TEST_MM_H
|
||||||
|
|
||||||
|
#include <aos/aos.h>
|
||||||
|
#include <mm/mm.h>
|
||||||
|
|
||||||
|
uint8_t test_mm_run(errval_t func(struct mm *), char *name, struct mm *mm);
|
||||||
|
errval_t test_mm_small(struct mm *mm);
|
||||||
|
errval_t test_mm_track_slots(struct mm *mm);
|
||||||
|
errval_t test_mm_fragments(struct mm *mm);
|
||||||
|
errval_t test_mm_rand(struct mm *mm);
|
||||||
|
errval_t test_mm_many(struct mm *mm);
|
||||||
|
errval_t test_mm_oom(struct mm *mm);
|
||||||
|
|
||||||
|
#endif /* __TEST_MM_H */
|
||||||
11
include/test_paging.h
Normal file
11
include/test_paging.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef __PAGING_TESTS_H
|
||||||
|
#define __PAGING_TESTS_H
|
||||||
|
|
||||||
|
#include <aos/aos.h>
|
||||||
|
|
||||||
|
uint8_t test_paging_run(errval_t func(void), char *name);
|
||||||
|
errval_t test_paging_full_l3(void);
|
||||||
|
errval_t test_paging_full_l2(void);
|
||||||
|
errval_t test_paging_big_regions(void);
|
||||||
|
|
||||||
|
#endif /* __PAGING_TESTS_H */
|
||||||
445
lib/aos/paging.c
445
lib/aos/paging.c
@ -23,14 +23,22 @@
|
|||||||
|
|
||||||
static struct paging_state current;
|
static struct paging_state current;
|
||||||
|
|
||||||
|
#define PT_PT_SLAB_MIN_SPACE 16
|
||||||
|
#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_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];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Helper function that allocates a slot and
|
* \brief Helper function that allocates a slot and
|
||||||
* creates a aarch64 page table capability for a certain level
|
* creates a aarch64 page table capability for a certain level
|
||||||
*/
|
*/
|
||||||
static errval_t pt_alloc(struct paging_state * st, enum objtype type,
|
static errval_t pt_alloc(struct paging_state * st, enum objtype type,
|
||||||
struct capref *ret)
|
struct capref *ret)
|
||||||
{
|
{
|
||||||
errval_t err;
|
errval_t err;
|
||||||
err = st->slot_alloc->alloc(st->slot_alloc, ret);
|
err = st->slot_alloc->alloc(st->slot_alloc, ret);
|
||||||
@ -56,18 +64,231 @@ __attribute__((unused)) static errval_t pt_alloc_l2(struct paging_state * st, st
|
|||||||
return pt_alloc(st, ObjType_VNode_AARCH64_l2, ret);
|
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);
|
return pt_alloc(st, ObjType_VNode_AARCH64_l3, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pt_print_state(struct paging_state *st) {
|
||||||
|
// iterates over all the page table entries and prints them
|
||||||
|
debug_printf("L0\n");
|
||||||
|
for(size_t i0 = 0; i0 < PTABLE_ENTRIES; ++i0) {
|
||||||
|
struct pt_t *l1_pt = st->l0_pt->children[i0];
|
||||||
|
if (l1_pt == NULL) continue;
|
||||||
|
|
||||||
|
debug_printf(" %lu -> L1\n", i0);
|
||||||
|
for(size_t i1 = 0; i1 < PTABLE_ENTRIES; ++i1) {
|
||||||
|
struct pt_t *l2_pt = l1_pt->children[i1];
|
||||||
|
if (l2_pt == NULL) continue;
|
||||||
|
debug_printf(" %lu -> L2\n", i1);
|
||||||
|
|
||||||
|
for(size_t i2 = 0; i2 < PTABLE_ENTRIES; ++i2) {
|
||||||
|
struct pt_t *l3_pt = l2_pt->children[i2];
|
||||||
|
if (l3_pt == NULL) continue;
|
||||||
|
debug_printf(" %lu -> L3\n", i2);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE rueegges: each paging fixed call can use up to 4 pt slabs, up to 3 children slabs and up to 7 slots
|
||||||
|
// slab refilling reserve cycles causing paging calls:
|
||||||
|
// - this slab
|
||||||
|
// - child slab
|
||||||
|
// - mm slab
|
||||||
|
static errval_t pt_ensure_slots_and_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");
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
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_slots_and_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);
|
||||||
|
}
|
||||||
|
// TODO rueegges: use fuctions for refill size
|
||||||
|
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");
|
||||||
|
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
return err_push(err, LIB_ERR_SLAB_REFILL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
case 1:
|
||||||
|
err = pt_alloc_l2(st, &pt_cap);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO rueegges: store the allocated pt
|
||||||
|
// 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: 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");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
pt_parent->children[pt_index] = pt_meta;
|
||||||
|
|
||||||
|
*pt_ret = pt_meta;
|
||||||
|
|
||||||
|
return SYS_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO(M2): Implement this function.
|
* TODO(M2): Implement this function.
|
||||||
* TODO(M4): Improve this function.
|
* TODO(M4): Improve this function.
|
||||||
* \brief Initialize the paging_state struct for the paging
|
* \brief Initialize the paging_state struct for the paging
|
||||||
* state of the calling process.
|
* state of the calling process.
|
||||||
*
|
*
|
||||||
* \param st The struct to be initialized, must not be NULL.
|
* \param st The struct to be initialized, must not be NULL.
|
||||||
* \param start_vaddr Virtual address allocation should start at
|
* \param start_vaddr Virtual address allocation should start at
|
||||||
* this address.
|
* this address.
|
||||||
@ -83,20 +304,39 @@ errval_t paging_init_state(struct paging_state *st, lvaddr_t start_vaddr,
|
|||||||
// TODO (M4): Implement page fault handler that installs frames when a page fault
|
// TODO (M4): Implement page fault handler that installs frames when a page fault
|
||||||
// occurs and keeps track of the virtual address space.
|
// occurs and keeps track of the virtual address space.
|
||||||
|
|
||||||
|
assert(ca != NULL);
|
||||||
|
|
||||||
st->slot_alloc = ca;
|
st->slot_alloc = ca;
|
||||||
|
st->refilling = 0;
|
||||||
|
|
||||||
// Note: The slot allocator is not initialized yet, so we can't use it now.
|
// initialize slab allocators
|
||||||
// So, defer the creation of vnodes until the first map operation.
|
// TODO rueegges: is this how we should initialize the slab allocators?
|
||||||
st->l0_vnode = pdir;
|
slab_init(&st->pt_slabs, sizeof(struct pt_t), NULL);
|
||||||
st->l2_vnode = NULL_CAP;
|
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);
|
||||||
|
|
||||||
for (size_t i = 0; i < PTABLE_ENTRIES; i++) {
|
// initialize shadow pages
|
||||||
st->l3_vnodes[i] = NULL_CAP;
|
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);
|
||||||
|
|
||||||
st->free_l3_vnode = NULL_CAP;
|
l0_pt->level = 0;
|
||||||
|
l0_pt->cap_pt = pdir;
|
||||||
|
l0_pt->children = l0_children;
|
||||||
|
|
||||||
st->next_vaddr = VADDR_OFFSET;
|
st->l0_pt = l0_pt;
|
||||||
|
st->next_vaddr = start_vaddr;
|
||||||
|
|
||||||
return SYS_ERR_OK;
|
return SYS_ERR_OK;
|
||||||
}
|
}
|
||||||
@ -106,7 +346,7 @@ errval_t paging_init_state(struct paging_state *st, lvaddr_t start_vaddr,
|
|||||||
* TODO(M4): Improve this function.
|
* TODO(M4): Improve this function.
|
||||||
* \brief Initialize the paging_state struct for the paging state
|
* \brief Initialize the paging_state struct for the paging state
|
||||||
* of a child process.
|
* of a child process.
|
||||||
*
|
*
|
||||||
* \param st The struct to be initialized, must not be NULL.
|
* \param st The struct to be initialized, must not be NULL.
|
||||||
* \param start_vaddr Virtual address allocation should start at
|
* \param start_vaddr Virtual address allocation should start at
|
||||||
* this address.
|
* this address.
|
||||||
@ -141,7 +381,7 @@ errval_t paging_init(void)
|
|||||||
// TIP: it might be a good idea to call paging_init_state() from here to
|
// TIP: it might be a good idea to call paging_init_state() from here to
|
||||||
// avoid code duplication.
|
// avoid code duplication.
|
||||||
|
|
||||||
err = paging_init_state(¤t, 0, cap_vroot, get_default_slot_allocator());
|
err = paging_init_state(¤t, VADDR_OFFSET, cap_vroot, get_default_slot_allocator());
|
||||||
if (err_is_fail(err)) return err;
|
if (err_is_fail(err)) return err;
|
||||||
|
|
||||||
set_current_paging_state(¤t);
|
set_current_paging_state(¤t);
|
||||||
@ -215,77 +455,6 @@ errval_t paging_map_frame_attr(struct paging_state *st, void **buf, size_t bytes
|
|||||||
return LIB_ERR_NOT_IMPLEMENTED;
|
return LIB_ERR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static errval_t init_vnodes(struct paging_state *st)
|
|
||||||
{
|
|
||||||
errval_t err;
|
|
||||||
struct capref l1_vnode;
|
|
||||||
err = pt_alloc_l1(st, &l1_vnode);
|
|
||||||
if (err_is_fail(err)) return err;
|
|
||||||
|
|
||||||
struct capref l1_vnode_mapping;
|
|
||||||
err = st->slot_alloc->alloc(st->slot_alloc, &l1_vnode_mapping);
|
|
||||||
if (err_is_fail(err)) return err_push(err, LIB_ERR_SLOT_ALLOC);
|
|
||||||
|
|
||||||
struct capref l2_vnode;
|
|
||||||
err = pt_alloc_l2(st, &l2_vnode);
|
|
||||||
if (err_is_fail(err)) return err;
|
|
||||||
|
|
||||||
struct capref l2_vnode_mapping;
|
|
||||||
err = st->slot_alloc->alloc(st->slot_alloc, &l2_vnode_mapping);
|
|
||||||
if (err_is_fail(err)) return err_push(err, LIB_ERR_SLOT_ALLOC);
|
|
||||||
|
|
||||||
if (capref_is_null(st->l2_vnode)) {
|
|
||||||
st->l2_vnode = l2_vnode;
|
|
||||||
err = vnode_map(st->l0_vnode, l1_vnode,
|
|
||||||
1, VREGION_FLAGS_READ_WRITE, 0, 1, l1_vnode_mapping);
|
|
||||||
if (err_is_fail(err)) return err_push(err, LIB_ERR_VNODE_MAP);
|
|
||||||
|
|
||||||
err = vnode_map(l1_vnode, st->l2_vnode,
|
|
||||||
0, VREGION_FLAGS_READ_WRITE, 0, 1, l2_vnode_mapping);
|
|
||||||
if (err_is_fail(err)) return err_push(err, LIB_ERR_VNODE_MAP);
|
|
||||||
} else {
|
|
||||||
// paging_map_fixed_attr was called recursively during an allocation above.
|
|
||||||
// This can happen at most once, so it's fine to leak the allocations.
|
|
||||||
}
|
|
||||||
|
|
||||||
return SYS_ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static errval_t allocate_l3_vnode(struct paging_state *st, size_t l2_index)
|
|
||||||
{
|
|
||||||
errval_t err;
|
|
||||||
struct capref l3_vnode_mapping;
|
|
||||||
err = st->slot_alloc->alloc(st->slot_alloc, &l3_vnode_mapping);
|
|
||||||
if (err_is_fail(err)) return err_push(err, LIB_ERR_SLOT_ALLOC);
|
|
||||||
|
|
||||||
struct capref l3_vnode;
|
|
||||||
if (!capref_is_null(st->free_l3_vnode)) {
|
|
||||||
l3_vnode = st->free_l3_vnode;
|
|
||||||
st->free_l3_vnode = NULL_CAP;
|
|
||||||
} else {
|
|
||||||
err = pt_alloc_l3(st, &l3_vnode);
|
|
||||||
if (err_is_fail(err)) {
|
|
||||||
st->slot_alloc->free(st->slot_alloc, l3_vnode_mapping);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (capref_is_null(st->l3_vnodes[l2_index])) {
|
|
||||||
st->l3_vnodes[l2_index] = l3_vnode;
|
|
||||||
err = vnode_map(st->l2_vnode, st->l3_vnodes[l2_index],
|
|
||||||
l2_index, VREGION_FLAGS_READ_WRITE, 0, 1,
|
|
||||||
l3_vnode_mapping);
|
|
||||||
if (err_is_fail(err)) return err_push(err, LIB_ERR_VNODE_MAP);
|
|
||||||
} else {
|
|
||||||
// paging_map_fixed_attr was called recursively during an allocation above.
|
|
||||||
err = st->slot_alloc->free(st->slot_alloc, l3_vnode_mapping);
|
|
||||||
assert(!err_is_fail(err));
|
|
||||||
st->free_l3_vnode = l3_vnode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SYS_ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief mapps the provided frame at the supplied address in the paging state
|
* @brief mapps the provided frame at the supplied address in the paging state
|
||||||
@ -304,7 +473,7 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr,
|
|||||||
{
|
{
|
||||||
errval_t err;
|
errval_t err;
|
||||||
/*
|
/*
|
||||||
* M1:
|
* TODO(M1):
|
||||||
* - Map a frame assuming all mappings will fit into one leaf page table (L3)
|
* - Map a frame assuming all mappings will fit into one leaf page table (L3)
|
||||||
* TODO(M2):
|
* TODO(M2):
|
||||||
* - General case: you will need to handle mappings spanning multiple leaf page tables.
|
* - General case: you will need to handle mappings spanning multiple leaf page tables.
|
||||||
@ -314,42 +483,98 @@ errval_t paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr,
|
|||||||
* - think about what mapping configurations are actually possible
|
* - think about what mapping configurations are actually possible
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// preconditions
|
||||||
assert(bytes % BASE_PAGE_SIZE == 0);
|
assert(bytes % BASE_PAGE_SIZE == 0);
|
||||||
lvaddr_t end_vaddr = vaddr + bytes;
|
lvaddr_t end_vaddr = vaddr + bytes;
|
||||||
assert(VADDR_OFFSET <= vaddr && vaddr < end_vaddr &&
|
assert(VADDR_OFFSET <= vaddr && vaddr < end_vaddr &&
|
||||||
end_vaddr <= VADDR_OFFSET + PTABLE_ENTRIES * PTABLE_ENTRIES * BASE_PAGE_SIZE);
|
end_vaddr <= VADDR_OFFSET + PTABLE_ENTRIES * PTABLE_ENTRIES * BASE_PAGE_SIZE);
|
||||||
|
|
||||||
|
// consistentcy checks
|
||||||
|
assert(st != NULL);
|
||||||
|
assert(st->slot_alloc != NULL);
|
||||||
|
assert(st->l0_pt->level == 0);
|
||||||
|
|
||||||
// Initialize if not done yet.
|
// debug_printf("DEBUG rueegges: paging_map_fixed_attr(%p, 0x%lx, cap, %lu, %d)\n", st, vaddr, bytes, flags);
|
||||||
if (capref_is_null(st->l2_vnode)) {
|
|
||||||
err = init_vnodes(st);
|
|
||||||
if (err_is_fail(err)) return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (vaddr != end_vaddr) {
|
// simple fix for now
|
||||||
size_t l2_index = VMSAv8_64_L2_INDEX(vaddr);
|
for(lvaddr_t current_vaddr = vaddr; current_vaddr < vaddr + bytes; current_vaddr += BASE_PAGE_SIZE) {
|
||||||
size_t l3_index = VMSAv8_64_L3_INDEX(vaddr);
|
capaddr_t l0_index = VMSAv8_64_L0_INDEX(current_vaddr);
|
||||||
size_t l3_count;
|
capaddr_t l1_index = VMSAv8_64_L1_INDEX(current_vaddr);
|
||||||
if (l2_index != VMSAv8_64_L2_INDEX(end_vaddr)) {
|
capaddr_t l2_index = VMSAv8_64_L2_INDEX(current_vaddr);
|
||||||
l3_count = PTABLE_ENTRIES - l3_index;
|
capaddr_t l3_index = VMSAv8_64_L3_INDEX(current_vaddr);
|
||||||
} else {
|
|
||||||
l3_count = VMSAv8_64_L3_INDEX(end_vaddr - vaddr);
|
// 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 l1 page table
|
||||||
|
struct pt_t *l1_pt;
|
||||||
|
err = pt_ensure(st, st->l0_pt, l0_index, &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);
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
DEBUG_ERR(err, "Could not ensure presence of sufficient slabs and slots");
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If needed, allocate L3 vnode
|
// debug_printf("DEBUG rueegges: paging_map_fixed_attr - allocate mapping meta\n");
|
||||||
if (capref_is_null(st->l3_vnodes[l2_index])) {
|
|
||||||
err = allocate_l3_vnode(st, l2_index);
|
// create structures for the new metadata
|
||||||
if (err_is_fail(err)) return err;
|
struct pt_t *pt_entry = (struct pt_t *) slab_alloc(&st->pt_slabs);
|
||||||
|
if (pt_entry == NULL) {
|
||||||
|
return LIB_ERR_SLAB_ALLOC_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct capref frame_mapping;
|
// set to null to indicate it is a frame mapping and not a page table mapping
|
||||||
err = st->slot_alloc->alloc(st->slot_alloc, &frame_mapping);
|
pt_entry->children = NULL;
|
||||||
if (err_is_fail(err)) return err_push(err, LIB_ERR_SLOT_ALLOC);
|
// NOTE rueegges: we set this to 4 to indicate its an entry not a map to another
|
||||||
// debug_printf("vnode_map l2_index=%lu, slot=%lu, count=%lu\n", l2_index, l3_index, l3_count);
|
// table even though for superpages the level would be 3
|
||||||
err = vnode_map(st->l3_vnodes[l2_index], frame, l3_index, flags, 0, l3_count, frame_mapping);
|
pt_entry->level = 4;
|
||||||
if (err_is_fail(err)) return err_push(err, LIB_ERR_VNODE_MAP);
|
// allocate the new mapping
|
||||||
|
err = st->slot_alloc->alloc(st->slot_alloc, &pt_entry->cap_mapping);
|
||||||
|
if (err_is_fail(err)) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
vaddr += l3_count * BASE_PAGE_SIZE;
|
// 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)) {
|
||||||
|
debug_printf("Failed to map vnode at vaddr 0x%lx\n", current_vaddr);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
|
||||||
return SYS_ERR_OK;
|
return SYS_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,9 @@
|
|||||||
target = "grading",
|
target = "grading",
|
||||||
cFiles = [
|
cFiles = [
|
||||||
"rpc.c",
|
"rpc.c",
|
||||||
"grading.c"
|
"grading.c",
|
||||||
|
"test_mm.c",
|
||||||
|
"test_paging.c"
|
||||||
],
|
],
|
||||||
addLibraries = [
|
addLibraries = [
|
||||||
]
|
]
|
||||||
|
|||||||
@ -8,6 +8,8 @@
|
|||||||
#include <grading.h>
|
#include <grading.h>
|
||||||
#include <spawn/spawn.h>
|
#include <spawn/spawn.h>
|
||||||
|
|
||||||
|
#include <test_mm.h>
|
||||||
|
#include <test_paging.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
grading_setup_bsp_init(int argc, char **argv) {
|
grading_setup_bsp_init(int argc, char **argv) {
|
||||||
@ -103,6 +105,17 @@ grading_test_mm(struct mm *test) {
|
|||||||
check_err(mm_free(testmm, caplist[alloc_count]));
|
check_err(mm_free(testmm, caplist[alloc_count]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_mm_run(test_mm_small, "test_mm_small", test);
|
||||||
|
test_mm_run(test_mm_track_slots, "test_mm_track_slots", test);
|
||||||
|
test_mm_run(test_mm_fragments, "test_mm_fragments", test);
|
||||||
|
test_mm_run(test_mm_rand, "test_mm_rand", test);
|
||||||
|
test_mm_run(test_mm_many, "test_mm_many", test);
|
||||||
|
test_mm_run(test_mm_oom, "test_mm_oom", test);
|
||||||
|
|
||||||
|
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
|
// Test paging
|
||||||
for (int i = 0; i < 40; i++) {
|
for (int i = 0; i < 40; i++) {
|
||||||
debug_printf("TEST: page %lu\n", i);
|
debug_printf("TEST: page %lu\n", i);
|
||||||
|
|||||||
173
lib/grading/test_mm.c
Normal file
173
lib/grading/test_mm.c
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
#include <aos/aos.h>
|
||||||
|
#include <test_mm.h>
|
||||||
|
#include <mm/mm.h>
|
||||||
|
|
||||||
|
// ASSESSMENT M1: can be used to show the speed issues in mm_alloc
|
||||||
|
#define TEST_MM_SMALL_COUNT 100
|
||||||
|
#define TEST_MM_BIG_COUNT 10000
|
||||||
|
|
||||||
|
// this is outside of the functions because otherwise we have issues with
|
||||||
|
// the function stack space in M1
|
||||||
|
struct capref caps_big[TEST_MM_BIG_COUNT];
|
||||||
|
struct capref caps[TEST_MM_SMALL_COUNT];
|
||||||
|
|
||||||
|
uint8_t test_mm_run(errval_t func(struct mm *), char *name, struct mm *mm) {
|
||||||
|
errval_t err;
|
||||||
|
|
||||||
|
// debug_printf("TEST_MM %19s: start\n", name);
|
||||||
|
err = func(mm);
|
||||||
|
|
||||||
|
if (err_is_ok(err)) {
|
||||||
|
debug_printf("TEST_MM %19s: OK\n", name);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
debug_printf("TEST_MM %19s: ERR\n", name);
|
||||||
|
DEBUG_ERR(err, "Test Failed with Error");
|
||||||
|
// mm_print_state(mm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if small allocation sizes work (<4KiB)
|
||||||
|
errval_t test_mm_small(struct mm *mm) {
|
||||||
|
errval_t err;
|
||||||
|
|
||||||
|
for(int i = 0; i < TEST_MM_SMALL_COUNT; ++i) {
|
||||||
|
err = mm_alloc_aligned(mm, 20, 1, &caps[i]);
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
debug_printf("Iteration: %d\n", i);
|
||||||
|
return err_push(err, MM_ERR_NEW_NODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int i = 0; i < TEST_MM_SMALL_COUNT; ++i) {
|
||||||
|
err = mm_free(mm, caps[i]);
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
debug_printf("Iteration: %d\n", i);
|
||||||
|
return err_push(err, MM_ERR_MM_FREE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SYS_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ASSESSMENT M1: show that free capability slots are tracked
|
||||||
|
errval_t test_mm_track_slots(struct mm *mm) {
|
||||||
|
errval_t err;
|
||||||
|
|
||||||
|
for(int i = 0; i < TEST_MM_SMALL_COUNT; ++i) {
|
||||||
|
err = mm_alloc(mm, 1 << 21, &caps[i]);
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
debug_printf("Iteration: %d\n", i);
|
||||||
|
return err_push(err, MM_ERR_NEW_NODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int i = 0; i < TEST_MM_SMALL_COUNT; ++i) {
|
||||||
|
err = mm_free(mm, caps[i]);
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
debug_printf("Iteration: %d\n", i);
|
||||||
|
return err_push(err, MM_ERR_MM_FREE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < TEST_MM_SMALL_COUNT; ++i) {
|
||||||
|
err = mm_alloc(mm, 1 << 21, &caps[i]);
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
debug_printf("Iteration: %d\n", i);
|
||||||
|
return err_push(err, MM_ERR_NEW_NODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int i = 0; i < TEST_MM_SMALL_COUNT; ++i) {
|
||||||
|
err = mm_free(mm, caps[i]);
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
debug_printf("Iteration: %d\n", i);
|
||||||
|
return err_push(err, MM_ERR_MM_FREE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SYS_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create fragmented memory and then free it
|
||||||
|
errval_t test_mm_fragments(struct mm *mm) {
|
||||||
|
errval_t err;
|
||||||
|
|
||||||
|
// fragment some memory
|
||||||
|
for(int i = 0; i < TEST_MM_SMALL_COUNT; ++i) {
|
||||||
|
err = mm_alloc_aligned(mm, 1 << 10, 1 << 10, &caps[i]);
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
debug_printf("Iteration: %d\n", i);
|
||||||
|
return err_push(err, MM_ERR_NEW_NODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int i = 0; i < TEST_MM_SMALL_COUNT; i += 2) {
|
||||||
|
err = mm_free(mm, caps[i]);
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
debug_printf("Iteration: %d\n", i);
|
||||||
|
return err_push(err, MM_ERR_MM_FREE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// free fragmented memory
|
||||||
|
for(int i = 1; i < TEST_MM_SMALL_COUNT; i += 2) {
|
||||||
|
err = mm_free(mm, caps[i]);
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
debug_printf("Iteration: %d\n", i);
|
||||||
|
return err_push(err, MM_ERR_MM_FREE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SYS_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ASSESSMENT M1: these tests demonstrate slot/slab refilling
|
||||||
|
// allocate memory of random sizes
|
||||||
|
errval_t test_mm_rand(struct mm *mm) {
|
||||||
|
errval_t err;
|
||||||
|
|
||||||
|
for(int i = 0; i < TEST_MM_SMALL_COUNT; ++i) {
|
||||||
|
err = mm_alloc(mm, rand() % LARGE_PAGE_SIZE + 1, &caps[i]);
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
debug_printf("Iteration: %d\n", i);
|
||||||
|
return err_push(err, MM_ERR_NEW_NODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int i = 0; i < TEST_MM_SMALL_COUNT; ++i) {
|
||||||
|
err = mm_free(mm, caps[i]);
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
debug_printf("Iteration: %d\n", i);
|
||||||
|
return err_push(err, MM_ERR_MM_FREE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SYS_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate loads of memory
|
||||||
|
errval_t test_mm_many(struct mm *mm) {
|
||||||
|
errval_t err;
|
||||||
|
|
||||||
|
for(int i = 0; i < TEST_MM_BIG_COUNT; ++i) {
|
||||||
|
err = mm_alloc_aligned(mm, 1 << 10, 1 << 10, &caps_big[i]);
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
debug_printf("Iteration: %d\n", i);
|
||||||
|
return err_push(err, MM_ERR_NEW_NODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// free loads of small memory
|
||||||
|
for(int i = 0; i < TEST_MM_BIG_COUNT; ++i) {
|
||||||
|
err = mm_free(mm, caps_big[i]);
|
||||||
|
if(err_is_fail(err)) {
|
||||||
|
debug_printf("Iteration: %d\n", i);
|
||||||
|
return err_push(err, MM_ERR_MM_FREE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SYS_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
errval_t test_mm_oom(struct mm *mm){
|
||||||
|
errval_t err;
|
||||||
|
|
||||||
|
// fail because of oom
|
||||||
|
err = mm_alloc(mm, 1L << 31, &caps[0]);
|
||||||
|
|
||||||
|
if(!err_is_fail(err) || err_no(err) != MM_ERR_OUT_OF_RAM) {
|
||||||
|
return ERR_NOTIMP;
|
||||||
|
}
|
||||||
|
return SYS_ERR_OK;
|
||||||
|
}
|
||||||
116
lib/grading/test_paging.c
Normal file
116
lib/grading/test_paging.c
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#include <aos/aos.h>
|
||||||
|
#include <test_paging.h>
|
||||||
|
#include <aos/paging.h>
|
||||||
|
|
||||||
|
// ASSESSMENT M1: these lines show mapping to fixed locations and read/write
|
||||||
|
|
||||||
|
// used to avoid conflicts between tests
|
||||||
|
lvaddr_t vaddr = 0x0000100000000000L;
|
||||||
|
|
||||||
|
uint8_t test_paging_run(errval_t func(void), char *name) {
|
||||||
|
errval_t err;
|
||||||
|
|
||||||
|
// debug_printf("TEST_PAGING %19s: start\n", name);
|
||||||
|
err = func();
|
||||||
|
|
||||||
|
if (err_is_ok(err)) {
|
||||||
|
debug_printf("TEST_PAGING %23s: OK\n", name);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
debug_printf("TEST_PAGING %23s: ERR\n", name);
|
||||||
|
DEBUG_ERR(err, "Test Failed with Error");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errval_t test_paging_full_l3(void) {
|
||||||
|
errval_t err;
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
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);
|
||||||
|
if (err_is_fail(err)) {
|
||||||
|
return err_push(err, LIB_ERR_PMAP_NOT_MAPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify mapping using a random value at a random location
|
||||||
|
uint8_t val = rand() % 256;
|
||||||
|
memset((void *) vaddr, val, mapping_size);
|
||||||
|
if(*((uint8_t *) vaddr + (rand() % mapping_size)) != val) {
|
||||||
|
return ERR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
vaddr += mapping_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SYS_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
errval_t test_paging_full_l2(void) {
|
||||||
|
errval_t err;
|
||||||
|
|
||||||
|
size_t mapping_size = BASE_PAGE_SIZE;
|
||||||
|
|
||||||
|
// map a page in all slots of a single l2 node (the 0-th slot was already used in a previous test)
|
||||||
|
for(size_t i = 1; i < VMSAv8_64_PTABLE_NUM_ENTRIES; ++i) {
|
||||||
|
struct capref frame;
|
||||||
|
err = frame_alloc(&frame, mapping_size, NULL);
|
||||||
|
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);
|
||||||
|
if (err_is_fail(err)) {
|
||||||
|
return err_push(err, LIB_ERR_PMAP_NOT_MAPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify mapping using a random value at a random location
|
||||||
|
uint8_t val = rand() % 256;
|
||||||
|
memset((void *) vaddr, val, mapping_size);
|
||||||
|
if(*((uint8_t *) vaddr + (rand() % mapping_size)) != val) {
|
||||||
|
return ERR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
vaddr += LARGE_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SYS_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
errval_t test_paging_big_regions(void) {
|
||||||
|
errval_t err;
|
||||||
|
|
||||||
|
size_t mapping_size;
|
||||||
|
|
||||||
|
// map larger areas
|
||||||
|
for(size_t i = 1; i <= VMSAv8_64_PTABLE_NUM_ENTRIES - 1; ++i) {
|
||||||
|
mapping_size = i * BASE_PAGE_SIZE;
|
||||||
|
|
||||||
|
struct capref frame;
|
||||||
|
err = frame_alloc(&frame, mapping_size, NULL);
|
||||||
|
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);
|
||||||
|
if (err_is_fail(err)) {
|
||||||
|
return err_push(err, LIB_ERR_PMAP_NOT_MAPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify mapping using a random value at a random location
|
||||||
|
uint8_t val = rand() % 256;
|
||||||
|
memset((void *) vaddr, val, mapping_size);
|
||||||
|
if(*((uint8_t *) vaddr + (rand() % mapping_size)) != val) {
|
||||||
|
return ERR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
vaddr += LARGE_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SYS_ERR_OK;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user