arm64: Add support for KERNEL_TEXT_RDONLY

When using FORCE_PAGES to allocate the kernel memory into pages,
provide an option to mark the the kernel text section as read only.
Since the kernel text pages are always mapped in the kernel, anyone
can write to the page if they have the address.
Enable this option to mark the kernel text pages as read only to
trigger a fault if any code attempts to write to a page that is
part of the kernel text section.

Change-Id: I2a9e105a3340686b4314bb10cc2a6c7bfa19ce8e
Signed-off-by: Rohit Vaswani <rvaswani@codeaurora.org>
diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug
index 4df6fc3..57a7d99 100644
--- a/arch/arm64/Kconfig.debug
+++ b/arch/arm64/Kconfig.debug
@@ -83,4 +83,16 @@
 
           If unsure, say N.
 
+config KERNEL_TEXT_RDONLY
+        bool "Set kernel text section pages as read only"
+	depends on FREE_PAGES_RDONLY
+        help
+          The kernel text pages are always mapped in the kernel.
+	  This means that anyone can write to the page if they have
+	  the address. Enable this option to mark the kernel text pages
+	  as read only to trigger a fault if any code attempts to write
+	  to a page part of the kernel text section. This may have a
+	  performance impact.
+
+          If unsure, say N.
 endmenu
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index 9a7a7d1..09c24c9 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -160,6 +160,11 @@
 int set_memory_rw(unsigned long addr, int numpages);
 int set_memory_x(unsigned long addr, int numpages);
 int set_memory_nx(unsigned long addr, int numpages);
+#ifdef CONFIG_KERNEL_TEXT_RDONLY
+void set_kernel_text_ro(void);
+#else
+static inline void set_kernel_text_ro(void) { }
+#endif
 
 #ifdef CONFIG_FREE_PAGES_RDONLY
 #define mark_addr_rdonly(a)	set_memory_ro((unsigned long)a, 1);
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 1997c5a..f795b09 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -366,3 +366,16 @@
 
 __setup("keepinitrd", keepinitrd_setup);
 #endif
+
+#ifdef CONFIG_KERNEL_TEXT_RDONLY
+void set_kernel_text_ro(void)
+{
+	unsigned long start = PFN_ALIGN(_stext);
+	unsigned long end = PFN_ALIGN(_etext);
+
+	/*
+	 * Set the kernel identity mapping for text RO.
+	 */
+	set_memory_ro(start, (end - start) >> PAGE_SHIFT);
+}
+#endif
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index cd6807ca..cfa2224 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -34,6 +34,7 @@
 #include <asm/sizes.h>
 #include <asm/tlb.h>
 #include <asm/mmu_context.h>
+#include <asm/cacheflush.h>
 
 #include "mm.h"
 
@@ -602,6 +603,8 @@
 	 */
 	cpu_set_reserved_ttbr0();
 	flush_tlb_all();
+	set_kernel_text_ro();
+	flush_tlb_all();
 }
 
 /*