diff --git a/include/test_helper.h b/include/test_helper.h new file mode 100644 index 0000000..11b5159 --- /dev/null +++ b/include/test_helper.h @@ -0,0 +1,23 @@ +#ifndef __TEST_HELPER_H +#define __TEST_HELPER_H + +#include +#include + +#define CHECK_ERR(expr) do { \ + errval_t _err = expr; \ + if (err_is_fail(_err)) { \ + USER_PANIC_ERR(_err, "Test failed."); \ + } \ +} while (0) + +extern struct mm *testmm; + +void *alloc_frame( + size_t bytes, + size_t alignment, + struct capref *ram_cap_ret, + struct capref *frame_cap_ret +); + +#endif /* __TEST_HELPER_H */ \ No newline at end of file diff --git a/include/test_mm.h b/include/test_mm.h index 177a4eb..89a88a0 100644 --- a/include/test_mm.h +++ b/include/test_mm.h @@ -2,14 +2,7 @@ #define __TEST_MM_H #include -#include -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); +void do_test_mm(void); #endif /* __TEST_MM_H */ diff --git a/include/test_paging.h b/include/test_paging.h index 137a252..065c075 100644 --- a/include/test_paging.h +++ b/include/test_paging.h @@ -3,9 +3,6 @@ #include -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); +void do_test_paging(void); #endif /* __PAGING_TESTS_H */ \ No newline at end of file diff --git a/lib/grading/Hakefile b/lib/grading/Hakefile index bc43c6c..de8629e 100644 --- a/lib/grading/Hakefile +++ b/lib/grading/Hakefile @@ -16,6 +16,7 @@ cFiles = [ "rpc.c", "grading.c", + "test_helper.c", "test_mm.c", "test_paging.c" ], diff --git a/lib/grading/grading.c b/lib/grading/grading.c index 6f86014..637a6b7 100644 --- a/lib/grading/grading.c +++ b/lib/grading/grading.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -23,106 +24,12 @@ void grading_setup_noninit(int *argc, char ***argv) { } -static void check_err(errval_t err) { - if (err_is_fail(err)) { - USER_PANIC_ERR(err, "Test failed."); - } -} - -static struct mm *testmm; - -static void *alloc_frame(size_t bytes, size_t alignment, - struct capref *ram_cap_ret, struct capref *frame_cap_ret) { - struct capref ram_cap; - if (ram_cap_ret == NULL) ram_cap_ret = &ram_cap; - struct capref frame_cap; - if (frame_cap_ret == NULL) frame_cap_ret = &frame_cap; - - assert(bytes == ROUND_UP(bytes, BASE_PAGE_SIZE)); - check_err(mm_alloc_aligned(testmm, bytes, alignment, ram_cap_ret)); - - check_err(slot_alloc(frame_cap_ret)); - check_err(cap_retype(*frame_cap_ret, *ram_cap_ret, 0, ObjType_Frame, bytes, 1)); - - struct paging_state *paging_state = get_current_paging_state(); - void *vaddr; - check_err(paging_map_frame_attr( - paging_state, &vaddr, - bytes, *frame_cap_ret, VREGION_FLAGS_READ_WRITE - )); - return vaddr; -} - void grading_test_mm(struct mm *test) { - errval_t err; testmm = test; - struct capref *caplist = alloc_frame(sizeof(struct capref) * 1024*1024, 16, NULL, NULL); - size_t alloc_count = 0; - - // Test partial free - struct capref big_block; - struct capref part1_of_big_block; - struct capref part2_of_big_block; - check_err(mm_alloc_aligned(testmm, 16*4096, 4096, &big_block)); - check_err(slot_alloc(&part1_of_big_block)); - check_err(slot_alloc(&part2_of_big_block)); - check_err(cap_retype(part1_of_big_block, big_block, 0, ObjType_RAM, 4096, 1)); - check_err(cap_retype(part2_of_big_block, big_block, 4096, ObjType_RAM, 15*4096, 1)); - check_err(cap_destroy(big_block)); - check_err(mm_free(testmm, part2_of_big_block)); - - // Allocate all available RAM and then deallocate it again, multiple times. - for (int it = 0; it < 5; it++) { - for (; alloc_count < 1024*1024; alloc_count++) { - err = mm_alloc_aligned(testmm, 256*BASE_PAGE_SIZE, BASE_PAGE_SIZE, &caplist[alloc_count]); - if (err_is_fail(err)) { - assert(err == MM_ERR_OUT_OF_RAM); - break; - } - if (alloc_count % 10000 == 0) debug_printf("TEST: allocated %lu\n", alloc_count); - } - debug_printf("TEST: Allocated %"PRIu64" MB of RAM.\n", alloc_count * 256*BASE_PAGE_SIZE / 1024 / 1024); - while (alloc_count > 0) { - alloc_count--; - check_err(mm_free(testmm, caplist[alloc_count])); - if (alloc_count % 1000 == 0) debug_printf("TEST: freeing %lu\n", alloc_count); - } - } - - // Test alignment ("e.g., a 4 KiB region must be aligned to a 1 MiB boundary.") - for (; alloc_count < 10; alloc_count++) { - check_err(mm_alloc_aligned(testmm, 4096, 1024*1024, &caplist[alloc_count])); - struct capability c; - check_err( cap_direct_identify(caplist[alloc_count], &c)); - genpaddr_t base = get_address(&c); - assert(base % (1024*1024) == 0); - } - while (alloc_count > 0) { - 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 - for (int i = 0; i < 40; i++) { - debug_printf("TEST: page %lu\n", i); - char *data = alloc_frame(5176*4096, 16, NULL, NULL); - memset(data, 33, 5176*4096); - } - - debug_printf("TEST: Finished!\n"); + // do_test_mm(); + // do_test_paging(); } void diff --git a/lib/grading/test_helper.c b/lib/grading/test_helper.c new file mode 100644 index 0000000..3d1f5d1 --- /dev/null +++ b/lib/grading/test_helper.c @@ -0,0 +1,25 @@ +#include + +struct mm *testmm; + +void *alloc_frame(size_t bytes, size_t alignment, + struct capref *ram_cap_ret, struct capref *frame_cap_ret) { + struct capref ram_cap; + if (ram_cap_ret == NULL) ram_cap_ret = &ram_cap; + struct capref frame_cap; + if (frame_cap_ret == NULL) frame_cap_ret = &frame_cap; + + assert(bytes == ROUND_UP(bytes, BASE_PAGE_SIZE)); + CHECK_ERR(mm_alloc_aligned(testmm, bytes, alignment, ram_cap_ret)); + + CHECK_ERR(slot_alloc(frame_cap_ret)); + CHECK_ERR(cap_retype(*frame_cap_ret, *ram_cap_ret, 0, ObjType_Frame, bytes, 1)); + + struct paging_state *paging_state = get_current_paging_state(); + void *vaddr; + CHECK_ERR(paging_map_frame_attr( + paging_state, &vaddr, + bytes, *frame_cap_ret, VREGION_FLAGS_READ_WRITE + )); + return vaddr; +} diff --git a/lib/grading/test_mm.c b/lib/grading/test_mm.c index 3fd49d1..d370018 100644 --- a/lib/grading/test_mm.c +++ b/lib/grading/test_mm.c @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -8,10 +8,10 @@ // 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]; +static struct capref caps_big[TEST_MM_BIG_COUNT]; +static struct capref caps[TEST_MM_SMALL_COUNT]; -uint8_t test_mm_run(errval_t func(struct mm *), char *name, struct mm *mm) { +static void test_mm_run(errval_t func(struct mm *), char *name, struct mm *mm) { errval_t err; // debug_printf("TEST_MM %19s: start\n", name); @@ -19,17 +19,15 @@ uint8_t test_mm_run(errval_t func(struct mm *), char *name, struct mm *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"); + USER_PANIC_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) { +static errval_t test_mm_small(struct mm *mm) { errval_t err; for(int i = 0; i < TEST_MM_SMALL_COUNT; ++i) { @@ -50,7 +48,7 @@ errval_t test_mm_small(struct mm *mm) { } // ASSESSMENT M1: show that free capability slots are tracked -errval_t test_mm_track_slots(struct mm *mm) { +static errval_t test_mm_track_slots(struct mm *mm) { errval_t err; for(int i = 0; i < TEST_MM_SMALL_COUNT; ++i) { @@ -67,7 +65,7 @@ errval_t test_mm_track_slots(struct mm *mm) { 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)) { @@ -86,7 +84,7 @@ errval_t test_mm_track_slots(struct mm *mm) { } // create fragmented memory and then free it -errval_t test_mm_fragments(struct mm *mm) { +static errval_t test_mm_fragments(struct mm *mm) { errval_t err; // fragment some memory @@ -118,7 +116,7 @@ errval_t test_mm_fragments(struct mm *mm) { // ASSESSMENT M1: these tests demonstrate slot/slab refilling // allocate memory of random sizes -errval_t test_mm_rand(struct mm *mm) { +static errval_t test_mm_rand(struct mm *mm) { errval_t err; for(int i = 0; i < TEST_MM_SMALL_COUNT; ++i) { @@ -139,7 +137,7 @@ errval_t test_mm_rand(struct mm *mm) { } // allocate loads of memory -errval_t test_mm_many(struct mm *mm) { +static errval_t test_mm_many(struct mm *mm) { errval_t err; for(int i = 0; i < TEST_MM_BIG_COUNT; ++i) { @@ -160,14 +158,70 @@ errval_t test_mm_many(struct mm *mm) { return SYS_ERR_OK; } -errval_t test_mm_oom(struct mm *mm){ +static 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; -} \ No newline at end of file +} + +void do_test_mm(void) { + errval_t err; + struct capref *caplist = alloc_frame(sizeof(struct capref) * 1024*1024, 16, NULL, NULL); + size_t alloc_count = 0; + + // Test partial free + struct capref big_block; + struct capref part1_of_big_block; + struct capref part2_of_big_block; + CHECK_ERR(mm_alloc_aligned(testmm, 16*4096, 4096, &big_block)); + CHECK_ERR(slot_alloc(&part1_of_big_block)); + CHECK_ERR(slot_alloc(&part2_of_big_block)); + CHECK_ERR(cap_retype(part1_of_big_block, big_block, 0, ObjType_RAM, 4096, 1)); + CHECK_ERR(cap_retype(part2_of_big_block, big_block, 4096, ObjType_RAM, 15*4096, 1)); + CHECK_ERR(cap_destroy(big_block)); + CHECK_ERR(mm_free(testmm, part2_of_big_block)); + + // Allocate all available RAM and then deallocate it again, multiple times. + for (int it = 0; it < 5; it++) { + for (; alloc_count < 1024*1024; alloc_count++) { + err = mm_alloc_aligned(testmm, 256*BASE_PAGE_SIZE, BASE_PAGE_SIZE, &caplist[alloc_count]); + if (err_is_fail(err)) { + assert(err == MM_ERR_OUT_OF_RAM); + break; + } + if (alloc_count % 10000 == 0) debug_printf("TEST: allocated %lu\n", alloc_count); + } + debug_printf("TEST: Allocated %"PRIu64" MB of RAM.\n", alloc_count * 256*BASE_PAGE_SIZE / 1024 / 1024); + while (alloc_count > 0) { + alloc_count--; + CHECK_ERR(mm_free(testmm, caplist[alloc_count])); + if (alloc_count % 1000 == 0) debug_printf("TEST: freeing %lu\n", alloc_count); + } + } + + // Test alignment ("e.g., a 4 KiB region must be aligned to a 1 MiB boundary.") + for (; alloc_count < 10; alloc_count++) { + CHECK_ERR(mm_alloc_aligned(testmm, 4096, 1024*1024, &caplist[alloc_count])); + struct capability c; + CHECK_ERR( cap_direct_identify(caplist[alloc_count], &c)); + genpaddr_t base = get_address(&c); + assert(base % (1024*1024) == 0); + } + while (alloc_count > 0) { + alloc_count--; + CHECK_ERR(mm_free(testmm, caplist[alloc_count])); + } + + test_mm_run(test_mm_small, "test_mm_small", testmm); + test_mm_run(test_mm_track_slots, "test_mm_track_slots", testmm); + test_mm_run(test_mm_fragments, "test_mm_fragments", testmm); + test_mm_run(test_mm_rand, "test_mm_rand", testmm); + test_mm_run(test_mm_many, "test_mm_many", testmm); + test_mm_run(test_mm_oom, "test_mm_oom", testmm); +} diff --git a/lib/grading/test_paging.c b/lib/grading/test_paging.c index 6aea57b..e50ca2e 100644 --- a/lib/grading/test_paging.c +++ b/lib/grading/test_paging.c @@ -1,13 +1,13 @@ -#include +#include #include #include // ASSESSMENT M1: these lines show mapping to fixed locations and read/write // used to avoid conflicts between tests -lvaddr_t vaddr = 0x0000100000000000L; +static lvaddr_t vaddr = 0x0000100000000000L; -uint8_t test_paging_run(errval_t func(void), char *name) { +static void test_paging_run(errval_t func(void), char *name) { errval_t err; // debug_printf("TEST_PAGING %19s: start\n", name); @@ -15,15 +15,13 @@ uint8_t test_paging_run(errval_t func(void), char *name) { 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; + USER_PANIC_ERR(err, "Test Failed with Error"); } } -errval_t test_paging_full_l3(void) { +static errval_t test_paging_full_l3(void) { errval_t err; size_t mapping_size = BASE_PAGE_SIZE; @@ -53,7 +51,7 @@ errval_t test_paging_full_l3(void) { return SYS_ERR_OK; } -errval_t test_paging_full_l2(void) { +static errval_t test_paging_full_l2(void) { errval_t err; size_t mapping_size = BASE_PAGE_SIZE; @@ -83,7 +81,7 @@ errval_t test_paging_full_l2(void) { return SYS_ERR_OK; } -errval_t test_paging_big_regions(void) { +static errval_t test_paging_big_regions(void) { errval_t err; size_t mapping_size; @@ -114,3 +112,16 @@ errval_t test_paging_big_regions(void) { return SYS_ERR_OK; } + +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 + for (int i = 0; i < 40; i++) { + debug_printf("TEST: page %lu\n", i); + char *data = alloc_frame(5176*4096, 16, NULL, NULL); + memset(data, 33, 5176*4096); + } +}