xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/builtins/aarch64/sme-abi.S (revision 36b606ae6aa4b24061096ba18582e0a08ccd5dba)
15f757f3fSDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
25f757f3fSDimitry Andric// See https://llvm.org/LICENSE.txt for license information.
35f757f3fSDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
45f757f3fSDimitry Andric
55f757f3fSDimitry Andric// This patch implements the support routines for the SME ABI,
65f757f3fSDimitry Andric// described here:
75f757f3fSDimitry Andric//  https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#sme-support-routines
85f757f3fSDimitry Andric
95f757f3fSDimitry Andric#include "../assembly.h"
105f757f3fSDimitry Andric
115f757f3fSDimitry Andric
125f757f3fSDimitry Andric#if !defined(__APPLE__)
135f757f3fSDimitry Andric#define TPIDR2_SYMBOL SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0)
145f757f3fSDimitry Andric#define TPIDR2_SYMBOL_OFFSET :lo12:SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0)
15*36b606aeSDimitry Andric#define CPU_FEATS_SYMBOL SYMBOL_NAME(__aarch64_cpu_features)
16*36b606aeSDimitry Andric#define CPU_FEATS_SYMBOL_OFFSET :lo12:SYMBOL_NAME(__aarch64_cpu_features)
175f757f3fSDimitry Andric#else
185f757f3fSDimitry Andric// MachO requires @page/@pageoff directives because the global is defined
195f757f3fSDimitry Andric// in a different file. Otherwise this file may fail to build.
205f757f3fSDimitry Andric#define TPIDR2_SYMBOL SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0)@page
215f757f3fSDimitry Andric#define TPIDR2_SYMBOL_OFFSET SYMBOL_NAME(__aarch64_has_sme_and_tpidr2_el0)@pageoff
22*36b606aeSDimitry Andric#define CPU_FEATS_SYMBOL SYMBOL_NAME(__aarch64_cpu_features)@page
23*36b606aeSDimitry Andric#define CPU_FEATS_SYMBOL_OFFSET SYMBOL_NAME(__aarch64_cpu_features)@pageoff
245f757f3fSDimitry Andric#endif
255f757f3fSDimitry Andric
265f757f3fSDimitry Andric.arch armv9-a+sme
275f757f3fSDimitry Andric
285f757f3fSDimitry Andric// Utility function which calls a system's abort() routine. Because the function
295f757f3fSDimitry Andric// is streaming-compatible it should disable streaming-SVE mode before calling
305f757f3fSDimitry Andric// abort(). Note that there is no need to preserve any state before the call,
315f757f3fSDimitry Andric// because the function does not return.
325f757f3fSDimitry AndricDEFINE_COMPILERRT_PRIVATE_FUNCTION(do_abort)
335f757f3fSDimitry Andric  .cfi_startproc
345f757f3fSDimitry Andric  .variant_pcs SYMBOL_NAME(do_abort)
350fca6ea1SDimitry Andric  BTI_C
365f757f3fSDimitry Andric  stp  x29, x30, [sp, #-32]!
375f757f3fSDimitry Andric  cntd x0
385f757f3fSDimitry Andric  // Store VG to a stack location that we describe with .cfi_offset
395f757f3fSDimitry Andric  str x0, [sp, #16]
405f757f3fSDimitry Andric  .cfi_def_cfa_offset 32
415f757f3fSDimitry Andric  .cfi_offset w30, -24
425f757f3fSDimitry Andric  .cfi_offset w29, -32
435f757f3fSDimitry Andric  .cfi_offset 46, -16
445f757f3fSDimitry Andric  bl  __arm_sme_state
455f757f3fSDimitry Andric  tbz  x0, #0, 2f
465f757f3fSDimitry Andric1:
475f757f3fSDimitry Andric  smstop sm
485f757f3fSDimitry Andric2:
495f757f3fSDimitry Andric  // We can't make this into a tail-call because the unwinder would
505f757f3fSDimitry Andric  // need to restore the value of VG.
515f757f3fSDimitry Andric  bl  SYMBOL_NAME(abort)
525f757f3fSDimitry Andric  .cfi_endproc
535f757f3fSDimitry AndricEND_COMPILERRT_FUNCTION(do_abort)
545f757f3fSDimitry Andric
555f757f3fSDimitry Andric// __arm_sme_state fills the result registers based on a local
565f757f3fSDimitry Andric// that is set as part of the compiler-rt startup code.
575f757f3fSDimitry Andric//   __aarch64_has_sme_and_tpidr2_el0
585f757f3fSDimitry AndricDEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sme_state)
595f757f3fSDimitry Andric  .variant_pcs __arm_sme_state
600fca6ea1SDimitry Andric  BTI_C
615f757f3fSDimitry Andric  mov x0, xzr
625f757f3fSDimitry Andric  mov x1, xzr
635f757f3fSDimitry Andric
645f757f3fSDimitry Andric  adrp  x16, TPIDR2_SYMBOL
655f757f3fSDimitry Andric  ldrb w16, [x16, TPIDR2_SYMBOL_OFFSET]
665f757f3fSDimitry Andric  cbz w16, 1f
675f757f3fSDimitry Andric0:
685f757f3fSDimitry Andric  orr x0, x0, #0xC000000000000000
695f757f3fSDimitry Andric  mrs x16, SVCR
705f757f3fSDimitry Andric  bfxil x0, x16, #0, #2
715f757f3fSDimitry Andric  mrs x1, TPIDR2_EL0
725f757f3fSDimitry Andric1:
735f757f3fSDimitry Andric  ret
745f757f3fSDimitry AndricEND_COMPILERRT_OUTLINE_FUNCTION(__arm_sme_state)
755f757f3fSDimitry Andric
765f757f3fSDimitry AndricDEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_tpidr2_restore)
775f757f3fSDimitry Andric  .variant_pcs __arm_tpidr2_restore
780fca6ea1SDimitry Andric  BTI_C
795f757f3fSDimitry Andric  // If TPIDR2_EL0 is nonnull, the subroutine aborts in some platform-specific
805f757f3fSDimitry Andric  // manner.
815f757f3fSDimitry Andric  mrs x14, TPIDR2_EL0
825f757f3fSDimitry Andric  cbnz  x14, 2f
835f757f3fSDimitry Andric
845f757f3fSDimitry Andric  // If any of the reserved bytes in the first 16 bytes of BLK are nonzero,
855f757f3fSDimitry Andric  // the subroutine [..] aborts in some platform-defined manner.
865f757f3fSDimitry Andric  ldrh  w14, [x0, #10]
875f757f3fSDimitry Andric  cbnz  w14, 2f
885f757f3fSDimitry Andric  ldr w14, [x0, #12]
895f757f3fSDimitry Andric  cbnz  w14, 2f
905f757f3fSDimitry Andric
915f757f3fSDimitry Andric  // If BLK.za_save_buffer is NULL, the subroutine does nothing.
925f757f3fSDimitry Andric  ldr x16, [x0]
935f757f3fSDimitry Andric  cbz x16, 1f
945f757f3fSDimitry Andric
955f757f3fSDimitry Andric  // If BLK.num_za_save_slices is zero, the subroutine does nothing.
965f757f3fSDimitry Andric  ldrh  w14, [x0, #8]
975f757f3fSDimitry Andric  cbz x14, 1f
985f757f3fSDimitry Andric
995f757f3fSDimitry Andric  mov x15, xzr
1005f757f3fSDimitry Andric0:
1015f757f3fSDimitry Andric  ldr za[w15,0], [x16]
1025f757f3fSDimitry Andric  addsvl x16, x16, #1
1035f757f3fSDimitry Andric  add x15, x15, #1
1045f757f3fSDimitry Andric  cmp x14, x15
1055f757f3fSDimitry Andric  b.ne  0b
1065f757f3fSDimitry Andric1:
1075f757f3fSDimitry Andric  ret
1085f757f3fSDimitry Andric2:
1095f757f3fSDimitry Andric  b  SYMBOL_NAME(do_abort)
1105f757f3fSDimitry AndricEND_COMPILERRT_OUTLINE_FUNCTION(__arm_tpidr2_restore)
1115f757f3fSDimitry Andric
1125f757f3fSDimitry AndricDEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_tpidr2_save)
1135f757f3fSDimitry Andric  .variant_pcs __arm_tpidr2_restore
1140fca6ea1SDimitry Andric  BTI_C
1155f757f3fSDimitry Andric  // If the current thread does not have access to TPIDR2_EL0, the subroutine
1165f757f3fSDimitry Andric  // does nothing.
1175f757f3fSDimitry Andric  adrp  x14, TPIDR2_SYMBOL
1185f757f3fSDimitry Andric  ldrb w14, [x14, TPIDR2_SYMBOL_OFFSET]
1195f757f3fSDimitry Andric  cbz w14, 1f
1205f757f3fSDimitry Andric
1215f757f3fSDimitry Andric  // If TPIDR2_EL0 is null, the subroutine does nothing.
1225f757f3fSDimitry Andric  mrs x16, TPIDR2_EL0
1235f757f3fSDimitry Andric  cbz x16, 1f
1245f757f3fSDimitry Andric
1255f757f3fSDimitry Andric  // If any of the reserved bytes in the first 16 bytes of the TPIDR2 block are
1265f757f3fSDimitry Andric  // nonzero, the subroutine [..] aborts in some platform-defined manner.
1275f757f3fSDimitry Andric  ldrh  w14, [x16, #10]
1285f757f3fSDimitry Andric  cbnz  w14, 2f
1295f757f3fSDimitry Andric  ldr w14, [x16, #12]
1305f757f3fSDimitry Andric  cbnz  w14, 2f
1315f757f3fSDimitry Andric
1325f757f3fSDimitry Andric  // If num_za_save_slices is zero, the subroutine does nothing.
1335f757f3fSDimitry Andric  ldrh  w14, [x16, #8]
1345f757f3fSDimitry Andric  cbz x14, 1f
1355f757f3fSDimitry Andric
1365f757f3fSDimitry Andric  // If za_save_buffer is NULL, the subroutine does nothing.
1375f757f3fSDimitry Andric  ldr x16, [x16]
1385f757f3fSDimitry Andric  cbz x16, 1f
1395f757f3fSDimitry Andric
1405f757f3fSDimitry Andric  mov x15, xzr
1415f757f3fSDimitry Andric0:
1425f757f3fSDimitry Andric  str za[w15,0], [x16]
1435f757f3fSDimitry Andric  addsvl x16, x16, #1
1445f757f3fSDimitry Andric  add x15, x15, #1
1455f757f3fSDimitry Andric  cmp x14, x15
1465f757f3fSDimitry Andric  b.ne  0b
1475f757f3fSDimitry Andric1:
1485f757f3fSDimitry Andric  ret
1495f757f3fSDimitry Andric2:
1505f757f3fSDimitry Andric  b  SYMBOL_NAME(do_abort)
1515f757f3fSDimitry AndricEND_COMPILERRT_OUTLINE_FUNCTION(__arm_tpidr2_save)
1525f757f3fSDimitry Andric
1535f757f3fSDimitry AndricDEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_za_disable)
1545f757f3fSDimitry Andric  .variant_pcs __arm_tpidr2_restore
1550fca6ea1SDimitry Andric  BTI_C
1565f757f3fSDimitry Andric  // If the current thread does not have access to SME, the subroutine does
1575f757f3fSDimitry Andric  // nothing.
1585f757f3fSDimitry Andric  adrp  x14, TPIDR2_SYMBOL
1595f757f3fSDimitry Andric  ldrb w14, [x14, TPIDR2_SYMBOL_OFFSET]
1605f757f3fSDimitry Andric  cbz w14, 0f
1615f757f3fSDimitry Andric
1625f757f3fSDimitry Andric  // Otherwise, the subroutine behaves as if it did the following:
1635f757f3fSDimitry Andric  // * Call __arm_tpidr2_save.
1645f757f3fSDimitry Andric  stp x29, x30, [sp, #-16]!
1655f757f3fSDimitry Andric  .cfi_def_cfa_offset 16
1665f757f3fSDimitry Andric  mov x29, sp
1675f757f3fSDimitry Andric  .cfi_def_cfa w29, 16
1685f757f3fSDimitry Andric  .cfi_offset w30, -8
1695f757f3fSDimitry Andric  .cfi_offset w29, -16
1705f757f3fSDimitry Andric  bl  __arm_tpidr2_save
1715f757f3fSDimitry Andric
1725f757f3fSDimitry Andric  // * Set TPIDR2_EL0 to null.
1735f757f3fSDimitry Andric  msr TPIDR2_EL0, xzr
1745f757f3fSDimitry Andric
1755f757f3fSDimitry Andric  // * Set PSTATE.ZA to 0.
1765f757f3fSDimitry Andric  smstop za
1775f757f3fSDimitry Andric
1785f757f3fSDimitry Andric  .cfi_def_cfa wsp, 16
1795f757f3fSDimitry Andric  ldp x29, x30, [sp], #16
1805f757f3fSDimitry Andric  .cfi_def_cfa_offset 0
1815f757f3fSDimitry Andric  .cfi_restore w30
1825f757f3fSDimitry Andric  .cfi_restore w29
1835f757f3fSDimitry Andric0:
1845f757f3fSDimitry Andric  ret
1855f757f3fSDimitry AndricEND_COMPILERRT_OUTLINE_FUNCTION(__arm_za_disable)
1860fca6ea1SDimitry Andric
187*36b606aeSDimitry AndricDEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_get_current_vg)
188*36b606aeSDimitry Andric  .variant_pcs __arm_get_current_vg
189*36b606aeSDimitry Andric  BTI_C
190*36b606aeSDimitry Andric
191*36b606aeSDimitry Andric  stp     x29, x30, [sp, #-16]!
192*36b606aeSDimitry Andric  .cfi_def_cfa_offset 16
193*36b606aeSDimitry Andric  mov     x29, sp
194*36b606aeSDimitry Andric  .cfi_def_cfa w29, 16
195*36b606aeSDimitry Andric  .cfi_offset w30, -8
196*36b606aeSDimitry Andric  .cfi_offset w29, -16
197*36b606aeSDimitry Andric  adrp    x17, CPU_FEATS_SYMBOL
198*36b606aeSDimitry Andric  ldr     w17, [x17, CPU_FEATS_SYMBOL_OFFSET]
199*36b606aeSDimitry Andric  tbnz    w17, #30, 0f
200*36b606aeSDimitry Andric  adrp    x16, TPIDR2_SYMBOL
201*36b606aeSDimitry Andric  ldrb    w16, [x16, TPIDR2_SYMBOL_OFFSET]
202*36b606aeSDimitry Andric  cbz     w16, 1f
203*36b606aeSDimitry Andric0:
204*36b606aeSDimitry Andric  mov     x18, x1
205*36b606aeSDimitry Andric  bl      __arm_sme_state
206*36b606aeSDimitry Andric  mov     x1, x18
207*36b606aeSDimitry Andric  and     x17, x17, #0x40000000
208*36b606aeSDimitry Andric  bfxil   x17, x0, #0, #1
209*36b606aeSDimitry Andric  cbz     x17, 1f
210*36b606aeSDimitry Andric  cntd    x0
211*36b606aeSDimitry Andric  .cfi_def_cfa wsp, 16
212*36b606aeSDimitry Andric  ldp     x29, x30, [sp], #16
213*36b606aeSDimitry Andric  .cfi_def_cfa_offset 0
214*36b606aeSDimitry Andric  .cfi_restore w30
215*36b606aeSDimitry Andric  .cfi_restore w29
216*36b606aeSDimitry Andric  ret
217*36b606aeSDimitry Andric1:
218*36b606aeSDimitry Andric  mov     x0, xzr
219*36b606aeSDimitry Andric  .cfi_def_cfa wsp, 16
220*36b606aeSDimitry Andric  ldp     x29, x30, [sp], #16
221*36b606aeSDimitry Andric  .cfi_def_cfa_offset 0
222*36b606aeSDimitry Andric  .cfi_restore w30
223*36b606aeSDimitry Andric  .cfi_restore w29
224*36b606aeSDimitry Andric  ret
225*36b606aeSDimitry AndricEND_COMPILERRT_OUTLINE_FUNCTION(__arm_get_current_vg)
226*36b606aeSDimitry Andric
2270fca6ea1SDimitry AndricNO_EXEC_STACK_DIRECTIVE
2280fca6ea1SDimitry Andric
2290fca6ea1SDimitry Andric// GNU property note for BTI and PAC
2300fca6ea1SDimitry AndricGNU_PROPERTY_BTI_PAC
231