@@ -656,3 +656,65 @@ test_fault_cloadtags_unmapped(const struct cheri_test *ctp __unused)
656
656
}
657
657
658
658
#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