Skip to content

Commit dfd22f1

Browse files
committed
cheritest: minimal capdirty test
1 parent c5fdd6b commit dfd22f1

File tree

3 files changed

+67
-0
lines changed

3 files changed

+67
-0
lines changed

bin/cheritest/cheritest.c

+4
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,10 @@ static const struct cheri_test cheri_tests[] = {
10591059
.ct_si_trapno = T_TLB_LD_MISS, },
10601060
#endif
10611061

1062+
{ .ct_name = "cheritest_vm_capdirty",
1063+
.ct_desc = "verify capdirty marking and mincore",
1064+
.ct_func = cheritest_vm_capdirty, },
1065+
10621066
#ifdef CHERI_LIBCHERI_TESTS
10631067
#if 0
10641068
/*

bin/cheritest/cheritest.h

+1
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ DECLARE_CHERI_TEST(cheritest_vm_cow_write);
560560
DECLARE_CHERI_TEST(test_cloadtags_mapped);
561561
DECLARE_CHERI_TEST(test_fault_cloadtags_unmapped);
562562
#endif
563+
DECLARE_CHERI_TEST(cheritest_vm_capdirty);
563564
const char *xfail_need_writable_tmp(const char *name);
564565

565566
#if 0

bin/cheritest/cheritest_vm.c

+62
Original file line numberDiff line numberDiff line change
@@ -656,3 +656,65 @@ test_fault_cloadtags_unmapped(const struct cheri_test *ctp __unused)
656656
}
657657

658658
#endif
659+
660+
/* Store a cap to a page and check that mincore reports it dirty */
661+
void
662+
cheritest_vm_capdirty(const struct cheri_test *ctp __unused)
663+
{
664+
static const size_t npg = 2;
665+
size_t sz = npg * getpagesize();
666+
667+
void * __capability * pg0;
668+
unsigned char mcv[npg] = { 0 };
669+
670+
pg0 = CHERITEST_CHECK_SYSCALL(mmap(NULL, sz,
671+
PROT_READ | PROT_WRITE, MAP_ANON, -1, 0));
672+
673+
void * __capability * pg1 = (void *)&((char *)pg0)[getpagesize()];
674+
675+
CHERITEST_CHECK_SYSCALL(mincore(pg0, sz, &mcv[0]));
676+
CHERITEST_VERIFY2(mcv[0] == 0, "page 0 status 0");
677+
CHERITEST_VERIFY2(mcv[1] == 0, "page 1 status 0");
678+
679+
*(char *)pg0 = 0x42;
680+
681+
CHERITEST_CHECK_SYSCALL(mincore(pg0, sz, &mcv[0]));
682+
CHERITEST_VERIFY2((mcv[0] & MINCORE_MODIFIED) != 0, "page 0 modified 1");
683+
CHERITEST_VERIFY2((mcv[0] & MINCORE_CAPSTORE) != 0, "page 0 capstore 1");
684+
CHERITEST_VERIFY2((mcv[0] & MINCORE_CAPDIRTY) == 0, "page 0 !capdirty 1");
685+
CHERITEST_VERIFY2(mcv[1] == 0, "page 1 status 1");
686+
687+
/*
688+
* To really spot-check what's going on, kick on user-mode tracing.
689+
* Assuming we haven't fast-path'd anything, we should get a series of
690+
* traps from the hardware. The slowest expected case is something
691+
* like this:
692+
*
693+
* 1. miss (puts the RO zero page in place)
694+
* 2. write (allocates physical frame)
695+
* 3. capdirty (just sets capdirty bit)
696+
*
697+
* Hardware should merge the first two together, giving us a "miss for
698+
* store" exception that causes the kernel to jump up to the allocated
699+
* physical frame immediately.
700+
*
701+
* CHERI-MIPS defines its capdirty trap to happen only for Valid, Dirty
702+
* entries, so that the capdirty emulation trap does not need to check,
703+
* so at least there there will always be two traps. Other CHERI archs
704+
* may be able to conflate this down to one trap.
705+
*/
706+
// CHERI_START_USER_TRACE;
707+
*pg1 = (void * __capability)pg0;
708+
// CHERI_STOP_USER_TRACE;
709+
710+
CHERITEST_CHECK_SYSCALL(mincore(pg0, sz, &mcv[0]));
711+
CHERITEST_VERIFY2((mcv[0] & MINCORE_MODIFIED) != 0, "page 0 modified 2");
712+
CHERITEST_VERIFY2((mcv[0] & MINCORE_CAPSTORE) != 0, "page 0 capstore 2");
713+
CHERITEST_VERIFY2((mcv[0] & MINCORE_CAPDIRTY) == 0, "page 0 !capdirty 2");
714+
CHERITEST_VERIFY2((mcv[1] & MINCORE_MODIFIED) != 0, "page 1 modified 2");
715+
CHERITEST_VERIFY2((mcv[1] & MINCORE_CAPSTORE) != 0, "page 1 capstore 2");
716+
CHERITEST_VERIFY2((mcv[1] & MINCORE_CAPDIRTY) != 0, "page 1 capdirty 2");
717+
718+
CHERITEST_CHECK_SYSCALL(munmap(pg0, sz));
719+
cheritest_success();
720+
}

0 commit comments

Comments
 (0)