| .. | .. |
|---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Based on arch/arm/mm/proc.S |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2001 Deep Blue Solutions Ltd. |
|---|
| 5 | 6 | * Copyright (C) 2012 ARM Ltd. |
|---|
| 6 | 7 | * 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 | 8 | */ |
|---|
| 20 | 9 | |
|---|
| 21 | 10 | #include <linux/init.h> |
|---|
| 22 | 11 | #include <linux/linkage.h> |
|---|
| 12 | +#include <linux/pgtable.h> |
|---|
| 23 | 13 | #include <asm/assembler.h> |
|---|
| 24 | 14 | #include <asm/asm-offsets.h> |
|---|
| 15 | +#include <asm/asm_pointer_auth.h> |
|---|
| 25 | 16 | #include <asm/hwcap.h> |
|---|
| 26 | | -#include <asm/pgtable.h> |
|---|
| 27 | 17 | #include <asm/pgtable-hwdef.h> |
|---|
| 28 | 18 | #include <asm/cpufeature.h> |
|---|
| 29 | 19 | #include <asm/alternative.h> |
|---|
| 20 | +#include <asm/smp.h> |
|---|
| 21 | +#include <asm/sysreg.h> |
|---|
| 30 | 22 | |
|---|
| 31 | 23 | #ifdef CONFIG_ARM64_64K_PAGES |
|---|
| 32 | 24 | #define TCR_TG_FLAGS TCR_TG0_64K | TCR_TG1_64K |
|---|
| .. | .. |
|---|
| 48 | 40 | #define TCR_CACHE_FLAGS TCR_IRGN_WBWA | TCR_ORGN_WBWA |
|---|
| 49 | 41 | |
|---|
| 50 | 42 | #ifdef CONFIG_KASAN_SW_TAGS |
|---|
| 51 | | -#define TCR_KASAN_FLAGS TCR_TBI1 |
|---|
| 43 | +#define TCR_KASAN_SW_FLAGS TCR_TBI1 | TCR_TBID1 |
|---|
| 52 | 44 | #else |
|---|
| 53 | | -#define TCR_KASAN_FLAGS 0 |
|---|
| 45 | +#define TCR_KASAN_SW_FLAGS 0 |
|---|
| 54 | 46 | #endif |
|---|
| 55 | 47 | |
|---|
| 56 | | -#define MAIR(attr, mt) ((attr) << ((mt) * 8)) |
|---|
| 48 | +#ifdef CONFIG_KASAN_HW_TAGS |
|---|
| 49 | +#define TCR_MTE_FLAGS SYS_TCR_EL1_TCMA1 | TCR_TBI1 | TCR_TBID1 |
|---|
| 50 | +#elif defined(CONFIG_ARM64_MTE) |
|---|
| 51 | +/* |
|---|
| 52 | + * The mte_zero_clear_page_tags() implementation uses DC GZVA, which relies on |
|---|
| 53 | + * TBI being enabled at EL1. |
|---|
| 54 | + */ |
|---|
| 55 | +#define TCR_MTE_FLAGS TCR_TBI1 | TCR_TBID1 |
|---|
| 56 | +#else |
|---|
| 57 | +#define TCR_MTE_FLAGS 0 |
|---|
| 58 | +#endif |
|---|
| 57 | 59 | |
|---|
| 58 | 60 | /* |
|---|
| 59 | | - * cpu_cache_off() |
|---|
| 60 | | - * |
|---|
| 61 | | - * Turn the CPU D-cache off. |
|---|
| 61 | + * Default MAIR_EL1. MT_NORMAL_TAGGED is initially mapped as Normal memory and |
|---|
| 62 | + * changed during mte_cpu_setup to Normal Tagged if the system supports MTE. |
|---|
| 62 | 63 | */ |
|---|
| 63 | | -ENTRY(cpu_cache_off) |
|---|
| 64 | | - mrs x0, sctlr_el1 |
|---|
| 65 | | - bic x0, x0, #1 << 2 // clear SCTLR.C |
|---|
| 66 | | - msr sctlr_el1, x0 |
|---|
| 67 | | - isb |
|---|
| 68 | | - ret |
|---|
| 69 | | -ENDPROC(cpu_cache_off) |
|---|
| 70 | | - |
|---|
| 71 | | -/* |
|---|
| 72 | | - * cpu_reset(loc) |
|---|
| 73 | | - * |
|---|
| 74 | | - * Perform a soft reset of the system. Put the CPU into the same state |
|---|
| 75 | | - * as it would be if it had been reset, and branch to what would be the |
|---|
| 76 | | - * reset vector. It must be executed with the flat identity mapping. |
|---|
| 77 | | - * |
|---|
| 78 | | - * - loc - location to jump to for soft reset |
|---|
| 79 | | - */ |
|---|
| 80 | | - .align 5 |
|---|
| 81 | | -ENTRY(cpu_reset) |
|---|
| 82 | | - mrs x1, sctlr_el1 |
|---|
| 83 | | - bic x1, x1, #1 |
|---|
| 84 | | - msr sctlr_el1, x1 // disable the MMU |
|---|
| 85 | | - isb |
|---|
| 86 | | - ret x0 |
|---|
| 87 | | -ENDPROC(cpu_reset) |
|---|
| 88 | | - |
|---|
| 89 | | -/* |
|---|
| 90 | | - * cpu_do_idle() |
|---|
| 91 | | - * |
|---|
| 92 | | - * Idle the processor (wait for interrupt). |
|---|
| 93 | | - */ |
|---|
| 94 | | -ENTRY(cpu_do_idle) |
|---|
| 95 | | - dsb sy // WFI may enter a low-power mode |
|---|
| 96 | | - wfi |
|---|
| 97 | | - ret |
|---|
| 98 | | -ENDPROC(cpu_do_idle) |
|---|
| 64 | +#define MAIR_EL1_SET \ |
|---|
| 65 | + (MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRnE, MT_DEVICE_nGnRnE) | \ |
|---|
| 66 | + MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRE, MT_DEVICE_nGnRE) | \ |
|---|
| 67 | + MAIR_ATTRIDX(MAIR_ATTR_DEVICE_GRE, MT_DEVICE_GRE) | \ |
|---|
| 68 | + MAIR_ATTRIDX(MAIR_ATTR_NORMAL_NC, MT_NORMAL_NC) | \ |
|---|
| 69 | + MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL) | \ |
|---|
| 70 | + MAIR_ATTRIDX(MAIR_ATTR_NORMAL_WT, MT_NORMAL_WT) | \ |
|---|
| 71 | + MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL_TAGGED) | \ |
|---|
| 72 | + MAIR_ATTRIDX(MAIR_ATTR_NORMAL_iNC_oWB, MT_NORMAL_iNC_oWB)) |
|---|
| 99 | 73 | |
|---|
| 100 | 74 | #ifdef CONFIG_CPU_PM |
|---|
| 101 | 75 | /** |
|---|
| .. | .. |
|---|
| 105 | 79 | * |
|---|
| 106 | 80 | * This must be kept in sync with struct cpu_suspend_ctx in <asm/suspend.h>. |
|---|
| 107 | 81 | */ |
|---|
| 108 | | -ENTRY(cpu_do_suspend) |
|---|
| 82 | +SYM_FUNC_START(cpu_do_suspend) |
|---|
| 109 | 83 | mrs x2, tpidr_el0 |
|---|
| 110 | 84 | mrs x3, tpidrro_el0 |
|---|
| 111 | 85 | mrs x4, contextidr_el1 |
|---|
| .. | .. |
|---|
| 134 | 108 | */ |
|---|
| 135 | 109 | str x18, [x0, #96] |
|---|
| 136 | 110 | ret |
|---|
| 137 | | -ENDPROC(cpu_do_suspend) |
|---|
| 111 | +SYM_FUNC_END(cpu_do_suspend) |
|---|
| 138 | 112 | |
|---|
| 139 | 113 | /** |
|---|
| 140 | 114 | * cpu_do_resume - restore CPU register context |
|---|
| .. | .. |
|---|
| 142 | 116 | * x0: Address of context pointer |
|---|
| 143 | 117 | */ |
|---|
| 144 | 118 | .pushsection ".idmap.text", "awx" |
|---|
| 145 | | -ENTRY(cpu_do_resume) |
|---|
| 119 | +SYM_FUNC_START(cpu_do_resume) |
|---|
| 146 | 120 | ldp x2, x3, [x0] |
|---|
| 147 | 121 | ldp x4, x5, [x0, #16] |
|---|
| 148 | 122 | ldp x6, x8, [x0, #32] |
|---|
| .. | .. |
|---|
| 191 | 165 | ubfx x11, x11, #1, #1 |
|---|
| 192 | 166 | msr oslar_el1, x11 |
|---|
| 193 | 167 | reset_pmuserenr_el0 x0 // Disable PMU access from EL0 |
|---|
| 168 | + reset_amuserenr_el0 x0 // Disable AMU access from EL0 |
|---|
| 194 | 169 | |
|---|
| 195 | 170 | alternative_if ARM64_HAS_RAS_EXTN |
|---|
| 196 | 171 | msr_s SYS_DISR_EL1, xzr |
|---|
| 197 | 172 | alternative_else_nop_endif |
|---|
| 198 | 173 | |
|---|
| 174 | + ptrauth_keys_install_kernel_nosync x14, x1, x2, x3 |
|---|
| 199 | 175 | isb |
|---|
| 200 | 176 | ret |
|---|
| 201 | | -ENDPROC(cpu_do_resume) |
|---|
| 177 | +SYM_FUNC_END(cpu_do_resume) |
|---|
| 202 | 178 | .popsection |
|---|
| 203 | 179 | #endif |
|---|
| 204 | | - |
|---|
| 205 | | -/* |
|---|
| 206 | | - * cpu_do_switch_mm(pgd_phys, tsk) |
|---|
| 207 | | - * |
|---|
| 208 | | - * Set the translation table base pointer to be pgd_phys. |
|---|
| 209 | | - * |
|---|
| 210 | | - * - pgd_phys - physical address of new TTB |
|---|
| 211 | | - */ |
|---|
| 212 | | -ENTRY(cpu_do_switch_mm) |
|---|
| 213 | | - mrs x2, ttbr1_el1 |
|---|
| 214 | | - mmid x1, x1 // get mm->context.id |
|---|
| 215 | | - phys_to_ttbr x3, x0 |
|---|
| 216 | | -#ifdef CONFIG_ARM64_SW_TTBR0_PAN |
|---|
| 217 | | - bfi x3, x1, #48, #16 // set the ASID field in TTBR0 |
|---|
| 218 | | -#endif |
|---|
| 219 | | - bfi x2, x1, #48, #16 // set the ASID |
|---|
| 220 | | - msr ttbr1_el1, x2 // in TTBR1 (since TCR.A1 is set) |
|---|
| 221 | | - isb |
|---|
| 222 | | - msr ttbr0_el1, x3 // now update TTBR0 |
|---|
| 223 | | - isb |
|---|
| 224 | | - b post_ttbr_update_workaround // Back to C code... |
|---|
| 225 | | -ENDPROC(cpu_do_switch_mm) |
|---|
| 226 | 180 | |
|---|
| 227 | 181 | .pushsection ".idmap.text", "awx" |
|---|
| 228 | 182 | |
|---|
| 229 | 183 | .macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2 |
|---|
| 230 | | - adrp \tmp1, empty_zero_page |
|---|
| 184 | + adrp \tmp1, reserved_pg_dir |
|---|
| 231 | 185 | phys_to_ttbr \tmp2, \tmp1 |
|---|
| 186 | + offset_ttbr1 \tmp2, \tmp1 |
|---|
| 232 | 187 | msr ttbr1_el1, \tmp2 |
|---|
| 233 | 188 | isb |
|---|
| 234 | 189 | tlbi vmalle1 |
|---|
| .. | .. |
|---|
| 237 | 192 | .endm |
|---|
| 238 | 193 | |
|---|
| 239 | 194 | /* |
|---|
| 240 | | - * void idmap_cpu_replace_ttbr1(phys_addr_t new_pgd) |
|---|
| 195 | + * void idmap_cpu_replace_ttbr1(phys_addr_t ttbr1) |
|---|
| 241 | 196 | * |
|---|
| 242 | 197 | * This is the low-level counterpart to cpu_replace_ttbr1, and should not be |
|---|
| 243 | 198 | * called by anything else. It can only be executed from a TTBR0 mapping. |
|---|
| 244 | 199 | */ |
|---|
| 245 | | -ENTRY(idmap_cpu_replace_ttbr1) |
|---|
| 200 | +SYM_FUNC_START(idmap_cpu_replace_ttbr1) |
|---|
| 246 | 201 | save_and_disable_daif flags=x2 |
|---|
| 247 | 202 | |
|---|
| 248 | 203 | __idmap_cpu_set_reserved_ttbr1 x1, x3 |
|---|
| 249 | 204 | |
|---|
| 250 | | - phys_to_ttbr x3, x0 |
|---|
| 251 | | - msr ttbr1_el1, x3 |
|---|
| 205 | + offset_ttbr1 x0, x3 |
|---|
| 206 | + msr ttbr1_el1, x0 |
|---|
| 252 | 207 | isb |
|---|
| 253 | 208 | |
|---|
| 254 | 209 | restore_daif x2 |
|---|
| 255 | 210 | |
|---|
| 256 | 211 | ret |
|---|
| 257 | | -ENDPROC(idmap_cpu_replace_ttbr1) |
|---|
| 212 | +SYM_FUNC_END(idmap_cpu_replace_ttbr1) |
|---|
| 258 | 213 | .popsection |
|---|
| 259 | 214 | |
|---|
| 260 | 215 | #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 |
|---|
| .. | .. |
|---|
| 282 | 237 | */ |
|---|
| 283 | 238 | __idmap_kpti_flag: |
|---|
| 284 | 239 | .long 1 |
|---|
| 285 | | -ENTRY(idmap_kpti_install_ng_mappings) |
|---|
| 240 | +SYM_FUNC_START(idmap_kpti_install_ng_mappings) |
|---|
| 286 | 241 | cpu .req w0 |
|---|
| 287 | 242 | num_cpus .req w1 |
|---|
| 288 | 243 | swapper_pa .req x2 |
|---|
| .. | .. |
|---|
| 302 | 257 | pte .req x16 |
|---|
| 303 | 258 | |
|---|
| 304 | 259 | mrs swapper_ttb, ttbr1_el1 |
|---|
| 260 | + restore_ttbr1 swapper_ttb |
|---|
| 305 | 261 | adr flag_ptr, __idmap_kpti_flag |
|---|
| 306 | 262 | |
|---|
| 307 | 263 | cbnz cpu, __idmap_kpti_secondary |
|---|
| .. | .. |
|---|
| 342 | 298 | /* We're done: fire up the MMU again */ |
|---|
| 343 | 299 | mrs x17, sctlr_el1 |
|---|
| 344 | 300 | orr x17, x17, #SCTLR_ELx_M |
|---|
| 345 | | - msr sctlr_el1, x17 |
|---|
| 346 | | - isb |
|---|
| 347 | | - |
|---|
| 348 | | - /* |
|---|
| 349 | | - * Invalidate the local I-cache so that any instructions fetched |
|---|
| 350 | | - * speculatively from the PoC are discarded, since they may have |
|---|
| 351 | | - * been dynamically patched at the PoU. |
|---|
| 352 | | - */ |
|---|
| 353 | | - ic iallu |
|---|
| 354 | | - dsb nsh |
|---|
| 355 | | - isb |
|---|
| 301 | + set_sctlr_el1 x17 |
|---|
| 356 | 302 | |
|---|
| 357 | 303 | /* Set the flag to zero to indicate that we're all done */ |
|---|
| 358 | 304 | str wzr, [flag_ptr] |
|---|
| .. | .. |
|---|
| 446 | 392 | cbnz w16, 1b |
|---|
| 447 | 393 | |
|---|
| 448 | 394 | /* All done, act like nothing happened */ |
|---|
| 395 | + offset_ttbr1 swapper_ttb, x16 |
|---|
| 449 | 396 | msr ttbr1_el1, swapper_ttb |
|---|
| 450 | 397 | isb |
|---|
| 451 | 398 | ret |
|---|
| 452 | 399 | |
|---|
| 453 | 400 | .unreq swapper_ttb |
|---|
| 454 | 401 | .unreq flag_ptr |
|---|
| 455 | | -ENDPROC(idmap_kpti_install_ng_mappings) |
|---|
| 402 | +SYM_FUNC_END(idmap_kpti_install_ng_mappings) |
|---|
| 456 | 403 | .popsection |
|---|
| 457 | 404 | #endif |
|---|
| 458 | 405 | |
|---|
| 459 | 406 | /* |
|---|
| 460 | 407 | * __cpu_setup |
|---|
| 461 | 408 | * |
|---|
| 462 | | - * Initialise the processor for turning the MMU on. Return in x0 the |
|---|
| 463 | | - * value of the SCTLR_EL1 register. |
|---|
| 409 | + * Initialise the processor for turning the MMU on. |
|---|
| 410 | + * |
|---|
| 411 | + * Output: |
|---|
| 412 | + * Return in x0 the value of the SCTLR_EL1 register. |
|---|
| 464 | 413 | */ |
|---|
| 465 | 414 | .pushsection ".idmap.text", "awx" |
|---|
| 466 | | -ENTRY(__cpu_setup) |
|---|
| 415 | +SYM_FUNC_START(__cpu_setup) |
|---|
| 467 | 416 | tlbi vmalle1 // Invalidate local TLB |
|---|
| 468 | 417 | dsb nsh |
|---|
| 469 | 418 | |
|---|
| 470 | | - mov x0, #3 << 20 |
|---|
| 471 | | - msr cpacr_el1, x0 // Enable FP/ASIMD |
|---|
| 472 | | - mov x0, #1 << 12 // Reset mdscr_el1 and disable |
|---|
| 473 | | - msr mdscr_el1, x0 // access to the DCC from EL0 |
|---|
| 419 | + mov x1, #3 << 20 |
|---|
| 420 | + msr cpacr_el1, x1 // Enable FP/ASIMD |
|---|
| 421 | + mov x1, #1 << 12 // Reset mdscr_el1 and disable |
|---|
| 422 | + msr mdscr_el1, x1 // access to the DCC from EL0 |
|---|
| 474 | 423 | isb // Unmask debug exceptions now, |
|---|
| 475 | 424 | enable_dbg // since this is per-cpu |
|---|
| 476 | | - reset_pmuserenr_el0 x0 // Disable PMU access from EL0 |
|---|
| 425 | + reset_pmuserenr_el0 x1 // Disable PMU access from EL0 |
|---|
| 426 | + reset_amuserenr_el0 x1 // Disable AMU access from EL0 |
|---|
| 427 | + |
|---|
| 477 | 428 | /* |
|---|
| 478 | | - * Memory region attributes for LPAE: |
|---|
| 479 | | - * |
|---|
| 480 | | - * n = AttrIndx[2:0] |
|---|
| 481 | | - * n MAIR |
|---|
| 482 | | - * DEVICE_nGnRnE 000 00000000 |
|---|
| 483 | | - * DEVICE_nGnRE 001 00000100 |
|---|
| 484 | | - * DEVICE_GRE 010 00001100 |
|---|
| 485 | | - * NORMAL_NC 011 01000100 |
|---|
| 486 | | - * NORMAL 100 11111111 |
|---|
| 487 | | - * NORMAL_WT 101 10111011 |
|---|
| 429 | + * Memory region attributes |
|---|
| 488 | 430 | */ |
|---|
| 489 | | - ldr x5, =MAIR(0x00, MT_DEVICE_nGnRnE) | \ |
|---|
| 490 | | - MAIR(0x04, MT_DEVICE_nGnRE) | \ |
|---|
| 491 | | - MAIR(0x0c, MT_DEVICE_GRE) | \ |
|---|
| 492 | | - MAIR(0x44, MT_NORMAL_NC) | \ |
|---|
| 493 | | - MAIR(0xff, MT_NORMAL) | \ |
|---|
| 494 | | - MAIR(0xbb, MT_NORMAL_WT) |
|---|
| 431 | + mov_q x5, MAIR_EL1_SET |
|---|
| 495 | 432 | msr mair_el1, x5 |
|---|
| 496 | 433 | /* |
|---|
| 497 | | - * Prepare SCTLR |
|---|
| 434 | + * Set/prepare TCR and TTBR. TCR_EL1.T1SZ gets further |
|---|
| 435 | + * adjusted if the kernel is compiled with 52bit VA support. |
|---|
| 498 | 436 | */ |
|---|
| 499 | | - mov_q x0, SCTLR_EL1_SET |
|---|
| 500 | | - /* |
|---|
| 501 | | - * Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for |
|---|
| 502 | | - * both user and kernel. |
|---|
| 503 | | - */ |
|---|
| 504 | | - ldr x10, =TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \ |
|---|
| 437 | + mov_q x10, TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \ |
|---|
| 505 | 438 | TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \ |
|---|
| 506 | | - TCR_TBI0 | TCR_A1 | TCR_KASAN_FLAGS |
|---|
| 507 | | - tcr_set_idmap_t0sz x10, x9 |
|---|
| 439 | + TCR_TBI0 | TCR_A1 | TCR_KASAN_SW_FLAGS | TCR_MTE_FLAGS |
|---|
| 440 | + |
|---|
| 441 | + tcr_clear_errata_bits x10, x9, x5 |
|---|
| 442 | + |
|---|
| 443 | +#ifdef CONFIG_ARM64_VA_BITS_52 |
|---|
| 444 | + ldr_l x9, vabits_actual |
|---|
| 445 | + sub x9, xzr, x9 |
|---|
| 446 | + add x9, x9, #64 |
|---|
| 447 | + tcr_set_t1sz x10, x9 |
|---|
| 448 | +#else |
|---|
| 449 | + ldr_l x9, idmap_t0sz |
|---|
| 450 | +#endif |
|---|
| 451 | + tcr_set_t0sz x10, x9 |
|---|
| 508 | 452 | |
|---|
| 509 | 453 | /* |
|---|
| 510 | 454 | * Set the IPS bits in TCR_EL1. |
|---|
| .. | .. |
|---|
| 523 | 467 | 1: |
|---|
| 524 | 468 | #endif /* CONFIG_ARM64_HW_AFDBM */ |
|---|
| 525 | 469 | msr tcr_el1, x10 |
|---|
| 470 | + /* |
|---|
| 471 | + * Prepare SCTLR |
|---|
| 472 | + */ |
|---|
| 473 | + mov_q x0, INIT_SCTLR_EL1_MMU_ON |
|---|
| 526 | 474 | ret // return to head.S |
|---|
| 527 | | -ENDPROC(__cpu_setup) |
|---|
| 475 | +SYM_FUNC_END(__cpu_setup) |
|---|