b735482e1529691533dd80d8a0ef6b8cd8bbfbdf
[linux-2.6-microblaze.git] / arch / powerpc / mm / nohash / 8xx.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * This file contains the routines for initializing the MMU
4  * on the 8xx series of chips.
5  *  -- christophe
6  *
7  *  Derived from arch/powerpc/mm/40x_mmu.c:
8  */
9
10 #include <linux/memblock.h>
11 #include <linux/mmu_context.h>
12 #include <asm/fixmap.h>
13 #include <asm/code-patching.h>
14 #include <asm/inst.h>
15
16 #include <mm/mmu_decl.h>
17
18 #define IMMR_SIZE (FIX_IMMR_SIZE << PAGE_SHIFT)
19
20 extern int __map_without_ltlbs;
21
22 static unsigned long block_mapped_ram;
23
24 /*
25  * Return PA for this VA if it is in an area mapped with LTLBs or fixmap.
26  * Otherwise, returns 0
27  */
28 phys_addr_t v_block_mapped(unsigned long va)
29 {
30         unsigned long p = PHYS_IMMR_BASE;
31
32         if (va >= VIRT_IMMR_BASE && va < VIRT_IMMR_BASE + IMMR_SIZE)
33                 return p + va - VIRT_IMMR_BASE;
34         if (__map_without_ltlbs)
35                 return 0;
36         if (va >= PAGE_OFFSET && va < PAGE_OFFSET + block_mapped_ram)
37                 return __pa(va);
38         return 0;
39 }
40
41 /*
42  * Return VA for a given PA mapped with LTLBs or fixmap
43  * Return 0 if not mapped
44  */
45 unsigned long p_block_mapped(phys_addr_t pa)
46 {
47         unsigned long p = PHYS_IMMR_BASE;
48
49         if (pa >= p && pa < p + IMMR_SIZE)
50                 return VIRT_IMMR_BASE + pa - p;
51         if (__map_without_ltlbs)
52                 return 0;
53         if (pa < block_mapped_ram)
54                 return (unsigned long)__va(pa);
55         return 0;
56 }
57
58 /*
59  * MMU_init_hw does the chip-specific initialization of the MMU hardware.
60  */
61 void __init MMU_init_hw(void)
62 {
63 }
64
65 static bool immr_is_mapped __initdata;
66
67 void __init mmu_mapin_immr(void)
68 {
69         unsigned long p = PHYS_IMMR_BASE;
70         unsigned long v = VIRT_IMMR_BASE;
71         int offset;
72
73         if (immr_is_mapped)
74                 return;
75
76         immr_is_mapped = true;
77
78         for (offset = 0; offset < IMMR_SIZE; offset += PAGE_SIZE)
79                 map_kernel_page(v + offset, p + offset, PAGE_KERNEL_NCG);
80 }
81
82 unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
83 {
84         mmu_mapin_immr();
85
86         return 0;
87 }
88
89 void mmu_mark_initmem_nx(void)
90 {
91 }
92
93 #ifdef CONFIG_STRICT_KERNEL_RWX
94 void mmu_mark_rodata_ro(void)
95 {
96 }
97 #endif
98
99 void __init setup_initial_memory_limit(phys_addr_t first_memblock_base,
100                                        phys_addr_t first_memblock_size)
101 {
102         /* We don't currently support the first MEMBLOCK not mapping 0
103          * physical on those processors
104          */
105         BUG_ON(first_memblock_base != 0);
106
107         /* 8xx can only access 32MB at the moment */
108         memblock_set_current_limit(min_t(u64, first_memblock_size, SZ_32M));
109 }
110
111 /*
112  * Set up to use a given MMU context.
113  * id is context number, pgd is PGD pointer.
114  *
115  * We place the physical address of the new task page directory loaded
116  * into the MMU base register, and set the ASID compare register with
117  * the new "context."
118  */
119 void set_context(unsigned long id, pgd_t *pgd)
120 {
121         s16 offset = (s16)(__pa(swapper_pg_dir));
122
123         /* Context switch the PTE pointer for the Abatron BDI2000.
124          * The PGDIR is passed as second argument.
125          */
126         if (IS_ENABLED(CONFIG_BDI_SWITCH))
127                 abatron_pteptrs[1] = pgd;
128
129         /* Register M_TWB will contain base address of level 1 table minus the
130          * lower part of the kernel PGDIR base address, so that all accesses to
131          * level 1 table are done relative to lower part of kernel PGDIR base
132          * address.
133          */
134         mtspr(SPRN_M_TWB, __pa(pgd) - offset);
135
136         /* Update context */
137         mtspr(SPRN_M_CASID, id - 1);
138         /* sync */
139         mb();
140 }
141
142 void flush_instruction_cache(void)
143 {
144         isync();
145         mtspr(SPRN_IC_CST, IDC_INVALL);
146         isync();
147 }
148
149 #ifdef CONFIG_PPC_KUEP
150 void __init setup_kuep(bool disabled)
151 {
152         if (disabled)
153                 return;
154
155         pr_info("Activating Kernel Userspace Execution Prevention\n");
156
157         mtspr(SPRN_MI_AP, MI_APG_KUEP);
158 }
159 #endif
160
161 #ifdef CONFIG_PPC_KUAP
162 void __init setup_kuap(bool disabled)
163 {
164         pr_info("Activating Kernel Userspace Access Protection\n");
165
166         if (disabled)
167                 pr_warn("KUAP cannot be disabled yet on 8xx when compiled in\n");
168
169         mtspr(SPRN_MD_AP, MD_APG_KUAP);
170 }
171 #endif