--- v4
+++ v24
@@ -1,63 +1,61 @@
-zicfiss and zicfilp extension gets enabled via b3 and b2 in *envcfg CSR.
-menvcfg controls enabling for S/HS mode. henvcfg control enabling for VS
-while senvcfg controls enabling for U/VU mode.
+`fork` implements copy on write (COW) by making pages readonly in child
+and parent both.
-zicfilp extension extends *status CSR to hold `expected landing pad` bit.
-A trap or interrupt can occur between an indirect jmp/call and target
-instr. `expected landing pad` bit from CPU is recorded into xstatus CSR so
-that when supervisor performs xret, `expected landing pad` state of CPU can
-be restored.
+ptep_set_wrprotect and pte_wrprotect clears _PAGE_WRITE in PTE.
+Assumption is that page is readable and on fault copy on write happens.
-zicfiss adds one new CSR
-- CSR_SSP: CSR_SSP contains current shadow stack pointer.
+To implement COW on shadow stack pages, clearing up W bit makes them XWR =
+000. This will result in wrong PTE setting which says no perms but V=1 and
+PFN field pointing to final page. Instead desired behavior is to turn it
+into a readable page, take an access (load/store) fault on sspush/sspop
+(shadow stack) and then perform COW on such pages. This way regular reads
+would still be allowed and not lead to COW maintaining current behavior
+of COW on non-shadow stack but writeable memory.
+On the other hand it doesn't interfere with existing COW for read-write
+memory. Assumption is always that _PAGE_READ must have been set and thus
+setting _PAGE_READ is harmless.
+
+Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com>
+Reviewed-by: Zong Li <zong.li@sifive.com>
+Tested-by: Andreas Korb <andreas.korb@aisec.fraunhofer.de>
+Tested-by: Valentin Haudiquet <valentin.haudiquet@canonical.com>
Signed-off-by: Deepak Gupta <debug@rivosinc.com>
-Reviewed-by: Charlie Jenkins <charlie@rivosinc.com>
---
- arch/riscv/include/asm/csr.h | 16 ++++++++++++++++
- 1 file changed, 16 insertions(+)
+ arch/riscv/include/asm/pgtable.h | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
-diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
-index 25966995da04..af7ed9bedaee 100644
---- a/arch/riscv/include/asm/csr.h
-+++ b/arch/riscv/include/asm/csr.h
-@@ -18,6 +18,15 @@
- #define SR_MPP _AC(0x00001800, UL) /* Previously Machine */
- #define SR_SUM _AC(0x00040000, UL) /* Supervisor User Memory Access */
+diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
+index b03e8f85221f..df4a04b64944 100644
+--- a/arch/riscv/include/asm/pgtable.h
++++ b/arch/riscv/include/asm/pgtable.h
+@@ -415,7 +415,7 @@ static inline int pte_special(pte_t pte)
-+/* zicfilp landing pad status bit */
-+#define SR_SPELP _AC(0x00800000, UL)
-+#define SR_MPELP _AC(0x020000000000, UL)
-+#ifdef CONFIG_RISCV_M_MODE
-+#define SR_ELP SR_MPELP
-+#else
-+#define SR_ELP SR_SPELP
-+#endif
-+
- #define SR_FS _AC(0x00006000, UL) /* Floating-point Status */
- #define SR_FS_OFF _AC(0x00000000, UL)
- #define SR_FS_INITIAL _AC(0x00002000, UL)
-@@ -197,6 +206,8 @@
- #define ENVCFG_PBMTE (_AC(1, ULL) << 62)
- #define ENVCFG_CBZE (_AC(1, UL) << 7)
- #define ENVCFG_CBCFE (_AC(1, UL) << 6)
-+#define ENVCFG_LPE (_AC(1, UL) << 2)
-+#define ENVCFG_SSE (_AC(1, UL) << 3)
- #define ENVCFG_CBIE_SHIFT 4
- #define ENVCFG_CBIE (_AC(0x3, UL) << ENVCFG_CBIE_SHIFT)
- #define ENVCFG_CBIE_ILL _AC(0x0, UL)
-@@ -215,6 +226,11 @@
- #define SMSTATEEN0_HSENVCFG (_ULL(1) << SMSTATEEN0_HSENVCFG_SHIFT)
- #define SMSTATEEN0_SSTATEEN0_SHIFT 63
- #define SMSTATEEN0_SSTATEEN0 (_ULL(1) << SMSTATEEN0_SSTATEEN0_SHIFT)
-+/*
-+ * zicfiss user mode csr
-+ * CSR_SSP holds current shadow stack pointer.
-+ */
-+#define CSR_SSP 0x011
+ static inline pte_t pte_wrprotect(pte_t pte)
+ {
+- return __pte(pte_val(pte) & ~(_PAGE_WRITE));
++ return __pte((pte_val(pte) & ~(_PAGE_WRITE)) | (_PAGE_READ));
+ }
- /* symbolic CSR names: */
- #define CSR_CYCLE 0xc00
+ /* static inline pte_t pte_mkread(pte_t pte) */
+@@ -611,7 +611,15 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
+ static inline void ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long address, pte_t *ptep)
+ {
+- atomic_long_and(~(unsigned long)_PAGE_WRITE, (atomic_long_t *)ptep);
++ pte_t read_pte = READ_ONCE(*ptep);
++ /*
++ * ptep_set_wrprotect can be called for shadow stack ranges too.
++ * shadow stack memory is XWR = 010 and thus clearing _PAGE_WRITE will lead to
++ * encoding 000b which is wrong encoding with V = 1. This should lead to page fault
++ * but we dont want this wrong configuration to be set in page tables.
++ */
++ atomic_long_set((atomic_long_t *)ptep,
++ ((pte_val(read_pte) & ~(unsigned long)_PAGE_WRITE) | _PAGE_READ));
+ }
+
+ #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
+
--
2.45.0