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