diff options
Diffstat (limited to 'arch/arm/mm/idmap.c')
-rw-r--r-- | arch/arm/mm/idmap.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c new file mode 100644 index 000000000000..2be9139a4ef3 --- /dev/null +++ b/arch/arm/mm/idmap.c | |||
@@ -0,0 +1,90 @@ | |||
1 | #include <linux/kernel.h> | ||
2 | |||
3 | #include <asm/cputype.h> | ||
4 | #include <asm/pgalloc.h> | ||
5 | #include <asm/pgtable.h> | ||
6 | |||
7 | static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end, | ||
8 | unsigned long prot) | ||
9 | { | ||
10 | pmd_t *pmd = pmd_offset(pud, addr); | ||
11 | |||
12 | addr = (addr & PMD_MASK) | prot; | ||
13 | pmd[0] = __pmd(addr); | ||
14 | addr += SECTION_SIZE; | ||
15 | pmd[1] = __pmd(addr); | ||
16 | flush_pmd_entry(pmd); | ||
17 | } | ||
18 | |||
19 | static void idmap_add_pud(pgd_t *pgd, unsigned long addr, unsigned long end, | ||
20 | unsigned long prot) | ||
21 | { | ||
22 | pud_t *pud = pud_offset(pgd, addr); | ||
23 | unsigned long next; | ||
24 | |||
25 | do { | ||
26 | next = pud_addr_end(addr, end); | ||
27 | idmap_add_pmd(pud, addr, next, prot); | ||
28 | } while (pud++, addr = next, addr != end); | ||
29 | } | ||
30 | |||
31 | void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end) | ||
32 | { | ||
33 | unsigned long prot, next; | ||
34 | |||
35 | prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE; | ||
36 | if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale()) | ||
37 | prot |= PMD_BIT4; | ||
38 | |||
39 | pgd += pgd_index(addr); | ||
40 | do { | ||
41 | next = pgd_addr_end(addr, end); | ||
42 | idmap_add_pud(pgd, addr, next, prot); | ||
43 | } while (pgd++, addr = next, addr != end); | ||
44 | } | ||
45 | |||
46 | #ifdef CONFIG_SMP | ||
47 | static void idmap_del_pmd(pud_t *pud, unsigned long addr, unsigned long end) | ||
48 | { | ||
49 | pmd_t *pmd = pmd_offset(pud, addr); | ||
50 | pmd_clear(pmd); | ||
51 | } | ||
52 | |||
53 | static void idmap_del_pud(pgd_t *pgd, unsigned long addr, unsigned long end) | ||
54 | { | ||
55 | pud_t *pud = pud_offset(pgd, addr); | ||
56 | unsigned long next; | ||
57 | |||
58 | do { | ||
59 | next = pud_addr_end(addr, end); | ||
60 | idmap_del_pmd(pud, addr, next); | ||
61 | } while (pud++, addr = next, addr != end); | ||
62 | } | ||
63 | |||
64 | void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end) | ||
65 | { | ||
66 | unsigned long next; | ||
67 | |||
68 | pgd += pgd_index(addr); | ||
69 | do { | ||
70 | next = pgd_addr_end(addr, end); | ||
71 | idmap_del_pud(pgd, addr, next); | ||
72 | } while (pgd++, addr = next, addr != end); | ||
73 | } | ||
74 | #endif | ||
75 | |||
76 | /* | ||
77 | * In order to soft-boot, we need to insert a 1:1 mapping in place of | ||
78 | * the user-mode pages. This will then ensure that we have predictable | ||
79 | * results when turning the mmu off | ||
80 | */ | ||
81 | void setup_mm_for_reboot(char mode) | ||
82 | { | ||
83 | /* | ||
84 | * We need to access to user-mode page tables here. For kernel threads | ||
85 | * we don't have any user-mode mappings so we use the context that we | ||
86 | * "borrowed". | ||
87 | */ | ||
88 | identity_mapping_add(current->active_mm->pgd, 0, TASK_SIZE); | ||
89 | local_flush_tlb_all(); | ||
90 | } | ||