2 * linux/arch/arm/mm/rodata.c
4 * Copyright (C) 2011 Google, Inc.
6 * Author: Colin Cross <ccross@android.com>
8 * Based on x86 implementation in arch/x86/mm/init_32.c
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
15 #include <linux/kernel.h>
17 #include <linux/module.h>
19 #include <asm/cache.h>
20 #include <asm/pgtable.h>
21 #include <asm/rodata.h>
22 #include <asm/sections.h>
23 #include <asm/tlbflush.h>
27 static int kernel_set_to_readonly __read_mostly;
29 #ifdef CONFIG_DEBUG_RODATA_TEST
30 static const int rodata_test_data = 0xC3;
32 static noinline void rodata_test(void)
36 pr_info("%s: attempting to write to read-only section:\n", __func__);
38 if (*(volatile int *)&rodata_test_data != 0xC3) {
39 pr_err("read only data changed before test\n");
44 * Attempt to to write to rodata_test_data, trapping the expected
45 * data abort. If the trap executed, result will be 1. If it didn't,
46 * result will be 0xFF.
49 "0: str %[zero], [%[rodata_test_data]]\n"
50 " mov %[result], #0xFF\n"
52 "1: mov %[result], #1\n"
55 /* Exception fixup - if store at label 0 faults, jumps to 1 */
56 ".pushsection __ex_table, \"a\"\n"
60 : [result] "=r" (result)
61 : [rodata_test_data] "r" (&rodata_test_data), [zero] "r" (0)
66 pr_info("write to read-only section trapped, success\n");
68 pr_err("write to read-only section NOT trapped, test failed\n");
70 if (*(volatile int *)&rodata_test_data != 0xC3)
71 pr_err("read only data changed during write\n");
74 static inline void rodata_test(void) { }
77 static int set_page_attributes(unsigned long virt, int numpages,
82 unsigned long start = virt;
83 unsigned long end = virt + (numpages << PAGE_SHIFT);
84 unsigned long pmd_end;
87 pmd = pmd_off_k(virt);
88 pmd_end = min(ALIGN(virt + 1, PMD_SIZE), end);
90 if ((pmd_val(*pmd) & PMD_TYPE_MASK) != PMD_TYPE_TABLE) {
91 pr_err("%s: pmd %p=%08lx for %08lx not page table\n",
92 __func__, pmd, pmd_val(*pmd), virt);
97 while (virt < pmd_end) {
98 pte = pte_offset_kernel(pmd, virt);
99 set_pte_ext(pte, f(*pte), 0);
104 flush_tlb_kernel_range(start, end);
109 int set_memory_ro(unsigned long virt, int numpages)
111 return set_page_attributes(virt, numpages, pte_wrprotect);
113 EXPORT_SYMBOL(set_memory_ro);
115 int set_memory_rw(unsigned long virt, int numpages)
117 return set_page_attributes(virt, numpages, pte_mkwrite);
119 EXPORT_SYMBOL(set_memory_rw);
121 void set_kernel_text_rw(void)
123 unsigned long start = PAGE_ALIGN((unsigned long)_text);
124 unsigned long size = PAGE_ALIGN((unsigned long)__end_rodata) - start;
126 if (!kernel_set_to_readonly)
129 pr_debug("Set kernel text: %lx - %lx to read-write\n",
130 start, start + size);
132 set_memory_rw(start, size >> PAGE_SHIFT);
135 void set_kernel_text_ro(void)
137 unsigned long start = PAGE_ALIGN((unsigned long)_text);
138 unsigned long size = PAGE_ALIGN((unsigned long)__end_rodata) - start;
140 if (!kernel_set_to_readonly)
143 pr_info_once("Write protecting the kernel text section %lx - %lx\n",
144 start, start + size);
146 pr_debug("Set kernel text: %lx - %lx to read only\n",
147 start, start + size);
149 set_memory_ro(start, size >> PAGE_SHIFT);
152 void mark_rodata_ro(void)
154 kernel_set_to_readonly = 1;
156 set_kernel_text_ro();