1/* 2 * Copyright (c) 2010-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <machine/asm.h> 30#include <arm64/proc_reg.h> 31#include <arm/pmap.h> 32#include <sys/errno.h> 33#include "assym.s" 34 35/* 36 * void InvalidatePoU_Icache(void) 37 * 38 * Invalidate i-cache 39 */ 40 .text 41 .align 2 42 .globl EXT(InvalidatePoU_Icache) 43 .globl EXT(invalidate_mmu_icache) 44LEXT(InvalidatePoU_Icache) 45LEXT(invalidate_mmu_icache) 46 ARM64_PROLOG 47 dsb sy 48 ic ialluis // Invalidate icache 49 dsb sy 50 isb sy 51 ret 52 53/* 54 * void InvalidatePoU_IcacheRegion(vm_offset_t va, unsigned length) 55 * 56 * Invalidate icache region 57 */ 58 .text 59 .align 2 60 .globl EXT(InvalidatePoU_IcacheRegion) 61LEXT(InvalidatePoU_IcacheRegion) 62 ARM64_STACK_PROLOG 63 PUSH_FRAME 64 bl EXT(CleanPoU_DcacheRegion) 65#if __ARM_IC_NOALIAS_ICACHE__ 66 mov x9, #((1<<MMU_I_CLINE)-1) 67 and x2, x0, x9 68 bic x0, x0, x9 // Cached aligned 69 add x1, x1, x2 70 sub x1, x1, #1 71 lsr x1, x1, #MMU_I_CLINE // Set cache line counter 72L_ipui_loop: 73 ic ivau, x0 // Invalidate icache line 74 add x0, x0, #1<<MMU_I_CLINE // Get next cache aligned addr 75 subs x1, x1, #1 // Decrementer cache line counter 76 b.pl L_ipui_loop // Loop in counter not null 77 dsb sy 78 isb sy 79#else 80 bl EXT(InvalidatePoU_Icache) 81#endif 82 POP_FRAME 83 ARM64_STACK_EPILOG 84 85/* 86 * Obtains cache physical layout information required for way/set 87 * data cache maintenance operations. 88 * 89 * $0: Data cache level, starting from 0 90 * $1: Output register for set increment 91 * $2: Output register for last valid set 92 * $3: Output register for way increment 93 */ 94.macro GET_CACHE_CONFIG 95 lsl $0, $0, #1 96 msr CSSELR_EL1, $0 // Select appropriate cache 97 isb // Synchronize context 98 99 mrs $0, CCSIDR_EL1 100 ubfx $1, $0, #3, #10 // extract number of ways - 1 101 mov $2, $1 102 add $1, $1, #1 // calculate number of ways 103 104 mov $0, #63 105 and $2, $2, $1 106 cmp $2, #0 107 cinc $0, $0, ne 108 clz $1, $1 109 sub $0, $0, $1 110 111 mov $1, #32 // calculate way increment 112 sub $3, $1, $0 113 mov $1, #1 114 lsl $3, $1, $3 115 116 mrs $0, CCSIDR_EL1 117 ubfx $1, $0, #0, #3 // extract log2(line size) - 4 118 add $1, $1, #4 // calculate log2(line size) 119 mov $2, #1 120 lsl $1, $2, $1 // calculate set increment 121 122 ubfx $2, $0, #13, #15 // extract number of sets - 1 123 add $2, $2, #1 // calculate number of sets 124 mul $2, $1, $2 // calculate last valid set 125.endmacro 126 127/* 128 * Returns the cache configuration for the specified level 129 * $0: Output register 130 * $1: Cache level register 131 * $2: Scratch register 132 */ 133.macro CACHE_AT_LEVEL 134 mrs $0, CLIDR_EL1 135 add $2, $1, $1, lsl #1 136 lsr $0, $0, $2 137 and $0, $0, #7 // extract cache type 138.endmacro 139 140/* 141 * Perform set/way maintenance to the desired cache level 142 * $0: 'dc' set/way variant, e.g. csw or cisw 143 * x0: maximum cache level, 0-based, inclusive 144 */ 145.macro DCACHE_SET_WAY 146 dmb sy 147 mov x1, #0 1481: 149 CACHE_AT_LEVEL x2, x1, x3 150 cbz x2, 5f // No cache at this level, all higher levels may be skipped 151 cmp x2, #2 152 b.lt 4f // No data cache at this level, skip to next level 153 mov x2, x1 154 GET_CACHE_CONFIG x2, x9, x10, x11 155 lsl x2, x1, #1 // level field for cisw/csw, bits 1:3 1562: 1573: 158 dc $0, x2 // clean dcache line by way/set 159 add x2, x2, x9 // increment set index 160 tst x2, x10 // look for overflow 161 b.eq 3b 162 bic x2, x2, x10 // clear set overflow 163 adds w2, w2, w11 // increment way 164 b.cc 2b // loop 165 dsb sy // ensure completion of prior level maintenance 1664: 167 add x1, x1, #1 168 cmp x1, x0 169 b.ls 1b // next level 1705: 171 ret 172.endmacro 173 174#if defined(APPLE_ARM64_ARCH_FAMILY) && !APPLEVIRTUALPLATFORM 175/* 176 * Enables cache maintenance by VA instructions on Apple SoCs. 177 * 178 * $0: Scratch register 179 * $1: Scratch register 180 */ 181.macro ENABLE_DC_MVA_OPS 182 isb sy 183 ARM64_IS_ECORE $0 184 ARM64_READ_CORE_SYSREG $0, $1, EHID4, HID4 185 and $1, $1, (~ARM64_REG_HID4_DisDcMVAOps) 186 ARM64_WRITE_CORE_SYSREG $0, $1, EHID4, HID4 187 isb sy 188.endmacro 189 190/* 191 * Disables cache maintenance by VA instructions on Apple SoCs. 192 * 193 * $0: Scratch register 194 * $1: Scratch register 195 */ 196.macro DISABLE_DC_MVA_OPS 197 isb sy 198 ARM64_IS_ECORE $0 199 ARM64_READ_CORE_SYSREG $0, $1, EHID4, HID4 200 orr $1, $1, ARM64_REG_HID4_DisDcMVAOps 201 ARM64_WRITE_CORE_SYSREG $0, $1, EHID4, HID4 202 isb sy 203.endmacro 204#endif 205 206/* 207 * void CleanPoC_Dcache(void) 208 * 209 * Clean all d-caches 210 */ 211 .text 212 .align 2 213 .globl EXT(CleanPoC_Dcache) 214 .globl EXT(clean_mmu_dcache) 215LEXT(CleanPoC_Dcache) 216 ARM64_PROLOG 217#if defined(APPLE_ARM64_ARCH_FAMILY) 218 dsb sy 219 ret 220 /* "Fully Coherent." */ 221#else /* !defined(APPLE_ARM64_ARCH_FAMILY) */ 222 mrs x0, CLIDR_EL1 223 ubfx x0, x0, #24, #3 // extract CLIDR_EL1.LoC 224 DCACHE_SET_WAY csw 225#endif /* defined(APPLE_ARM64_ARCH_FAMILY) */ 226 227/* 228 * void CleanPoU_Dcache(void) 229 * 230 * Clean D-cache to Point of Unification 231 */ 232 .text 233 .align 2 234 .globl EXT(CleanPoU_Dcache) 235LEXT(CleanPoU_Dcache) 236 ARM64_PROLOG 237#if defined(APPLE_ARM64_ARCH_FAMILY) 238 dsb sy 239 ret 240 /* "Fully Coherent." */ 241#else /* !defined(APPLE_ARM64_ARCH_FAMILY) */ 242 mrs x0, CLIDR_EL1 243 ubfx x0, x0, #21, 3 // extract CLIDR_EL1.LoUIS 244 DCACHE_SET_WAY csw 245#endif /* defined(APPLE_ARM64_ARCH_FAMILY) */ 246 247/* 248 * void CleanPoU_DcacheRegion(vm_offset_t va, unsigned length) 249 * 250 * Clean d-cache region to Point of Unification 251 */ 252 .text 253 .align 2 254 .globl EXT(CleanPoU_DcacheRegion) 255LEXT(CleanPoU_DcacheRegion) 256 ARM64_PROLOG 257#if defined(APPLE_ARM64_ARCH_FAMILY) 258 /* "Fully Coherent." */ 259#else /* !defined(APPLE_ARM64_ARCH_FAMILY) */ 260 mov x9, #((1<<MMU_CLINE)-1) 261 and x2, x0, x9 262 bic x3, x0, x9 // Cached aligned 263 add x4, x1, x2 264 sub x4, x4, #1 265 lsr x4, x4, #MMU_CLINE // Set cache line counter 266 dmb sy 267L_cpudr_loop: 268 dc cvau, x3 // Clean dcache line to PoU 269 add x3, x3, #(1<<MMU_CLINE) // Get next cache aligned addr 270 subs x4, x4, #1 // Decrementer cache line counter 271 b.pl L_cpudr_loop // Loop in counter not null 272#endif /* defined(APPLE_ARM64_ARCH_FAMILY) */ 273 dsb sy 274 ret 275 276.macro CLEANPOC_DCACHEREGION 277 #define CLINE_FLUSH_STRIDE MMU_CLINE 278 279 ARM64_PROLOG 280 mov x9, #((1<<CLINE_FLUSH_STRIDE)-1) 281 and x2, x0, x9 282 bic x0, x0, x9 // Cached aligned 283 add x1, x1, x2 284 sub x1, x1, #1 285 lsr x1, x1, #(CLINE_FLUSH_STRIDE) // Set cache line counter 2861: 287#if defined(APPLE_ARM64_ARCH_FAMILY) 288 // It may be tempting to clean the cache (dc cvac), but it's always a NOP on 289 // Apple hardware. 290 dc civac, x0 // Clean & Invalidate dcache line to PoC 291#else /* defined(APPLE_ARM64_ARCH_FAMILY) */ 292 dc cvac, x0 // Clean dcache line to PoC 293#endif /* defined(APPLE_ARM64_ARCH_FAMILY) */ 294 add x0, x0, #(1<<CLINE_FLUSH_STRIDE) // Get next cache aligned addr 295 subs x1, x1, #1 // Decrementer cache line counter 296 b.pl 1b // Loop in counter not null 297.endmacro 298 299 300/* 301 * void CleanPoC_DcacheRegion_internal(vm_offset_t va, size_t length) 302 * 303 * Clean d-cache region to Point of Coherency 304 */ 305 .text 306 .align 2 307LEXT(CleanPoC_DcacheRegion_internal) 308 dsb sy 309 CLEANPOC_DCACHEREGION 310 dsb sy 311 ret 312 313/* 314 * void CleanPoC_DcacheRegion(vm_offset_t va, size_t length) 315 * 316 * Clean d-cache region to Point of Coherency 317 */ 318 .text 319 .align 2 320 .globl EXT(CleanPoC_DcacheRegion) 321LEXT(CleanPoC_DcacheRegion) 322 ARM64_PROLOG 323#if defined(APPLE_ARM64_ARCH_FAMILY) 324 /* "Fully Coherent." */ 325 dsb sy 326 ret 327#else /* !defined(APPLE_ARM64_ARCH_FAMILY) */ 328 b EXT(CleanPoC_DcacheRegion_internal) 329#endif /* defined(APPLE_ARM64_ARCH_FAMILY) */ 330 331 332/* 333 * void CleanPoC_DcacheRegion_Force(vm_offset_t va, size_t length) 334 * 335 * Clean d-cache region to Point of Coherency - when you really 336 * need to flush even on coherent platforms, e.g. panic log 337 */ 338 .text 339 .align 2 340 .globl EXT(CleanPoC_DcacheRegion_Force) 341LEXT(CleanPoC_DcacheRegion_Force) 342#if defined(APPLE_ARM64_ARCH_FAMILY) 343 ARM64_STACK_PROLOG 344 PUSH_FRAME 345 stp x0, x1, [sp, #-16]! 346 bl EXT(_disable_preemption) 347 ldp x0, x1, [sp], #16 348 bl EXT(CleanPoC_DcacheRegion_Force_nopreempt) 349 bl EXT(_enable_preemption) 350 POP_FRAME 351 ARM64_STACK_EPILOG 352#else 353 ARM64_PROLOG 354 b EXT(CleanPoC_DcacheRegion_internal) 355#endif /* APPLE_ARM64_ARCH_FAMILY */ 356 357/* 358 * void FlushPoC_Dcache(void) 359 * 360 * Clean and Invalidate dcaches to Point of Coherency 361 */ 362 .text 363 .align 2 364 .globl EXT(FlushPoC_Dcache) 365LEXT(FlushPoC_Dcache) 366 ARM64_PROLOG 367#if defined(APPLE_ARM64_ARCH_FAMILY) 368 dsb sy 369 ret 370 /* "Fully Coherent." */ 371#else /* !defined(APPLE_ARM64_ARCH_FAMILY) */ 372 mrs x0, CLIDR_EL1 373 ubfx x0, x0, #24, #3 // extract CLIDR_EL1.LoC 374 DCACHE_SET_WAY cisw 375#endif /* defined(APPLE_ARM64_ARCH_FAMILY) */ 376 377/* 378 * void Flush_Dcache(void) 379 * 380 * Clean and invalidate D-cache, all levels 381 */ 382 .text 383 .align 2 384 .globl EXT(Flush_Dcache) 385LEXT(Flush_Dcache) 386 ARM64_PROLOG 387 mov x0, #6 // Maximum allowable caching level (0-based) 388 DCACHE_SET_WAY cisw 389 390/* 391 * void FlushPoU_Dcache(void) 392 * 393 * Flush D-cache to Point of Unification 394 */ 395 .text 396 .align 2 397 .globl EXT(FlushPoU_Dcache) 398LEXT(FlushPoU_Dcache) 399 ARM64_PROLOG 400#if defined(APPLE_ARM64_ARCH_FAMILY) 401 dsb sy 402 ret 403 /* "Fully Coherent." */ 404#else /* !defined(APPLE_ARM64_ARCH_FAMILY) */ 405 mrs x0, CLIDR_EL1 406 ubfx x0, x0, #21, 3 // extract CLIDR_EL1.LoUIS 407 DCACHE_SET_WAY cisw 408#endif /* defined(APPLE_ARM64_ARCH_FAMILY) */ 409 410/* 411 * void FlushPoC_DcacheRegion(vm_offset_t va, unsigned length) 412 * 413 * Clean and Invalidate d-cache region to Point of Coherency 414 */ 415 .text 416 .align 2 417 .globl EXT(FlushPoC_DcacheRegion) 418LEXT(FlushPoC_DcacheRegion) 419 ARM64_PROLOG 420#if defined(APPLE_ARM64_ARCH_FAMILY) 421 /* "Fully Coherent." */ 422#else /* !defined(APPLE_ARM64_ARCH_FAMILY) */ 423 mov x9, #((1<<MMU_CLINE)-1) 424 and x2, x0, x9 425 bic x0, x0, x9 // Cached aligned 426 add x1, x1, x2 427 sub x1, x1, #1 428 lsr x1, x1, #MMU_CLINE // Set cache line counter 429 dmb sy 430L_fpcdr_loop: 431 dc civac, x0 // Clean invalidate dcache line to PoC 432 add x0, x0, #(1<<MMU_CLINE) // Get next cache aligned addr 433 subs x1, x1, #1 // Decrementer cache line counter 434 b.pl L_fpcdr_loop // Loop in counter not null 435#endif /* defined(APPLE_ARM64_ARCH_FAMILY) */ 436 dsb sy 437 ret 438 439/* 440 * void flush_dcache64(addr64_t addr, unsigned length, boolean_t phys) 441 */ 442 .text 443 .align 2 444 .globl EXT(flush_dcache64) 445LEXT(flush_dcache64) 446 ARM64_PROLOG 447 BRANCH_EXTERN flush_dcache 448 449/* 450 * void clean_dcache64(addr64_t addr, unsigned length, boolean_t phys) 451 */ 452 .text 453 .align 2 454 .globl EXT(clean_dcache64) 455LEXT(clean_dcache64) 456 ARM64_PROLOG 457 BRANCH_EXTERN clean_dcache 458 459/* 460 * void invalidate_icache(vm_offset_t va, unsigned length, boolean_t phys) 461 * void invalidate_icache64(addr64_t va, unsigned length, boolean_t phys) 462 */ 463 .text 464 .align 2 465 .globl EXT(invalidate_icache64) 466 .globl EXT(invalidate_icache) 467LEXT(invalidate_icache64) 468LEXT(invalidate_icache) 469 ARM64_PROLOG 470 cmp w2, #0 // Is it physical? 471 b.eq Lcall_invalidate_worker 472 adrp x2, _gPhysBase@page 473 add x2, x2, _gPhysBase@pageoff 474 ldr x2, [x2] 475 sub x0, x0, x2 476 adrp x2, _gVirtBase@page 477 add x2, x2, _gVirtBase@pageoff 478 ldr x2, [x2] 479 add x0, x0, x2 480Lcall_invalidate_worker: 481 b EXT(InvalidatePoU_IcacheRegion) 482 483 484/* vim: set ts=4: */ 485