arm64: Fix TTBR + PAN + 52-bit PA logic in cpu_do_switch_mm
[linux-2.6-microblaze.git] / arch / arm64 / mm / proc.S
1 /*
2  * Based on arch/arm/mm/proc.S
3  *
4  * Copyright (C) 2001 Deep Blue Solutions Ltd.
5  * Copyright (C) 2012 ARM Ltd.
6  * Author: Catalin Marinas <catalin.marinas@arm.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <linux/init.h>
22 #include <linux/linkage.h>
23 #include <asm/assembler.h>
24 #include <asm/asm-offsets.h>
25 #include <asm/hwcap.h>
26 #include <asm/pgtable.h>
27 #include <asm/pgtable-hwdef.h>
28 #include <asm/cpufeature.h>
29 #include <asm/alternative.h>
30
31 #ifdef CONFIG_ARM64_64K_PAGES
32 #define TCR_TG_FLAGS    TCR_TG0_64K | TCR_TG1_64K
33 #elif defined(CONFIG_ARM64_16K_PAGES)
34 #define TCR_TG_FLAGS    TCR_TG0_16K | TCR_TG1_16K
35 #else /* CONFIG_ARM64_4K_PAGES */
36 #define TCR_TG_FLAGS    TCR_TG0_4K | TCR_TG1_4K
37 #endif
38
39 #define TCR_SMP_FLAGS   TCR_SHARED
40
41 /* PTWs cacheable, inner/outer WBWA */
42 #define TCR_CACHE_FLAGS TCR_IRGN_WBWA | TCR_ORGN_WBWA
43
44 #define MAIR(attr, mt)  ((attr) << ((mt) * 8))
45
46 /*
47  *      cpu_do_idle()
48  *
49  *      Idle the processor (wait for interrupt).
50  */
51 ENTRY(cpu_do_idle)
52         dsb     sy                              // WFI may enter a low-power mode
53         wfi
54         ret
55 ENDPROC(cpu_do_idle)
56
57 #ifdef CONFIG_CPU_PM
58 /**
59  * cpu_do_suspend - save CPU registers context
60  *
61  * x0: virtual address of context pointer
62  */
63 ENTRY(cpu_do_suspend)
64         mrs     x2, tpidr_el0
65         mrs     x3, tpidrro_el0
66         mrs     x4, contextidr_el1
67         mrs     x5, cpacr_el1
68         mrs     x6, tcr_el1
69         mrs     x7, vbar_el1
70         mrs     x8, mdscr_el1
71         mrs     x9, oslsr_el1
72         mrs     x10, sctlr_el1
73 alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
74         mrs     x11, tpidr_el1
75 alternative_else
76         mrs     x11, tpidr_el2
77 alternative_endif
78         mrs     x12, sp_el0
79         stp     x2, x3, [x0]
80         stp     x4, xzr, [x0, #16]
81         stp     x5, x6, [x0, #32]
82         stp     x7, x8, [x0, #48]
83         stp     x9, x10, [x0, #64]
84         stp     x11, x12, [x0, #80]
85         ret
86 ENDPROC(cpu_do_suspend)
87
88 /**
89  * cpu_do_resume - restore CPU register context
90  *
91  * x0: Address of context pointer
92  */
93         .pushsection ".idmap.text", "ax"
94 ENTRY(cpu_do_resume)
95         ldp     x2, x3, [x0]
96         ldp     x4, x5, [x0, #16]
97         ldp     x6, x8, [x0, #32]
98         ldp     x9, x10, [x0, #48]
99         ldp     x11, x12, [x0, #64]
100         ldp     x13, x14, [x0, #80]
101         msr     tpidr_el0, x2
102         msr     tpidrro_el0, x3
103         msr     contextidr_el1, x4
104         msr     cpacr_el1, x6
105
106         /* Don't change t0sz here, mask those bits when restoring */
107         mrs     x5, tcr_el1
108         bfi     x8, x5, TCR_T0SZ_OFFSET, TCR_TxSZ_WIDTH
109
110         msr     tcr_el1, x8
111         msr     vbar_el1, x9
112
113         /*
114          * __cpu_setup() cleared MDSCR_EL1.MDE and friends, before unmasking
115          * debug exceptions. By restoring MDSCR_EL1 here, we may take a debug
116          * exception. Mask them until local_daif_restore() in cpu_suspend()
117          * resets them.
118          */
119         disable_daif
120         msr     mdscr_el1, x10
121
122         msr     sctlr_el1, x12
123 alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
124         msr     tpidr_el1, x13
125 alternative_else
126         msr     tpidr_el2, x13
127 alternative_endif
128         msr     sp_el0, x14
129         /*
130          * Restore oslsr_el1 by writing oslar_el1
131          */
132         ubfx    x11, x11, #1, #1
133         msr     oslar_el1, x11
134         reset_pmuserenr_el0 x0                  // Disable PMU access from EL0
135
136 alternative_if ARM64_HAS_RAS_EXTN
137         msr_s   SYS_DISR_EL1, xzr
138 alternative_else_nop_endif
139
140         isb
141         ret
142 ENDPROC(cpu_do_resume)
143         .popsection
144 #endif
145
146 /*
147  *      cpu_do_switch_mm(pgd_phys, tsk)
148  *
149  *      Set the translation table base pointer to be pgd_phys.
150  *
151  *      - pgd_phys - physical address of new TTB
152  */
153 ENTRY(cpu_do_switch_mm)
154         mrs     x2, ttbr1_el1
155         mmid    x1, x1                          // get mm->context.id
156         phys_to_ttbr x0, x3
157 #ifdef CONFIG_ARM64_SW_TTBR0_PAN
158         bfi     x3, x1, #48, #16                // set the ASID field in TTBR0
159 #endif
160         bfi     x2, x1, #48, #16                // set the ASID
161         msr     ttbr1_el1, x2                   // in TTBR1 (since TCR.A1 is set)
162         isb
163         msr     ttbr0_el1, x3                   // now update TTBR0
164         isb
165         b       post_ttbr_update_workaround     // Back to C code...
166 ENDPROC(cpu_do_switch_mm)
167
168         .pushsection ".idmap.text", "ax"
169 /*
170  * void idmap_cpu_replace_ttbr1(phys_addr_t new_pgd)
171  *
172  * This is the low-level counterpart to cpu_replace_ttbr1, and should not be
173  * called by anything else. It can only be executed from a TTBR0 mapping.
174  */
175 ENTRY(idmap_cpu_replace_ttbr1)
176         save_and_disable_daif flags=x2
177
178         adrp    x1, empty_zero_page
179         phys_to_ttbr x1, x3
180         msr     ttbr1_el1, x3
181         isb
182
183         tlbi    vmalle1
184         dsb     nsh
185         isb
186
187         phys_to_ttbr x0, x3
188         msr     ttbr1_el1, x3
189         isb
190
191         restore_daif x2
192
193         ret
194 ENDPROC(idmap_cpu_replace_ttbr1)
195         .popsection
196
197 /*
198  *      __cpu_setup
199  *
200  *      Initialise the processor for turning the MMU on.  Return in x0 the
201  *      value of the SCTLR_EL1 register.
202  */
203         .pushsection ".idmap.text", "ax"
204 ENTRY(__cpu_setup)
205         tlbi    vmalle1                         // Invalidate local TLB
206         dsb     nsh
207
208         mov     x0, #3 << 20
209         msr     cpacr_el1, x0                   // Enable FP/ASIMD
210         mov     x0, #1 << 12                    // Reset mdscr_el1 and disable
211         msr     mdscr_el1, x0                   // access to the DCC from EL0
212         isb                                     // Unmask debug exceptions now,
213         enable_dbg                              // since this is per-cpu
214         reset_pmuserenr_el0 x0                  // Disable PMU access from EL0
215         /*
216          * Memory region attributes for LPAE:
217          *
218          *   n = AttrIndx[2:0]
219          *                      n       MAIR
220          *   DEVICE_nGnRnE      000     00000000
221          *   DEVICE_nGnRE       001     00000100
222          *   DEVICE_GRE         010     00001100
223          *   NORMAL_NC          011     01000100
224          *   NORMAL             100     11111111
225          *   NORMAL_WT          101     10111011
226          */
227         ldr     x5, =MAIR(0x00, MT_DEVICE_nGnRnE) | \
228                      MAIR(0x04, MT_DEVICE_nGnRE) | \
229                      MAIR(0x0c, MT_DEVICE_GRE) | \
230                      MAIR(0x44, MT_NORMAL_NC) | \
231                      MAIR(0xff, MT_NORMAL) | \
232                      MAIR(0xbb, MT_NORMAL_WT)
233         msr     mair_el1, x5
234         /*
235          * Prepare SCTLR
236          */
237         mov_q   x0, SCTLR_EL1_SET
238         /*
239          * Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for
240          * both user and kernel.
241          */
242         ldr     x10, =TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \
243                         TCR_TG_FLAGS | TCR_ASID16 | TCR_TBI0 | TCR_A1
244         tcr_set_idmap_t0sz      x10, x9
245
246         /*
247          * Set the IPS bits in TCR_EL1.
248          */
249         tcr_compute_pa_size x10, #TCR_IPS_SHIFT, x5, x6
250 #ifdef CONFIG_ARM64_HW_AFDBM
251         /*
252          * Hardware update of the Access and Dirty bits.
253          */
254         mrs     x9, ID_AA64MMFR1_EL1
255         and     x9, x9, #0xf
256         cbz     x9, 2f
257         cmp     x9, #2
258         b.lt    1f
259         orr     x10, x10, #TCR_HD               // hardware Dirty flag update
260 1:      orr     x10, x10, #TCR_HA               // hardware Access flag update
261 2:
262 #endif  /* CONFIG_ARM64_HW_AFDBM */
263         msr     tcr_el1, x10
264         ret                                     // return to head.S
265 ENDPROC(__cpu_setup)