@@ -602,3 +602,65 @@ cheritest_vm_cow_write(const struct cheri_test *ctp __unused)
602
602
CHERITEST_CHECK_SYSCALL (close (fd ));
603
603
cheritest_success ();
604
604
}
605
+
606
+ /* Store a cap to a page and check that mincore reports it dirty */
607
+ void
608
+ cheritest_vm_capdirty (const struct cheri_test * ctp __unused )
609
+ {
610
+ static const size_t npg = 2 ;
611
+ size_t sz = npg * getpagesize ();
612
+
613
+ void * __capability * pg0 ;
614
+ unsigned char mcv [npg ] = { 0 };
615
+
616
+ pg0 = CHERITEST_CHECK_SYSCALL (mmap (NULL , sz ,
617
+ PROT_READ | PROT_WRITE , MAP_ANON , -1 , 0 ));
618
+
619
+ void * __capability * pg1 = (void * )& ((char * )pg0 )[getpagesize ()];
620
+
621
+ CHERITEST_CHECK_SYSCALL (mincore (pg0 , sz , & mcv [0 ]));
622
+ CHERITEST_VERIFY2 (mcv [0 ] == 0 , "page 0 status 0" );
623
+ CHERITEST_VERIFY2 (mcv [1 ] == 0 , "page 1 status 0" );
624
+
625
+ * (char * )pg0 = 0x42 ;
626
+
627
+ CHERITEST_CHECK_SYSCALL (mincore (pg0 , sz , & mcv [0 ]));
628
+ CHERITEST_VERIFY2 ((mcv [0 ] & MINCORE_MODIFIED ) != 0 , "page 0 modified 1" );
629
+ CHERITEST_VERIFY2 ((mcv [0 ] & MINCORE_CAPSTORE ) != 0 , "page 0 capstore 1" );
630
+ CHERITEST_VERIFY2 ((mcv [0 ] & MINCORE_CAPDIRTY ) == 0 , "page 0 !capdirty 1" );
631
+ CHERITEST_VERIFY2 (mcv [1 ] == 0 , "page 1 status 1" );
632
+
633
+ /*
634
+ * To really spot-check what's going on, kick on user-mode tracing.
635
+ * Assuming we haven't fast-path'd anything, we should get a series of
636
+ * traps from the hardware. The slowest expected case is something
637
+ * like this:
638
+ *
639
+ * 1. miss (puts the RO zero page in place)
640
+ * 2. write (allocates physical frame)
641
+ * 3. capdirty (just sets capdirty bit)
642
+ *
643
+ * Hardware should merge the first two together, giving us a "miss for
644
+ * store" exception that causes the kernel to jump up to the allocated
645
+ * physical frame immediately.
646
+ *
647
+ * CHERI-MIPS defines its capdirty trap to happen only for Valid, Dirty
648
+ * entries, so that the capdirty emulation trap does not need to check,
649
+ * so at least there there will always be two traps. Other CHERI archs
650
+ * may be able to conflate this down to one trap.
651
+ */
652
+ // CHERI_START_USER_TRACE;
653
+ * pg1 = (void * __capability )pg0 ;
654
+ // CHERI_STOP_USER_TRACE;
655
+
656
+ CHERITEST_CHECK_SYSCALL (mincore (pg0 , sz , & mcv [0 ]));
657
+ CHERITEST_VERIFY2 ((mcv [0 ] & MINCORE_MODIFIED ) != 0 , "page 0 modified 2" );
658
+ CHERITEST_VERIFY2 ((mcv [0 ] & MINCORE_CAPSTORE ) != 0 , "page 0 capstore 2" );
659
+ CHERITEST_VERIFY2 ((mcv [0 ] & MINCORE_CAPDIRTY ) == 0 , "page 0 !capdirty 2" );
660
+ CHERITEST_VERIFY2 ((mcv [1 ] & MINCORE_MODIFIED ) != 0 , "page 1 modified 2" );
661
+ CHERITEST_VERIFY2 ((mcv [1 ] & MINCORE_CAPSTORE ) != 0 , "page 1 capstore 2" );
662
+ CHERITEST_VERIFY2 ((mcv [1 ] & MINCORE_CAPDIRTY ) != 0 , "page 1 capdirty 2" );
663
+
664
+ CHERITEST_CHECK_SYSCALL (munmap (pg0 , sz ));
665
+ cheritest_success ();
666
+ }
0 commit comments