Merge branches 'for-next/sysreg', 'for-next/sme', 'for-next/kselftest', 'for-next...
authorCatalin Marinas <catalin.marinas@arm.com>
Fri, 10 Feb 2023 18:51:49 +0000 (18:51 +0000)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 10 Feb 2023 18:51:49 +0000 (18:51 +0000)
* arm64/for-next/perf:
  perf: arm_spe: Print the version of SPE detected
  perf: arm_spe: Add support for SPEv1.2 inverted event filtering
  perf: Add perf_event_attr::config3
  drivers/perf: fsl_imx8_ddr_perf: Remove set-but-not-used variable
  perf: arm_spe: Support new SPEv1.2/v8.7 'not taken' event
  perf: arm_spe: Use new PMSIDR_EL1 register enums
  perf: arm_spe: Drop BIT() and use FIELD_GET/PREP accessors
  arm64/sysreg: Convert SPE registers to automatic generation
  arm64: Drop SYS_ from SPE register defines
  perf: arm_spe: Use feature numbering for PMSEVFR_EL1 defines
  perf/marvell: Add ACPI support to TAD uncore driver
  perf/marvell: Add ACPI support to DDR uncore driver
  perf/arm-cmn: Reset DTM_PMU_CONFIG at probe
  drivers/perf: hisi: Extract initialization of "cpa_pmu->pmu"
  drivers/perf: hisi: Simplify the parameters of hisi_pmu_init()
  drivers/perf: hisi: Advertise the PERF_PMU_CAP_NO_EXCLUDE capability

* for-next/sysreg:
  : arm64 sysreg and cpufeature fixes/updates
  KVM: arm64: Use symbolic definition for ISR_EL1.A
  arm64/sysreg: Add definition of ISR_EL1
  arm64/sysreg: Add definition for ICC_NMIAR1_EL1
  arm64/cpufeature: Remove 4 bit assumption in ARM64_FEATURE_MASK()
  arm64/sysreg: Fix errors in 32 bit enumeration values
  arm64/cpufeature: Fix field sign for DIT hwcap detection

* for-next/sme:
  : SME-related updates
  arm64/sme: Optimise SME exit on syscall entry
  arm64/sme: Don't use streaming mode to probe the maximum SME VL
  arm64/ptrace: Use system_supports_tpidr2() to check for TPIDR2 support

* for-next/kselftest: (23 commits)
  : arm64 kselftest fixes and improvements
  kselftest/arm64: Don't require FA64 for streaming SVE+ZA tests
  kselftest/arm64: Copy whole EXTRA context
  kselftest/arm64: Fix enumeration of systems without 128 bit SME for SSVE+ZA
  kselftest/arm64: Fix enumeration of systems without 128 bit SME
  kselftest/arm64: Don't require FA64 for streaming SVE tests
  kselftest/arm64: Limit the maximum VL we try to set via ptrace
  kselftest/arm64: Correct buffer size for SME ZA storage
  kselftest/arm64: Remove the local NUM_VL definition
  kselftest/arm64: Verify simultaneous SSVE and ZA context generation
  kselftest/arm64: Verify that SSVE signal context has SVE_SIG_FLAG_SM set
  kselftest/arm64: Remove spurious comment from MTE test Makefile
  kselftest/arm64: Support build of MTE tests with clang
  kselftest/arm64: Initialise current at build time in signal tests
  kselftest/arm64: Don't pass headers to the compiler as source
  kselftest/arm64: Remove redundant _start labels from FP tests
  kselftest/arm64: Fix .pushsection for strings in FP tests
  kselftest/arm64: Run BTI selftests on systems without BTI
  kselftest/arm64: Fix test numbering when skipping tests
  kselftest/arm64: Skip non-power of 2 SVE vector lengths in fp-stress
  kselftest/arm64: Only enumerate power of two VLs in syscall-abi
  ...

* for-next/misc:
  : Miscellaneous arm64 updates
  arm64/mm: Intercept pfn changes in set_pte_at()
  Documentation: arm64: correct spelling
  arm64: traps: attempt to dump all instructions
  arm64: Apply dynamic shadow call stack patching in two passes
  arm64: el2_setup.h: fix spelling typo in comments
  arm64: Kconfig: fix spelling
  arm64: cpufeature: Use kstrtobool() instead of strtobool()
  arm64: Avoid repeated AA64MMFR1_EL1 register read on pagefault path
  arm64: make ARCH_FORCE_MAX_ORDER selectable

* for-next/sme2: (23 commits)
  : Support for arm64 SME 2 and 2.1
  arm64/sme: Fix __finalise_el2 SMEver check
  kselftest/arm64: Remove redundant _start labels from zt-test
  kselftest/arm64: Add coverage of SME 2 and 2.1 hwcaps
  kselftest/arm64: Add coverage of the ZT ptrace regset
  kselftest/arm64: Add SME2 coverage to syscall-abi
  kselftest/arm64: Add test coverage for ZT register signal frames
  kselftest/arm64: Teach the generic signal context validation about ZT
  kselftest/arm64: Enumerate SME2 in the signal test utility code
  kselftest/arm64: Cover ZT in the FP stress test
  kselftest/arm64: Add a stress test program for ZT0
  arm64/sme: Add hwcaps for SME 2 and 2.1 features
  arm64/sme: Implement ZT0 ptrace support
  arm64/sme: Implement signal handling for ZT
  arm64/sme: Implement context switching for ZT0
  arm64/sme: Provide storage for ZT0
  arm64/sme: Add basic enumeration for SME2
  arm64/sme: Enable host kernel to access ZT0
  arm64/sme: Manually encode ZT0 load and store instructions
  arm64/esr: Document ISS for ZT0 being disabled
  arm64/sme: Document SME 2 and SME 2.1 ABI
  ...

* for-next/tpidr2:
  : Include TPIDR2 in the signal context
  kselftest/arm64: Add test case for TPIDR2 signal frame records
  kselftest/arm64: Add TPIDR2 to the set of known signal context records
  arm64/signal: Include TPIDR2 in the signal context
  arm64/sme: Document ABI for TPIDR2 signal information

* for-next/scs:
  : arm64: harden shadow call stack pointer handling
  arm64: Stash shadow stack pointer in the task struct on interrupt
  arm64: Always load shadow stack pointer directly from the task struct

* for-next/compat-hwcap:
  : arm64: Expose compat ARMv8 AArch32 features (HWCAPs)
  arm64: Add compat hwcap SSBS
  arm64: Add compat hwcap SB
  arm64: Add compat hwcap I8MM
  arm64: Add compat hwcap ASIMDBF16
  arm64: Add compat hwcap ASIMDFHM
  arm64: Add compat hwcap ASIMDDP
  arm64: Add compat hwcap FPHP and ASIMDHP

* for-next/ftrace:
  : Add arm64 support for DYNAMICE_FTRACE_WITH_CALL_OPS
  arm64: avoid executing padding bytes during kexec / hibernation
  arm64: Implement HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS
  arm64: ftrace: Update stale comment
  arm64: patching: Add aarch64_insn_write_literal_u64()
  arm64: insn: Add helpers for BTI
  arm64: Extend support for CONFIG_FUNCTION_ALIGNMENT
  ACPI: Don't build ACPICA with '-Os'
  Compiler attributes: GCC cold function alignment workarounds
  ftrace: Add DYNAMIC_FTRACE_WITH_CALL_OPS

* for-next/efi-boot-mmu-on:
  : Permit arm64 EFI boot with MMU and caches on
  arm64: kprobes: Drop ID map text from kprobes blacklist
  arm64: head: Switch endianness before populating the ID map
  efi: arm64: enter with MMU and caches enabled
  arm64: head: Clean the ID map and the HYP text to the PoC if needed
  arm64: head: avoid cache invalidation when entering with the MMU on
  arm64: head: record the MMU state at primary entry
  arm64: kernel: move identity map out of .text mapping
  arm64: head: Move all finalise_el2 calls to after __enable_mmu

* for-next/ptrauth:
  : arm64 pointer authentication cleanup
  arm64: pauth: don't sign leaf functions
  arm64: unify asm-arch manipulation

* for-next/pseudo-nmi:
  : Pseudo-NMI code generation optimisations
  arm64: irqflags: use alternative branches for pseudo-NMI logic
  arm64: add ARM64_HAS_GIC_PRIO_RELAXED_SYNC cpucap
  arm64: make ARM64_HAS_GIC_PRIO_MASKING depend on ARM64_HAS_GIC_CPUIF_SYSREGS
  arm64: rename ARM64_HAS_IRQ_PRIO_MASKING to ARM64_HAS_GIC_PRIO_MASKING
  arm64: rename ARM64_HAS_SYSREG_GIC_CPUIF to ARM64_HAS_GIC_CPUIF_SYSREGS

120 files changed:
Documentation/arm64/booting.rst
Documentation/arm64/elf_hwcaps.rst
Documentation/arm64/sme.rst
Documentation/arm64/sve.rst
arch/arm/include/asm/arch_gicv3.h
arch/arm64/Kconfig
arch/arm64/Kconfig.platforms
arch/arm64/Makefile
arch/arm64/include/asm/arch_gicv3.h
arch/arm64/include/asm/barrier.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/efi.h
arch/arm64/include/asm/el2_setup.h
arch/arm64/include/asm/esr.h
arch/arm64/include/asm/fpsimd.h
arch/arm64/include/asm/fpsimdmacros.h
arch/arm64/include/asm/ftrace.h
arch/arm64/include/asm/hwcap.h
arch/arm64/include/asm/insn.h
arch/arm64/include/asm/irqflags.h
arch/arm64/include/asm/linkage.h
arch/arm64/include/asm/patching.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/ptrace.h
arch/arm64/include/asm/scs.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/uapi/asm/hwcap.h
arch/arm64/include/uapi/asm/sigcontext.h
arch/arm64/kernel/asm-offsets.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/cpuinfo.c
arch/arm64/kernel/entry-fpsimd.S
arch/arm64/kernel/entry-ftrace.S
arch/arm64/kernel/entry.S
arch/arm64/kernel/fpsimd.c
arch/arm64/kernel/ftrace.c
arch/arm64/kernel/head.S
arch/arm64/kernel/hyp-stub.S
arch/arm64/kernel/idreg-override.c
arch/arm64/kernel/image-vars.h
arch/arm64/kernel/patch-scs.c
arch/arm64/kernel/patching.c
arch/arm64/kernel/probes/kprobes.c
arch/arm64/kernel/process.c
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/setup.c
arch/arm64/kernel/signal.c
arch/arm64/kernel/sleep.S
arch/arm64/kernel/syscall.c
arch/arm64/kernel/traps.c
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/kvm/debug.c
arch/arm64/kvm/fpsimd.c
arch/arm64/kvm/hyp/entry.S
arch/arm64/kvm/hyp/nvhe/debug-sr.c
arch/arm64/mm/cache.S
arch/arm64/mm/mmu.c
arch/arm64/mm/proc.S
arch/arm64/tools/cpucaps
arch/arm64/tools/sysreg
drivers/acpi/acpica/Makefile
drivers/firmware/efi/libstub/Makefile
drivers/firmware/efi/libstub/arm64-entry.S [deleted file]
drivers/firmware/efi/libstub/arm64-stub.c
drivers/firmware/efi/libstub/arm64.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-gic.c
drivers/perf/arm-cmn.c
drivers/perf/arm_spe_pmu.c
drivers/perf/fsl_imx8_ddr_perf.c
drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c
drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c
drivers/perf/hisilicon/hisi_uncore_hha_pmu.c
drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c
drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
drivers/perf/hisilicon/hisi_uncore_pmu.c
drivers/perf/hisilicon/hisi_uncore_pmu.h
drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c
drivers/perf/marvell_cn10k_ddr_pmu.c
drivers/perf/marvell_cn10k_tad_pmu.c
include/linux/compiler_attributes.h
include/linux/compiler_types.h
include/linux/ftrace.h
include/uapi/linux/elf.h
include/uapi/linux/perf_event.h
kernel/exit.c
kernel/trace/Kconfig
kernel/trace/ftrace.c
tools/testing/selftests/arm64/abi/hwcap.c
tools/testing/selftests/arm64/abi/syscall-abi-asm.S
tools/testing/selftests/arm64/abi/syscall-abi.c
tools/testing/selftests/arm64/bti/test.c
tools/testing/selftests/arm64/fp/.gitignore
tools/testing/selftests/arm64/fp/Makefile
tools/testing/selftests/arm64/fp/assembler.h
tools/testing/selftests/arm64/fp/fp-pidbench.S
tools/testing/selftests/arm64/fp/fp-stress.c
tools/testing/selftests/arm64/fp/fpsimd-test.S
tools/testing/selftests/arm64/fp/sme-inst.h
tools/testing/selftests/arm64/fp/sve-ptrace.c
tools/testing/selftests/arm64/fp/sve-test.S
tools/testing/selftests/arm64/fp/za-ptrace.c
tools/testing/selftests/arm64/fp/za-test.S
tools/testing/selftests/arm64/fp/zt-ptrace.c [new file with mode: 0644]
tools/testing/selftests/arm64/fp/zt-test.S [new file with mode: 0644]
tools/testing/selftests/arm64/mte/Makefile
tools/testing/selftests/arm64/signal/.gitignore
tools/testing/selftests/arm64/signal/Makefile
tools/testing/selftests/arm64/signal/test_signals.c
tools/testing/selftests/arm64/signal/test_signals.h
tools/testing/selftests/arm64/signal/test_signals_utils.c
tools/testing/selftests/arm64/signal/testcases/ssve_regs.c
tools/testing/selftests/arm64/signal/testcases/ssve_za_regs.c [new file with mode: 0644]
tools/testing/selftests/arm64/signal/testcases/testcases.c
tools/testing/selftests/arm64/signal/testcases/testcases.h
tools/testing/selftests/arm64/signal/testcases/tpidr2_siginfo.c [new file with mode: 0644]
tools/testing/selftests/arm64/signal/testcases/za_regs.c
tools/testing/selftests/arm64/signal/testcases/zt_no_regs.c [new file with mode: 0644]
tools/testing/selftests/arm64/signal/testcases/zt_regs.c [new file with mode: 0644]

index 96fe10e..ffeccdd 100644 (file)
@@ -223,7 +223,7 @@ Before jumping into the kernel, the following conditions must be met:
   For systems with a GICv3 interrupt controller to be used in v3 mode:
   - If EL3 is present:
 
-      - ICC_SRE_EL3.Enable (bit 3) must be initialiased to 0b1.
+      - ICC_SRE_EL3.Enable (bit 3) must be initialised to 0b1.
       - ICC_SRE_EL3.SRE (bit 0) must be initialised to 0b1.
       - ICC_CTLR_EL3.PMHE (bit 6) must be set to the same value across
         all CPUs the kernel is executing on, and must stay constant
@@ -369,6 +369,16 @@ Before jumping into the kernel, the following conditions must be met:
 
     - HCR_EL2.ATA (bit 56) must be initialised to 0b1.
 
+  For CPUs with the Scalable Matrix Extension version 2 (FEAT_SME2):
+
+  - If EL3 is present:
+
+    - SMCR_EL3.EZT0 (bit 30) must be initialised to 0b1.
+
+ - If the kernel is entered at EL1 and EL2 is present:
+
+    - SMCR_EL2.EZT0 (bit 30) must be initialised to 0b1.
+
 The requirements described above for CPU mode, caches, MMUs, architected
 timers, coherency and system registers apply to all CPUs.  All CPUs must
 enter the kernel in the same exception level.  Where the values documented
index 6fed84f..83e57e4 100644 (file)
@@ -14,7 +14,7 @@ Some hardware or software features are only available on some CPU
 implementations, and/or with certain kernel configurations, but have no
 architected discovery mechanism available to userspace code at EL0. The
 kernel exposes the presence of these features to userspace through a set
-of flags called hwcaps, exposed in the auxilliary vector.
+of flags called hwcaps, exposed in the auxiliary vector.
 
 Userspace software can test for features by acquiring the AT_HWCAP or
 AT_HWCAP2 entry of the auxiliary vector, and testing whether the relevant
@@ -284,6 +284,24 @@ HWCAP2_RPRFM
 HWCAP2_SVE2P1
     Functionality implied by ID_AA64ZFR0_EL1.SVEver == 0b0010.
 
+HWCAP2_SME2
+    Functionality implied by ID_AA64SMFR0_EL1.SMEver == 0b0001.
+
+HWCAP2_SME2P1
+    Functionality implied by ID_AA64SMFR0_EL1.SMEver == 0b0010.
+
+HWCAP2_SMEI16I32
+    Functionality implied by ID_AA64SMFR0_EL1.I16I32 == 0b0101
+
+HWCAP2_SMEBI32I32
+    Functionality implied by ID_AA64SMFR0_EL1.BI32I32 == 0b1
+
+HWCAP2_SMEB16B16
+    Functionality implied by ID_AA64SMFR0_EL1.B16B16 == 0b1
+
+HWCAP2_SMEF16F16
+    Functionality implied by ID_AA64SMFR0_EL1.F16F16 == 0b1
+
 4. Unused AT_HWCAP bits
 -----------------------
 
index 16d2db4..1c43ea1 100644 (file)
@@ -18,14 +18,19 @@ model features for SME is included in Appendix A.
 1.  General
 -----------
 
-* PSTATE.SM, PSTATE.ZA, the streaming mode vector length, the ZA
-  register state and TPIDR2_EL0 are tracked per thread.
+* PSTATE.SM, PSTATE.ZA, the streaming mode vector length, the ZA and (when
+  present) ZTn register state and TPIDR2_EL0 are tracked per thread.
 
 * The presence of SME is reported to userspace via HWCAP2_SME in the aux vector
   AT_HWCAP2 entry.  Presence of this flag implies the presence of the SME
   instructions and registers, and the Linux-specific system interfaces
   described in this document.  SME is reported in /proc/cpuinfo as "sme".
 
+* The presence of SME2 is reported to userspace via HWCAP2_SME2 in the
+  aux vector AT_HWCAP2 entry.  Presence of this flag implies the presence of
+  the SME2 instructions and ZT0, and the Linux-specific system interfaces
+  described in this document.  SME2 is reported in /proc/cpuinfo as "sme2".
+
 * Support for the execution of SME instructions in userspace can also be
   detected by reading the CPU ID register ID_AA64PFR1_EL1 using an MRS
   instruction, and checking that the value of the SME field is nonzero. [3]
@@ -44,6 +49,7 @@ model features for SME is included in Appendix A.
        HWCAP2_SME_B16F32
        HWCAP2_SME_F32F32
        HWCAP2_SME_FA64
+        HWCAP2_SME2
 
   This list may be extended over time as the SME architecture evolves.
 
@@ -52,8 +58,8 @@ model features for SME is included in Appendix A.
   cpu-feature-registers.txt for details.
 
 * Debuggers should restrict themselves to interacting with the target via the
-  NT_ARM_SVE, NT_ARM_SSVE and NT_ARM_ZA regsets.  The recommended way
-  of detecting support for these regsets is to connect to a target process
+  NT_ARM_SVE, NT_ARM_SSVE, NT_ARM_ZA and NT_ARM_ZT regsets.  The recommended
+  way of detecting support for these regsets is to connect to a target process
   first and then attempt a
 
        ptrace(PTRACE_GETREGSET, pid, NT_ARM_<regset>, &iov).
@@ -89,13 +95,13 @@ be zeroed.
 -------------------------
 
 * On syscall PSTATE.ZA is preserved, if PSTATE.ZA==1 then the contents of the
-  ZA matrix are preserved.
+  ZA matrix and ZTn (if present) are preserved.
 
 * On syscall PSTATE.SM will be cleared and the SVE registers will be handled
   as per the standard SVE ABI.
 
-* Neither the SVE registers nor ZA are used to pass arguments to or receive
-  results from any syscall.
+* None of the SVE registers, ZA or ZTn are used to pass arguments to
+  or receive results from any syscall.
 
 * On process creation (eg, clone()) the newly created process will have
   PSTATE.SM cleared.
@@ -111,6 +117,9 @@ be zeroed.
 
 * Signal handlers are invoked with streaming mode and ZA disabled.
 
+* A new signal frame record TPIDR2_MAGIC is added formatted as a struct
+  tpidr2_context to allow access to TPIDR2_EL0 from signal handlers.
+
 * A new signal frame record za_context encodes the ZA register contents on
   signal delivery. [1]
 
@@ -134,6 +143,14 @@ be zeroed.
   __reserved[] referencing this space.  za_context is then written in the
   extra space.  Refer to [1] for further details about this mechanism.
 
+* If ZTn is supported and PSTATE.ZA==1 then a signal frame record for ZTn will
+  be generated.
+
+* The signal record for ZTn has magic ZT_MAGIC (0x5a544e01) and consists of a
+  standard signal frame header followed by a struct zt_context specifying
+  the number of ZTn registers supported by the system, then zt_context.nregs
+  blocks of 64 bytes of data per register.
+
 
 5.  Signal return
 -----------------
@@ -151,6 +168,9 @@ When returning from a signal handler:
   the signal frame does not match the current vector length, the signal return
   attempt is treated as illegal, resulting in a forced SIGSEGV.
 
+* If ZTn is not supported or PSTATE.ZA==0 then it is illegal to have a
+  signal frame record for ZTn, resulting in a forced SIGSEGV.
+
 
 6.  prctl extensions
 --------------------
@@ -214,8 +234,8 @@ prctl(PR_SME_SET_VL, unsigned long arg)
       vector length that will be applied at the next execve() by the calling
       thread.
 
-    * Changing the vector length causes all of ZA, P0..P15, FFR and all bits of
-      Z0..Z31 except for Z0 bits [127:0] .. Z31 bits [127:0] to become
+    * Changing the vector length causes all of ZA, ZTn, P0..P15, FFR and all
+      bits of Z0..Z31 except for Z0 bits [127:0] .. Z31 bits [127:0] to become
       unspecified, including both streaming and non-streaming SVE state.
       Calling PR_SME_SET_VL with vl equal to the thread's current vector
       length, or calling PR_SME_SET_VL with the PR_SVE_SET_VL_ONEXEC flag,
@@ -317,6 +337,15 @@ The regset data starts with struct user_za_header, containing:
 
 * The effect of writing a partial, incomplete payload is unspecified.
 
+* A new regset NT_ARM_ZT is defined for access to ZTn state via
+  PTRACE_GETREGSET and PTRACE_SETREGSET.
+
+* The NT_ARM_ZT regset consists of a single 512 bit register.
+
+* When PSTATE.ZA==0 reads of NT_ARM_ZT will report all bits of ZTn as 0.
+
+* Writes to NT_ARM_ZT will set PSTATE.ZA to 1.
+
 
 8.  ELF coredump extensions
 ---------------------------
@@ -331,6 +360,11 @@ The regset data starts with struct user_za_header, containing:
   been read if a PTRACE_GETREGSET of NT_ARM_ZA were executed for each thread
   when the coredump was generated.
 
+* A NT_ARM_ZT note will be added to each coredump for each thread of the
+  dumped process.  The contents will be equivalent to the data that would have
+  been read if a PTRACE_GETREGSET of NT_ARM_ZT were executed for each thread
+  when the coredump was generated.
+
 * The NT_ARM_TLS note will be extended to two registers, the second register
   will contain TPIDR2_EL0 on systems that support SME and will be read as
   zero with writes ignored otherwise.
@@ -406,6 +440,9 @@ In A64 state, SME adds the following:
   For best system performance it is strongly encouraged for software to enable
   ZA only when it is actively being used.
 
+* A new ZT0 register is introduced when SME2 is present. This is a 512 bit
+  register which is accessible when PSTATE.ZA is set, as ZA itself is.
+
 * Two new 1 bit fields in PSTATE which may be controlled via the SMSTART and
   SMSTOP instructions or by access to the SVCR system register:
 
index c7a356b..1b90a30 100644 (file)
@@ -175,7 +175,7 @@ the SVE instruction set architecture.
 When returning from a signal handler:
 
 * If there is no sve_context record in the signal frame, or if the record is
-  present but contains no register data as desribed in the previous section,
+  present but contains no register data as described in the previous section,
   then the SVE registers/bits become non-live and take unspecified values.
 
 * If sve_context is present in the signal frame and contains full register
@@ -223,7 +223,7 @@ prctl(PR_SVE_SET_VL, unsigned long arg)
            Defer the requested vector length change until the next execve()
            performed by this thread.
 
-           The effect is equivalent to implicit exceution of the following
+           The effect is equivalent to implicit execution of the following
            call immediately after the next execve() (if any) by the thread:
 
                prctl(PR_SVE_SET_VL, arg & ~PR_SVE_SET_VL_ONEXEC)
index f82a819..311e830 100644 (file)
@@ -252,5 +252,10 @@ static inline void gic_arch_enable_irqs(void)
        WARN_ON_ONCE(true);
 }
 
+static inline bool gic_has_relaxed_pmr_sync(void)
+{
+       return false;
+}
+
 #endif /* !__ASSEMBLY__ */
 #endif /* !__ASM_ARCH_GICV3_H */
index be760ad..619ab04 100644 (file)
@@ -123,6 +123,8 @@ config ARM64
        select DMA_DIRECT_REMAP
        select EDAC_SUPPORT
        select FRAME_POINTER
+       select FUNCTION_ALIGNMENT_4B
+       select FUNCTION_ALIGNMENT_8B if DYNAMIC_FTRACE_WITH_CALL_OPS
        select GENERIC_ALLOCATOR
        select GENERIC_ARCH_TOPOLOGY
        select GENERIC_CLOCKEVENTS_BROADCAST
@@ -186,6 +188,8 @@ config ARM64
        select HAVE_DYNAMIC_FTRACE
        select HAVE_DYNAMIC_FTRACE_WITH_ARGS \
                if $(cc-option,-fpatchable-function-entry=2)
+       select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS \
+               if (DYNAMIC_FTRACE_WITH_ARGS && !CFI_CLANG)
        select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY \
                if DYNAMIC_FTRACE_WITH_ARGS
        select HAVE_EFFICIENT_UNALIGNED_ACCESS
@@ -1456,10 +1460,23 @@ config XEN
        help
          Say Y if you want to run Linux in a Virtual Machine on Xen on ARM64.
 
+# include/linux/mmzone.h requires the following to be true:
+#
+#   MAX_ORDER - 1 + PAGE_SHIFT <= SECTION_SIZE_BITS
+#
+# so the maximum value of MAX_ORDER is SECTION_SIZE_BITS + 1 - PAGE_SHIFT:
+#
+#     | SECTION_SIZE_BITS |  PAGE_SHIFT  |  max MAX_ORDER  |  default MAX_ORDER |
+# ----+-------------------+--------------+-----------------+--------------------+
+# 4K  |       27          |      12      |       16        |         11         |
+# 16K |       27          |      14      |       14        |         12         |
+# 64K |       29          |      16      |       14        |         14         |
 config ARCH_FORCE_MAX_ORDER
-       int
+       int "Maximum zone order" if ARM64_4K_PAGES || ARM64_16K_PAGES
        default "14" if ARM64_64K_PAGES
+       range 12 14 if ARM64_16K_PAGES
        default "12" if ARM64_16K_PAGES
+       range 11 16 if ARM64_4K_PAGES
        default "11"
        help
          The kernel memory allocator divides physically contiguous memory
@@ -1472,7 +1489,7 @@ config ARCH_FORCE_MAX_ORDER
          This config option is actually maximum order plus one. For example,
          a value of 11 means that the largest free memory block is 2^10 pages.
 
-         We make sure that we can allocate upto a HugePage size for each configuration.
+         We make sure that we can allocate up to a HugePage size for each configuration.
          Hence we have :
                MAX_ORDER = (PMD_SHIFT - PAGE_SHIFT) + 1 => PAGE_SHIFT - 2
 
index d1970ad..333d0af 100644 (file)
@@ -187,7 +187,7 @@ config ARCH_MVEBU
        select PINCTRL_ARMADA_CP110
        select PINCTRL_AC5
        help
-         This enables support for Marvell EBU familly, including:
+         This enables support for Marvell EBU family, including:
           - Armada 3700 SoC Family
           - Armada 7K SoC Family
           - Armada 8K SoC Family
index ab1f12b..c33b5da 100644 (file)
@@ -126,7 +126,10 @@ endif
 
 CHECKFLAGS     += -D__aarch64__
 
-ifeq ($(CONFIG_DYNAMIC_FTRACE_WITH_ARGS),y)
+ifeq ($(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS),y)
+  KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY
+  CC_FLAGS_FTRACE := -fpatchable-function-entry=4,2
+else ifeq ($(CONFIG_DYNAMIC_FTRACE_WITH_ARGS),y)
   KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY
   CC_FLAGS_FTRACE := -fpatchable-function-entry=2
 endif
index 48d4473..01281a5 100644 (file)
@@ -190,5 +190,10 @@ static inline void gic_arch_enable_irqs(void)
        asm volatile ("msr daifclr, #3" : : : "memory");
 }
 
+static inline bool gic_has_relaxed_pmr_sync(void)
+{
+       return cpus_have_cap(ARM64_HAS_GIC_PRIO_RELAXED_SYNC);
+}
+
 #endif /* __ASSEMBLY__ */
 #endif /* __ASM_ARCH_GICV3_H */
index 2cfc424..3dd8982 100644 (file)
@@ -11,6 +11,8 @@
 
 #include <linux/kasan-checks.h>
 
+#include <asm/alternative-macros.h>
+
 #define __nops(n)      ".rept  " #n "\nnop\n.endr\n"
 #define nops(n)                asm volatile(__nops(n))
 
 #ifdef CONFIG_ARM64_PSEUDO_NMI
 #define pmr_sync()                                             \
        do {                                                    \
-               extern struct static_key_false gic_pmr_sync;    \
-                                                               \
-               if (static_branch_unlikely(&gic_pmr_sync))      \
-                       dsb(sy);                                \
+               asm volatile(                                   \
+               ALTERNATIVE_CB("dsb sy",                        \
+                              ARM64_HAS_GIC_PRIO_RELAXED_SYNC, \
+                              alt_cb_patch_nops)               \
+               );                                              \
        } while(0)
 #else
 #define pmr_sync()     do {} while (0)
index 03d1c9d..6bf013f 100644 (file)
@@ -769,6 +769,12 @@ static __always_inline bool system_supports_sme(void)
                cpus_have_const_cap(ARM64_SME);
 }
 
+static __always_inline bool system_supports_sme2(void)
+{
+       return IS_ENABLED(CONFIG_ARM64_SME) &&
+               cpus_have_const_cap(ARM64_SME2);
+}
+
 static __always_inline bool system_supports_fa64(void)
 {
        return IS_ENABLED(CONFIG_ARM64_SME) &&
@@ -806,7 +812,7 @@ static inline bool system_has_full_ptr_auth(void)
 static __always_inline bool system_uses_irq_prio_masking(void)
 {
        return IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) &&
-              cpus_have_const_cap(ARM64_HAS_IRQ_PRIO_MASKING);
+              cpus_have_const_cap(ARM64_HAS_GIC_PRIO_MASKING);
 }
 
 static inline bool system_supports_mte(void)
@@ -864,7 +870,11 @@ static inline bool cpu_has_hw_af(void)
        if (!IS_ENABLED(CONFIG_ARM64_HW_AFDBM))
                return false;
 
-       mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
+       /*
+        * Use cached version to avoid emulated msr operation on KVM
+        * guests.
+        */
+       mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
        return cpuid_feature_extract_unsigned_field(mmfr1,
                                                ID_AA64MMFR1_EL1_HAFDBS_SHIFT);
 }
index 31d13a6..0f0e729 100644 (file)
@@ -105,6 +105,8 @@ static inline unsigned long efi_get_kimg_min_align(void)
 #define EFI_ALLOC_ALIGN                SZ_64K
 #define EFI_ALLOC_LIMIT                ((1UL << 48) - 1)
 
+extern unsigned long primary_entry_offset(void);
+
 /*
  * On ARM systems, virtually remapped UEFI runtime services are set up in two
  * distinct stages:
index 668569a..2cdd010 100644 (file)
        cbz     x0, .Lskip_spe_\@               // Skip if SPE not present
 
        mrs_s   x0, SYS_PMBIDR_EL1              // If SPE available at EL2,
-       and     x0, x0, #(1 << SYS_PMBIDR_EL1_P_SHIFT)
+       and     x0, x0, #(1 << PMBIDR_EL1_P_SHIFT)
        cbnz    x0, .Lskip_spe_el2_\@           // then permit sampling of physical
-       mov     x0, #(1 << SYS_PMSCR_EL2_PCT_SHIFT | \
-                     1 << SYS_PMSCR_EL2_PA_SHIFT)
+       mov     x0, #(1 << PMSCR_EL2_PCT_SHIFT | \
+                     1 << PMSCR_EL2_PA_SHIFT)
        msr_s   SYS_PMSCR_EL2, x0               // addresses and physical counter
 .Lskip_spe_el2_\@:
        mov     x0, #(MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT)
 /**
  * Initialize EL2 registers to sane values. This should be called early on all
  * cores that were booted in EL2. Note that everything gets initialised as
- * if VHE was not evailable. The kernel context will be upgraded to VHE
+ * if VHE was not available. The kernel context will be upgraded to VHE
  * if possible later on in the boot process
  *
  * Regs: x0, x1 and x2 are clobbered.
index 15b34fb..5f3271e 100644 (file)
 #define ESR_ELx_SME_ISS_ILL            1
 #define ESR_ELx_SME_ISS_SM_DISABLED    2
 #define ESR_ELx_SME_ISS_ZA_DISABLED    3
+#define ESR_ELx_SME_ISS_ZT_DISABLED    4
 
 #ifndef __ASSEMBLY__
 #include <asm/types.h>
index e6fa1e2..67f2fb7 100644 (file)
@@ -61,7 +61,7 @@ extern void fpsimd_kvm_prepare(void);
 struct cpu_fp_state {
        struct user_fpsimd_state *st;
        void *sve_state;
-       void *za_state;
+       void *sme_state;
        u64 *svcr;
        unsigned int sve_vl;
        unsigned int sme_vl;
@@ -105,6 +105,13 @@ static inline void *sve_pffr(struct thread_struct *thread)
        return (char *)thread->sve_state + sve_ffr_offset(vl);
 }
 
+static inline void *thread_zt_state(struct thread_struct *thread)
+{
+       /* The ZT register state is stored immediately after the ZA state */
+       unsigned int sme_vq = sve_vq_from_vl(thread_get_sme_vl(thread));
+       return thread->sme_state + ZA_SIG_REGS_SIZE(sme_vq);
+}
+
 extern void sve_save_state(void *state, u32 *pfpsr, int save_ffr);
 extern void sve_load_state(void const *state, u32 const *pfpsr,
                           int restore_ffr);
@@ -112,12 +119,13 @@ extern void sve_flush_live(bool flush_ffr, unsigned long vq_minus_1);
 extern unsigned int sve_get_vl(void);
 extern void sve_set_vq(unsigned long vq_minus_1);
 extern void sme_set_vq(unsigned long vq_minus_1);
-extern void za_save_state(void *state);
-extern void za_load_state(void const *state);
+extern void sme_save_state(void *state, int zt);
+extern void sme_load_state(void const *state, int zt);
 
 struct arm64_cpu_capabilities;
 extern void sve_kernel_enable(const struct arm64_cpu_capabilities *__unused);
 extern void sme_kernel_enable(const struct arm64_cpu_capabilities *__unused);
+extern void sme2_kernel_enable(const struct arm64_cpu_capabilities *__unused);
 extern void fa64_kernel_enable(const struct arm64_cpu_capabilities *__unused);
 
 extern u64 read_zcr_features(void);
@@ -355,14 +363,20 @@ extern int sme_get_current_vl(void);
 
 /*
  * Return how many bytes of memory are required to store the full SME
- * specific state (currently just ZA) for task, given task's currently
- * configured vector length.
+ * specific state for task, given task's currently configured vector
+ * length.
  */
-static inline size_t za_state_size(struct task_struct const *task)
+static inline size_t sme_state_size(struct task_struct const *task)
 {
        unsigned int vl = task_get_sme_vl(task);
+       size_t size;
+
+       size = ZA_SIG_REGS_SIZE(sve_vq_from_vl(vl));
+
+       if (system_supports_sme2())
+               size += ZT_SIG_REG_SIZE;
 
-       return ZA_SIG_REGS_SIZE(sve_vq_from_vl(vl));
+       return size;
 }
 
 #else
@@ -382,7 +396,7 @@ static inline int sme_max_virtualisable_vl(void) { return 0; }
 static inline int sme_set_current_vl(unsigned long arg) { return -EINVAL; }
 static inline int sme_get_current_vl(void) { return -EINVAL; }
 
-static inline size_t za_state_size(struct task_struct const *task)
+static inline size_t sme_state_size(struct task_struct const *task)
 {
        return 0;
 }
index 5e0910c..cd03819 100644 (file)
                | ((\offset) & 7)
 .endm
 
+/*
+ * LDR (ZT0)
+ *
+ *     LDR ZT0, nx
+ */
+.macro _ldr_zt nx
+       _check_general_reg \nx
+       .inst   0xe11f8000      \
+                | (\nx << 5)
+.endm
+
+/*
+ * STR (ZT0)
+ *
+ *     STR ZT0, nx
+ */
+.macro _str_zt nx
+       _check_general_reg \nx
+       .inst   0xe13f8000              \
+               | (\nx << 5)
+.endm
+
 /*
  * Zero the entire ZA array
  *     ZERO ZA
index 5664729..1c2672b 100644 (file)
@@ -62,20 +62,7 @@ extern unsigned long ftrace_graph_call;
 
 extern void return_to_handler(void);
 
-static inline unsigned long ftrace_call_adjust(unsigned long addr)
-{
-       /*
-        * Adjust addr to point at the BL in the callsite.
-        * See ftrace_init_nop() for the callsite sequence.
-        */
-       if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_ARGS))
-               return addr + AARCH64_INSN_SIZE;
-       /*
-        * addr is the address of the mcount call instruction.
-        * recordmcount does the necessary offset calculation.
-        */
-       return addr;
-}
+unsigned long ftrace_call_adjust(unsigned long addr);
 
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
 struct dyn_ftrace;
index 06dd12c..5d45f19 100644 (file)
 #define COMPAT_HWCAP_VFPD32    (1 << 19)
 #define COMPAT_HWCAP_LPAE      (1 << 20)
 #define COMPAT_HWCAP_EVTSTRM   (1 << 21)
+#define COMPAT_HWCAP_FPHP      (1 << 22)
+#define COMPAT_HWCAP_ASIMDHP   (1 << 23)
+#define COMPAT_HWCAP_ASIMDDP   (1 << 24)
+#define COMPAT_HWCAP_ASIMDFHM  (1 << 25)
+#define COMPAT_HWCAP_ASIMDBF16 (1 << 26)
+#define COMPAT_HWCAP_I8MM      (1 << 27)
 
 #define COMPAT_HWCAP2_AES      (1 << 0)
 #define COMPAT_HWCAP2_PMULL    (1 << 1)
 #define COMPAT_HWCAP2_SHA1     (1 << 2)
 #define COMPAT_HWCAP2_SHA2     (1 << 3)
 #define COMPAT_HWCAP2_CRC32    (1 << 4)
+#define COMPAT_HWCAP2_SB       (1 << 5)
+#define COMPAT_HWCAP2_SSBS     (1 << 6)
 
 #ifndef __ASSEMBLY__
 #include <linux/log2.h>
 #define KERNEL_HWCAP_CSSC              __khwcap2_feature(CSSC)
 #define KERNEL_HWCAP_RPRFM             __khwcap2_feature(RPRFM)
 #define KERNEL_HWCAP_SVE2P1            __khwcap2_feature(SVE2P1)
+#define KERNEL_HWCAP_SME2              __khwcap2_feature(SME2)
+#define KERNEL_HWCAP_SME2P1            __khwcap2_feature(SME2P1)
+#define KERNEL_HWCAP_SME_I16I32                __khwcap2_feature(SME_I16I32)
+#define KERNEL_HWCAP_SME_BI32I32       __khwcap2_feature(SME_BI32I32)
+#define KERNEL_HWCAP_SME_B16B16                __khwcap2_feature(SME_B16B16)
+#define KERNEL_HWCAP_SME_F16F16                __khwcap2_feature(SME_F16F16)
 
 /*
  * This yields a mask that user programs can use to figure out what
index aaf1f52..139a88e 100644 (file)
@@ -420,6 +420,7 @@ __AARCH64_INSN_FUNCS(sb,    0xFFFFFFFF, 0xD50330FF)
 __AARCH64_INSN_FUNCS(clrex,    0xFFFFF0FF, 0xD503305F)
 __AARCH64_INSN_FUNCS(ssbb,     0xFFFFFFFF, 0xD503309F)
 __AARCH64_INSN_FUNCS(pssbb,    0xFFFFFFFF, 0xD503349F)
+__AARCH64_INSN_FUNCS(bti,      0xFFFFFF3F, 0xD503241f)
 
 #undef __AARCH64_INSN_FUNCS
 
index b57b9b1..e0f5f6b 100644 (file)
  * exceptions should be unmasked.
  */
 
-/*
- * CPU interrupt mask handling.
- */
-static inline void arch_local_irq_enable(void)
+static __always_inline bool __irqflags_uses_pmr(void)
 {
-       if (system_has_prio_mask_debugging()) {
-               u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1);
+       return IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) &&
+              alternative_has_feature_unlikely(ARM64_HAS_GIC_PRIO_MASKING);
+}
 
+static __always_inline void __daif_local_irq_enable(void)
+{
+       barrier();
+       asm volatile("msr daifclr, #3");
+       barrier();
+}
+
+static __always_inline void __pmr_local_irq_enable(void)
+{
+       if (IS_ENABLED(CONFIG_ARM64_DEBUG_PRIORITY_MASKING)) {
+               u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1);
                WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF);
        }
 
-       asm volatile(ALTERNATIVE(
-               "msr    daifclr, #3             // arch_local_irq_enable",
-               __msr_s(SYS_ICC_PMR_EL1, "%0"),
-               ARM64_HAS_IRQ_PRIO_MASKING)
-               :
-               : "r" ((unsigned long) GIC_PRIO_IRQON)
-               : "memory");
-
+       barrier();
+       write_sysreg_s(GIC_PRIO_IRQON, SYS_ICC_PMR_EL1);
        pmr_sync();
+       barrier();
 }
 
-static inline void arch_local_irq_disable(void)
+static inline void arch_local_irq_enable(void)
 {
-       if (system_has_prio_mask_debugging()) {
-               u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1);
+       if (__irqflags_uses_pmr()) {
+               __pmr_local_irq_enable();
+       } else {
+               __daif_local_irq_enable();
+       }
+}
 
+static __always_inline void __daif_local_irq_disable(void)
+{
+       barrier();
+       asm volatile("msr daifset, #3");
+       barrier();
+}
+
+static __always_inline void __pmr_local_irq_disable(void)
+{
+       if (IS_ENABLED(CONFIG_ARM64_DEBUG_PRIORITY_MASKING)) {
+               u32 pmr = read_sysreg_s(SYS_ICC_PMR_EL1);
                WARN_ON_ONCE(pmr != GIC_PRIO_IRQON && pmr != GIC_PRIO_IRQOFF);
        }
 
-       asm volatile(ALTERNATIVE(
-               "msr    daifset, #3             // arch_local_irq_disable",
-               __msr_s(SYS_ICC_PMR_EL1, "%0"),
-               ARM64_HAS_IRQ_PRIO_MASKING)
-               :
-               : "r" ((unsigned long) GIC_PRIO_IRQOFF)
-               : "memory");
+       barrier();
+       write_sysreg_s(GIC_PRIO_IRQOFF, SYS_ICC_PMR_EL1);
+       barrier();
+}
+
+static inline void arch_local_irq_disable(void)
+{
+       if (__irqflags_uses_pmr()) {
+               __pmr_local_irq_disable();
+       } else {
+               __daif_local_irq_disable();
+       }
+}
+
+static __always_inline unsigned long __daif_local_save_flags(void)
+{
+       return read_sysreg(daif);
+}
+
+static __always_inline unsigned long __pmr_local_save_flags(void)
+{
+       return read_sysreg_s(SYS_ICC_PMR_EL1);
 }
 
 /*
@@ -65,69 +99,108 @@ static inline void arch_local_irq_disable(void)
  */
 static inline unsigned long arch_local_save_flags(void)
 {
-       unsigned long flags;
+       if (__irqflags_uses_pmr()) {
+               return __pmr_local_save_flags();
+       } else {
+               return __daif_local_save_flags();
+       }
+}
 
-       asm volatile(ALTERNATIVE(
-               "mrs    %0, daif",
-               __mrs_s("%0", SYS_ICC_PMR_EL1),
-               ARM64_HAS_IRQ_PRIO_MASKING)
-               : "=&r" (flags)
-               :
-               : "memory");
+static __always_inline bool __daif_irqs_disabled_flags(unsigned long flags)
+{
+       return flags & PSR_I_BIT;
+}
 
-       return flags;
+static __always_inline bool __pmr_irqs_disabled_flags(unsigned long flags)
+{
+       return flags != GIC_PRIO_IRQON;
 }
 
-static inline int arch_irqs_disabled_flags(unsigned long flags)
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
 {
-       int res;
+       if (__irqflags_uses_pmr()) {
+               return __pmr_irqs_disabled_flags(flags);
+       } else {
+               return __daif_irqs_disabled_flags(flags);
+       }
+}
 
-       asm volatile(ALTERNATIVE(
-               "and    %w0, %w1, #" __stringify(PSR_I_BIT),
-               "eor    %w0, %w1, #" __stringify(GIC_PRIO_IRQON),
-               ARM64_HAS_IRQ_PRIO_MASKING)
-               : "=&r" (res)
-               : "r" ((int) flags)
-               : "memory");
+static __always_inline bool __daif_irqs_disabled(void)
+{
+       return __daif_irqs_disabled_flags(__daif_local_save_flags());
+}
 
-       return res;
+static __always_inline bool __pmr_irqs_disabled(void)
+{
+       return __pmr_irqs_disabled_flags(__pmr_local_save_flags());
 }
 
-static inline int arch_irqs_disabled(void)
+static inline bool arch_irqs_disabled(void)
 {
-       return arch_irqs_disabled_flags(arch_local_save_flags());
+       if (__irqflags_uses_pmr()) {
+               return __pmr_irqs_disabled();
+       } else {
+               return __daif_irqs_disabled();
+       }
 }
 
-static inline unsigned long arch_local_irq_save(void)
+static __always_inline unsigned long __daif_local_irq_save(void)
 {
-       unsigned long flags;
+       unsigned long flags = __daif_local_save_flags();
+
+       __daif_local_irq_disable();
+
+       return flags;
+}
 
-       flags = arch_local_save_flags();
+static __always_inline unsigned long __pmr_local_irq_save(void)
+{
+       unsigned long flags = __pmr_local_save_flags();
 
        /*
         * There are too many states with IRQs disabled, just keep the current
         * state if interrupts are already disabled/masked.
         */
-       if (!arch_irqs_disabled_flags(flags))
-               arch_local_irq_disable();
+       if (!__pmr_irqs_disabled_flags(flags))
+               __pmr_local_irq_disable();
 
        return flags;
 }
 
+static inline unsigned long arch_local_irq_save(void)
+{
+       if (__irqflags_uses_pmr()) {
+               return __pmr_local_irq_save();
+       } else {
+               return __daif_local_irq_save();
+       }
+}
+
+static __always_inline void __daif_local_irq_restore(unsigned long flags)
+{
+       barrier();
+       write_sysreg(flags, daif);
+       barrier();
+}
+
+static __always_inline void __pmr_local_irq_restore(unsigned long flags)
+{
+       barrier();
+       write_sysreg_s(flags, SYS_ICC_PMR_EL1);
+       pmr_sync();
+       barrier();
+}
+
 /*
  * restore saved IRQ state
  */
 static inline void arch_local_irq_restore(unsigned long flags)
 {
-       asm volatile(ALTERNATIVE(
-               "msr    daif, %0",
-               __msr_s(SYS_ICC_PMR_EL1, "%0"),
-               ARM64_HAS_IRQ_PRIO_MASKING)
-               :
-               : "r" (flags)
-               : "memory");
-
-       pmr_sync();
+       if (__irqflags_uses_pmr()) {
+               __pmr_local_irq_restore(flags);
+       } else {
+               __daif_local_irq_restore(flags);
+       }
 }
 
 #endif /* __ASM_IRQFLAGS_H */
index 1436fa1..d3acd9c 100644 (file)
@@ -5,8 +5,8 @@
 #include <asm/assembler.h>
 #endif
 
-#define __ALIGN                .align 2
-#define __ALIGN_STR    ".align 2"
+#define __ALIGN                .balign CONFIG_FUNCTION_ALIGNMENT
+#define __ALIGN_STR    ".balign " #CONFIG_FUNCTION_ALIGNMENT
 
 /*
  * When using in-kernel BTI we need to ensure that PCS-conformant
index 6bf5adc..68908b8 100644 (file)
@@ -7,6 +7,8 @@
 int aarch64_insn_read(void *addr, u32 *insnp);
 int aarch64_insn_write(void *addr, u32 insn);
 
+int aarch64_insn_write_literal_u64(void *addr, u64 val);
+
 int aarch64_insn_patch_text_nosync(void *addr, u32 insn);
 int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt);
 
index b4bbeed..832c9c8 100644 (file)
@@ -275,6 +275,7 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
 }
 
 extern void __sync_icache_dcache(pte_t pteval);
+bool pgattr_change_is_safe(u64 old, u64 new);
 
 /*
  * PTE bits configuration in the presence of hardware Dirty Bit Management
@@ -292,7 +293,7 @@ extern void __sync_icache_dcache(pte_t pteval);
  *   PTE_DIRTY || (PTE_WRITE && !PTE_RDONLY)
  */
 
-static inline void __check_racy_pte_update(struct mm_struct *mm, pte_t *ptep,
+static inline void __check_safe_pte_update(struct mm_struct *mm, pte_t *ptep,
                                           pte_t pte)
 {
        pte_t old_pte;
@@ -318,6 +319,9 @@ static inline void __check_racy_pte_update(struct mm_struct *mm, pte_t *ptep,
        VM_WARN_ONCE(pte_write(old_pte) && !pte_dirty(pte),
                     "%s: racy dirty state clearing: 0x%016llx -> 0x%016llx",
                     __func__, pte_val(old_pte), pte_val(pte));
+       VM_WARN_ONCE(!pgattr_change_is_safe(pte_val(old_pte), pte_val(pte)),
+                    "%s: unsafe attribute change: 0x%016llx -> 0x%016llx",
+                    __func__, pte_val(old_pte), pte_val(pte));
 }
 
 static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
@@ -346,7 +350,7 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
                        mte_sync_tags(old_pte, pte);
        }
 
-       __check_racy_pte_update(mm, ptep, pte);
+       __check_safe_pte_update(mm, ptep, pte);
 
        set_pte(ptep, pte);
 }
index d51b32a..3918f2a 100644 (file)
@@ -161,7 +161,7 @@ struct thread_struct {
        enum fp_type            fp_type;        /* registers FPSIMD or SVE? */
        unsigned int            fpsimd_cpu;
        void                    *sve_state;     /* SVE registers, if any */
-       void                    *za_state;      /* ZA register, if any */
+       void                    *sme_state;     /* ZA and ZT state, if any */
        unsigned int            vl[ARM64_VEC_MAX];      /* vector length */
        unsigned int            vl_onexec[ARM64_VEC_MAX]; /* vl after next exec */
        unsigned long           fault_address;  /* fault info */
index 41b332c..47ec580 100644 (file)
@@ -194,7 +194,7 @@ struct pt_regs {
        u32 unused2;
 #endif
        u64 sdei_ttbr1;
-       /* Only valid when ARM64_HAS_IRQ_PRIO_MASKING is enabled. */
+       /* Only valid when ARM64_HAS_GIC_PRIO_MASKING is enabled. */
        u64 pmr_save;
        u64 stackframe[2];
 
index ff7da12..13df982 100644 (file)
 #ifdef CONFIG_SHADOW_CALL_STACK
        scs_sp  .req    x18
 
-       .macro scs_load tsk
-       ldr     scs_sp, [\tsk, #TSK_TI_SCS_SP]
+       .macro scs_load_current
+       get_current_task scs_sp
+       ldr     scs_sp, [scs_sp, #TSK_TI_SCS_SP]
        .endm
 
        .macro scs_save tsk
        str     scs_sp, [\tsk, #TSK_TI_SCS_SP]
        .endm
 #else
-       .macro scs_load tsk
+       .macro scs_load_current
        .endm
 
        .macro scs_save tsk
index 1312fb4..043ecc3 100644 (file)
 #define SYS_PAR_EL1_FST                        GENMASK(6, 1)
 
 /*** Statistical Profiling Extension ***/
-/* ID registers */
-#define SYS_PMSIDR_EL1                 sys_reg(3, 0, 9, 9, 7)
-#define SYS_PMSIDR_EL1_FE_SHIFT                0
-#define SYS_PMSIDR_EL1_FT_SHIFT                1
-#define SYS_PMSIDR_EL1_FL_SHIFT                2
-#define SYS_PMSIDR_EL1_ARCHINST_SHIFT  3
-#define SYS_PMSIDR_EL1_LDS_SHIFT       4
-#define SYS_PMSIDR_EL1_ERND_SHIFT      5
-#define SYS_PMSIDR_EL1_INTERVAL_SHIFT  8
-#define SYS_PMSIDR_EL1_INTERVAL_MASK   0xfUL
-#define SYS_PMSIDR_EL1_MAXSIZE_SHIFT   12
-#define SYS_PMSIDR_EL1_MAXSIZE_MASK    0xfUL
-#define SYS_PMSIDR_EL1_COUNTSIZE_SHIFT 16
-#define SYS_PMSIDR_EL1_COUNTSIZE_MASK  0xfUL
-
-#define SYS_PMBIDR_EL1                 sys_reg(3, 0, 9, 10, 7)
-#define SYS_PMBIDR_EL1_ALIGN_SHIFT     0
-#define SYS_PMBIDR_EL1_ALIGN_MASK      0xfU
-#define SYS_PMBIDR_EL1_P_SHIFT         4
-#define SYS_PMBIDR_EL1_F_SHIFT         5
-
-/* Sampling controls */
-#define SYS_PMSCR_EL1                  sys_reg(3, 0, 9, 9, 0)
-#define SYS_PMSCR_EL1_E0SPE_SHIFT      0
-#define SYS_PMSCR_EL1_E1SPE_SHIFT      1
-#define SYS_PMSCR_EL1_CX_SHIFT         3
-#define SYS_PMSCR_EL1_PA_SHIFT         4
-#define SYS_PMSCR_EL1_TS_SHIFT         5
-#define SYS_PMSCR_EL1_PCT_SHIFT                6
-
-#define SYS_PMSCR_EL2                  sys_reg(3, 4, 9, 9, 0)
-#define SYS_PMSCR_EL2_E0HSPE_SHIFT     0
-#define SYS_PMSCR_EL2_E2SPE_SHIFT      1
-#define SYS_PMSCR_EL2_CX_SHIFT         3
-#define SYS_PMSCR_EL2_PA_SHIFT         4
-#define SYS_PMSCR_EL2_TS_SHIFT         5
-#define SYS_PMSCR_EL2_PCT_SHIFT                6
-
-#define SYS_PMSICR_EL1                 sys_reg(3, 0, 9, 9, 2)
-
-#define SYS_PMSIRR_EL1                 sys_reg(3, 0, 9, 9, 3)
-#define SYS_PMSIRR_EL1_RND_SHIFT       0
-#define SYS_PMSIRR_EL1_INTERVAL_SHIFT  8
-#define SYS_PMSIRR_EL1_INTERVAL_MASK   0xffffffUL
-
-/* Filtering controls */
-#define SYS_PMSNEVFR_EL1               sys_reg(3, 0, 9, 9, 1)
-
-#define SYS_PMSFCR_EL1                 sys_reg(3, 0, 9, 9, 4)
-#define SYS_PMSFCR_EL1_FE_SHIFT                0
-#define SYS_PMSFCR_EL1_FT_SHIFT                1
-#define SYS_PMSFCR_EL1_FL_SHIFT                2
-#define SYS_PMSFCR_EL1_B_SHIFT         16
-#define SYS_PMSFCR_EL1_LD_SHIFT                17
-#define SYS_PMSFCR_EL1_ST_SHIFT                18
-
-#define SYS_PMSEVFR_EL1                        sys_reg(3, 0, 9, 9, 5)
-#define SYS_PMSEVFR_EL1_RES0_8_2       \
+#define PMSEVFR_EL1_RES0_IMP   \
        (GENMASK_ULL(47, 32) | GENMASK_ULL(23, 16) | GENMASK_ULL(11, 8) |\
         BIT_ULL(6) | BIT_ULL(4) | BIT_ULL(2) | BIT_ULL(0))
-#define SYS_PMSEVFR_EL1_RES0_8_3       \
-       (SYS_PMSEVFR_EL1_RES0_8_2 & ~(BIT_ULL(18) | BIT_ULL(17) | BIT_ULL(11)))
-
-#define SYS_PMSLATFR_EL1               sys_reg(3, 0, 9, 9, 6)
-#define SYS_PMSLATFR_EL1_MINLAT_SHIFT  0
-
-/* Buffer controls */
-#define SYS_PMBLIMITR_EL1              sys_reg(3, 0, 9, 10, 0)
-#define SYS_PMBLIMITR_EL1_E_SHIFT      0
-#define SYS_PMBLIMITR_EL1_FM_SHIFT     1
-#define SYS_PMBLIMITR_EL1_FM_MASK      0x3UL
-#define SYS_PMBLIMITR_EL1_FM_STOP_IRQ  (0 << SYS_PMBLIMITR_EL1_FM_SHIFT)
-
-#define SYS_PMBPTR_EL1                 sys_reg(3, 0, 9, 10, 1)
+#define PMSEVFR_EL1_RES0_V1P1  \
+       (PMSEVFR_EL1_RES0_IMP & ~(BIT_ULL(18) | BIT_ULL(17) | BIT_ULL(11)))
+#define PMSEVFR_EL1_RES0_V1P2  \
+       (PMSEVFR_EL1_RES0_V1P1 & ~BIT_ULL(6))
 
 /* Buffer error reporting */
-#define SYS_PMBSR_EL1                  sys_reg(3, 0, 9, 10, 3)
-#define SYS_PMBSR_EL1_COLL_SHIFT       16
-#define SYS_PMBSR_EL1_S_SHIFT          17
-#define SYS_PMBSR_EL1_EA_SHIFT         18
-#define SYS_PMBSR_EL1_DL_SHIFT         19
-#define SYS_PMBSR_EL1_EC_SHIFT         26
-#define SYS_PMBSR_EL1_EC_MASK          0x3fUL
-
-#define SYS_PMBSR_EL1_EC_BUF           (0x0UL << SYS_PMBSR_EL1_EC_SHIFT)
-#define SYS_PMBSR_EL1_EC_FAULT_S1      (0x24UL << SYS_PMBSR_EL1_EC_SHIFT)
-#define SYS_PMBSR_EL1_EC_FAULT_S2      (0x25UL << SYS_PMBSR_EL1_EC_SHIFT)
-
-#define SYS_PMBSR_EL1_FAULT_FSC_SHIFT  0
-#define SYS_PMBSR_EL1_FAULT_FSC_MASK   0x3fUL
+#define PMBSR_EL1_FAULT_FSC_SHIFT      PMBSR_EL1_MSS_SHIFT
+#define PMBSR_EL1_FAULT_FSC_MASK       PMBSR_EL1_MSS_MASK
 
-#define SYS_PMBSR_EL1_BUF_BSC_SHIFT    0
-#define SYS_PMBSR_EL1_BUF_BSC_MASK     0x3fUL
+#define PMBSR_EL1_BUF_BSC_SHIFT                PMBSR_EL1_MSS_SHIFT
+#define PMBSR_EL1_BUF_BSC_MASK         PMBSR_EL1_MSS_MASK
 
-#define SYS_PMBSR_EL1_BUF_BSC_FULL     (0x1UL << SYS_PMBSR_EL1_BUF_BSC_SHIFT)
+#define PMBSR_EL1_BUF_BSC_FULL         0x1UL
 
 /*** End of Statistical Profiling Extension ***/
 
 #define SCTLR_ELx_DSSBS        (BIT(44))
 #define SCTLR_ELx_ATA  (BIT(43))
 
+#define SCTLR_ELx_EE_SHIFT     25
 #define SCTLR_ELx_ENIA_SHIFT   31
 
 #define SCTLR_ELx_ITFSB         (BIT(37))
 #define SCTLR_ELx_LSMAOE (BIT(29))
 #define SCTLR_ELx_nTLSMD (BIT(28))
 #define SCTLR_ELx_ENDA  (BIT(27))
-#define SCTLR_ELx_EE     (BIT(25))
+#define SCTLR_ELx_EE     (BIT(SCTLR_ELx_EE_SHIFT))
 #define SCTLR_ELx_EIS   (BIT(22))
 #define SCTLR_ELx_IESB  (BIT(21))
 #define SCTLR_ELx_TSCXT         (BIT(20))
 
 #define ARM64_FEATURE_FIELD_BITS       4
 
-/* Create a mask for the feature bits of the specified feature. */
-#define ARM64_FEATURE_MASK(x)  (GENMASK_ULL(x##_SHIFT + ARM64_FEATURE_FIELD_BITS - 1, x##_SHIFT))
+/* Defined for compatibility only, do not add new users. */
+#define ARM64_FEATURE_MASK(x)  (x##_MASK)
 
 #ifdef __ASSEMBLY__
 
index b713d30..69a4fb7 100644 (file)
 #define HWCAP2_CSSC            (1UL << 34)
 #define HWCAP2_RPRFM           (1UL << 35)
 #define HWCAP2_SVE2P1          (1UL << 36)
+#define HWCAP2_SME2            (1UL << 37)
+#define HWCAP2_SME2P1          (1UL << 38)
+#define HWCAP2_SME_I16I32      (1UL << 39)
+#define HWCAP2_SME_BI32I32     (1UL << 40)
+#define HWCAP2_SME_B16B16      (1UL << 41)
+#define HWCAP2_SME_F16F16      (1UL << 42)
 
 #endif /* _UAPI__ASM_HWCAP_H */
index 9525041..656a10e 100644 (file)
@@ -144,6 +144,14 @@ struct sve_context {
 
 #define SVE_SIG_FLAG_SM        0x1     /* Context describes streaming mode */
 
+/* TPIDR2_EL0 context */
+#define TPIDR2_MAGIC   0x54504902
+
+struct tpidr2_context {
+       struct _aarch64_ctx head;
+       __u64 tpidr2;
+};
+
 #define ZA_MAGIC       0x54366345
 
 struct za_context {
@@ -152,6 +160,14 @@ struct za_context {
        __u16 __reserved[3];
 };
 
+#define ZT_MAGIC       0x5a544e01
+
+struct zt_context {
+       struct _aarch64_ctx head;
+       __u16 nregs;
+       __u16 __reserved[3];
+};
+
 #endif /* !__ASSEMBLY__ */
 
 #include <asm/sve_context.h>
@@ -304,4 +320,15 @@ struct za_context {
 #define ZA_SIG_CONTEXT_SIZE(vq) \
                (ZA_SIG_REGS_OFFSET + ZA_SIG_REGS_SIZE(vq))
 
+#define ZT_SIG_REG_SIZE 512
+
+#define ZT_SIG_REG_BYTES (ZT_SIG_REG_SIZE / 8)
+
+#define ZT_SIG_REGS_OFFSET sizeof(struct zt_context)
+
+#define ZT_SIG_REGS_SIZE(n) (ZT_SIG_REG_BYTES * n)
+
+#define ZT_SIG_CONTEXT_SIZE(n) \
+       (sizeof(struct zt_context) + ZT_SIG_REGS_SIZE(n))
+
 #endif /* _UAPI__ASM_SIGCONTEXT_H */
index 2234624..ae345b0 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/arm_sdei.h>
 #include <linux/sched.h>
+#include <linux/ftrace.h>
 #include <linux/kexec.h>
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
@@ -193,6 +194,9 @@ int main(void)
   DEFINE(KIMAGE_HEAD,                  offsetof(struct kimage, head));
   DEFINE(KIMAGE_START,                 offsetof(struct kimage, start));
   BLANK();
+#endif
+#ifdef CONFIG_FUNCTION_TRACER
+  DEFINE(FTRACE_OPS_FUNC,              offsetof(struct ftrace_ops, func));
 #endif
   return 0;
 }
index a77315b..da0f656 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/bsearch.h>
 #include <linux/cpumask.h>
 #include <linux/crash_dump.h>
+#include <linux/kstrtox.h>
 #include <linux/sort.h>
 #include <linux/stop_machine.h>
 #include <linux/sysfs.h>
@@ -282,16 +283,26 @@ static const struct arm64_ftr_bits ftr_id_aa64zfr0[] = {
 static const struct arm64_ftr_bits ftr_id_aa64smfr0[] = {
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
                       FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_FA64_SHIFT, 1, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
+                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_SMEver_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
                       FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_I16I64_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
                       FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_F64F64_SHIFT, 1, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
+                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_I16I32_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
+                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_B16B16_SHIFT, 1, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
+                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_F16F16_SHIFT, 1, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
                       FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_I8I32_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
                       FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_F16F32_SHIFT, 1, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
                       FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_B16F32_SHIFT, 1, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
+                      FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_BI32I32_SHIFT, 1, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME),
                       FTR_STRICT, FTR_EXACT, ID_AA64SMFR0_EL1_F32F32_SHIFT, 1, 0),
        ARM64_FTR_END,
@@ -444,8 +455,8 @@ static const struct arm64_ftr_bits ftr_mvfr0[] = {
 
 static const struct arm64_ftr_bits ftr_mvfr1[] = {
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_SIMDFMAC_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_FPHP_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_SIMDHP_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_FPHP_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_SIMDHP_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_SIMDSP_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_SIMDInt_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, MVFR1_EL1_SIMDLS_SHIFT, 4, 0),
@@ -529,12 +540,12 @@ static const struct arm64_ftr_bits ftr_id_mmfr5[] = {
 };
 
 static const struct arm64_ftr_bits ftr_id_isar6[] = {
-       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_I8MM_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_BF16_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_I8MM_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_BF16_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_SPECRES_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_SB_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_FHM_SHIFT, 4, 0),
-       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_DP_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_SB_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_FHM_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_DP_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_ISAR6_EL1_JSCVT_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
@@ -562,7 +573,7 @@ static const struct arm64_ftr_bits ftr_id_pfr1[] = {
 };
 
 static const struct arm64_ftr_bits ftr_id_pfr2[] = {
-       ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_PFR2_EL1_SSBS_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_PFR2_EL1_SSBS_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_PFR2_EL1_CSV3_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
@@ -1795,7 +1806,7 @@ kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
 static int __init parse_kpti(char *str)
 {
        bool enabled;
-       int ret = strtobool(str, &enabled);
+       int ret = kstrtobool(str, &enabled);
 
        if (ret)
                return ret;
@@ -2039,14 +2050,50 @@ static bool enable_pseudo_nmi;
 
 static int __init early_enable_pseudo_nmi(char *p)
 {
-       return strtobool(p, &enable_pseudo_nmi);
+       return kstrtobool(p, &enable_pseudo_nmi);
 }
 early_param("irqchip.gicv3_pseudo_nmi", early_enable_pseudo_nmi);
 
 static bool can_use_gic_priorities(const struct arm64_cpu_capabilities *entry,
                                   int scope)
 {
-       return enable_pseudo_nmi && has_useable_gicv3_cpuif(entry, scope);
+       /*
+        * ARM64_HAS_GIC_CPUIF_SYSREGS has a lower index, and is a boot CPU
+        * feature, so will be detected earlier.
+        */
+       BUILD_BUG_ON(ARM64_HAS_GIC_PRIO_MASKING <= ARM64_HAS_GIC_CPUIF_SYSREGS);
+       if (!cpus_have_cap(ARM64_HAS_GIC_CPUIF_SYSREGS))
+               return false;
+
+       return enable_pseudo_nmi;
+}
+
+static bool has_gic_prio_relaxed_sync(const struct arm64_cpu_capabilities *entry,
+                                     int scope)
+{
+       /*
+        * If we're not using priority masking then we won't be poking PMR_EL1,
+        * and there's no need to relax synchronization of writes to it, and
+        * ICC_CTLR_EL1 might not be accessible and we must avoid reads from
+        * that.
+        *
+        * ARM64_HAS_GIC_PRIO_MASKING has a lower index, and is a boot CPU
+        * feature, so will be detected earlier.
+        */
+       BUILD_BUG_ON(ARM64_HAS_GIC_PRIO_RELAXED_SYNC <= ARM64_HAS_GIC_PRIO_MASKING);
+       if (!cpus_have_cap(ARM64_HAS_GIC_PRIO_MASKING))
+               return false;
+
+       /*
+        * When Priority Mask Hint Enable (PMHE) == 0b0, PMR is not used as a
+        * hint for interrupt distribution, a DSB is not necessary when
+        * unmasking IRQs via PMR, and we can relax the barrier to a NOP.
+        *
+        * Linux itself doesn't use 1:N distribution, so has no need to
+        * set PMHE. The only reason to have it set is if EL3 requires it
+        * (and we can't change it).
+        */
+       return (gic_read_ctlr() & ICC_CTLR_EL1_PMHE_MASK) == 0;
 }
 #endif
 
@@ -2142,7 +2189,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
        },
        {
                .desc = "GIC system register CPU interface",
-               .capability = ARM64_HAS_SYSREG_GIC_CPUIF,
+               .capability = ARM64_HAS_GIC_CPUIF_SYSREGS,
                .type = ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE,
                .matches = has_useable_gicv3_cpuif,
                .sys_reg = SYS_ID_AA64PFR0_EL1,
@@ -2534,14 +2581,17 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                 * Depends on having GICv3
                 */
                .desc = "IRQ priority masking",
-               .capability = ARM64_HAS_IRQ_PRIO_MASKING,
+               .capability = ARM64_HAS_GIC_PRIO_MASKING,
                .type = ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE,
                .matches = can_use_gic_priorities,
-               .sys_reg = SYS_ID_AA64PFR0_EL1,
-               .field_pos = ID_AA64PFR0_EL1_GIC_SHIFT,
-               .field_width = 4,
-               .sign = FTR_UNSIGNED,
-               .min_field_value = 1,
+       },
+       {
+               /*
+                * Depends on ARM64_HAS_GIC_PRIO_MASKING
+                */
+               .capability = ARM64_HAS_GIC_PRIO_RELAXED_SYNC,
+               .type = ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE,
+               .matches = has_gic_prio_relaxed_sync,
        },
 #endif
 #ifdef CONFIG_ARM64_E0PD
@@ -2649,6 +2699,18 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .matches = has_cpuid_feature,
                .cpu_enable = fa64_kernel_enable,
        },
+       {
+               .desc = "SME2",
+               .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+               .capability = ARM64_SME2,
+               .sys_reg = SYS_ID_AA64PFR1_EL1,
+               .sign = FTR_UNSIGNED,
+               .field_pos = ID_AA64PFR1_EL1_SME_SHIFT,
+               .field_width = ID_AA64PFR1_EL1_SME_WIDTH,
+               .min_field_value = ID_AA64PFR1_EL1_SME_SME2,
+               .matches = has_cpuid_feature,
+               .cpu_enable = sme2_kernel_enable,
+       },
 #endif /* CONFIG_ARM64_SME */
        {
                .desc = "WFx with timeout",
@@ -2777,7 +2839,7 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
        HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_EL1_FP_SHIFT, 4, FTR_SIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_FPHP),
        HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_EL1_AdvSIMD_SHIFT, 4, FTR_SIGNED, 0, CAP_HWCAP, KERNEL_HWCAP_ASIMD),
        HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_EL1_AdvSIMD_SHIFT, 4, FTR_SIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_ASIMDHP),
-       HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_EL1_DIT_SHIFT, 4, FTR_SIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_DIT),
+       HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_EL1_DIT_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_DIT),
        HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_DPB_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_DCPOP),
        HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_DPB_SHIFT, 4, FTR_UNSIGNED, 2, CAP_HWCAP, KERNEL_HWCAP_DCPODP),
        HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_EL1_JSCVT_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_JSCVT),
@@ -2827,11 +2889,17 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
 #ifdef CONFIG_ARM64_SME
        HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_EL1_SME_SHIFT, 4, FTR_UNSIGNED, ID_AA64PFR1_EL1_SME_IMP, CAP_HWCAP, KERNEL_HWCAP_SME),
        HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_FA64_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_EL1_FA64_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_FA64),
+       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_SMEver_SHIFT, 4, FTR_UNSIGNED, ID_AA64SMFR0_EL1_SMEver_SME2p1, CAP_HWCAP, KERNEL_HWCAP_SME2P1),
+       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_SMEver_SHIFT, 4, FTR_UNSIGNED, ID_AA64SMFR0_EL1_SMEver_SME2, CAP_HWCAP, KERNEL_HWCAP_SME2),
        HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_I16I64_SHIFT, 4, FTR_UNSIGNED, ID_AA64SMFR0_EL1_I16I64_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_I16I64),
        HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_F64F64_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_EL1_F64F64_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_F64F64),
+       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_I16I32_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_EL1_I16I32_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_I16I32),
+       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_B16B16_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_EL1_B16B16_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_B16B16),
+       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_F16F16_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_EL1_F16F16_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_F16F16),
        HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_I8I32_SHIFT, 4, FTR_UNSIGNED, ID_AA64SMFR0_EL1_I8I32_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_I8I32),
        HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_F16F32_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_EL1_F16F32_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_F16F32),
        HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_B16F32_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_EL1_B16F32_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_B16F32),
+       HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_BI32I32_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_EL1_BI32I32_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_BI32I32),
        HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_EL1_F32F32_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_EL1_F32F32_IMP, CAP_HWCAP, KERNEL_HWCAP_SME_F32F32),
 #endif /* CONFIG_ARM64_SME */
        {},
@@ -2866,11 +2934,19 @@ static const struct arm64_cpu_capabilities compat_elf_hwcaps[] = {
        /* Arm v8 mandates MVFR0.FPDP == {0, 2}. So, piggy back on this for the presence of VFP support */
        HWCAP_CAP(SYS_MVFR0_EL1, MVFR0_EL1_FPDP_SHIFT, 4, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP, COMPAT_HWCAP_VFP),
        HWCAP_CAP(SYS_MVFR0_EL1, MVFR0_EL1_FPDP_SHIFT, 4, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP, COMPAT_HWCAP_VFPv3),
+       HWCAP_CAP(SYS_MVFR1_EL1, MVFR1_EL1_FPHP_SHIFT, 4, FTR_UNSIGNED, 3, CAP_COMPAT_HWCAP, COMPAT_HWCAP_FPHP),
+       HWCAP_CAP(SYS_MVFR1_EL1, MVFR1_EL1_SIMDHP_SHIFT, 4, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP, COMPAT_HWCAP_ASIMDHP),
        HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_EL1_AES_SHIFT, 4, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_PMULL),
        HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_EL1_AES_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_AES),
        HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_EL1_SHA1_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA1),
        HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_EL1_SHA2_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA2),
        HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_EL1_CRC32_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_CRC32),
+       HWCAP_CAP(SYS_ID_ISAR6_EL1, ID_ISAR6_EL1_DP_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP, COMPAT_HWCAP_ASIMDDP),
+       HWCAP_CAP(SYS_ID_ISAR6_EL1, ID_ISAR6_EL1_FHM_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP, COMPAT_HWCAP_ASIMDFHM),
+       HWCAP_CAP(SYS_ID_ISAR6_EL1, ID_ISAR6_EL1_SB_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SB),
+       HWCAP_CAP(SYS_ID_ISAR6_EL1, ID_ISAR6_EL1_BF16_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP, COMPAT_HWCAP_ASIMDBF16),
+       HWCAP_CAP(SYS_ID_ISAR6_EL1, ID_ISAR6_EL1_I8MM_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP, COMPAT_HWCAP_I8MM),
+       HWCAP_CAP(SYS_ID_PFR2_EL1, ID_PFR2_EL1_SSBS_SHIFT, 4, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SSBS),
 #endif
        {},
 };
index 3796952..eb4378c 100644 (file)
@@ -119,6 +119,12 @@ static const char *const hwcap_str[] = {
        [KERNEL_HWCAP_CSSC]             = "cssc",
        [KERNEL_HWCAP_RPRFM]            = "rprfm",
        [KERNEL_HWCAP_SVE2P1]           = "sve2p1",
+       [KERNEL_HWCAP_SME2]             = "sme2",
+       [KERNEL_HWCAP_SME2P1]           = "sme2p1",
+       [KERNEL_HWCAP_SME_I16I32]       = "smei16i32",
+       [KERNEL_HWCAP_SME_BI32I32]      = "smebi32i32",
+       [KERNEL_HWCAP_SME_B16B16]       = "smeb16b16",
+       [KERNEL_HWCAP_SME_F16F16]       = "smef16f16",
 };
 
 #ifdef CONFIG_COMPAT
@@ -146,6 +152,12 @@ static const char *const compat_hwcap_str[] = {
        [COMPAT_KERNEL_HWCAP(VFPD32)]   = NULL, /* Not possible on arm64 */
        [COMPAT_KERNEL_HWCAP(LPAE)]     = "lpae",
        [COMPAT_KERNEL_HWCAP(EVTSTRM)]  = "evtstrm",
+       [COMPAT_KERNEL_HWCAP(FPHP)]     = "fphp",
+       [COMPAT_KERNEL_HWCAP(ASIMDHP)]  = "asimdhp",
+       [COMPAT_KERNEL_HWCAP(ASIMDDP)]  = "asimddp",
+       [COMPAT_KERNEL_HWCAP(ASIMDFHM)] = "asimdfhm",
+       [COMPAT_KERNEL_HWCAP(ASIMDBF16)] = "asimdbf16",
+       [COMPAT_KERNEL_HWCAP(I8MM)]     = "i8mm",
 };
 
 #define COMPAT_KERNEL_HWCAP2(x)        const_ilog2(COMPAT_HWCAP2_ ## x)
@@ -155,6 +167,8 @@ static const char *const compat_hwcap2_str[] = {
        [COMPAT_KERNEL_HWCAP2(SHA1)]    = "sha1",
        [COMPAT_KERNEL_HWCAP2(SHA2)]    = "sha2",
        [COMPAT_KERNEL_HWCAP2(CRC32)]   = "crc32",
+       [COMPAT_KERNEL_HWCAP2(SB)]      = "sb",
+       [COMPAT_KERNEL_HWCAP2(SSBS)]    = "ssbs",
 };
 #endif /* CONFIG_COMPAT */
 
index 229436f..6325db1 100644 (file)
@@ -100,25 +100,35 @@ SYM_FUNC_START(sme_set_vq)
 SYM_FUNC_END(sme_set_vq)
 
 /*
- * Save the SME state
+ * Save the ZA and ZT state
  *
  * x0 - pointer to buffer for state
+ * x1 - number of ZT registers to save
  */
-SYM_FUNC_START(za_save_state)
-       _sme_rdsvl      1, 1            // x1 = VL/8
-       sme_save_za 0, x1, 12
+SYM_FUNC_START(sme_save_state)
+       _sme_rdsvl      2, 1            // x2 = VL/8
+       sme_save_za 0, x2, 12           // Leaves x0 pointing to the end of ZA
+
+       cbz     x1, 1f
+       _str_zt 0
+1:
        ret
-SYM_FUNC_END(za_save_state)
+SYM_FUNC_END(sme_save_state)
 
 /*
- * Load the SME state
+ * Load the ZA and ZT state
  *
  * x0 - pointer to buffer for state
+ * x1 - number of ZT registers to save
  */
-SYM_FUNC_START(za_load_state)
-       _sme_rdsvl      1, 1            // x1 = VL/8
-       sme_load_za 0, x1, 12
+SYM_FUNC_START(sme_load_state)
+       _sme_rdsvl      2, 1            // x2 = VL/8
+       sme_load_za 0, x2, 12           // Leaves x0 pointing to the end of ZA
+
+       cbz     x1, 1f
+       _ldr_zt 0
+1:
        ret
-SYM_FUNC_END(za_load_state)
+SYM_FUNC_END(sme_load_state)
 
 #endif /* CONFIG_ARM64_SME */
index 3b625f7..350ed81 100644 (file)
@@ -65,13 +65,35 @@ SYM_CODE_START(ftrace_caller)
        stp     x29, x30, [sp, #FREGS_SIZE]
        add     x29, sp, #FREGS_SIZE
 
-       sub     x0, x30, #AARCH64_INSN_SIZE     // ip (callsite's BL insn)
-       mov     x1, x9                          // parent_ip (callsite's LR)
-       ldr_l   x2, function_trace_op           // op
-       mov     x3, sp                          // regs
+       /* Prepare arguments for the the tracer func */
+       sub     x0, x30, #AARCH64_INSN_SIZE             // ip (callsite's BL insn)
+       mov     x1, x9                                  // parent_ip (callsite's LR)
+       mov     x3, sp                                  // regs
+
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
+       /*
+        * The literal pointer to the ops is at an 8-byte aligned boundary
+        * which is either 12 or 16 bytes before the BL instruction in the call
+        * site. See ftrace_call_adjust() for details.
+        *
+        * Therefore here the LR points at `literal + 16` or `literal + 20`,
+        * and we can find the address of the literal in either case by
+        * aligning to an 8-byte boundary and subtracting 16. We do the
+        * alignment first as this allows us to fold the subtraction into the
+        * LDR.
+        */
+       bic     x2, x30, 0x7
+       ldr     x2, [x2, #-16]                          // op
+
+       ldr     x4, [x2, #FTRACE_OPS_FUNC]              // op->func
+       blr     x4                                      // op->func(ip, parent_ip, op, regs)
+
+#else
+       ldr_l   x2, function_trace_op                   // op
 
 SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
-       bl      ftrace_stub
+       bl      ftrace_stub                             // func(ip, parent_ip, op, regs)
+#endif
 
 /*
  * At the callsite x0-x8 and x19-x30 were live. Any C code will have preserved
index 11cb99c..ab2a6e3 100644 (file)
@@ -275,7 +275,7 @@ alternative_if ARM64_HAS_ADDRESS_AUTH
 alternative_else_nop_endif
 1:
 
-       scs_load tsk
+       scs_load_current
        .else
        add     x21, sp, #PT_REGS_SIZE
        get_current_task tsk
@@ -311,13 +311,16 @@ alternative_else_nop_endif
        .endif
 
 #ifdef CONFIG_ARM64_PSEUDO_NMI
-       /* Save pmr */
-alternative_if ARM64_HAS_IRQ_PRIO_MASKING
+alternative_if_not ARM64_HAS_GIC_PRIO_MASKING
+       b       .Lskip_pmr_save\@
+alternative_else_nop_endif
+
        mrs_s   x20, SYS_ICC_PMR_EL1
        str     x20, [sp, #S_PMR_SAVE]
        mov     x20, #GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET
        msr_s   SYS_ICC_PMR_EL1, x20
-alternative_else_nop_endif
+
+.Lskip_pmr_save\@:
 #endif
 
        /*
@@ -336,15 +339,19 @@ alternative_else_nop_endif
        .endif
 
 #ifdef CONFIG_ARM64_PSEUDO_NMI
-       /* Restore pmr */
-alternative_if ARM64_HAS_IRQ_PRIO_MASKING
+alternative_if_not ARM64_HAS_GIC_PRIO_MASKING
+       b       .Lskip_pmr_restore\@
+alternative_else_nop_endif
+
        ldr     x20, [sp, #S_PMR_SAVE]
        msr_s   SYS_ICC_PMR_EL1, x20
-       mrs_s   x21, SYS_ICC_CTLR_EL1
-       tbz     x21, #6, .L__skip_pmr_sync\@    // Check for ICC_CTLR_EL1.PMHE
-       dsb     sy                              // Ensure priority change is seen by redistributor
-.L__skip_pmr_sync\@:
+
+       /* Ensure priority change is seen by redistributor */
+alternative_if_not ARM64_HAS_GIC_PRIO_RELAXED_SYNC
+       dsb     sy
 alternative_else_nop_endif
+
+.Lskip_pmr_restore\@:
 #endif
 
        ldp     x21, x22, [sp, #S_PC]           // load ELR, SPSR
@@ -848,7 +855,7 @@ SYM_FUNC_START(cpu_switch_to)
        msr     sp_el0, x1
        ptrauth_keys_install_kernel x1, x8, x9, x10
        scs_save x0
-       scs_load x1
+       scs_load_current
        ret
 SYM_FUNC_END(cpu_switch_to)
 NOKPROBE(cpu_switch_to)
@@ -876,19 +883,19 @@ NOKPROBE(ret_from_fork)
  */
 SYM_FUNC_START(call_on_irq_stack)
 #ifdef CONFIG_SHADOW_CALL_STACK
-       stp     scs_sp, xzr, [sp, #-16]!
+       get_current_task x16
+       scs_save x16
        ldr_this_cpu scs_sp, irq_shadow_call_stack_ptr, x17
 #endif
+
        /* Create a frame record to save our LR and SP (implicit in FP) */
        stp     x29, x30, [sp, #-16]!
        mov     x29, sp
 
        ldr_this_cpu x16, irq_stack_ptr, x17
-       mov     x15, #IRQ_STACK_SIZE
-       add     x16, x16, x15
 
        /* Move to the new stack and call the function there */
-       mov     sp, x16
+       add     sp, x16, #IRQ_STACK_SIZE
        blr     x1
 
        /*
@@ -897,9 +904,7 @@ SYM_FUNC_START(call_on_irq_stack)
         */
        mov     sp, x29
        ldp     x29, x30, [sp], #16
-#ifdef CONFIG_SHADOW_CALL_STACK
-       ldp     scs_sp, xzr, [sp], #16
-#endif
+       scs_load_current
        ret
 SYM_FUNC_END(call_on_irq_stack)
 NOKPROBE(call_on_irq_stack)
index dcc81e7..c11cb44 100644 (file)
@@ -299,7 +299,7 @@ void task_set_vl_onexec(struct task_struct *task, enum vec_type type,
 /*
  * TIF_SME controls whether a task can use SME without trapping while
  * in userspace, when TIF_SME is set then we must have storage
- * alocated in sve_state and za_state to store the contents of both ZA
+ * alocated in sve_state and sme_state to store the contents of both ZA
  * and the SVE registers for both streaming and non-streaming modes.
  *
  * If both SVCR.ZA and SVCR.SM are disabled then at any point we
@@ -429,7 +429,8 @@ static void task_fpsimd_load(void)
                write_sysreg_s(current->thread.svcr, SYS_SVCR);
 
                if (thread_za_enabled(&current->thread))
-                       za_load_state(current->thread.za_state);
+                       sme_load_state(current->thread.sme_state,
+                                      system_supports_sme2());
 
                if (thread_sm_enabled(&current->thread))
                        restore_ffr = system_supports_fa64();
@@ -490,7 +491,8 @@ static void fpsimd_save(void)
                *svcr = read_sysreg_s(SYS_SVCR);
 
                if (*svcr & SVCR_ZA_MASK)
-                       za_save_state(last->za_state);
+                       sme_save_state(last->sme_state,
+                                      system_supports_sme2());
 
                /* If we are in streaming mode override regular SVE. */
                if (*svcr & SVCR_SM_MASK) {
@@ -1257,30 +1259,30 @@ void fpsimd_release_task(struct task_struct *dead_task)
 #ifdef CONFIG_ARM64_SME
 
 /*
- * Ensure that task->thread.za_state is allocated and sufficiently large.
+ * Ensure that task->thread.sme_state is allocated and sufficiently large.
  *
  * This function should be used only in preparation for replacing
- * task->thread.za_state with new data.  The memory is always zeroed
+ * task->thread.sme_state with new data.  The memory is always zeroed
  * here to prevent stale data from showing through: this is done in
  * the interest of testability and predictability, the architecture
  * guarantees that when ZA is enabled it will be zeroed.
  */
 void sme_alloc(struct task_struct *task)
 {
-       if (task->thread.za_state) {
-               memset(task->thread.za_state, 0, za_state_size(task));
+       if (task->thread.sme_state) {
+               memset(task->thread.sme_state, 0, sme_state_size(task));
                return;
        }
 
        /* This could potentially be up to 64K. */
-       task->thread.za_state =
-               kzalloc(za_state_size(task), GFP_KERNEL);
+       task->thread.sme_state =
+               kzalloc(sme_state_size(task), GFP_KERNEL);
 }
 
 static void sme_free(struct task_struct *task)
 {
-       kfree(task->thread.za_state);
-       task->thread.za_state = NULL;
+       kfree(task->thread.sme_state);
+       task->thread.sme_state = NULL;
 }
 
 void sme_kernel_enable(const struct arm64_cpu_capabilities *__always_unused p)
@@ -1298,6 +1300,17 @@ void sme_kernel_enable(const struct arm64_cpu_capabilities *__always_unused p)
        isb();
 }
 
+/*
+ * This must be called after sme_kernel_enable(), we rely on the
+ * feature table being sorted to ensure this.
+ */
+void sme2_kernel_enable(const struct arm64_cpu_capabilities *__always_unused p)
+{
+       /* Allow use of ZT0 */
+       write_sysreg_s(read_sysreg_s(SYS_SMCR_EL1) | SMCR_ELx_EZT0_MASK,
+                      SYS_SMCR_EL1);
+}
+
 /*
  * This must be called after sme_kernel_enable(), we rely on the
  * feature table being sorted to ensure this.
@@ -1322,7 +1335,6 @@ u64 read_smcr_features(void)
        unsigned int vq_max;
 
        sme_kernel_enable(NULL);
-       sme_smstart_sm();
 
        /*
         * Set the maximum possible VL.
@@ -1332,11 +1344,9 @@ u64 read_smcr_features(void)
 
        smcr = read_sysreg_s(SYS_SMCR_EL1);
        smcr &= ~(u64)SMCR_ELx_LEN_MASK; /* Only the LEN field */
-       vq_max = sve_vq_from_vl(sve_get_vl());
+       vq_max = sve_vq_from_vl(sme_get_vl());
        smcr |= vq_max - 1; /* set LEN field to maximum effective value */
 
-       sme_smstop_sm();
-
        return smcr;
 }
 
@@ -1488,7 +1498,7 @@ void do_sme_acc(unsigned long esr, struct pt_regs *regs)
 
        sve_alloc(current, false);
        sme_alloc(current);
-       if (!current->thread.sve_state || !current->thread.za_state) {
+       if (!current->thread.sve_state || !current->thread.sme_state) {
                force_sig(SIGKILL);
                return;
        }
@@ -1609,7 +1619,7 @@ static void fpsimd_flush_thread_vl(enum vec_type type)
 void fpsimd_flush_thread(void)
 {
        void *sve_state = NULL;
-       void *za_state = NULL;
+       void *sme_state = NULL;
 
        if (!system_supports_fpsimd())
                return;
@@ -1634,8 +1644,8 @@ void fpsimd_flush_thread(void)
                clear_thread_flag(TIF_SME);
 
                /* Defer kfree() while in atomic context */
-               za_state = current->thread.za_state;
-               current->thread.za_state = NULL;
+               sme_state = current->thread.sme_state;
+               current->thread.sme_state = NULL;
 
                fpsimd_flush_thread_vl(ARM64_VEC_SME);
                current->thread.svcr = 0;
@@ -1645,7 +1655,7 @@ void fpsimd_flush_thread(void)
 
        put_cpu_fpsimd_context();
        kfree(sve_state);
-       kfree(za_state);
+       kfree(sme_state);
 }
 
 /*
@@ -1711,7 +1721,7 @@ static void fpsimd_bind_task_to_cpu(void)
        WARN_ON(!system_supports_fpsimd());
        last->st = &current->thread.uw.fpsimd_state;
        last->sve_state = current->thread.sve_state;
-       last->za_state = current->thread.za_state;
+       last->sme_state = current->thread.sme_state;
        last->sve_vl = task_get_sve_vl(current);
        last->sme_vl = task_get_sme_vl(current);
        last->svcr = &current->thread.svcr;
index b30b955..5545fe1 100644 (file)
@@ -60,6 +60,89 @@ int ftrace_regs_query_register_offset(const char *name)
 }
 #endif
 
+unsigned long ftrace_call_adjust(unsigned long addr)
+{
+       /*
+        * When using mcount, addr is the address of the mcount call
+        * instruction, and no adjustment is necessary.
+        */
+       if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_ARGS))
+               return addr;
+
+       /*
+        * When using patchable-function-entry without pre-function NOPS, addr
+        * is the address of the first NOP after the function entry point.
+        *
+        * The compiler has either generated:
+        *
+        * addr+00:     func:   NOP             // To be patched to MOV X9, LR
+        * addr+04:             NOP             // To be patched to BL <caller>
+        *
+        * Or:
+        *
+        * addr-04:             BTI     C
+        * addr+00:     func:   NOP             // To be patched to MOV X9, LR
+        * addr+04:             NOP             // To be patched to BL <caller>
+        *
+        * We must adjust addr to the address of the NOP which will be patched
+        * to `BL <caller>`, which is at `addr + 4` bytes in either case.
+        *
+        */
+       if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS))
+               return addr + AARCH64_INSN_SIZE;
+
+       /*
+        * When using patchable-function-entry with pre-function NOPs, addr is
+        * the address of the first pre-function NOP.
+        *
+        * Starting from an 8-byte aligned base, the compiler has either
+        * generated:
+        *
+        * addr+00:             NOP             // Literal (first 32 bits)
+        * addr+04:             NOP             // Literal (last 32 bits)
+        * addr+08:     func:   NOP             // To be patched to MOV X9, LR
+        * addr+12:             NOP             // To be patched to BL <caller>
+        *
+        * Or:
+        *
+        * addr+00:             NOP             // Literal (first 32 bits)
+        * addr+04:             NOP             // Literal (last 32 bits)
+        * addr+08:     func:   BTI     C
+        * addr+12:             NOP             // To be patched to MOV X9, LR
+        * addr+16:             NOP             // To be patched to BL <caller>
+        *
+        * We must adjust addr to the address of the NOP which will be patched
+        * to `BL <caller>`, which is at either addr+12 or addr+16 depending on
+        * whether there is a BTI.
+        */
+
+       if (!IS_ALIGNED(addr, sizeof(unsigned long))) {
+               WARN_RATELIMIT(1, "Misaligned patch-site %pS\n",
+                              (void *)(addr + 8));
+               return 0;
+       }
+
+       /* Skip the NOPs placed before the function entry point */
+       addr += 2 * AARCH64_INSN_SIZE;
+
+       /* Skip any BTI */
+       if (IS_ENABLED(CONFIG_ARM64_BTI_KERNEL)) {
+               u32 insn = le32_to_cpu(*(__le32 *)addr);
+
+               if (aarch64_insn_is_bti(insn)) {
+                       addr += AARCH64_INSN_SIZE;
+               } else if (insn != aarch64_insn_gen_nop()) {
+                       WARN_RATELIMIT(1, "unexpected insn in patch-site %pS: 0x%08x\n",
+                                      (void *)addr, insn);
+               }
+       }
+
+       /* Skip the first NOP after function entry */
+       addr += AARCH64_INSN_SIZE;
+
+       return addr;
+}
+
 /*
  * Replace a single instruction, which may be a branch or NOP.
  * If @validate == true, a replaced instruction is checked against 'old'.
@@ -98,6 +181,13 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
        unsigned long pc;
        u32 new;
 
+       /*
+        * When using CALL_OPS, the function to call is associated with the
+        * call site, and we don't have a global function pointer to update.
+        */
+       if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS))
+               return 0;
+
        pc = (unsigned long)ftrace_call;
        new = aarch64_insn_gen_branch_imm(pc, (unsigned long)func,
                                          AARCH64_INSN_BRANCH_LINK);
@@ -176,6 +266,44 @@ static bool ftrace_find_callable_addr(struct dyn_ftrace *rec,
        return true;
 }
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
+static const struct ftrace_ops *arm64_rec_get_ops(struct dyn_ftrace *rec)
+{
+       const struct ftrace_ops *ops = NULL;
+
+       if (rec->flags & FTRACE_FL_CALL_OPS_EN) {
+               ops = ftrace_find_unique_ops(rec);
+               WARN_ON_ONCE(!ops);
+       }
+
+       if (!ops)
+               ops = &ftrace_list_ops;
+
+       return ops;
+}
+
+static int ftrace_rec_set_ops(const struct dyn_ftrace *rec,
+                             const struct ftrace_ops *ops)
+{
+       unsigned long literal = ALIGN_DOWN(rec->ip - 12, 8);
+       return aarch64_insn_write_literal_u64((void *)literal,
+                                             (unsigned long)ops);
+}
+
+static int ftrace_rec_set_nop_ops(struct dyn_ftrace *rec)
+{
+       return ftrace_rec_set_ops(rec, &ftrace_nop_ops);
+}
+
+static int ftrace_rec_update_ops(struct dyn_ftrace *rec)
+{
+       return ftrace_rec_set_ops(rec, arm64_rec_get_ops(rec));
+}
+#else
+static int ftrace_rec_set_nop_ops(struct dyn_ftrace *rec) { return 0; }
+static int ftrace_rec_update_ops(struct dyn_ftrace *rec) { return 0; }
+#endif
+
 /*
  * Turn on the call to ftrace_caller() in instrumented function
  */
@@ -183,6 +311,11 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 {
        unsigned long pc = rec->ip;
        u32 old, new;
+       int ret;
+
+       ret = ftrace_rec_update_ops(rec);
+       if (ret)
+               return ret;
 
        if (!ftrace_find_callable_addr(rec, NULL, &addr))
                return -EINVAL;
@@ -193,6 +326,19 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
        return ftrace_modify_code(pc, old, new, true);
 }
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
+int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
+                      unsigned long addr)
+{
+       if (WARN_ON_ONCE(old_addr != (unsigned long)ftrace_caller))
+               return -EINVAL;
+       if (WARN_ON_ONCE(addr != (unsigned long)ftrace_caller))
+               return -EINVAL;
+
+       return ftrace_rec_update_ops(rec);
+}
+#endif
+
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
 /*
  * The compiler has inserted two NOPs before the regular function prologue.
@@ -209,7 +355,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
  * | NOP      | MOV X9, LR | MOV X9, LR |
  * | NOP      | NOP        | BL <entry> |
  *
- * The LR value will be recovered by ftrace_regs_entry, and restored into LR
+ * The LR value will be recovered by ftrace_caller, and restored into LR
  * before returning to the regular function prologue. When a function is not
  * being traced, the MOV is not harmful given x9 is not live per the AAPCS.
  *
@@ -220,6 +366,11 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
 {
        unsigned long pc = rec->ip - AARCH64_INSN_SIZE;
        u32 old, new;
+       int ret;
+
+       ret = ftrace_rec_set_nop_ops(rec);
+       if (ret)
+               return ret;
 
        old = aarch64_insn_gen_nop();
        new = aarch64_insn_gen_move_reg(AARCH64_INSN_REG_9,
@@ -237,9 +388,14 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
 {
        unsigned long pc = rec->ip;
        u32 old = 0, new;
+       int ret;
 
        new = aarch64_insn_gen_nop();
 
+       ret = ftrace_rec_set_nop_ops(rec);
+       if (ret)
+               return ret;
+
        /*
         * When using mcount, callsites in modules may have been initalized to
         * call an arbitrary module PLT (which redirects to the _mcount stub)
index 952e17b..212d93a 100644 (file)
 
        __EFI_PE_HEADER
 
-       __INIT
+       .section ".idmap.text","awx"
 
        /*
         * The following callee saved general purpose registers are used on the
         * primary lowlevel boot path:
         *
         *  Register   Scope                      Purpose
+        *  x19        primary_entry() .. start_kernel()        whether we entered with the MMU on
         *  x20        primary_entry() .. __primary_switch()    CPU boot mode
         *  x21        primary_entry() .. start_kernel()        FDT pointer passed at boot in x0
         *  x22        create_idmap() .. start_kernel()         ID map VA of the DT blob
         *  x28        create_idmap()                           callee preserved temp register
         */
 SYM_CODE_START(primary_entry)
+       bl      record_mmu_state
        bl      preserve_boot_args
+       bl      create_idmap
+
+       /*
+        * If we entered with the MMU and caches on, clean the ID mapped part
+        * of the primary boot code to the PoC so we can safely execute it with
+        * the MMU off.
+        */
+       cbz     x19, 0f
+       adrp    x0, __idmap_text_start
+       adr_l   x1, __idmap_text_end
+       bl      dcache_clean_poc
+0:     mov     x0, x19
        bl      init_kernel_el                  // w0=cpu_boot_mode
        mov     x20, x0
-       bl      create_idmap
 
        /*
         * The following calls CPU setup code, see arch/arm64/mm/proc.S for
@@ -109,6 +122,40 @@ SYM_CODE_START(primary_entry)
        b       __primary_switch
 SYM_CODE_END(primary_entry)
 
+       __INIT
+SYM_CODE_START_LOCAL(record_mmu_state)
+       mrs     x19, CurrentEL
+       cmp     x19, #CurrentEL_EL2
+       mrs     x19, sctlr_el1
+       b.ne    0f
+       mrs     x19, sctlr_el2
+0:
+CPU_LE( tbnz   x19, #SCTLR_ELx_EE_SHIFT, 1f    )
+CPU_BE( tbz    x19, #SCTLR_ELx_EE_SHIFT, 1f    )
+       tst     x19, #SCTLR_ELx_C               // Z := (C == 0)
+       and     x19, x19, #SCTLR_ELx_M          // isolate M bit
+       csel    x19, xzr, x19, eq               // clear x19 if Z
+       ret
+
+       /*
+        * Set the correct endianness early so all memory accesses issued
+        * before init_kernel_el() occur in the correct byte order. Note that
+        * this means the MMU must be disabled, or the active ID map will end
+        * up getting interpreted with the wrong byte order.
+        */
+1:     eor     x19, x19, #SCTLR_ELx_EE
+       bic     x19, x19, #SCTLR_ELx_M
+       b.ne    2f
+       pre_disable_mmu_workaround
+       msr     sctlr_el2, x19
+       b       3f
+       pre_disable_mmu_workaround
+2:     msr     sctlr_el1, x19
+3:     isb
+       mov     x19, xzr
+       ret
+SYM_CODE_END(record_mmu_state)
+
 /*
  * Preserve the arguments passed by the bootloader in x0 .. x3
  */
@@ -119,11 +166,14 @@ SYM_CODE_START_LOCAL(preserve_boot_args)
        stp     x21, x1, [x0]                   // x0 .. x3 at kernel entry
        stp     x2, x3, [x0, #16]
 
+       cbnz    x19, 0f                         // skip cache invalidation if MMU is on
        dmb     sy                              // needed before dc ivac with
                                                // MMU off
 
        add     x1, x0, #0x20                   // 4 x 8 bytes
        b       dcache_inval_poc                // tail call
+0:     str_l   x19, mmu_enabled_at_boot, x0
+       ret
 SYM_CODE_END(preserve_boot_args)
 
 SYM_FUNC_START_LOCAL(clear_page_tables)
@@ -360,12 +410,13 @@ SYM_FUNC_START_LOCAL(create_idmap)
         * accesses (MMU disabled), invalidate those tables again to
         * remove any speculatively loaded cache lines.
         */
+       cbnz    x19, 0f                         // skip cache invalidation if MMU is on
        dmb     sy
 
        adrp    x0, init_idmap_pg_dir
        adrp    x1, init_idmap_pg_end
        bl      dcache_inval_poc
-       ret     x28
+0:     ret     x28
 SYM_FUNC_END(create_idmap)
 
 SYM_FUNC_START_LOCAL(create_kernel_mapping)
@@ -404,7 +455,7 @@ SYM_FUNC_END(create_kernel_mapping)
        stp     xzr, xzr, [sp, #S_STACKFRAME]
        add     x29, sp, #S_STACKFRAME
 
-       scs_load \tsk
+       scs_load_current
 
        adr_l   \tmp1, __per_cpu_offset
        ldr     w\tmp2, [\tsk, #TSK_TI_CPU]
@@ -489,14 +540,17 @@ SYM_FUNC_END(__primary_switched)
  * Returns either BOOT_CPU_MODE_EL1 or BOOT_CPU_MODE_EL2 in x0 if
  * booted in EL1 or EL2 respectively, with the top 32 bits containing
  * potential context flags. These flags are *not* stored in __boot_cpu_mode.
+ *
+ * x0: whether we are being called from the primary boot path with the MMU on
  */
 SYM_FUNC_START(init_kernel_el)
-       mrs     x0, CurrentEL
-       cmp     x0, #CurrentEL_EL2
+       mrs     x1, CurrentEL
+       cmp     x1, #CurrentEL_EL2
        b.eq    init_el2
 
 SYM_INNER_LABEL(init_el1, SYM_L_LOCAL)
        mov_q   x0, INIT_SCTLR_EL1_MMU_OFF
+       pre_disable_mmu_workaround
        msr     sctlr_el1, x0
        isb
        mov_q   x0, INIT_PSTATE_EL1
@@ -506,6 +560,14 @@ SYM_INNER_LABEL(init_el1, SYM_L_LOCAL)
        eret
 
 SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
+       msr     elr_el2, lr
+
+       // clean all HYP code to the PoC if we booted at EL2 with the MMU on
+       cbz     x0, 0f
+       adrp    x0, __hyp_idmap_text_start
+       adr_l   x1, __hyp_text_end
+       bl      dcache_clean_poc
+0:
        mov_q   x0, HCR_HOST_NVHE_FLAGS
        msr     hcr_el2, x0
        isb
@@ -529,38 +591,27 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
        cbz     x0, 1f
 
        /* Set a sane SCTLR_EL1, the VHE way */
+       pre_disable_mmu_workaround
        msr_s   SYS_SCTLR_EL12, x1
        mov     x2, #BOOT_CPU_FLAG_E2H
        b       2f
 
 1:
+       pre_disable_mmu_workaround
        msr     sctlr_el1, x1
        mov     x2, xzr
 2:
-       msr     elr_el2, lr
        mov     w0, #BOOT_CPU_MODE_EL2
        orr     x0, x0, x2
        eret
 SYM_FUNC_END(init_kernel_el)
 
-/*
- * Sets the __boot_cpu_mode flag depending on the CPU boot mode passed
- * in w0. See arch/arm64/include/asm/virt.h for more info.
- */
-SYM_FUNC_START_LOCAL(set_cpu_boot_mode_flag)
-       adr_l   x1, __boot_cpu_mode
-       cmp     w0, #BOOT_CPU_MODE_EL2
-       b.ne    1f
-       add     x1, x1, #4
-1:     str     w0, [x1]                        // Save CPU boot mode
-       ret
-SYM_FUNC_END(set_cpu_boot_mode_flag)
-
        /*
         * This provides a "holding pen" for platforms to hold all secondary
         * cores are held until we're ready for them to initialise.
         */
 SYM_FUNC_START(secondary_holding_pen)
+       mov     x0, xzr
        bl      init_kernel_el                  // w0=cpu_boot_mode
        mrs     x2, mpidr_el1
        mov_q   x1, MPIDR_HWID_BITMASK
@@ -578,6 +629,7 @@ SYM_FUNC_END(secondary_holding_pen)
         * be used where CPUs are brought online dynamically by the kernel.
         */
 SYM_FUNC_START(secondary_entry)
+       mov     x0, xzr
        bl      init_kernel_el                  // w0=cpu_boot_mode
        b       secondary_startup
 SYM_FUNC_END(secondary_entry)
@@ -587,7 +639,6 @@ SYM_FUNC_START_LOCAL(secondary_startup)
         * Common entry point for secondary CPUs.
         */
        mov     x20, x0                         // preserve boot mode
-       bl      finalise_el2
        bl      __cpu_secondary_check52bitva
 #if VA_BITS > 48
        ldr_l   x0, vabits_actual
@@ -600,9 +651,14 @@ SYM_FUNC_START_LOCAL(secondary_startup)
        br      x8
 SYM_FUNC_END(secondary_startup)
 
+       .text
 SYM_FUNC_START_LOCAL(__secondary_switched)
        mov     x0, x20
        bl      set_cpu_boot_mode_flag
+
+       mov     x0, x20
+       bl      finalise_el2
+
        str_l   xzr, __early_cpu_boot_status, x3
        adr_l   x5, vectors
        msr     vbar_el1, x5
@@ -628,6 +684,19 @@ SYM_FUNC_START_LOCAL(__secondary_too_slow)
        b       __secondary_too_slow
 SYM_FUNC_END(__secondary_too_slow)
 
+/*
+ * Sets the __boot_cpu_mode flag depending on the CPU boot mode passed
+ * in w0. See arch/arm64/include/asm/virt.h for more info.
+ */
+SYM_FUNC_START_LOCAL(set_cpu_boot_mode_flag)
+       adr_l   x1, __boot_cpu_mode
+       cmp     w0, #BOOT_CPU_MODE_EL2
+       b.ne    1f
+       add     x1, x1, #4
+1:     str     w0, [x1]                        // Save CPU boot mode
+       ret
+SYM_FUNC_END(set_cpu_boot_mode_flag)
+
 /*
  * The booting CPU updates the failed status @__early_cpu_boot_status,
  * with MMU turned off.
@@ -659,6 +728,7 @@ SYM_FUNC_END(__secondary_too_slow)
  * Checks if the selected granule size is supported by the CPU.
  * If it isn't, park the CPU
  */
+       .section ".idmap.text","awx"
 SYM_FUNC_START(__enable_mmu)
        mrs     x3, ID_AA64MMFR0_EL1
        ubfx    x3, x3, #ID_AA64MMFR0_EL1_TGRAN_SHIFT, 4
index 2ee18c8..111ff33 100644 (file)
@@ -132,6 +132,13 @@ SYM_CODE_START_LOCAL(__finalise_el2)
        orr     x0, x0, SMCR_ELx_FA64_MASK
 .Lskip_sme_fa64:
 
+       // ZT0 available?
+       mrs_s   x1, SYS_ID_AA64SMFR0_EL1
+       __check_override id_aa64smfr0 ID_AA64SMFR0_EL1_SMEver_SHIFT 4 .Linit_sme_zt0 .Lskip_sme_zt0
+.Linit_sme_zt0:
+       orr     x0, x0, SMCR_ELx_EZT0_MASK
+.Lskip_sme_zt0:
+
        orr     x0, x0, #SMCR_ELx_LEN_MASK      // Enable full SME vector
        msr_s   SYS_SMCR_EL2, x0                // length for EL1.
 
index 9513376..d833d78 100644 (file)
@@ -131,6 +131,7 @@ static const struct ftr_set_desc smfr0 __initconst = {
        .name           = "id_aa64smfr0",
        .override       = &id_aa64smfr0_override,
        .fields         = {
+               FIELD("smever", ID_AA64SMFR0_EL1_SMEver_SHIFT, NULL),
                /* FA64 is a one bit field... :-/ */
                { "fa64", ID_AA64SMFR0_EL1_FA64_SHIFT, 1, },
                {}
index d0e9bb5..8309197 100644 (file)
@@ -10,7 +10,7 @@
 #error This file should only be included in vmlinux.lds.S
 #endif
 
-PROVIDE(__efistub_primary_entry_offset = primary_entry - _text);
+PROVIDE(__efistub_primary_entry                = primary_entry);
 
 /*
  * The EFI stub has its own symbol namespace prefixed by __efistub_, to
@@ -21,10 +21,11 @@ PROVIDE(__efistub_primary_entry_offset      = primary_entry - _text);
  * linked at. The routines below are all implemented in assembler in a
  * position independent manner
  */
-PROVIDE(__efistub_dcache_clean_poc     = __pi_dcache_clean_poc);
+PROVIDE(__efistub_caches_clean_inval_pou = __pi_caches_clean_inval_pou);
 
 PROVIDE(__efistub__text                        = _text);
 PROVIDE(__efistub__end                 = _end);
+PROVIDE(__efistub___inittext_end               = __inittext_end);
 PROVIDE(__efistub__edata               = _edata);
 PROVIDE(__efistub_screen_info          = screen_info);
 PROVIDE(__efistub__ctype               = _ctype);
@@ -67,9 +68,7 @@ KVM_NVHE_ALIAS(__hyp_stub_vectors);
 KVM_NVHE_ALIAS(vgic_v2_cpuif_trap);
 KVM_NVHE_ALIAS(vgic_v3_cpuif_trap);
 
-/* Static key checked in pmr_sync(). */
 #ifdef CONFIG_ARM64_PSEUDO_NMI
-KVM_NVHE_ALIAS(gic_pmr_sync);
 /* Static key checked in GIC_PRIO_IRQOFF. */
 KVM_NVHE_ALIAS(gic_nonsecure_priorities);
 #endif
index 1b3da02..a1fe4b4 100644 (file)
@@ -130,7 +130,8 @@ struct eh_frame {
 
 static int noinstr scs_handle_fde_frame(const struct eh_frame *frame,
                                        bool fde_has_augmentation_data,
-                                       int code_alignment_factor)
+                                       int code_alignment_factor,
+                                       bool dry_run)
 {
        int size = frame->size - offsetof(struct eh_frame, opcodes) + 4;
        u64 loc = (u64)offset_to_ptr(&frame->initial_loc);
@@ -184,7 +185,8 @@ static int noinstr scs_handle_fde_frame(const struct eh_frame *frame,
                        break;
 
                case DW_CFA_negate_ra_state:
-                       scs_patch_loc(loc - 4);
+                       if (!dry_run)
+                               scs_patch_loc(loc - 4);
                        break;
 
                case 0x40 ... 0x7f:
@@ -235,9 +237,12 @@ int noinstr scs_patch(const u8 eh_frame[], int size)
                } else {
                        ret = scs_handle_fde_frame(frame,
                                                   fde_has_augmentation_data,
-                                                  code_alignment_factor);
+                                                  code_alignment_factor,
+                                                  true);
                        if (ret)
                                return ret;
+                       scs_handle_fde_frame(frame, fde_has_augmentation_data,
+                                            code_alignment_factor, false);
                }
 
                p += sizeof(frame->size) + frame->size;
index 33e0fab..b4835f6 100644 (file)
@@ -88,6 +88,23 @@ int __kprobes aarch64_insn_write(void *addr, u32 insn)
        return __aarch64_insn_write(addr, cpu_to_le32(insn));
 }
 
+noinstr int aarch64_insn_write_literal_u64(void *addr, u64 val)
+{
+       u64 *waddr;
+       unsigned long flags;
+       int ret;
+
+       raw_spin_lock_irqsave(&patch_lock, flags);
+       waddr = patch_map(addr, FIX_TEXT_POKE0);
+
+       ret = copy_to_kernel_nofault(waddr, &val, sizeof(val));
+
+       patch_unmap(FIX_TEXT_POKE0);
+       raw_spin_unlock_irqrestore(&patch_lock, flags);
+
+       return ret;
+}
+
 int __kprobes aarch64_insn_patch_text_nosync(void *addr, u32 insn)
 {
        u32 *tp = addr;
index f35d059..70b91a8 100644 (file)
@@ -387,10 +387,6 @@ int __init arch_populate_kprobe_blacklist(void)
                                        (unsigned long)__irqentry_text_end);
        if (ret)
                return ret;
-       ret = kprobe_add_area_blacklist((unsigned long)__idmap_text_start,
-                                       (unsigned long)__idmap_text_end);
-       if (ret)
-               return ret;
        ret = kprobe_add_area_blacklist((unsigned long)__hyp_text_start,
                                        (unsigned long)__hyp_text_end);
        if (ret || is_kernel_in_hyp_mode())
index 269ac1c..71d59b5 100644 (file)
@@ -307,27 +307,28 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 
        /*
         * In the unlikely event that we create a new thread with ZA
-        * enabled we should retain the ZA state so duplicate it here.
-        * This may be shortly freed if we exec() or if CLONE_SETTLS
-        * but it's simpler to do it here. To avoid confusing the rest
-        * of the code ensure that we have a sve_state allocated
-        * whenever za_state is allocated.
+        * enabled we should retain the ZA and ZT state so duplicate
+        * it here.  This may be shortly freed if we exec() or if
+        * CLONE_SETTLS but it's simpler to do it here. To avoid
+        * confusing the rest of the code ensure that we have a
+        * sve_state allocated whenever sme_state is allocated.
         */
        if (thread_za_enabled(&src->thread)) {
                dst->thread.sve_state = kzalloc(sve_state_size(src),
                                                GFP_KERNEL);
                if (!dst->thread.sve_state)
                        return -ENOMEM;
-               dst->thread.za_state = kmemdup(src->thread.za_state,
-                                              za_state_size(src),
-                                              GFP_KERNEL);
-               if (!dst->thread.za_state) {
+
+               dst->thread.sme_state = kmemdup(src->thread.sme_state,
+                                               sme_state_size(src),
+                                               GFP_KERNEL);
+               if (!dst->thread.sme_state) {
                        kfree(dst->thread.sve_state);
                        dst->thread.sve_state = NULL;
                        return -ENOMEM;
                }
        } else {
-               dst->thread.za_state = NULL;
+               dst->thread.sme_state = NULL;
                clear_tsk_thread_flag(dst, TIF_SME);
        }
 
index 2686ab1..143a971 100644 (file)
@@ -683,7 +683,7 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset,
        unsigned long tls[2];
 
        tls[0] = target->thread.uw.tp_value;
-       if (system_supports_sme())
+       if (system_supports_tpidr2())
                tls[1] = target->thread.tpidr2_el0;
 
        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, tls, 0, count);
@@ -691,7 +691,7 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset,
                return ret;
 
        target->thread.uw.tp_value = tls[0];
-       if (system_supports_sme())
+       if (system_supports_tpidr2())
                target->thread.tpidr2_el0 = tls[1];
 
        return ret;
@@ -1045,7 +1045,7 @@ static int za_get(struct task_struct *target,
        if (thread_za_enabled(&target->thread)) {
                start = end;
                end = ZA_PT_SIZE(vq);
-               membuf_write(&to, target->thread.za_state, end - start);
+               membuf_write(&to, target->thread.sme_state, end - start);
        }
 
        /* Zero any trailing padding */
@@ -1099,7 +1099,7 @@ static int za_set(struct task_struct *target,
 
        /* Allocate/reinit ZA storage */
        sme_alloc(target);
-       if (!target->thread.za_state) {
+       if (!target->thread.sme_state) {
                ret = -ENOMEM;
                goto out;
        }
@@ -1124,7 +1124,7 @@ static int za_set(struct task_struct *target,
        start = ZA_PT_ZA_OFFSET;
        end = ZA_PT_SIZE(vq);
        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                                target->thread.za_state,
+                                target->thread.sme_state,
                                 start, end);
        if (ret)
                goto out;
@@ -1138,6 +1138,51 @@ out:
        return ret;
 }
 
+static int zt_get(struct task_struct *target,
+                 const struct user_regset *regset,
+                 struct membuf to)
+{
+       if (!system_supports_sme2())
+               return -EINVAL;
+
+       /*
+        * If PSTATE.ZA is not set then ZT will be zeroed when it is
+        * enabled so report the current register value as zero.
+        */
+       if (thread_za_enabled(&target->thread))
+               membuf_write(&to, thread_zt_state(&target->thread),
+                            ZT_SIG_REG_BYTES);
+       else
+               membuf_zero(&to, ZT_SIG_REG_BYTES);
+
+       return 0;
+}
+
+static int zt_set(struct task_struct *target,
+                 const struct user_regset *regset,
+                 unsigned int pos, unsigned int count,
+                 const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+
+       if (!system_supports_sme2())
+               return -EINVAL;
+
+       if (!thread_za_enabled(&target->thread)) {
+               sme_alloc(target);
+               if (!target->thread.sme_state)
+                       return -ENOMEM;
+       }
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                thread_zt_state(&target->thread),
+                                0, ZT_SIG_REG_BYTES);
+       if (ret == 0)
+               target->thread.svcr |= SVCR_ZA_MASK;
+
+       return ret;
+}
+
 #endif /* CONFIG_ARM64_SME */
 
 #ifdef CONFIG_ARM64_PTR_AUTH
@@ -1360,6 +1405,7 @@ enum aarch64_regset {
 #ifdef CONFIG_ARM64_SVE
        REGSET_SSVE,
        REGSET_ZA,
+       REGSET_ZT,
 #endif
 #ifdef CONFIG_ARM64_PTR_AUTH
        REGSET_PAC_MASK,
@@ -1467,6 +1513,14 @@ static const struct user_regset aarch64_regsets[] = {
                .regset_get = za_get,
                .set = za_set,
        },
+       [REGSET_ZT] = { /* SME ZT */
+               .core_note_type = NT_ARM_ZT,
+               .n = 1,
+               .size = ZT_SIG_REG_BYTES,
+               .align = sizeof(u64),
+               .regset_get = zt_get,
+               .set = zt_set,
+       },
 #endif
 #ifdef CONFIG_ARM64_PTR_AUTH
        [REGSET_PAC_MASK] = {
index 12cfe9d..b8ec7b3 100644 (file)
@@ -58,6 +58,7 @@ static int num_standard_resources;
 static struct resource *standard_resources;
 
 phys_addr_t __fdt_pointer __initdata;
+u64 mmu_enabled_at_boot __initdata;
 
 /*
  * Standard memory resources
@@ -332,8 +333,12 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
        xen_early_init();
        efi_init();
 
-       if (!efi_enabled(EFI_BOOT) && ((u64)_text % MIN_KIMG_ALIGN) != 0)
-            pr_warn(FW_BUG "Kernel image misaligned at boot, please fix your bootloader!");
+       if (!efi_enabled(EFI_BOOT)) {
+               if ((u64)_text % MIN_KIMG_ALIGN)
+                       pr_warn(FW_BUG "Kernel image misaligned at boot, please fix your bootloader!");
+               WARN_TAINT(mmu_enabled_at_boot, TAINT_FIRMWARE_WORKAROUND,
+                          FW_BUG "Booted with MMU enabled!");
+       }
 
        arm64_memblock_init();
 
@@ -442,3 +447,11 @@ static int __init register_arm64_panic_block(void)
        return 0;
 }
 device_initcall(register_arm64_panic_block);
+
+static int __init check_mmu_enabled_at_boot(void)
+{
+       if (!efi_enabled(EFI_BOOT) && mmu_enabled_at_boot)
+               panic("Non-EFI boot detected with MMU and caches enabled");
+       return 0;
+}
+device_initcall_sync(check_mmu_enabled_at_boot);
index e0d09bf..ed69228 100644 (file)
@@ -56,7 +56,9 @@ struct rt_sigframe_user_layout {
        unsigned long fpsimd_offset;
        unsigned long esr_offset;
        unsigned long sve_offset;
+       unsigned long tpidr2_offset;
        unsigned long za_offset;
+       unsigned long zt_offset;
        unsigned long extra_offset;
        unsigned long end_offset;
 };
@@ -220,7 +222,9 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
 struct user_ctxs {
        struct fpsimd_context __user *fpsimd;
        struct sve_context __user *sve;
+       struct tpidr2_context __user *tpidr2;
        struct za_context __user *za;
+       struct zt_context __user *zt;
 };
 
 #ifdef CONFIG_ARM64_SVE
@@ -361,6 +365,32 @@ extern int preserve_sve_context(void __user *ctx);
 
 #ifdef CONFIG_ARM64_SME
 
+static int preserve_tpidr2_context(struct tpidr2_context __user *ctx)
+{
+       int err = 0;
+
+       current->thread.tpidr2_el0 = read_sysreg_s(SYS_TPIDR2_EL0);
+
+       __put_user_error(TPIDR2_MAGIC, &ctx->head.magic, err);
+       __put_user_error(sizeof(*ctx), &ctx->head.size, err);
+       __put_user_error(current->thread.tpidr2_el0, &ctx->tpidr2, err);
+
+       return err;
+}
+
+static int restore_tpidr2_context(struct user_ctxs *user)
+{
+       u64 tpidr2_el0;
+       int err = 0;
+
+       /* Magic and size were validated deciding to call this function */
+       __get_user_error(tpidr2_el0, &user->tpidr2->tpidr2, err);
+       if (!err)
+               current->thread.tpidr2_el0 = tpidr2_el0;
+
+       return err;
+}
+
 static int preserve_za_context(struct za_context __user *ctx)
 {
        int err = 0;
@@ -389,7 +419,7 @@ static int preserve_za_context(struct za_context __user *ctx)
                 * fpsimd_signal_preserve_current_state().
                 */
                err |= __copy_to_user((char __user *)ctx + ZA_SIG_REGS_OFFSET,
-                                     current->thread.za_state,
+                                     current->thread.sme_state,
                                      ZA_SIG_REGS_SIZE(vq));
        }
 
@@ -420,7 +450,7 @@ static int restore_za_context(struct user_ctxs *user)
 
        /*
         * Careful: we are about __copy_from_user() directly into
-        * thread.za_state with preemption enabled, so protection is
+        * thread.sme_state with preemption enabled, so protection is
         * needed to prevent a racing context switch from writing stale
         * registers back over the new data.
         */
@@ -429,13 +459,13 @@ static int restore_za_context(struct user_ctxs *user)
        /* From now, fpsimd_thread_switch() won't touch thread.sve_state */
 
        sme_alloc(current);
-       if (!current->thread.za_state) {
+       if (!current->thread.sme_state) {
                current->thread.svcr &= ~SVCR_ZA_MASK;
                clear_thread_flag(TIF_SME);
                return -ENOMEM;
        }
 
-       err = __copy_from_user(current->thread.za_state,
+       err = __copy_from_user(current->thread.sme_state,
                               (char __user const *)user->za +
                                        ZA_SIG_REGS_OFFSET,
                               ZA_SIG_REGS_SIZE(vq));
@@ -447,11 +477,83 @@ static int restore_za_context(struct user_ctxs *user)
 
        return 0;
 }
+
+static int preserve_zt_context(struct zt_context __user *ctx)
+{
+       int err = 0;
+       u16 reserved[ARRAY_SIZE(ctx->__reserved)];
+
+       if (WARN_ON(!thread_za_enabled(&current->thread)))
+               return -EINVAL;
+
+       memset(reserved, 0, sizeof(reserved));
+
+       __put_user_error(ZT_MAGIC, &ctx->head.magic, err);
+       __put_user_error(round_up(ZT_SIG_CONTEXT_SIZE(1), 16),
+                        &ctx->head.size, err);
+       __put_user_error(1, &ctx->nregs, err);
+       BUILD_BUG_ON(sizeof(ctx->__reserved) != sizeof(reserved));
+       err |= __copy_to_user(&ctx->__reserved, reserved, sizeof(reserved));
+
+       /*
+        * This assumes that the ZT state has already been saved to
+        * the task struct by calling the function
+        * fpsimd_signal_preserve_current_state().
+        */
+       err |= __copy_to_user((char __user *)ctx + ZT_SIG_REGS_OFFSET,
+                             thread_zt_state(&current->thread),
+                             ZT_SIG_REGS_SIZE(1));
+
+       return err ? -EFAULT : 0;
+}
+
+static int restore_zt_context(struct user_ctxs *user)
+{
+       int err;
+       struct zt_context zt;
+
+       /* ZA must be restored first for this check to be valid */
+       if (!thread_za_enabled(&current->thread))
+               return -EINVAL;
+
+       if (__copy_from_user(&zt, user->zt, sizeof(zt)))
+               return -EFAULT;
+
+       if (zt.nregs != 1)
+               return -EINVAL;
+
+       if (zt.head.size != ZT_SIG_CONTEXT_SIZE(zt.nregs))
+               return -EINVAL;
+
+       /*
+        * Careful: we are about __copy_from_user() directly into
+        * thread.zt_state with preemption enabled, so protection is
+        * needed to prevent a racing context switch from writing stale
+        * registers back over the new data.
+        */
+
+       fpsimd_flush_task_state(current);
+       /* From now, fpsimd_thread_switch() won't touch ZT in thread state */
+
+       err = __copy_from_user(thread_zt_state(&current->thread),
+                              (char __user const *)user->zt +
+                                       ZT_SIG_REGS_OFFSET,
+                              ZT_SIG_REGS_SIZE(1));
+       if (err)
+               return -EFAULT;
+
+       return 0;
+}
+
 #else /* ! CONFIG_ARM64_SME */
 
 /* Turn any non-optimised out attempts to use these into a link error: */
+extern int preserve_tpidr2_context(void __user *ctx);
+extern int restore_tpidr2_context(struct user_ctxs *user);
 extern int preserve_za_context(void __user *ctx);
 extern int restore_za_context(struct user_ctxs *user);
+extern int preserve_zt_context(void __user *ctx);
+extern int restore_zt_context(struct user_ctxs *user);
 
 #endif /* ! CONFIG_ARM64_SME */
 
@@ -468,7 +570,9 @@ static int parse_user_sigframe(struct user_ctxs *user,
 
        user->fpsimd = NULL;
        user->sve = NULL;
+       user->tpidr2 = NULL;
        user->za = NULL;
+       user->zt = NULL;
 
        if (!IS_ALIGNED((unsigned long)base, 16))
                goto invalid;
@@ -534,6 +638,19 @@ static int parse_user_sigframe(struct user_ctxs *user,
                        user->sve = (struct sve_context __user *)head;
                        break;
 
+               case TPIDR2_MAGIC:
+                       if (!system_supports_sme())
+                               goto invalid;
+
+                       if (user->tpidr2)
+                               goto invalid;
+
+                       if (size != sizeof(*user->tpidr2))
+                               goto invalid;
+
+                       user->tpidr2 = (struct tpidr2_context __user *)head;
+                       break;
+
                case ZA_MAGIC:
                        if (!system_supports_sme())
                                goto invalid;
@@ -547,6 +664,19 @@ static int parse_user_sigframe(struct user_ctxs *user,
                        user->za = (struct za_context __user *)head;
                        break;
 
+               case ZT_MAGIC:
+                       if (!system_supports_sme2())
+                               goto invalid;
+
+                       if (user->zt)
+                               goto invalid;
+
+                       if (size < sizeof(*user->zt))
+                               goto invalid;
+
+                       user->zt = (struct zt_context __user *)head;
+                       break;
+
                case EXTRA_MAGIC:
                        if (have_extra_context)
                                goto invalid;
@@ -666,9 +796,15 @@ static int restore_sigframe(struct pt_regs *regs,
                        err = restore_fpsimd_context(user.fpsimd);
        }
 
+       if (err == 0 && system_supports_sme() && user.tpidr2)
+               err = restore_tpidr2_context(&user);
+
        if (err == 0 && system_supports_sme() && user.za)
                err = restore_za_context(&user);
 
+       if (err == 0 && system_supports_sme2() && user.zt)
+               err = restore_zt_context(&user);
+
        return err;
 }
 
@@ -760,6 +896,11 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
                else
                        vl = task_get_sme_vl(current);
 
+               err = sigframe_alloc(user, &user->tpidr2_offset,
+                                    sizeof(struct tpidr2_context));
+               if (err)
+                       return err;
+
                if (thread_za_enabled(&current->thread))
                        vq = sve_vq_from_vl(vl);
 
@@ -769,6 +910,15 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
                        return err;
        }
 
+       if (system_supports_sme2()) {
+               if (add_all || thread_za_enabled(&current->thread)) {
+                       err = sigframe_alloc(user, &user->zt_offset,
+                                            ZT_SIG_CONTEXT_SIZE(1));
+                       if (err)
+                               return err;
+               }
+       }
+
        return sigframe_alloc_end(user);
 }
 
@@ -817,6 +967,13 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user,
                err |= preserve_sve_context(sve_ctx);
        }
 
+       /* TPIDR2 if supported */
+       if (system_supports_sme() && err == 0) {
+               struct tpidr2_context __user *tpidr2_ctx =
+                       apply_user_offset(user, user->tpidr2_offset);
+               err |= preserve_tpidr2_context(tpidr2_ctx);
+       }
+
        /* ZA state if present */
        if (system_supports_sme() && err == 0 && user->za_offset) {
                struct za_context __user *za_ctx =
@@ -824,6 +981,13 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user,
                err |= preserve_za_context(za_ctx);
        }
 
+       /* ZT state if present */
+       if (system_supports_sme2() && err == 0 && user->zt_offset) {
+               struct zt_context __user *zt_ctx =
+                       apply_user_offset(user, user->zt_offset);
+               err |= preserve_zt_context(zt_ctx);
+       }
+
        if (err == 0 && user->extra_offset) {
                char __user *sfp = (char __user *)user->sigframe;
                char __user *userp =
index 97c9de5..2ae7cff 100644 (file)
@@ -99,8 +99,9 @@ SYM_FUNC_END(__cpu_suspend_enter)
 
        .pushsection ".idmap.text", "awx"
 SYM_CODE_START(cpu_resume)
+       mov     x0, xzr
        bl      init_kernel_el
-       bl      finalise_el2
+       mov     x19, x0                 // preserve boot mode
 #if VA_BITS > 48
        ldr_l   x0, vabits_actual
 #endif
@@ -116,6 +117,9 @@ SYM_CODE_END(cpu_resume)
        .popsection
 
 SYM_FUNC_START(_cpu_resume)
+       mov     x0, x19
+       bl      finalise_el2
+
        mrs     x1, mpidr_el1
        adr_l   x8, mpidr_hash          // x8 = struct mpidr_hash virt address
 
index a5de47e..da84cf8 100644 (file)
@@ -173,12 +173,8 @@ static inline void fp_user_discard(void)
         * register state to track, if this changes the KVM code will
         * need updating.
         */
-       if (system_supports_sme() && test_thread_flag(TIF_SME)) {
-               u64 svcr = read_sysreg_s(SYS_SVCR);
-
-               if (svcr & SVCR_SM_MASK)
-                       sme_smstop_sm();
-       }
+       if (system_supports_sme())
+               sme_smstop_sm();
 
        if (!system_supports_sve())
                return;
index 4c0caa5..0ccc063 100644 (file)
@@ -162,10 +162,8 @@ static void dump_kernel_instr(const char *lvl, struct pt_regs *regs)
 
                if (!bad)
                        p += sprintf(p, i == 0 ? "(%08x) " : "%08x ", val);
-               else {
-                       p += sprintf(p, "bad PC value");
-                       break;
-               }
+               else
+                       p += sprintf(p, i == 0 ? "(????????) " : "???????? ");
        }
 
        printk("%sCode: %s\n", lvl, str);
index 4c13daf..1a43df2 100644 (file)
@@ -93,6 +93,7 @@ jiffies = jiffies_64;
 
 #ifdef CONFIG_HIBERNATION
 #define HIBERNATE_TEXT                                 \
+       ALIGN_FUNCTION();                               \
        __hibernate_exit_text_start = .;                \
        *(.hibernate_exit.text)                         \
        __hibernate_exit_text_end = .;
@@ -102,6 +103,7 @@ jiffies = jiffies_64;
 
 #ifdef CONFIG_KEXEC_CORE
 #define KEXEC_TEXT                                     \
+       ALIGN_FUNCTION();                               \
        __relocate_new_kernel_start = .;                \
        *(.kexec_relocate.text)                         \
        __relocate_new_kernel_end = .;
@@ -179,7 +181,6 @@ SECTIONS
                        LOCK_TEXT
                        KPROBES_TEXT
                        HYPERVISOR_TEXT
-                       IDMAP_TEXT
                        *(.gnu.warning)
                . = ALIGN(16);
                *(.got)                 /* Global offset table          */
@@ -206,6 +207,7 @@ SECTIONS
                TRAMP_TEXT
                HIBERNATE_TEXT
                KEXEC_TEXT
+               IDMAP_TEXT
                . = ALIGN(PAGE_SIZE);
        }
 
@@ -355,6 +357,8 @@ ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K,
 #ifdef CONFIG_HIBERNATION
 ASSERT(__hibernate_exit_text_end - __hibernate_exit_text_start <= SZ_4K,
        "Hibernate exit text is bigger than 4 KiB")
+ASSERT(__hibernate_exit_text_start == swsusp_arch_suspend_exit,
+       "Hibernate exit text does not start with swsusp_arch_suspend_exit")
 #endif
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) <= 3*PAGE_SIZE,
@@ -381,4 +385,6 @@ ASSERT(swapper_pg_dir - tramp_pg_dir == TRAMP_SWAPPER_OFFSET,
 ASSERT(__relocate_new_kernel_end - __relocate_new_kernel_start <= SZ_4K,
        "kexec relocation code is bigger than 4 KiB")
 ASSERT(KEXEC_CONTROL_PAGE_SIZE >= SZ_4K, "KEXEC_CONTROL_PAGE_SIZE is broken")
+ASSERT(__relocate_new_kernel_start == arm64_relocate_new_kernel,
+       "kexec control page does not start with arm64_relocate_new_kernel")
 #endif
index fccf9ec..55f80fb 100644 (file)
@@ -328,7 +328,7 @@ void kvm_arch_vcpu_load_debug_state_flags(struct kvm_vcpu *vcpu)
         * we may need to check if the host state needs to be saved.
         */
        if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_EL1_PMSVer_SHIFT) &&
-           !(read_sysreg_s(SYS_PMBIDR_EL1) & BIT(SYS_PMBIDR_EL1_P_SHIFT)))
+           !(read_sysreg_s(SYS_PMBIDR_EL1) & BIT(PMBIDR_EL1_P_SHIFT)))
                vcpu_set_flag(vcpu, DEBUG_STATE_SAVE_SPE);
 
        /* Check if we have TRBE implemented and available at the host */
index 02dd7e9..235775d 100644 (file)
@@ -143,7 +143,7 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
                fp_state.st = &vcpu->arch.ctxt.fp_regs;
                fp_state.sve_state = vcpu->arch.sve_state;
                fp_state.sve_vl = vcpu->arch.sve_max_vl;
-               fp_state.za_state = NULL;
+               fp_state.sme_state = NULL;
                fp_state.svcr = &vcpu->arch.svcr;
                fp_state.fp_type = &vcpu->arch.fp_type;
 
index 435346e..f3aa773 100644 (file)
@@ -171,7 +171,7 @@ alternative_else
        dsb     sy              // Synchronize against in-flight ld/st
        isb                     // Prevent an early read of side-effect free ISR
        mrs     x2, isr_el1
-       tbnz    x2, #8, 2f      // ISR_EL1.A
+       tbnz    x2, #ISR_EL1_A_SHIFT, 2f
        ret
        nop
 2:
index e174557..2673bde 100644 (file)
@@ -27,7 +27,7 @@ static void __debug_save_spe(u64 *pmscr_el1)
         * Check if the host is actually using it ?
         */
        reg = read_sysreg_s(SYS_PMBLIMITR_EL1);
-       if (!(reg & BIT(SYS_PMBLIMITR_EL1_E_SHIFT)))
+       if (!(reg & BIT(PMBLIMITR_EL1_E_SHIFT)))
                return;
 
        /* Yes; save the control register and disable data generation */
index 081058d..503567c 100644 (file)
@@ -56,6 +56,7 @@ SYM_FUNC_START(caches_clean_inval_pou)
        caches_clean_inval_pou_macro
        ret
 SYM_FUNC_END(caches_clean_inval_pou)
+SYM_FUNC_ALIAS(__pi_caches_clean_inval_pou, caches_clean_inval_pou)
 
 /*
  *     caches_clean_inval_user_pou(start,end)
index 14c87e8..34d5f7c 100644 (file)
@@ -133,7 +133,7 @@ static phys_addr_t __init early_pgtable_alloc(int shift)
        return phys;
 }
 
-static bool pgattr_change_is_safe(u64 old, u64 new)
+bool pgattr_change_is_safe(u64 old, u64 new)
 {
        /*
         * The following mapping attributes may be updated in live
@@ -142,9 +142,13 @@ static bool pgattr_change_is_safe(u64 old, u64 new)
        pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE | PTE_NG;
 
        /* creating or taking down mappings is always safe */
-       if (old == 0 || new == 0)
+       if (!pte_valid(__pte(old)) || !pte_valid(__pte(new)))
                return true;
 
+       /* A live entry's pfn should not change */
+       if (pte_pfn(__pte(old)) != pte_pfn(__pte(new)))
+               return false;
+
        /* live contiguous mappings may not be manipulated at all */
        if ((old | new) & PTE_CONT)
                return false;
index 066fa60..91410f4 100644 (file)
@@ -110,7 +110,6 @@ SYM_FUNC_END(cpu_do_suspend)
  *
  * x0: Address of context pointer
  */
-       .pushsection ".idmap.text", "awx"
 SYM_FUNC_START(cpu_do_resume)
        ldp     x2, x3, [x0]
        ldp     x4, x5, [x0, #16]
@@ -166,7 +165,6 @@ alternative_else_nop_endif
        isb
        ret
 SYM_FUNC_END(cpu_do_resume)
-       .popsection
 #endif
 
        .pushsection ".idmap.text", "awx"
index a86ee37..b98f711 100644 (file)
@@ -28,7 +28,9 @@ HAS_GENERIC_AUTH
 HAS_GENERIC_AUTH_ARCH_QARMA3
 HAS_GENERIC_AUTH_ARCH_QARMA5
 HAS_GENERIC_AUTH_IMP_DEF
-HAS_IRQ_PRIO_MASKING
+HAS_GIC_CPUIF_SYSREGS
+HAS_GIC_PRIO_MASKING
+HAS_GIC_PRIO_RELAXED_SYNC
 HAS_LDAPR
 HAS_LSE_ATOMICS
 HAS_NO_FPSIMD
@@ -38,7 +40,6 @@ HAS_RAS_EXTN
 HAS_RNG
 HAS_SB
 HAS_STAGE2_FWB
-HAS_SYSREG_GIC_CPUIF
 HAS_TIDCP1
 HAS_TLB_RANGE
 HAS_VIRT_HOST_EXTN
@@ -50,6 +51,7 @@ MTE
 MTE_ASYMM
 SME
 SME_FA64
+SME2
 SPECTRE_V2
 SPECTRE_V3A
 SPECTRE_V4
index 184e58f..ef9995c 100644 (file)
@@ -689,17 +689,17 @@ EndEnum
 Enum   11:8    FPDP
        0b0000  NI
        0b0001  VFPv2
-       0b0001  VFPv3
+       0b0010  VFPv3
 EndEnum
 Enum   7:4     FPSP
        0b0000  NI
        0b0001  VFPv2
-       0b0001  VFPv3
+       0b0010  VFPv3
 EndEnum
 Enum   3:0     SIMDReg
        0b0000  NI
        0b0001  IMP_16x64
-       0b0001  IMP_32x64
+       0b0010  IMP_32x64
 EndEnum
 EndSysreg
 
@@ -718,7 +718,7 @@ EndEnum
 Enum   23:20   SIMDHP
        0b0000  NI
        0b0001  SIMDHP
-       0b0001  SIMDHP_FLOAT
+       0b0010  SIMDHP_FLOAT
 EndEnum
 Enum   19:16   SIMDSP
        0b0000  NI
@@ -894,6 +894,7 @@ EndEnum
 Enum   27:24   SME
        0b0000  NI
        0b0001  IMP
+       0b0010  SME2
 EndEnum
 Res0   23:20
 Enum   19:16   MPAM_frac
@@ -975,7 +976,9 @@ Enum        63      FA64
 EndEnum
 Res0   62:60
 Enum   59:56   SMEver
-       0b0000  IMP
+       0b0000  SME
+       0b0001  SME2
+       0b0010  SME2p1
 EndEnum
 Enum   55:52   I16I64
        0b0000  NI
@@ -986,7 +989,19 @@ Enum       48      F64F64
        0b0     NI
        0b1     IMP
 EndEnum
-Res0   47:40
+Enum   47:44   I16I32
+       0b0000  NI
+       0b0101  IMP
+EndEnum
+Enum   43      B16B16
+       0b0     NI
+       0b1     IMP
+EndEnum
+Enum   42      F16F16
+       0b0     NI
+       0b1     IMP
+EndEnum
+Res0   41:40
 Enum   39:36   I8I32
        0b0000  NI
        0b1111  IMP
@@ -999,7 +1014,10 @@ Enum      34      B16F32
        0b0     NI
        0b1     IMP
 EndEnum
-Res0   33
+Enum   33      BI32I32
+       0b0     NI
+       0b1     IMP
+EndEnum
 Enum   32      F32F32
        0b0     NI
        0b1     IMP
@@ -1599,7 +1617,8 @@ EndSysreg
 SysregFields   SMCR_ELx
 Res0   63:32
 Field  31      FA64
-Res0   30:9
+Field  30      EZT0
+Res0   29:9
 Raz    8:4
 Field  3:0     LEN
 EndSysregFields
@@ -1618,6 +1637,130 @@ Sysreg  FAR_EL1 3       0       6       0       0
 Field  63:0    ADDR
 EndSysreg
 
+Sysreg PMSCR_EL1       3       0       9       9       0
+Res0   63:8
+Field  7:6     PCT
+Field  5       TS
+Field  4       PA
+Field  3       CX
+Res0   2
+Field  1       E1SPE
+Field  0       E0SPE
+EndSysreg
+
+Sysreg PMSNEVFR_EL1    3       0       9       9       1
+Field  63:0    E
+EndSysreg
+
+Sysreg PMSICR_EL1      3       0       9       9       2
+Field  63:56   ECOUNT
+Res0   55:32
+Field  31:0    COUNT
+EndSysreg
+
+Sysreg PMSIRR_EL1      3       0       9       9       3
+Res0   63:32
+Field  31:8    INTERVAL
+Res0   7:1
+Field  0       RND
+EndSysreg
+
+Sysreg PMSFCR_EL1      3       0       9       9       4
+Res0   63:19
+Field  18      ST
+Field  17      LD
+Field  16      B
+Res0   15:4
+Field  3       FnE
+Field  2       FL
+Field  1       FT
+Field  0       FE
+EndSysreg
+
+Sysreg PMSEVFR_EL1     3       0       9       9       5
+Field  63:0    E
+EndSysreg
+
+Sysreg PMSLATFR_EL1    3       0       9       9       6
+Res0   63:16
+Field  15:0    MINLAT
+EndSysreg
+
+Sysreg PMSIDR_EL1      3       0       9       9       7
+Res0   63:25
+Field  24      PBT
+Field  23:20   FORMAT
+Enum   19:16   COUNTSIZE
+       0b0010  12_BIT_SAT
+       0b0011  16_BIT_SAT
+EndEnum
+Field  15:12   MAXSIZE
+Enum   11:8    INTERVAL
+       0b0000  256
+       0b0010  512
+       0b0011  768
+       0b0100  1024
+       0b0101  1536
+       0b0110  2048
+       0b0111  3072
+       0b1000  4096
+EndEnum
+Res0   7
+Field  6       FnE
+Field  5       ERND
+Field  4       LDS
+Field  3       ARCHINST
+Field  2       FL
+Field  1       FT
+Field  0       FE
+EndSysreg
+
+Sysreg PMBLIMITR_EL1   3       0       9       10      0
+Field  63:12   LIMIT
+Res0   11:6
+Field  5       PMFZ
+Res0   4:3
+Enum   2:1     FM
+       0b00    FILL
+       0b10    DISCARD
+EndEnum
+Field  0       E
+EndSysreg
+
+Sysreg PMBPTR_EL1      3       0       9       10      1
+Field  63:0    PTR
+EndSysreg
+
+Sysreg PMBSR_EL1       3       0       9       10      3
+Res0   63:32
+Enum   31:26   EC
+       0b000000        BUF
+       0b100100        FAULT_S1
+       0b100101        FAULT_S2
+       0b011110        FAULT_GPC
+       0b011111        IMP_DEF
+EndEnum
+Res0   25:20
+Field  19      DL
+Field  18      EA
+Field  17      S
+Field  16      COLL
+Field  15:0    MSS
+EndSysreg
+
+Sysreg PMBIDR_EL1      3       0       9       10      7
+Res0   63:12
+Enum   11:8    EA
+       0b0000  NotDescribed
+       0b0001  Ignored
+       0b0010  SError
+EndEnum
+Res0   7:6
+Field  5       F
+Field  4       P
+Field  3:0     ALIGN
+EndSysreg
+
 SysregFields   CONTEXTIDR_ELx
 Res0   63:32
 Field  31:0    PROCID
@@ -1772,6 +1915,21 @@ Sysreg   FAR_EL2 3       4       6       0       0
 Field  63:0    ADDR
 EndSysreg
 
+Sysreg PMSCR_EL2       3       4       9       9       0
+Res0   63:8
+Enum   7:6     PCT
+       0b00    VIRT
+       0b01    PHYS
+       0b11    GUEST
+EndEnum
+Field  5       TS
+Field  4       PA
+Field  3       CX
+Res0   2
+Field  1       E2SPE
+Field  0       E0HSPE
+EndSysreg
+
 Sysreg CONTEXTIDR_EL2  3       4       13      0       1
 Fields CONTEXTIDR_ELx
 EndSysreg
@@ -1842,3 +2000,18 @@ Field    23:16   LD
 Res0   15:8
 Field  7:0     LR
 EndSysreg
+
+Sysreg ISR_EL1 3       0       12      1       0
+Res0   63:11
+Field  10      IS
+Field  9       FS
+Field  8       A
+Field  7       I
+Field  6       F
+Res0   5:0
+EndSysreg
+
+Sysreg ICC_NMIAR1_EL1  3       0       12      9       5
+Res0   63:24
+Field  23:0    INTID
+EndSysreg
index 9e0d95d..30f3fc1 100644 (file)
@@ -3,7 +3,7 @@
 # Makefile for ACPICA Core interpreter
 #
 
-ccflags-y                      := -Os -D_LINUX -DBUILDING_ACPICA
+ccflags-y                      := -D_LINUX -DBUILDING_ACPICA
 ccflags-$(CONFIG_ACPI_DEBUG)   += -DACPI_DEBUG_OUTPUT
 
 # use acpi.o to put all files here into acpi.o modparam namespace
index be8b8c6..80d85a5 100644 (file)
@@ -87,7 +87,7 @@ lib-$(CONFIG_EFI_GENERIC_STUB)        += efi-stub.o string.o intrinsics.o systable.o \
                                   screen_info.o efi-stub-entry.o
 
 lib-$(CONFIG_ARM)              += arm32-stub.o
-lib-$(CONFIG_ARM64)            += arm64.o arm64-stub.o arm64-entry.o smbios.o
+lib-$(CONFIG_ARM64)            += arm64.o arm64-stub.o smbios.o
 lib-$(CONFIG_X86)              += x86-stub.o
 lib-$(CONFIG_RISCV)            += riscv.o riscv-stub.o
 lib-$(CONFIG_LOONGARCH)                += loongarch.o loongarch-stub.o
@@ -141,7 +141,7 @@ STUBCOPY_RELOC-$(CONFIG_ARM)        := R_ARM_ABS
 #
 STUBCOPY_FLAGS-$(CONFIG_ARM64) += --prefix-alloc-sections=.init \
                                   --prefix-symbols=__efistub_
-STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS64
+STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS
 
 # For RISC-V, we don't need anything special other than arm64. Keep all the
 # symbols in .init section and make sure that no absolute symbols references
diff --git a/drivers/firmware/efi/libstub/arm64-entry.S b/drivers/firmware/efi/libstub/arm64-entry.S
deleted file mode 100644 (file)
index b5c17e8..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * EFI entry point.
- *
- * Copyright (C) 2013, 2014 Red Hat, Inc.
- * Author: Mark Salter <msalter@redhat.com>
- */
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-
-       /*
-        * The entrypoint of a arm64 bare metal image is at offset #0 of the
-        * image, so this is a reasonable default for primary_entry_offset.
-        * Only when the EFI stub is integrated into the core kernel, it is not
-        * guaranteed that the PE/COFF header has been copied to memory too, so
-        * in this case, primary_entry_offset should be overridden by the
-        * linker and point to primary_entry() directly.
-        */
-       .weak   primary_entry_offset
-
-SYM_CODE_START(efi_enter_kernel)
-       /*
-        * efi_pe_entry() will have copied the kernel image if necessary and we
-        * end up here with device tree address in x1 and the kernel entry
-        * point stored in x0. Save those values in registers which are
-        * callee preserved.
-        */
-       ldr     w2, =primary_entry_offset
-       add     x19, x0, x2             // relocated Image entrypoint
-
-       mov     x0, x1                  // DTB address
-       mov     x1, xzr
-       mov     x2, xzr
-       mov     x3, xzr
-
-       /*
-        * Clean the remainder of this routine to the PoC
-        * so that we can safely disable the MMU and caches.
-        */
-       adr     x4, 1f
-       dc      civac, x4
-       dsb     sy
-
-       /* Turn off Dcache and MMU */
-       mrs     x4, CurrentEL
-       cmp     x4, #CurrentEL_EL2
-       mrs     x4, sctlr_el1
-       b.ne    0f
-       mrs     x4, sctlr_el2
-0:     bic     x4, x4, #SCTLR_ELx_M
-       bic     x4, x4, #SCTLR_ELx_C
-       b.eq    1f
-       b       2f
-
-       .balign 32
-1:     pre_disable_mmu_workaround
-       msr     sctlr_el2, x4
-       isb
-       br      x19             // jump to kernel entrypoint
-
-2:     pre_disable_mmu_workaround
-       msr     sctlr_el1, x4
-       isb
-       br      x19             // jump to kernel entrypoint
-
-       .org    1b + 32
-SYM_CODE_END(efi_enter_kernel)
index 7327b98..d4a6b12 100644 (file)
@@ -58,7 +58,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
                                 efi_handle_t image_handle)
 {
        efi_status_t status;
-       unsigned long kernel_size, kernel_memsize = 0;
+       unsigned long kernel_size, kernel_codesize, kernel_memsize;
        u32 phys_seed = 0;
        u64 min_kimg_align = efi_get_kimg_min_align();
 
@@ -93,6 +93,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
                        SEGMENT_ALIGN >> 10);
 
        kernel_size = _edata - _text;
+       kernel_codesize = __inittext_end - _text;
        kernel_memsize = kernel_size + (_end - _edata);
        *reserve_size = kernel_memsize;
 
@@ -121,7 +122,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
                         */
                        *image_addr = (u64)_text;
                        *reserve_size = 0;
-                       goto clean_image_to_poc;
+                       return EFI_SUCCESS;
                }
 
                status = efi_allocate_pages_aligned(*reserve_size, reserve_addr,
@@ -137,14 +138,21 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 
        *image_addr = *reserve_addr;
        memcpy((void *)*image_addr, _text, kernel_size);
+       caches_clean_inval_pou(*image_addr, *image_addr + kernel_codesize);
 
-clean_image_to_poc:
+       return EFI_SUCCESS;
+}
+
+asmlinkage void primary_entry(void);
+
+unsigned long primary_entry_offset(void)
+{
        /*
-        * Clean the copied Image to the PoC, and ensure it is not shadowed by
-        * stale icache entries from before relocation.
+        * When built as part of the kernel, the EFI stub cannot branch to the
+        * kernel proper via the image header, as the PE/COFF header is
+        * strictly not part of the in-memory presentation of the image, only
+        * of the file representation. So instead, we need to jump to the
+        * actual entrypoint in the .text region of the image.
         */
-       dcache_clean_poc(*image_addr, *image_addr + kernel_size);
-       asm("ic ialluis");
-
-       return EFI_SUCCESS;
+       return (char *)primary_entry - _text;
 }
index ff2d18c..f5da4fb 100644 (file)
@@ -56,6 +56,12 @@ efi_status_t check_platform_features(void)
        return EFI_SUCCESS;
 }
 
+#ifdef CONFIG_ARM64_WORKAROUND_CLEAN_CACHE
+#define DCTYPE "civac"
+#else
+#define DCTYPE "cvau"
+#endif
+
 void efi_cache_sync_image(unsigned long image_base,
                          unsigned long alloc_size,
                          unsigned long code_size)
@@ -64,13 +70,38 @@ void efi_cache_sync_image(unsigned long image_base,
        u64 lsize = 4 << cpuid_feature_extract_unsigned_field(ctr,
                                                CTR_EL0_DminLine_SHIFT);
 
-       do {
-               asm("dc civac, %0" :: "r"(image_base));
-               image_base += lsize;
-               alloc_size -= lsize;
-       } while (alloc_size >= lsize);
+       /* only perform the cache maintenance if needed for I/D coherency */
+       if (!(ctr & BIT(CTR_EL0_IDC_SHIFT))) {
+               do {
+                       asm("dc " DCTYPE ", %0" :: "r"(image_base));
+                       image_base += lsize;
+                       code_size -= lsize;
+               } while (code_size >= lsize);
+       }
 
        asm("ic ialluis");
        dsb(ish);
        isb();
 }
+
+unsigned long __weak primary_entry_offset(void)
+{
+       /*
+        * By default, we can invoke the kernel via the branch instruction in
+        * the image header, so offset #0. This will be overridden by the EFI
+        * stub build that is linked into the core kernel, as in that case, the
+        * image header may not have been loaded into memory, or may be mapped
+        * with non-executable permissions.
+        */
+       return 0;
+}
+
+void __noreturn efi_enter_kernel(unsigned long entrypoint,
+                                unsigned long fdt_addr,
+                                unsigned long fdt_size)
+{
+       void (* __noreturn enter_kernel)(u64, u64, u64, u64);
+
+       enter_kernel = (void *)entrypoint + primary_entry_offset();
+       enter_kernel(fdt_addr, 0, 0, 0);
+}
index 997104d..3779836 100644 (file)
@@ -89,15 +89,6 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
  */
 static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis);
 
-/*
- * Global static key controlling whether an update to PMR allowing more
- * interrupts requires to be propagated to the redistributor (DSB SY).
- * And this needs to be exported for modules to be able to enable
- * interrupts...
- */
-DEFINE_STATIC_KEY_FALSE(gic_pmr_sync);
-EXPORT_SYMBOL(gic_pmr_sync);
-
 DEFINE_STATIC_KEY_FALSE(gic_nonsecure_priorities);
 EXPORT_SYMBOL(gic_nonsecure_priorities);
 
@@ -1768,16 +1759,8 @@ static void gic_enable_nmi_support(void)
        for (i = 0; i < gic_data.ppi_nr; i++)
                refcount_set(&ppi_nmi_refs[i], 0);
 
-       /*
-        * Linux itself doesn't use 1:N distribution, so has no need to
-        * set PMHE. The only reason to have it set is if EL3 requires it
-        * (and we can't change it).
-        */
-       if (gic_read_ctlr() & ICC_CTLR_EL1_PMHE_MASK)
-               static_branch_enable(&gic_pmr_sync);
-
        pr_info("Pseudo-NMIs enabled using %s ICC_PMR_EL1 synchronisation\n",
-               static_branch_unlikely(&gic_pmr_sync) ? "forced" : "relaxed");
+               gic_has_relaxed_pmr_sync() ? "relaxed" : "forced");
 
        /*
         * How priority values are used by the GIC depends on two things:
index 210bc2f..6ae697a 100644 (file)
@@ -54,7 +54,7 @@
 
 static void gic_check_cpu_features(void)
 {
-       WARN_TAINT_ONCE(this_cpu_has_cap(ARM64_HAS_SYSREG_GIC_CPUIF),
+       WARN_TAINT_ONCE(this_cpu_has_cap(ARM64_HAS_GIC_CPUIF_SYSREGS),
                        TAINT_CPU_OUT_OF_SPEC,
                        "GICv3 system registers enabled, broken firmware!\n");
 }
index b80a9b7..e220714 100644 (file)
@@ -1865,6 +1865,7 @@ static void arm_cmn_init_dtm(struct arm_cmn_dtm *dtm, struct arm_cmn_node *xp, i
 
        dtm->base = xp->pmu_base + CMN_DTM_OFFSET(idx);
        dtm->pmu_config_low = CMN_DTM_PMU_CONFIG_PMU_EN;
+       writeq_relaxed(dtm->pmu_config_low, dtm->base + CMN_DTM_PMU_CONFIG);
        for (i = 0; i < 4; i++) {
                dtm->wp_event[i] = -1;
                writeq_relaxed(0, dtm->base + CMN_DTM_WPn_MASK(i));
index 00e3a63..b9ba4c4 100644 (file)
@@ -12,6 +12,7 @@
 #define DRVNAME                                        PMUNAME "_pmu"
 #define pr_fmt(fmt)                            DRVNAME ": " fmt
 
+#include <linux/bitfield.h>
 #include <linux/bitops.h>
 #include <linux/bug.h>
 #include <linux/capability.h>
@@ -84,6 +85,7 @@ struct arm_spe_pmu {
 #define SPE_PMU_FEAT_ARCH_INST                 (1UL << 3)
 #define SPE_PMU_FEAT_LDS                       (1UL << 4)
 #define SPE_PMU_FEAT_ERND                      (1UL << 5)
+#define SPE_PMU_FEAT_INV_FILT_EVT              (1UL << 6)
 #define SPE_PMU_FEAT_DEV_PROBED                        (1UL << 63)
        u64                                     features;
 
@@ -201,6 +203,10 @@ static const struct attribute_group arm_spe_pmu_cap_group = {
 #define ATTR_CFG_FLD_min_latency_LO            0
 #define ATTR_CFG_FLD_min_latency_HI            11
 
+#define ATTR_CFG_FLD_inv_event_filter_CFG      config3 /* PMSNEVFR_EL1 */
+#define ATTR_CFG_FLD_inv_event_filter_LO       0
+#define ATTR_CFG_FLD_inv_event_filter_HI       63
+
 /* Why does everything I do descend into this? */
 #define __GEN_PMU_FORMAT_ATTR(cfg, lo, hi)                             \
        (lo) == (hi) ? #cfg ":" #lo "\n" : #cfg ":" #lo "-" #hi
@@ -231,6 +237,7 @@ GEN_PMU_FORMAT_ATTR(branch_filter);
 GEN_PMU_FORMAT_ATTR(load_filter);
 GEN_PMU_FORMAT_ATTR(store_filter);
 GEN_PMU_FORMAT_ATTR(event_filter);
+GEN_PMU_FORMAT_ATTR(inv_event_filter);
 GEN_PMU_FORMAT_ATTR(min_latency);
 
 static struct attribute *arm_spe_pmu_formats_attr[] = {
@@ -242,12 +249,27 @@ static struct attribute *arm_spe_pmu_formats_attr[] = {
        &format_attr_load_filter.attr,
        &format_attr_store_filter.attr,
        &format_attr_event_filter.attr,
+       &format_attr_inv_event_filter.attr,
        &format_attr_min_latency.attr,
        NULL,
 };
 
+static umode_t arm_spe_pmu_format_attr_is_visible(struct kobject *kobj,
+                                                 struct attribute *attr,
+                                                 int unused)
+       {
+       struct device *dev = kobj_to_dev(kobj);
+       struct arm_spe_pmu *spe_pmu = dev_get_drvdata(dev);
+
+       if (attr == &format_attr_inv_event_filter.attr && !(spe_pmu->features & SPE_PMU_FEAT_INV_FILT_EVT))
+               return 0;
+
+       return attr->mode;
+}
+
 static const struct attribute_group arm_spe_pmu_format_group = {
        .name   = "format",
+       .is_visible = arm_spe_pmu_format_attr_is_visible,
        .attrs  = arm_spe_pmu_formats_attr,
 };
 
@@ -282,18 +304,18 @@ static u64 arm_spe_event_to_pmscr(struct perf_event *event)
        struct perf_event_attr *attr = &event->attr;
        u64 reg = 0;
 
-       reg |= ATTR_CFG_GET_FLD(attr, ts_enable) << SYS_PMSCR_EL1_TS_SHIFT;
-       reg |= ATTR_CFG_GET_FLD(attr, pa_enable) << SYS_PMSCR_EL1_PA_SHIFT;
-       reg |= ATTR_CFG_GET_FLD(attr, pct_enable) << SYS_PMSCR_EL1_PCT_SHIFT;
+       reg |= FIELD_PREP(PMSCR_EL1_TS, ATTR_CFG_GET_FLD(attr, ts_enable));
+       reg |= FIELD_PREP(PMSCR_EL1_PA, ATTR_CFG_GET_FLD(attr, pa_enable));
+       reg |= FIELD_PREP(PMSCR_EL1_PCT, ATTR_CFG_GET_FLD(attr, pct_enable));
 
        if (!attr->exclude_user)
-               reg |= BIT(SYS_PMSCR_EL1_E0SPE_SHIFT);
+               reg |= PMSCR_EL1_E0SPE;
 
        if (!attr->exclude_kernel)
-               reg |= BIT(SYS_PMSCR_EL1_E1SPE_SHIFT);
+               reg |= PMSCR_EL1_E1SPE;
 
        if (get_spe_event_has_cx(event))
-               reg |= BIT(SYS_PMSCR_EL1_CX_SHIFT);
+               reg |= PMSCR_EL1_CX;
 
        return reg;
 }
@@ -302,8 +324,7 @@ static void arm_spe_event_sanitise_period(struct perf_event *event)
 {
        struct arm_spe_pmu *spe_pmu = to_spe_pmu(event->pmu);
        u64 period = event->hw.sample_period;
-       u64 max_period = SYS_PMSIRR_EL1_INTERVAL_MASK
-                        << SYS_PMSIRR_EL1_INTERVAL_SHIFT;
+       u64 max_period = PMSIRR_EL1_INTERVAL_MASK;
 
        if (period < spe_pmu->min_period)
                period = spe_pmu->min_period;
@@ -322,7 +343,7 @@ static u64 arm_spe_event_to_pmsirr(struct perf_event *event)
 
        arm_spe_event_sanitise_period(event);
 
-       reg |= ATTR_CFG_GET_FLD(attr, jitter) << SYS_PMSIRR_EL1_RND_SHIFT;
+       reg |= FIELD_PREP(PMSIRR_EL1_RND, ATTR_CFG_GET_FLD(attr, jitter));
        reg |= event->hw.sample_period;
 
        return reg;
@@ -333,18 +354,21 @@ static u64 arm_spe_event_to_pmsfcr(struct perf_event *event)
        struct perf_event_attr *attr = &event->attr;
        u64 reg = 0;
 
-       reg |= ATTR_CFG_GET_FLD(attr, load_filter) << SYS_PMSFCR_EL1_LD_SHIFT;
-       reg |= ATTR_CFG_GET_FLD(attr, store_filter) << SYS_PMSFCR_EL1_ST_SHIFT;
-       reg |= ATTR_CFG_GET_FLD(attr, branch_filter) << SYS_PMSFCR_EL1_B_SHIFT;
+       reg |= FIELD_PREP(PMSFCR_EL1_LD, ATTR_CFG_GET_FLD(attr, load_filter));
+       reg |= FIELD_PREP(PMSFCR_EL1_ST, ATTR_CFG_GET_FLD(attr, store_filter));
+       reg |= FIELD_PREP(PMSFCR_EL1_B, ATTR_CFG_GET_FLD(attr, branch_filter));
 
        if (reg)
-               reg |= BIT(SYS_PMSFCR_EL1_FT_SHIFT);
+               reg |= PMSFCR_EL1_FT;
 
        if (ATTR_CFG_GET_FLD(attr, event_filter))
-               reg |= BIT(SYS_PMSFCR_EL1_FE_SHIFT);
+               reg |= PMSFCR_EL1_FE;
+
+       if (ATTR_CFG_GET_FLD(attr, inv_event_filter))
+               reg |= PMSFCR_EL1_FnE;
 
        if (ATTR_CFG_GET_FLD(attr, min_latency))
-               reg |= BIT(SYS_PMSFCR_EL1_FL_SHIFT);
+               reg |= PMSFCR_EL1_FL;
 
        return reg;
 }
@@ -355,11 +379,16 @@ static u64 arm_spe_event_to_pmsevfr(struct perf_event *event)
        return ATTR_CFG_GET_FLD(attr, event_filter);
 }
 
+static u64 arm_spe_event_to_pmsnevfr(struct perf_event *event)
+{
+       struct perf_event_attr *attr = &event->attr;
+       return ATTR_CFG_GET_FLD(attr, inv_event_filter);
+}
+
 static u64 arm_spe_event_to_pmslatfr(struct perf_event *event)
 {
        struct perf_event_attr *attr = &event->attr;
-       return ATTR_CFG_GET_FLD(attr, min_latency)
-              << SYS_PMSLATFR_EL1_MINLAT_SHIFT;
+       return FIELD_PREP(PMSLATFR_EL1_MINLAT, ATTR_CFG_GET_FLD(attr, min_latency));
 }
 
 static void arm_spe_pmu_pad_buf(struct perf_output_handle *handle, int len)
@@ -511,7 +540,7 @@ static void arm_spe_perf_aux_output_begin(struct perf_output_handle *handle,
        limit = buf->snapshot ? arm_spe_pmu_next_snapshot_off(handle)
                              : arm_spe_pmu_next_off(handle);
        if (limit)
-               limit |= BIT(SYS_PMBLIMITR_EL1_E_SHIFT);
+               limit |= PMBLIMITR_EL1_E;
 
        limit += (u64)buf->base;
        base = (u64)buf->base + PERF_IDX2OFF(handle->head, buf);
@@ -570,28 +599,28 @@ arm_spe_pmu_buf_get_fault_act(struct perf_output_handle *handle)
 
        /* Service required? */
        pmbsr = read_sysreg_s(SYS_PMBSR_EL1);
-       if (!(pmbsr & BIT(SYS_PMBSR_EL1_S_SHIFT)))
+       if (!FIELD_GET(PMBSR_EL1_S, pmbsr))
                return SPE_PMU_BUF_FAULT_ACT_SPURIOUS;
 
        /*
         * If we've lost data, disable profiling and also set the PARTIAL
         * flag to indicate that the last record is corrupted.
         */
-       if (pmbsr & BIT(SYS_PMBSR_EL1_DL_SHIFT))
+       if (FIELD_GET(PMBSR_EL1_DL, pmbsr))
                perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED |
                                             PERF_AUX_FLAG_PARTIAL);
 
        /* Report collisions to userspace so that it can up the period */
-       if (pmbsr & BIT(SYS_PMBSR_EL1_COLL_SHIFT))
+       if (FIELD_GET(PMBSR_EL1_COLL, pmbsr))
                perf_aux_output_flag(handle, PERF_AUX_FLAG_COLLISION);
 
        /* We only expect buffer management events */
-       switch (pmbsr & (SYS_PMBSR_EL1_EC_MASK << SYS_PMBSR_EL1_EC_SHIFT)) {
-       case SYS_PMBSR_EL1_EC_BUF:
+       switch (FIELD_GET(PMBSR_EL1_EC, pmbsr)) {
+       case PMBSR_EL1_EC_BUF:
                /* Handled below */
                break;
-       case SYS_PMBSR_EL1_EC_FAULT_S1:
-       case SYS_PMBSR_EL1_EC_FAULT_S2:
+       case PMBSR_EL1_EC_FAULT_S1:
+       case PMBSR_EL1_EC_FAULT_S2:
                err_str = "Unexpected buffer fault";
                goto out_err;
        default:
@@ -600,9 +629,8 @@ arm_spe_pmu_buf_get_fault_act(struct perf_output_handle *handle)
        }
 
        /* Buffer management event */
-       switch (pmbsr &
-               (SYS_PMBSR_EL1_BUF_BSC_MASK << SYS_PMBSR_EL1_BUF_BSC_SHIFT)) {
-       case SYS_PMBSR_EL1_BUF_BSC_FULL:
+       switch (FIELD_GET(PMBSR_EL1_BUF_BSC_MASK, pmbsr)) {
+       case PMBSR_EL1_BUF_BSC_FULL:
                ret = SPE_PMU_BUF_FAULT_ACT_OK;
                goto out_stop;
        default:
@@ -677,11 +705,13 @@ static u64 arm_spe_pmsevfr_res0(u16 pmsver)
 {
        switch (pmsver) {
        case ID_AA64DFR0_EL1_PMSVer_IMP:
-               return SYS_PMSEVFR_EL1_RES0_8_2;
+               return PMSEVFR_EL1_RES0_IMP;
        case ID_AA64DFR0_EL1_PMSVer_V1P1:
+               return PMSEVFR_EL1_RES0_V1P1;
+       case ID_AA64DFR0_EL1_PMSVer_V1P2:
        /* Return the highest version we support in default */
        default:
-               return SYS_PMSEVFR_EL1_RES0_8_3;
+               return PMSEVFR_EL1_RES0_V1P2;
        }
 }
 
@@ -703,6 +733,9 @@ static int arm_spe_pmu_event_init(struct perf_event *event)
        if (arm_spe_event_to_pmsevfr(event) & arm_spe_pmsevfr_res0(spe_pmu->pmsver))
                return -EOPNOTSUPP;
 
+       if (arm_spe_event_to_pmsnevfr(event) & arm_spe_pmsevfr_res0(spe_pmu->pmsver))
+               return -EOPNOTSUPP;
+
        if (attr->exclude_idle)
                return -EOPNOTSUPP;
 
@@ -717,23 +750,26 @@ static int arm_spe_pmu_event_init(struct perf_event *event)
                return -EINVAL;
 
        reg = arm_spe_event_to_pmsfcr(event);
-       if ((reg & BIT(SYS_PMSFCR_EL1_FE_SHIFT)) &&
+       if ((FIELD_GET(PMSFCR_EL1_FE, reg)) &&
            !(spe_pmu->features & SPE_PMU_FEAT_FILT_EVT))
                return -EOPNOTSUPP;
 
-       if ((reg & BIT(SYS_PMSFCR_EL1_FT_SHIFT)) &&
+       if ((FIELD_GET(PMSFCR_EL1_FnE, reg)) &&
+           !(spe_pmu->features & SPE_PMU_FEAT_INV_FILT_EVT))
+               return -EOPNOTSUPP;
+
+       if ((FIELD_GET(PMSFCR_EL1_FT, reg)) &&
            !(spe_pmu->features & SPE_PMU_FEAT_FILT_TYP))
                return -EOPNOTSUPP;
 
-       if ((reg & BIT(SYS_PMSFCR_EL1_FL_SHIFT)) &&
+       if ((FIELD_GET(PMSFCR_EL1_FL, reg)) &&
            !(spe_pmu->features & SPE_PMU_FEAT_FILT_LAT))
                return -EOPNOTSUPP;
 
        set_spe_event_has_cx(event);
        reg = arm_spe_event_to_pmscr(event);
        if (!perfmon_capable() &&
-           (reg & (BIT(SYS_PMSCR_EL1_PA_SHIFT) |
-                   BIT(SYS_PMSCR_EL1_PCT_SHIFT))))
+           (reg & (PMSCR_EL1_PA | PMSCR_EL1_PCT)))
                return -EACCES;
 
        return 0;
@@ -757,6 +793,11 @@ static void arm_spe_pmu_start(struct perf_event *event, int flags)
        reg = arm_spe_event_to_pmsevfr(event);
        write_sysreg_s(reg, SYS_PMSEVFR_EL1);
 
+       if (spe_pmu->features & SPE_PMU_FEAT_INV_FILT_EVT) {
+               reg = arm_spe_event_to_pmsnevfr(event);
+               write_sysreg_s(reg, SYS_PMSNEVFR_EL1);
+       }
+
        reg = arm_spe_event_to_pmslatfr(event);
        write_sysreg_s(reg, SYS_PMSLATFR_EL1);
 
@@ -971,14 +1012,14 @@ static void __arm_spe_pmu_dev_probe(void *info)
 
        /* Read PMBIDR first to determine whether or not we have access */
        reg = read_sysreg_s(SYS_PMBIDR_EL1);
-       if (reg & BIT(SYS_PMBIDR_EL1_P_SHIFT)) {
+       if (FIELD_GET(PMBIDR_EL1_P, reg)) {
                dev_err(dev,
                        "profiling buffer owned by higher exception level\n");
                return;
        }
 
        /* Minimum alignment. If it's out-of-range, then fail the probe */
-       fld = reg >> SYS_PMBIDR_EL1_ALIGN_SHIFT & SYS_PMBIDR_EL1_ALIGN_MASK;
+       fld = FIELD_GET(PMBIDR_EL1_ALIGN, reg);
        spe_pmu->align = 1 << fld;
        if (spe_pmu->align > SZ_2K) {
                dev_err(dev, "unsupported PMBIDR.Align [%d] on CPU %d\n",
@@ -988,58 +1029,61 @@ static void __arm_spe_pmu_dev_probe(void *info)
 
        /* It's now safe to read PMSIDR and figure out what we've got */
        reg = read_sysreg_s(SYS_PMSIDR_EL1);
-       if (reg & BIT(SYS_PMSIDR_EL1_FE_SHIFT))
+       if (FIELD_GET(PMSIDR_EL1_FE, reg))
                spe_pmu->features |= SPE_PMU_FEAT_FILT_EVT;
 
-       if (reg & BIT(SYS_PMSIDR_EL1_FT_SHIFT))
+       if (FIELD_GET(PMSIDR_EL1_FnE, reg))
+               spe_pmu->features |= SPE_PMU_FEAT_INV_FILT_EVT;
+
+       if (FIELD_GET(PMSIDR_EL1_FT, reg))
                spe_pmu->features |= SPE_PMU_FEAT_FILT_TYP;
 
-       if (reg & BIT(SYS_PMSIDR_EL1_FL_SHIFT))
+       if (FIELD_GET(PMSIDR_EL1_FL, reg))
                spe_pmu->features |= SPE_PMU_FEAT_FILT_LAT;
 
-       if (reg & BIT(SYS_PMSIDR_EL1_ARCHINST_SHIFT))
+       if (FIELD_GET(PMSIDR_EL1_ARCHINST, reg))
                spe_pmu->features |= SPE_PMU_FEAT_ARCH_INST;
 
-       if (reg & BIT(SYS_PMSIDR_EL1_LDS_SHIFT))
+       if (FIELD_GET(PMSIDR_EL1_LDS, reg))
                spe_pmu->features |= SPE_PMU_FEAT_LDS;
 
-       if (reg & BIT(SYS_PMSIDR_EL1_ERND_SHIFT))
+       if (FIELD_GET(PMSIDR_EL1_ERND, reg))
                spe_pmu->features |= SPE_PMU_FEAT_ERND;
 
        /* This field has a spaced out encoding, so just use a look-up */
-       fld = reg >> SYS_PMSIDR_EL1_INTERVAL_SHIFT & SYS_PMSIDR_EL1_INTERVAL_MASK;
+       fld = FIELD_GET(PMSIDR_EL1_INTERVAL, reg);
        switch (fld) {
-       case 0:
+       case PMSIDR_EL1_INTERVAL_256:
                spe_pmu->min_period = 256;
                break;
-       case 2:
+       case PMSIDR_EL1_INTERVAL_512:
                spe_pmu->min_period = 512;
                break;
-       case 3:
+       case PMSIDR_EL1_INTERVAL_768:
                spe_pmu->min_period = 768;
                break;
-       case 4:
+       case PMSIDR_EL1_INTERVAL_1024:
                spe_pmu->min_period = 1024;
                break;
-       case 5:
+       case PMSIDR_EL1_INTERVAL_1536:
                spe_pmu->min_period = 1536;
                break;
-       case 6:
+       case PMSIDR_EL1_INTERVAL_2048:
                spe_pmu->min_period = 2048;
                break;
-       case 7:
+       case PMSIDR_EL1_INTERVAL_3072:
                spe_pmu->min_period = 3072;
                break;
        default:
                dev_warn(dev, "unknown PMSIDR_EL1.Interval [%d]; assuming 8\n",
                         fld);
                fallthrough;
-       case 8:
+       case PMSIDR_EL1_INTERVAL_4096:
                spe_pmu->min_period = 4096;
        }
 
        /* Maximum record size. If it's out-of-range, then fail the probe */
-       fld = reg >> SYS_PMSIDR_EL1_MAXSIZE_SHIFT & SYS_PMSIDR_EL1_MAXSIZE_MASK;
+       fld = FIELD_GET(PMSIDR_EL1_MAXSIZE, reg);
        spe_pmu->max_record_sz = 1 << fld;
        if (spe_pmu->max_record_sz > SZ_2K || spe_pmu->max_record_sz < 16) {
                dev_err(dev, "unsupported PMSIDR_EL1.MaxSize [%d] on CPU %d\n",
@@ -1047,22 +1091,22 @@ static void __arm_spe_pmu_dev_probe(void *info)
                return;
        }
 
-       fld = reg >> SYS_PMSIDR_EL1_COUNTSIZE_SHIFT & SYS_PMSIDR_EL1_COUNTSIZE_MASK;
+       fld = FIELD_GET(PMSIDR_EL1_COUNTSIZE, reg);
        switch (fld) {
        default:
                dev_warn(dev, "unknown PMSIDR_EL1.CountSize [%d]; assuming 2\n",
                         fld);
                fallthrough;
-       case 2:
+       case PMSIDR_EL1_COUNTSIZE_12_BIT_SAT:
                spe_pmu->counter_sz = 12;
                break;
-       case 3:
+       case PMSIDR_EL1_COUNTSIZE_16_BIT_SAT:
                spe_pmu->counter_sz = 16;
        }
 
        dev_info(dev,
-                "probed for CPUs %*pbl [max_record_sz %u, align %u, features 0x%llx]\n",
-                cpumask_pr_args(&spe_pmu->supported_cpus),
+                "probed SPEv1.%d for CPUs %*pbl [max_record_sz %u, align %u, features 0x%llx]\n",
+                spe_pmu->pmsver - 1, cpumask_pr_args(&spe_pmu->supported_cpus),
                 spe_pmu->max_record_sz, spe_pmu->align, spe_pmu->features);
 
        spe_pmu->features |= SPE_PMU_FEAT_DEV_PROBED;
index 8e058e0..5222ba1 100644 (file)
@@ -97,7 +97,6 @@ struct ddr_pmu {
        struct  hlist_node node;
        struct  device *dev;
        struct perf_event *events[NUM_COUNTERS];
-       int active_events;
        enum cpuhp_state cpuhp_state;
        const struct fsl_ddr_devtype_data *devtype_data;
        int irq;
@@ -530,7 +529,6 @@ static int ddr_perf_event_add(struct perf_event *event, int flags)
        }
 
        pmu->events[counter] = event;
-       pmu->active_events++;
        hwc->idx = counter;
 
        hwc->state |= PERF_HES_STOPPED;
@@ -562,7 +560,6 @@ static void ddr_perf_event_del(struct perf_event *event, int flags)
        ddr_perf_event_stop(event, PERF_EF_UPDATE);
 
        ddr_perf_free_counter(pmu, counter);
-       pmu->active_events--;
        hwc->idx = -1;
 }
 
index a9bb73f..4c67d57 100644 (file)
@@ -316,21 +316,7 @@ static int hisi_cpa_pmu_probe(struct platform_device *pdev)
        if (!name)
                return -ENOMEM;
 
-       cpa_pmu->pmu = (struct pmu) {
-               .name           = name,
-               .module         = THIS_MODULE,
-               .task_ctx_nr    = perf_invalid_context,
-               .event_init     = hisi_uncore_pmu_event_init,
-               .pmu_enable     = hisi_uncore_pmu_enable,
-               .pmu_disable    = hisi_uncore_pmu_disable,
-               .add            = hisi_uncore_pmu_add,
-               .del            = hisi_uncore_pmu_del,
-               .start          = hisi_uncore_pmu_start,
-               .stop           = hisi_uncore_pmu_stop,
-               .read           = hisi_uncore_pmu_read,
-               .attr_groups    = cpa_pmu->pmu_events.attr_groups,
-               .capabilities   = PERF_PMU_CAP_NO_EXCLUDE,
-       };
+       hisi_pmu_init(cpa_pmu, name, THIS_MODULE);
 
        /* Power Management should be disabled before using CPA PMU. */
        hisi_cpa_pmu_disable_pm(cpa_pmu);
index 50d0c0a..8c3ffcb 100644 (file)
@@ -516,7 +516,7 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev)
                                      "hisi_sccl%u_ddrc%u", ddrc_pmu->sccl_id,
                                      ddrc_pmu->index_id);
 
-       hisi_pmu_init(&ddrc_pmu->pmu, name, ddrc_pmu->pmu_events.attr_groups, THIS_MODULE);
+       hisi_pmu_init(ddrc_pmu, name, THIS_MODULE);
 
        ret = perf_pmu_register(&ddrc_pmu->pmu, name, -1);
        if (ret) {
index 13017b3..806698b 100644 (file)
@@ -519,7 +519,7 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev)
 
        name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_hha%u",
                              hha_pmu->sccl_id, hha_pmu->index_id);
-       hisi_pmu_init(&hha_pmu->pmu, name, hha_pmu->pmu_events.attr_groups, THIS_MODULE);
+       hisi_pmu_init(hha_pmu, name, THIS_MODULE);
 
        ret = perf_pmu_register(&hha_pmu->pmu, name, -1);
        if (ret) {
index 2995f36..5b2c35f 100644 (file)
@@ -557,7 +557,7 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev)
         */
        name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_l3c%u",
                              l3c_pmu->sccl_id, l3c_pmu->ccl_id);
-       hisi_pmu_init(&l3c_pmu->pmu, name, l3c_pmu->pmu_events.attr_groups, THIS_MODULE);
+       hisi_pmu_init(l3c_pmu, name, THIS_MODULE);
 
        ret = perf_pmu_register(&l3c_pmu->pmu, name, -1);
        if (ret) {
index 47d3cc9..afe3419 100644 (file)
@@ -412,7 +412,7 @@ static int hisi_pa_pmu_probe(struct platform_device *pdev)
                return ret;
        }
 
-       hisi_pmu_init(&pa_pmu->pmu, name, pa_pmu->pmu_events.attr_groups, THIS_MODULE);
+       hisi_pmu_init(pa_pmu, name, THIS_MODULE);
        ret = perf_pmu_register(&pa_pmu->pmu, name, -1);
        if (ret) {
                dev_err(pa_pmu->dev, "PMU register failed, ret = %d\n", ret);
index fbc8a93..f1b0f5e 100644 (file)
@@ -531,9 +531,11 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
 }
 EXPORT_SYMBOL_GPL(hisi_uncore_pmu_offline_cpu);
 
-void hisi_pmu_init(struct pmu *pmu, const char *name,
-               const struct attribute_group **attr_groups, struct module *module)
+void hisi_pmu_init(struct hisi_pmu *hisi_pmu, const char *name,
+                  struct module *module)
 {
+       struct pmu *pmu = &hisi_pmu->pmu;
+
        pmu->name               = name;
        pmu->module             = module;
        pmu->task_ctx_nr        = perf_invalid_context;
@@ -545,7 +547,8 @@ void hisi_pmu_init(struct pmu *pmu, const char *name,
        pmu->start              = hisi_uncore_pmu_start;
        pmu->stop               = hisi_uncore_pmu_stop;
        pmu->read               = hisi_uncore_pmu_read;
-       pmu->attr_groups        = attr_groups;
+       pmu->attr_groups        = hisi_pmu->pmu_events.attr_groups;
+       pmu->capabilities       = PERF_PMU_CAP_NO_EXCLUDE;
 }
 EXPORT_SYMBOL_GPL(hisi_pmu_init);
 
index b59de33..f8e3cc6 100644 (file)
@@ -121,6 +121,6 @@ ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev,
 int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu,
                             struct platform_device *pdev);
 
-void hisi_pmu_init(struct pmu *pmu, const char *name,
-               const struct attribute_group **attr_groups, struct module *module);
+void hisi_pmu_init(struct hisi_pmu *hisi_pmu, const char *name,
+                  struct module *module);
 #endif /* __HISI_UNCORE_PMU_H__ */
index b9c79f1..1e35443 100644 (file)
@@ -445,7 +445,7 @@ static int hisi_sllc_pmu_probe(struct platform_device *pdev)
                return ret;
        }
 
-       hisi_pmu_init(&sllc_pmu->pmu, name, sllc_pmu->pmu_events.attr_groups, THIS_MODULE);
+       hisi_pmu_init(sllc_pmu, name, THIS_MODULE);
 
        ret = perf_pmu_register(&sllc_pmu->pmu, name, -1);
        if (ret) {
index 665b382..b94a5f6 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/of_device.h>
 #include <linux/perf_event.h>
 #include <linux/hrtimer.h>
+#include <linux/acpi.h>
 
 /* Performance Counters Operating Mode Control Registers */
 #define DDRC_PERF_CNT_OP_MODE_CTRL     0x8020
@@ -717,10 +718,19 @@ static const struct of_device_id cn10k_ddr_pmu_of_match[] = {
 MODULE_DEVICE_TABLE(of, cn10k_ddr_pmu_of_match);
 #endif
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id cn10k_ddr_pmu_acpi_match[] = {
+       {"MRVL000A", 0},
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, cn10k_ddr_pmu_acpi_match);
+#endif
+
 static struct platform_driver cn10k_ddr_pmu_driver = {
        .driver = {
                .name   = "cn10k-ddr-pmu",
                .of_match_table = of_match_ptr(cn10k_ddr_pmu_of_match),
+               .acpi_match_table  = ACPI_PTR(cn10k_ddr_pmu_acpi_match),
                .suppress_bind_attrs = true,
        },
        .probe          = cn10k_ddr_perf_probe,
index a1166af..3972197 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/cpuhotplug.h>
 #include <linux/perf_event.h>
 #include <linux/platform_device.h>
+#include <linux/acpi.h>
 
 #define TAD_PFC_OFFSET         0x800
 #define TAD_PFC(counter)       (TAD_PFC_OFFSET | (counter << 3))
@@ -254,7 +255,7 @@ static const struct attribute_group *tad_pmu_attr_groups[] = {
 
 static int tad_pmu_probe(struct platform_device *pdev)
 {
-       struct device_node *node = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
        struct tad_region *regions;
        struct tad_pmu *tad_pmu;
        struct resource *res;
@@ -276,21 +277,21 @@ static int tad_pmu_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       ret = of_property_read_u32(node, "marvell,tad-page-size",
-                                  &tad_page_size);
+       ret = device_property_read_u32(dev, "marvell,tad-page-size",
+                                      &tad_page_size);
        if (ret) {
                dev_err(&pdev->dev, "Can't find tad-page-size property\n");
                return ret;
        }
 
-       ret = of_property_read_u32(node, "marvell,tad-pmu-page-size",
-                                  &tad_pmu_page_size);
+       ret = device_property_read_u32(dev, "marvell,tad-pmu-page-size",
+                                      &tad_pmu_page_size);
        if (ret) {
                dev_err(&pdev->dev, "Can't find tad-pmu-page-size property\n");
                return ret;
        }
 
-       ret = of_property_read_u32(node, "marvell,tad-cnt", &tad_cnt);
+       ret = device_property_read_u32(dev, "marvell,tad-cnt", &tad_cnt);
        if (ret) {
                dev_err(&pdev->dev, "Can't find tad-cnt property\n");
                return ret;
@@ -369,10 +370,19 @@ static const struct of_device_id tad_pmu_of_match[] = {
 };
 #endif
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id tad_pmu_acpi_match[] = {
+       {"MRVL000B", 0},
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, tad_pmu_acpi_match);
+#endif
+
 static struct platform_driver tad_pmu_driver = {
        .driver         = {
                .name   = "cn10k_tad_pmu",
                .of_match_table = of_match_ptr(tad_pmu_of_match),
+               .acpi_match_table = ACPI_PTR(tad_pmu_acpi_match),
                .suppress_bind_attrs = true,
        },
        .probe          = tad_pmu_probe,
index 898b345..b831264 100644 (file)
 # define __assume_aligned(a, ...)
 #endif
 
-/*
- *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-cold-function-attribute
- *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Label-Attributes.html#index-cold-label-attribute
- */
-#define __cold                          __attribute__((__cold__))
-
 /*
  * Note the long name.
  *
index 7c1afe0..aab34e3 100644 (file)
@@ -79,6 +79,33 @@ static inline void __chk_io_ptr(const volatile void __iomem *ptr) { }
 /* Attributes */
 #include <linux/compiler_attributes.h>
 
+#if CONFIG_FUNCTION_ALIGNMENT > 0
+#define __function_aligned             __aligned(CONFIG_FUNCTION_ALIGNMENT)
+#else
+#define __function_aligned
+#endif
+
+/*
+ *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-cold-function-attribute
+ *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Label-Attributes.html#index-cold-label-attribute
+ *
+ * When -falign-functions=N is in use, we must avoid the cold attribute as
+ * contemporary versions of GCC drop the alignment for cold functions. Worse,
+ * GCC can implicitly mark callees of cold functions as cold themselves, so
+ * it's not sufficient to add __function_aligned here as that will not ensure
+ * that callees are correctly aligned.
+ *
+ * See:
+ *
+ *   https://lore.kernel.org/lkml/Y77%2FqVgvaJidFpYt@FVFF77S0Q05N
+ *   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88345#c9
+ */
+#if !defined(CONFIG_CC_IS_GCC) || (CONFIG_FUNCTION_ALIGNMENT == 0)
+#define __cold                         __attribute__((__cold__))
+#else
+#define __cold
+#endif
+
 /* Builtins */
 
 /*
index 99f1146..366c730 100644 (file)
@@ -39,6 +39,7 @@ static inline void ftrace_boot_snapshot(void) { }
 
 struct ftrace_ops;
 struct ftrace_regs;
+struct dyn_ftrace;
 
 #ifdef CONFIG_FUNCTION_TRACER
 /*
@@ -57,6 +58,9 @@ void arch_ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip);
 void arch_ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
                               struct ftrace_ops *op, struct ftrace_regs *fregs);
 #endif
+extern const struct ftrace_ops ftrace_nop_ops;
+extern const struct ftrace_ops ftrace_list_ops;
+struct ftrace_ops *ftrace_find_unique_ops(struct dyn_ftrace *rec);
 #endif /* CONFIG_FUNCTION_TRACER */
 
 /* Main tracing buffer and events set up */
@@ -391,8 +395,6 @@ struct ftrace_func_entry {
        unsigned long direct; /* for direct lookup only */
 };
 
-struct dyn_ftrace;
-
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 extern int ftrace_direct_func_count;
 int register_ftrace_direct(unsigned long ip, unsigned long addr);
@@ -563,6 +565,8 @@ bool is_ftrace_trampoline(unsigned long addr);
  *  IPMODIFY - the record allows for the IP address to be changed.
  *  DISABLED - the record is not ready to be touched yet
  *  DIRECT   - there is a direct function to call
+ *  CALL_OPS - the record can use callsite-specific ops
+ *  CALL_OPS_EN - the function is set up to use callsite-specific ops
  *
  * When a new ftrace_ops is registered and wants a function to save
  * pt_regs, the rec->flags REGS is set. When the function has been
@@ -580,9 +584,11 @@ enum {
        FTRACE_FL_DISABLED      = (1UL << 25),
        FTRACE_FL_DIRECT        = (1UL << 24),
        FTRACE_FL_DIRECT_EN     = (1UL << 23),
+       FTRACE_FL_CALL_OPS      = (1UL << 22),
+       FTRACE_FL_CALL_OPS_EN   = (1UL << 21),
 };
 
-#define FTRACE_REF_MAX_SHIFT   23
+#define FTRACE_REF_MAX_SHIFT   21
 #define FTRACE_REF_MAX         ((1UL << FTRACE_REF_MAX_SHIFT) - 1)
 
 #define ftrace_rec_count(rec)  ((rec)->flags & FTRACE_REF_MAX)
@@ -820,7 +826,8 @@ static inline int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
  */
 extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);
 
-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+#if defined(CONFIG_DYNAMIC_FTRACE_WITH_REGS) || \
+       defined(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS)
 /**
  * ftrace_modify_call - convert from one addr to another (no nop)
  * @rec: the call site record (e.g. mcount/fentry)
@@ -833,6 +840,9 @@ extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);
  * what we expect it to be, and then on success of the compare,
  * it should write to the location.
  *
+ * When using call ops, this is called when the associated ops change, even
+ * when (addr == old_addr).
+ *
  * The code segment at @rec->ip should be a caller to @old_addr
  *
  * Return must be:
index 4c6a8fa..68de6f4 100644 (file)
@@ -434,6 +434,7 @@ typedef struct elf64_shdr {
 #define NT_ARM_PAC_ENABLED_KEYS        0x40a   /* arm64 ptr auth enabled keys (prctl()) */
 #define NT_ARM_SSVE    0x40b           /* ARM Streaming SVE registers */
 #define NT_ARM_ZA      0x40c           /* ARM SME ZA registers */
+#define NT_ARM_ZT      0x40d           /* ARM SME ZT registers */
 #define NT_ARC_V2      0x600           /* ARCv2 accumulator/extra registers */
 #define NT_VMCOREDD    0x700           /* Vmcore Device Dump Note */
 #define NT_MIPS_DSP    0x800           /* MIPS DSP ASE registers */
index ccb7f5d..3767543 100644 (file)
@@ -374,6 +374,7 @@ enum perf_event_read_format {
 #define PERF_ATTR_SIZE_VER5    112     /* add: aux_watermark */
 #define PERF_ATTR_SIZE_VER6    120     /* add: aux_sample_size */
 #define PERF_ATTR_SIZE_VER7    128     /* add: sig_data */
+#define PERF_ATTR_SIZE_VER8    136     /* add: config3 */
 
 /*
  * Hardware event_id to monitor via a performance monitoring event:
@@ -515,6 +516,8 @@ struct perf_event_attr {
         * truncated accordingly on 32 bit architectures.
         */
        __u64   sig_data;
+
+       __u64   config3; /* extension of config2 */
 };
 
 /*
index 15dc2ec..c8e0375 100644 (file)
@@ -1898,7 +1898,14 @@ bool thread_group_exited(struct pid *pid)
 }
 EXPORT_SYMBOL(thread_group_exited);
 
-__weak void abort(void)
+/*
+ * This needs to be __function_aligned as GCC implicitly makes any
+ * implementation of abort() cold and drops alignment specified by
+ * -falign-functions=N.
+ *
+ * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88345#c11
+ */
+__weak __function_aligned void abort(void)
 {
        BUG();
 
index 1975452..5df427a 100644 (file)
@@ -42,6 +42,9 @@ config HAVE_DYNAMIC_FTRACE_WITH_REGS
 config HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
        bool
 
+config HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS
+       bool
+
 config HAVE_DYNAMIC_FTRACE_WITH_ARGS
        bool
        help
@@ -257,6 +260,10 @@ config DYNAMIC_FTRACE_WITH_DIRECT_CALLS
        depends on DYNAMIC_FTRACE_WITH_REGS
        depends on HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 
+config DYNAMIC_FTRACE_WITH_CALL_OPS
+       def_bool y
+       depends on HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS
+
 config DYNAMIC_FTRACE_WITH_ARGS
        def_bool y
        depends on DYNAMIC_FTRACE
index 442438b..e634b80 100644 (file)
@@ -125,6 +125,33 @@ struct ftrace_ops global_ops;
 void ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
                          struct ftrace_ops *op, struct ftrace_regs *fregs);
 
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
+/*
+ * Stub used to invoke the list ops without requiring a separate trampoline.
+ */
+const struct ftrace_ops ftrace_list_ops = {
+       .func   = ftrace_ops_list_func,
+       .flags  = FTRACE_OPS_FL_STUB,
+};
+
+static void ftrace_ops_nop_func(unsigned long ip, unsigned long parent_ip,
+                               struct ftrace_ops *op,
+                               struct ftrace_regs *fregs)
+{
+       /* do nothing */
+}
+
+/*
+ * Stub used when a call site is disabled. May be called transiently by threads
+ * which have made it into ftrace_caller but haven't yet recovered the ops at
+ * the point the call site is disabled.
+ */
+const struct ftrace_ops ftrace_nop_ops = {
+       .func   = ftrace_ops_nop_func,
+       .flags  = FTRACE_OPS_FL_STUB,
+};
+#endif
+
 static inline void ftrace_ops_init(struct ftrace_ops *ops)
 {
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -1814,6 +1841,18 @@ static bool __ftrace_hash_rec_update(struct ftrace_ops *ops,
                         * if rec count is zero.
                         */
                }
+
+               /*
+                * If the rec has a single associated ops, and ops->func can be
+                * called directly, allow the call site to call via the ops.
+                */
+               if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS) &&
+                   ftrace_rec_count(rec) == 1 &&
+                   ftrace_ops_get_func(ops) == ops->func)
+                       rec->flags |= FTRACE_FL_CALL_OPS;
+               else
+                       rec->flags &= ~FTRACE_FL_CALL_OPS;
+
                count++;
 
                /* Must match FTRACE_UPDATE_CALLS in ftrace_modify_all_code() */
@@ -2108,8 +2147,9 @@ void ftrace_bug(int failed, struct dyn_ftrace *rec)
                struct ftrace_ops *ops = NULL;
 
                pr_info("ftrace record flags: %lx\n", rec->flags);
-               pr_cont(" (%ld)%s", ftrace_rec_count(rec),
-                       rec->flags & FTRACE_FL_REGS ? " R" : "  ");
+               pr_cont(" (%ld)%s%s", ftrace_rec_count(rec),
+                       rec->flags & FTRACE_FL_REGS ? " R" : "  ",
+                       rec->flags & FTRACE_FL_CALL_OPS ? " O" : "  ");
                if (rec->flags & FTRACE_FL_TRAMP_EN) {
                        ops = ftrace_find_tramp_ops_any(rec);
                        if (ops) {
@@ -2177,6 +2217,7 @@ static int ftrace_check_record(struct dyn_ftrace *rec, bool enable, bool update)
                 * want the direct enabled (it will be done via the
                 * direct helper). But if DIRECT_EN is set, and
                 * the count is not one, we need to clear it.
+                *
                 */
                if (ftrace_rec_count(rec) == 1) {
                        if (!(rec->flags & FTRACE_FL_DIRECT) !=
@@ -2185,6 +2226,19 @@ static int ftrace_check_record(struct dyn_ftrace *rec, bool enable, bool update)
                } else if (rec->flags & FTRACE_FL_DIRECT_EN) {
                        flag |= FTRACE_FL_DIRECT;
                }
+
+               /*
+                * Ops calls are special, as count matters.
+                * As with direct calls, they must only be enabled when count
+                * is one, otherwise they'll be handled via the list ops.
+                */
+               if (ftrace_rec_count(rec) == 1) {
+                       if (!(rec->flags & FTRACE_FL_CALL_OPS) !=
+                           !(rec->flags & FTRACE_FL_CALL_OPS_EN))
+                               flag |= FTRACE_FL_CALL_OPS;
+               } else if (rec->flags & FTRACE_FL_CALL_OPS_EN) {
+                       flag |= FTRACE_FL_CALL_OPS;
+               }
        }
 
        /* If the state of this record hasn't changed, then do nothing */
@@ -2229,6 +2283,21 @@ static int ftrace_check_record(struct dyn_ftrace *rec, bool enable, bool update)
                                        rec->flags &= ~FTRACE_FL_DIRECT_EN;
                                }
                        }
+
+                       if (flag & FTRACE_FL_CALL_OPS) {
+                               if (ftrace_rec_count(rec) == 1) {
+                                       if (rec->flags & FTRACE_FL_CALL_OPS)
+                                               rec->flags |= FTRACE_FL_CALL_OPS_EN;
+                                       else
+                                               rec->flags &= ~FTRACE_FL_CALL_OPS_EN;
+                               } else {
+                                       /*
+                                        * Can only call directly if there's
+                                        * only one set of associated ops.
+                                        */
+                                       rec->flags &= ~FTRACE_FL_CALL_OPS_EN;
+                               }
+                       }
                }
 
                /*
@@ -2258,7 +2327,8 @@ static int ftrace_check_record(struct dyn_ftrace *rec, bool enable, bool update)
                         * and REGS states. The _EN flags must be disabled though.
                         */
                        rec->flags &= ~(FTRACE_FL_ENABLED | FTRACE_FL_TRAMP_EN |
-                                       FTRACE_FL_REGS_EN | FTRACE_FL_DIRECT_EN);
+                                       FTRACE_FL_REGS_EN | FTRACE_FL_DIRECT_EN |
+                                       FTRACE_FL_CALL_OPS_EN);
        }
 
        ftrace_bug_type = FTRACE_BUG_NOP;
@@ -2431,6 +2501,25 @@ ftrace_find_tramp_ops_new(struct dyn_ftrace *rec)
        return NULL;
 }
 
+struct ftrace_ops *
+ftrace_find_unique_ops(struct dyn_ftrace *rec)
+{
+       struct ftrace_ops *op, *found = NULL;
+       unsigned long ip = rec->ip;
+
+       do_for_each_ftrace_op(op, ftrace_ops_list) {
+
+               if (hash_contains_ip(ip, op->func_hash)) {
+                       if (found)
+                               return NULL;
+                       found = op;
+               }
+
+       } while_for_each_ftrace_op(op);
+
+       return found;
+}
+
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 /* Protected by rcu_tasks for reading, and direct_mutex for writing */
 static struct ftrace_hash *direct_functions = EMPTY_HASH;
@@ -3780,11 +3869,12 @@ static int t_show(struct seq_file *m, void *v)
        if (iter->flags & FTRACE_ITER_ENABLED) {
                struct ftrace_ops *ops;
 
-               seq_printf(m, " (%ld)%s%s%s",
+               seq_printf(m, " (%ld)%s%s%s%s",
                           ftrace_rec_count(rec),
                           rec->flags & FTRACE_FL_REGS ? " R" : "  ",
                           rec->flags & FTRACE_FL_IPMODIFY ? " I" : "  ",
-                          rec->flags & FTRACE_FL_DIRECT ? " D" : "  ");
+                          rec->flags & FTRACE_FL_DIRECT ? " D" : "  ",
+                          rec->flags & FTRACE_FL_CALL_OPS ? " O" : "  ");
                if (rec->flags & FTRACE_FL_TRAMP_EN) {
                        ops = ftrace_find_tramp_ops_any(rec);
                        if (ops) {
@@ -3800,6 +3890,15 @@ static int t_show(struct seq_file *m, void *v)
                } else {
                        add_trampoline_func(m, NULL, rec);
                }
+               if (rec->flags & FTRACE_FL_CALL_OPS_EN) {
+                       ops = ftrace_find_unique_ops(rec);
+                       if (ops) {
+                               seq_printf(m, "\tops: %pS (%pS)",
+                                          ops, ops->func);
+                       } else {
+                               seq_puts(m, "\tops: ERROR!");
+                       }
+               }
                if (rec->flags & FTRACE_FL_DIRECT) {
                        unsigned long direct;
 
index 9f255bc..93333a9 100644 (file)
@@ -50,6 +50,78 @@ static void sme_sigill(void)
        asm volatile(".inst 0x04bf5800" : : : "x0");
 }
 
+static void sme2_sigill(void)
+{
+       /* SMSTART ZA */
+       asm volatile("msr S0_3_C4_C5_3, xzr" : : : );
+
+       /* ZERO ZT0 */
+       asm volatile(".inst 0xc0480001" : : : );
+
+       /* SMSTOP */
+       asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
+}
+
+static void sme2p1_sigill(void)
+{
+       /* SMSTART SM */
+       asm volatile("msr S0_3_C4_C3_3, xzr" : : : );
+
+       /* BFCLAMP { Z0.H - Z1.H }, Z0.H, Z0.H */
+       asm volatile(".inst 0xc120C000" : : : );
+
+       /* SMSTOP */
+       asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
+}
+
+static void smei16i32_sigill(void)
+{
+       /* SMSTART */
+       asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
+
+       /* SMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */
+       asm volatile(".inst 0xa0800000" : : : );
+
+       /* SMSTOP */
+       asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
+}
+
+static void smebi32i32_sigill(void)
+{
+       /* SMSTART */
+       asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
+
+       /* BMOPA ZA0.S, P0/M, P0/M, Z0.B, Z0.B */
+       asm volatile(".inst 0x80800008" : : : );
+
+       /* SMSTOP */
+       asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
+}
+
+static void smeb16b16_sigill(void)
+{
+       /* SMSTART */
+       asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
+
+       /* BFADD ZA.H[W0, 0], {Z0.H-Z1.H} */
+       asm volatile(".inst 0xC1E41C00" : : : );
+
+       /* SMSTOP */
+       asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
+}
+
+static void smef16f16_sigill(void)
+{
+       /* SMSTART */
+       asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
+
+       /* FADD ZA.H[W0, 0], { Z0.H-Z1.H } */
+       asm volatile(".inst 0xc1a41C00" : : : );
+
+       /* SMSTOP */
+       asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
+}
+
 static void sve_sigill(void)
 {
        /* RDVL x0, #0 */
@@ -158,6 +230,49 @@ static const struct hwcap_data {
                .sigill_fn = sme_sigill,
                .sigill_reliable = true,
        },
+       {
+               .name = "SME2",
+               .at_hwcap = AT_HWCAP2,
+               .hwcap_bit = HWCAP2_SME2,
+               .cpuinfo = "sme2",
+               .sigill_fn = sme2_sigill,
+               .sigill_reliable = true,
+       },
+       {
+               .name = "SME 2.1",
+               .at_hwcap = AT_HWCAP2,
+               .hwcap_bit = HWCAP2_SME2P1,
+               .cpuinfo = "sme2p1",
+               .sigill_fn = sme2p1_sigill,
+       },
+       {
+               .name = "SME I16I32",
+               .at_hwcap = AT_HWCAP2,
+               .hwcap_bit = HWCAP2_SME_I16I32,
+               .cpuinfo = "smei16i32",
+               .sigill_fn = smei16i32_sigill,
+       },
+       {
+               .name = "SME BI32I32",
+               .at_hwcap = AT_HWCAP2,
+               .hwcap_bit = HWCAP2_SME_BI32I32,
+               .cpuinfo = "smebi32i32",
+               .sigill_fn = smebi32i32_sigill,
+       },
+       {
+               .name = "SME B16B16",
+               .at_hwcap = AT_HWCAP2,
+               .hwcap_bit = HWCAP2_SME_B16B16,
+               .cpuinfo = "smeb16b16",
+               .sigill_fn = smeb16b16_sigill,
+       },
+       {
+               .name = "SME F16F16",
+               .at_hwcap = AT_HWCAP2,
+               .hwcap_bit = HWCAP2_SME_F16F16,
+               .cpuinfo = "smef16f16",
+               .sigill_fn = smef16f16_sigill,
+       },
        {
                .name = "SVE",
                .at_hwcap = AT_HWCAP,
index acd5e9f..df3230f 100644 (file)
@@ -23,6 +23,9 @@
 
 .arch_extension sve
 
+#define ID_AA64SMFR0_EL1_SMEver_SHIFT           56
+#define ID_AA64SMFR0_EL1_SMEver_WIDTH           4
+
 /*
  * LDR (vector to ZA array):
  *     LDR ZA[\nw, #\offset], [X\nxbase, #\offset, MUL VL]
                | ((\offset) & 7)
 .endm
 
+/*
+ * LDR (ZT0)
+ *
+ *     LDR ZT0, nx
+ */
+.macro _ldr_zt nx
+       .inst   0xe11f8000                      \
+               | (((\nx) & 0x1f) << 5)
+.endm
+
+/*
+ * STR (ZT0)
+ *
+ *     STR ZT0, nx
+ */
+.macro _str_zt nx
+       .inst   0xe13f8000                      \
+               | (((\nx) & 0x1f) << 5)
+.endm
+
 .globl do_syscall
 do_syscall:
        // Store callee saved registers x19-x29 (80 bytes) plus x0 and x1
@@ -64,7 +87,7 @@ do_syscall:
        msr     S3_3_C4_C2_2, x2
 1:
 
-       // Load ZA if it's enabled - uses x12 as scratch due to SME LDR
+       // Load ZA and ZT0 if enabled - uses x12 as scratch due to SME LDR
        tbz     x2, #SVCR_ZA_SHIFT, 1f
        mov     w12, #0
        ldr     x2, =za_in
@@ -73,6 +96,15 @@ do_syscall:
        add     x12, x12, #1
        cmp     x1, x12
        bne     2b
+
+       // ZT0
+       mrs     x2, S3_0_C0_C4_5        // ID_AA64SMFR0_EL1
+       ubfx    x2, x2, #ID_AA64SMFR0_EL1_SMEver_SHIFT, \
+                        #ID_AA64SMFR0_EL1_SMEver_WIDTH
+       cbz     x2, 1f
+       adrp    x2, zt_in
+       add     x2, x2, :lo12:zt_in
+       _ldr_zt 2
 1:
 
        // Load GPRs x8-x28, and save our SP/FP for later comparison
@@ -92,8 +124,11 @@ do_syscall:
        str     x29, [x2], #8           // FP
        str     x30, [x2], #8           // LR
 
-       // Load FPRs if we're not doing SVE
+       // Load FPRs if we're not doing neither SVE nor streaming SVE
        cbnz    x0, 1f
+       ldr     x2, =svcr_in
+       tbnz    x2, #SVCR_SM_SHIFT, 1f
+
        ldr     x2, =fpr_in
        ldp     q0, q1, [x2]
        ldp     q2, q3, [x2, #16 * 2]
@@ -111,10 +146,11 @@ do_syscall:
        ldp     q26, q27, [x2, #16 * 26]
        ldp     q28, q29, [x2, #16 * 28]
        ldp     q30, q31, [x2, #16 * 30]
+
+       b       2f
 1:
 
        // Load the SVE registers if we're doing SVE/SME
-       cbz     x0, 1f
 
        ldr     x2, =z_in
        ldr     z0, [x2, #0, MUL VL]
@@ -155,9 +191,9 @@ do_syscall:
        ldr     x2, =ffr_in
        ldr     p0, [x2]
        ldr     x2, [x2, #0]
-       cbz     x2, 2f
+       cbz     x2, 1f
        wrffr   p0.b
-2:
+1:
 
        ldr     x2, =p_in
        ldr     p0, [x2, #0, MUL VL]
@@ -176,7 +212,7 @@ do_syscall:
        ldr     p13, [x2, #13, MUL VL]
        ldr     p14, [x2, #14, MUL VL]
        ldr     p15, [x2, #15, MUL VL]
-1:
+2:
 
        // Do the syscall
        svc     #0
@@ -235,6 +271,15 @@ do_syscall:
        add     x12, x12, #1
        cmp     x1, x12
        bne     2b
+
+       // ZT0
+       mrs     x2, S3_0_C0_C4_5        // ID_AA64SMFR0_EL1
+       ubfx    x2, x2, #ID_AA64SMFR0_EL1_SMEver_SHIFT, \
+                       #ID_AA64SMFR0_EL1_SMEver_WIDTH
+       cbz     x2, 1f
+       adrp    x2, zt_out
+       add     x2, x2, :lo12:zt_out
+       _str_zt 2
 1:
 
        // Save the SVE state if we have some
index dd7ebe5..18cc123 100644 (file)
 
 #include "syscall-abi.h"
 
-#define NUM_VL ((SVE_VQ_MAX - SVE_VQ_MIN) + 1)
-
 static int default_sme_vl;
 
+static int sve_vl_count;
+static unsigned int sve_vls[SVE_VQ_MAX];
+static int sme_vl_count;
+static unsigned int sme_vls[SVE_VQ_MAX];
+
 extern void do_syscall(int sve_vl, int sme_vl);
 
 static void fill_random(void *buf, size_t size)
@@ -83,6 +86,7 @@ static int check_gpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl, uint64_t s
 #define NUM_FPR 32
 uint64_t fpr_in[NUM_FPR * 2];
 uint64_t fpr_out[NUM_FPR * 2];
+uint64_t fpr_zero[NUM_FPR * 2];
 
 static void setup_fpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
                      uint64_t svcr)
@@ -97,7 +101,7 @@ static int check_fpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
        int errors = 0;
        int i;
 
-       if (!sve_vl) {
+       if (!sve_vl && !(svcr & SVCR_SM_MASK)) {
                for (i = 0; i < ARRAY_SIZE(fpr_in); i++) {
                        if (fpr_in[i] != fpr_out[i]) {
                                ksft_print_msg("%s Q%d/%d mismatch %llx != %llx\n",
@@ -109,6 +113,18 @@ static int check_fpr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
                }
        }
 
+       /*
+        * In streaming mode the whole register set should be cleared
+        * by the transition out of streaming mode.
+        */
+       if (svcr & SVCR_SM_MASK) {
+               if (memcmp(fpr_zero, fpr_out, sizeof(fpr_out)) != 0) {
+                       ksft_print_msg("%s FPSIMD registers non-zero exiting SM\n",
+                                      cfg->name);
+                       errors++;
+               }
+       }
+
        return errors;
 }
 
@@ -284,8 +300,8 @@ static int check_svcr(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
        return errors;
 }
 
-uint8_t za_in[SVE_NUM_PREGS * __SVE_ZREG_SIZE(SVE_VQ_MAX)];
-uint8_t za_out[SVE_NUM_PREGS * __SVE_ZREG_SIZE(SVE_VQ_MAX)];
+uint8_t za_in[ZA_SIG_REGS_SIZE(SVE_VQ_MAX)];
+uint8_t za_out[ZA_SIG_REGS_SIZE(SVE_VQ_MAX)];
 
 static void setup_za(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
                     uint64_t svcr)
@@ -311,6 +327,35 @@ static int check_za(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
        return errors;
 }
 
+uint8_t zt_in[ZT_SIG_REG_BYTES] __attribute__((aligned(16)));
+uint8_t zt_out[ZT_SIG_REG_BYTES] __attribute__((aligned(16)));
+
+static void setup_zt(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
+                    uint64_t svcr)
+{
+       fill_random(zt_in, sizeof(zt_in));
+       memset(zt_out, 0, sizeof(zt_out));
+}
+
+static int check_zt(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
+                   uint64_t svcr)
+{
+       int errors = 0;
+
+       if (!(getauxval(AT_HWCAP2) & HWCAP2_SME2))
+               return 0;
+
+       if (!(svcr & SVCR_ZA_MASK))
+               return 0;
+
+       if (memcmp(zt_in, zt_out, sizeof(zt_in)) != 0) {
+               ksft_print_msg("SME VL %d ZT does not match\n", sme_vl);
+               errors++;
+       }
+
+       return errors;
+}
+
 typedef void (*setup_fn)(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
                         uint64_t svcr);
 typedef int (*check_fn)(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
@@ -334,6 +379,7 @@ static struct {
        { setup_ffr, check_ffr },
        { setup_svcr, check_svcr },
        { setup_za, check_za },
+       { setup_zt, check_zt },
 };
 
 static bool do_test(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
@@ -355,73 +401,78 @@ static bool do_test(struct syscall_cfg *cfg, int sve_vl, int sme_vl,
 
 static void test_one_syscall(struct syscall_cfg *cfg)
 {
-       int sve_vq, sve_vl;
-       int sme_vq, sme_vl;
+       int sve, sme;
+       int ret;
 
        /* FPSIMD only case */
        ksft_test_result(do_test(cfg, 0, default_sme_vl, 0),
                         "%s FPSIMD\n", cfg->name);
 
-       if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
-               return;
-
-       for (sve_vq = SVE_VQ_MAX; sve_vq > 0; --sve_vq) {
-               sve_vl = prctl(PR_SVE_SET_VL, sve_vq * 16);
-               if (sve_vl == -1)
+       for (sve = 0; sve < sve_vl_count; sve++) {
+               ret = prctl(PR_SVE_SET_VL, sve_vls[sve]);
+               if (ret == -1)
                        ksft_exit_fail_msg("PR_SVE_SET_VL failed: %s (%d)\n",
                                           strerror(errno), errno);
 
-               sve_vl &= PR_SVE_VL_LEN_MASK;
-
-               if (sve_vq != sve_vq_from_vl(sve_vl))
-                       sve_vq = sve_vq_from_vl(sve_vl);
-
-               ksft_test_result(do_test(cfg, sve_vl, default_sme_vl, 0),
-                                "%s SVE VL %d\n", cfg->name, sve_vl);
-
-               if (!(getauxval(AT_HWCAP2) & HWCAP2_SME))
-                       continue;
+               ksft_test_result(do_test(cfg, sve_vls[sve], default_sme_vl, 0),
+                                "%s SVE VL %d\n", cfg->name, sve_vls[sve]);
 
-               for (sme_vq = SVE_VQ_MAX; sme_vq > 0; --sme_vq) {
-                       sme_vl = prctl(PR_SME_SET_VL, sme_vq * 16);
-                       if (sme_vl == -1)
+               for (sme = 0; sme < sme_vl_count; sme++) {
+                       ret = prctl(PR_SME_SET_VL, sme_vls[sme]);
+                       if (ret == -1)
                                ksft_exit_fail_msg("PR_SME_SET_VL failed: %s (%d)\n",
                                                   strerror(errno), errno);
 
-                       sme_vl &= PR_SME_VL_LEN_MASK;
-
-                       if (sme_vq != sve_vq_from_vl(sme_vl))
-                               sme_vq = sve_vq_from_vl(sme_vl);
-
-                       ksft_test_result(do_test(cfg, sve_vl, sme_vl,
+                       ksft_test_result(do_test(cfg, sve_vls[sve],
+                                                sme_vls[sme],
                                                 SVCR_ZA_MASK | SVCR_SM_MASK),
                                         "%s SVE VL %d/SME VL %d SM+ZA\n",
-                                        cfg->name, sve_vl, sme_vl);
-                       ksft_test_result(do_test(cfg, sve_vl, sme_vl,
-                                                SVCR_SM_MASK),
+                                        cfg->name, sve_vls[sve],
+                                        sme_vls[sme]);
+                       ksft_test_result(do_test(cfg, sve_vls[sve],
+                                                sme_vls[sme], SVCR_SM_MASK),
                                         "%s SVE VL %d/SME VL %d SM\n",
-                                        cfg->name, sve_vl, sme_vl);
-                       ksft_test_result(do_test(cfg, sve_vl, sme_vl,
-                                                SVCR_ZA_MASK),
+                                        cfg->name, sve_vls[sve],
+                                        sme_vls[sme]);
+                       ksft_test_result(do_test(cfg, sve_vls[sve],
+                                                sme_vls[sme], SVCR_ZA_MASK),
                                         "%s SVE VL %d/SME VL %d ZA\n",
-                                        cfg->name, sve_vl, sme_vl);
+                                        cfg->name, sve_vls[sve],
+                                        sme_vls[sme]);
                }
        }
+
+       for (sme = 0; sme < sme_vl_count; sme++) {
+               ret = prctl(PR_SME_SET_VL, sme_vls[sme]);
+               if (ret == -1)
+                       ksft_exit_fail_msg("PR_SME_SET_VL failed: %s (%d)\n",
+                                                  strerror(errno), errno);
+
+               ksft_test_result(do_test(cfg, 0, sme_vls[sme],
+                                        SVCR_ZA_MASK | SVCR_SM_MASK),
+                                "%s SME VL %d SM+ZA\n",
+                                cfg->name, sme_vls[sme]);
+               ksft_test_result(do_test(cfg, 0, sme_vls[sme], SVCR_SM_MASK),
+                                "%s SME VL %d SM\n",
+                                cfg->name, sme_vls[sme]);
+               ksft_test_result(do_test(cfg, 0, sme_vls[sme], SVCR_ZA_MASK),
+                                "%s SME VL %d ZA\n",
+                                cfg->name, sme_vls[sme]);
+       }
 }
 
-int sve_count_vls(void)
+void sve_count_vls(void)
 {
        unsigned int vq;
-       int vl_count = 0;
        int vl;
 
        if (!(getauxval(AT_HWCAP) & HWCAP_SVE))
-               return 0;
+               return;
 
        /*
         * Enumerate up to SVE_VQ_MAX vector lengths
         */
-       for (vq = SVE_VQ_MAX; vq > 0; --vq) {
+       for (vq = SVE_VQ_MAX; vq > 0; vq /= 2) {
                vl = prctl(PR_SVE_SET_VL, vq * 16);
                if (vl == -1)
                        ksft_exit_fail_msg("PR_SVE_SET_VL failed: %s (%d)\n",
@@ -432,28 +483,22 @@ int sve_count_vls(void)
                if (vq != sve_vq_from_vl(vl))
                        vq = sve_vq_from_vl(vl);
 
-               vl_count++;
+               sve_vls[sve_vl_count++] = vl;
        }
-
-       return vl_count;
 }
 
-int sme_count_vls(void)
+void sme_count_vls(void)
 {
        unsigned int vq;
-       int vl_count = 0;
        int vl;
 
        if (!(getauxval(AT_HWCAP2) & HWCAP2_SME))
-               return 0;
-
-       /* Ensure we configure a SME VL, used to flag if SVCR is set */
-       default_sme_vl = 16;
+               return;
 
        /*
         * Enumerate up to SVE_VQ_MAX vector lengths
         */
-       for (vq = SVE_VQ_MAX; vq > 0; --vq) {
+       for (vq = SVE_VQ_MAX; vq > 0; vq /= 2) {
                vl = prctl(PR_SME_SET_VL, vq * 16);
                if (vl == -1)
                        ksft_exit_fail_msg("PR_SME_SET_VL failed: %s (%d)\n",
@@ -461,31 +506,47 @@ int sme_count_vls(void)
 
                vl &= PR_SME_VL_LEN_MASK;
 
+               /* Found lowest VL */
+               if (sve_vq_from_vl(vl) > vq)
+                       break;
+
                if (vq != sve_vq_from_vl(vl))
                        vq = sve_vq_from_vl(vl);
 
-               vl_count++;
+               sme_vls[sme_vl_count++] = vl;
        }
 
-       return vl_count;
+       /* Ensure we configure a SME VL, used to flag if SVCR is set */
+       default_sme_vl = sme_vls[0];
 }
 
 int main(void)
 {
        int i;
        int tests = 1;  /* FPSIMD */
+       int sme_ver;
 
        srandom(getpid());
 
        ksft_print_header();
-       tests += sve_count_vls();
-       tests += (sve_count_vls() * sme_count_vls()) * 3;
+
+       sve_count_vls();
+       sme_count_vls();
+
+       tests += sve_vl_count;
+       tests += sme_vl_count * 3;
+       tests += (sve_vl_count * sme_vl_count) * 3;
        ksft_set_plan(ARRAY_SIZE(syscalls) * tests);
 
+       if (getauxval(AT_HWCAP2) & HWCAP2_SME2)
+               sme_ver = 2;
+       else
+               sme_ver = 1;
+
        if (getauxval(AT_HWCAP2) & HWCAP2_SME_FA64)
-               ksft_print_msg("SME with FA64\n");
+               ksft_print_msg("SME%d with FA64\n", sme_ver);
        else if (getauxval(AT_HWCAP2) & HWCAP2_SME)
-               ksft_print_msg("SME without FA64\n");
+               ksft_print_msg("SME%d without FA64\n", sme_ver);
 
        for (i = 0; i < ARRAY_SIZE(syscalls); i++)
                test_one_syscall(&syscalls[i]);
index 67b77ab..2cd8dce 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "system.h"
 
+#include <stdbool.h>
 #include <stddef.h>
 #include <linux/errno.h>
 #include <linux/auxvec.h>
@@ -101,7 +102,8 @@ static void handler(int n, siginfo_t *si __always_unused,
        uc->uc_mcontext.pstate &= ~PSR_BTYPE_MASK;
 }
 
-static int skip_all;
+/* Does the system have BTI? */
+static bool have_bti;
 
 static void __do_test(void (*trampoline)(void (*)(void)),
                      void (*fn)(void),
@@ -109,19 +111,11 @@ static void __do_test(void (*trampoline)(void (*)(void)),
                      const char *name,
                      int expect_sigill)
 {
-       if (skip_all) {
-               test_skipped++;
-               putstr("ok ");
-               putnum(test_num);
-               putstr(" ");
-               puttestname(name, trampoline_name);
-               putstr(" # SKIP\n");
-
-               return;
-       }
-
-       /* Branch Target exceptions should only happen in BTI binaries: */
-       if (!BTI)
+       /*
+        * Branch Target exceptions should only happen for BTI
+        * binaries running on a system with BTI:
+        */
+       if (!BTI || !have_bti)
                expect_sigill = 0;
 
        sigill_expected = expect_sigill;
@@ -199,9 +193,10 @@ void start(int *argcp)
                putstr("# HWCAP2_BTI present\n");
                if (!(hwcap & HWCAP_PACA))
                        putstr("# Bad hardware?  Expect problems.\n");
+               have_bti = true;
        } else {
                putstr("# HWCAP2_BTI not present\n");
-               skip_all = 1;
+               have_bti = false;
        }
 
        putstr("# Test binary");
index 36db613..50a7022 100644 (file)
@@ -14,6 +14,8 @@ TEST_GEN_PROGS_EXTENDED := fp-pidbench fpsimd-test \
        sve-test \
        ssve-test \
        za-test \
+       zt-ptrace \
+       zt-test \
        vlset
 TEST_PROGS_EXTENDED := fpsimd-stress sve-stress ssve-stress za-stress
 
@@ -41,5 +43,8 @@ $(OUTPUT)/za-fork: za-fork.c $(OUTPUT)/za-fork-asm.o
 $(OUTPUT)/za-ptrace: za-ptrace.c
 $(OUTPUT)/za-test: za-test.S $(OUTPUT)/asm-utils.o
        $(CC) -nostdlib $^ -o $@
+$(OUTPUT)/zt-ptrace: zt-ptrace.c
+$(OUTPUT)/zt-test: zt-test.S $(OUTPUT)/asm-utils.o
+       $(CC) -nostdlib $^ -o $@
 
 include ../../lib.mk
index 90bd433..9b38a0d 100644 (file)
@@ -57,7 +57,7 @@ endfunction
 // Utility macro to print a literal string
 // Clobbers x0-x4,x8
 .macro puts string
-       .pushsection .rodata.str1.1, "aMS", 1
+       .pushsection .rodata.str1.1, "aMS", @progbits, 1
 .L__puts_literal\@: .string "\string"
        .popsection
 
index 16a4363..73830f6 100644 (file)
@@ -31,7 +31,6 @@
 // Main program entry point
 .globl _start
 function _start
-_start:
        puts    "Iterations per test: "
        mov     x20, #10000
        lsl     x20, x20, #8
index f8b2f41..dd31647 100644 (file)
@@ -370,6 +370,19 @@ static void start_za(struct child_data *child, int vl, int cpu)
        ksft_print_msg("Started %s\n", child->name);
 }
 
+static void start_zt(struct child_data *child, int cpu)
+{
+       int ret;
+
+       ret = asprintf(&child->name, "ZT-%d", cpu);
+       if (ret == -1)
+               ksft_exit_fail_msg("asprintf() failed\n");
+
+       child_start(child, "./zt-test");
+
+       ksft_print_msg("Started %s\n", child->name);
+}
+
 static void probe_vls(int vls[], int *vl_count, int set_vl)
 {
        unsigned int vq;
@@ -377,7 +390,7 @@ static void probe_vls(int vls[], int *vl_count, int set_vl)
 
        *vl_count = 0;
 
-       for (vq = SVE_VQ_MAX; vq > 0; --vq) {
+       for (vq = SVE_VQ_MAX; vq > 0; vq /= 2) {
                vl = prctl(set_vl, vq * 16);
                if (vl == -1)
                        ksft_exit_fail_msg("SET_VL failed: %s (%d)\n",
@@ -385,6 +398,9 @@ static void probe_vls(int vls[], int *vl_count, int set_vl)
 
                vl &= PR_SVE_VL_LEN_MASK;
 
+               if (*vl_count && (vl == vls[*vl_count - 1]))
+                       break;
+
                vq = sve_vq_from_vl(vl);
 
                vls[*vl_count] = vl;
@@ -426,6 +442,7 @@ int main(int argc, char **argv)
        bool all_children_started = false;
        int seen_children;
        int sve_vls[MAX_VLS], sme_vls[MAX_VLS];
+       bool have_sme2;
        struct sigaction sa;
 
        while ((c = getopt_long(argc, argv, "t:", options, NULL)) != -1) {
@@ -458,6 +475,13 @@ int main(int argc, char **argv)
                sme_vl_count = 0;
        }
 
+       if (getauxval(AT_HWCAP2) & HWCAP2_SME2) {
+               tests += cpus;
+               have_sme2 = true;
+       } else {
+               have_sme2 = false;
+       }
+
        /* Force context switching if we only have FPSIMD */
        if (!sve_vl_count && !sme_vl_count)
                fpsimd_per_cpu = 2;
@@ -468,8 +492,9 @@ int main(int argc, char **argv)
        ksft_print_header();
        ksft_set_plan(tests);
 
-       ksft_print_msg("%d CPUs, %d SVE VLs, %d SME VLs\n",
-                      cpus, sve_vl_count, sme_vl_count);
+       ksft_print_msg("%d CPUs, %d SVE VLs, %d SME VLs, SME2 %s\n",
+                      cpus, sve_vl_count, sme_vl_count,
+                      have_sme2 ? "present" : "absent");
 
        if (timeout > 0)
                ksft_print_msg("Will run for %ds\n", timeout);
@@ -527,6 +552,9 @@ int main(int argc, char **argv)
                        start_ssve(&children[num_children++], sme_vls[j], i);
                        start_za(&children[num_children++], sme_vls[j], i);
                }
+
+               if (have_sme2)
+                       start_zt(&children[num_children++], i);
        }
 
        /*
index 918d048..8b960d0 100644 (file)
@@ -215,7 +215,6 @@ endfunction
 // Main program entry point
 .globl _start
 function _start
-_start:
        mov     x23, #0         // signal count
 
        mov     w0, #SIGINT
index 7191e53..9292bba 100644 (file)
                | ((\offset) & 7)
 .endm
 
+/*
+ * LDR (ZT0)
+ *
+ *     LDR ZT0, nx
+ */
+.macro _ldr_zt nx
+       .inst   0xe11f8000                      \
+               | (((\nx) & 0x1f) << 5)
+.endm
+
+/*
+ * STR (ZT0)
+ *
+ *     STR ZT0, nx
+ */
+.macro _str_zt nx
+       .inst   0xe13f8000                      \
+               | (((\nx) & 0x1f) << 5)
+.endm
+
 #endif
index 8c48479..6d61992 100644 (file)
 #define NT_ARM_SSVE 0x40b
 #endif
 
+/*
+ * The architecture defines the maximum VQ as 16 but for extensibility
+ * the kernel specifies the SVE_VQ_MAX as 512 resulting in us running
+ * a *lot* more tests than are useful if we use it.  Until the
+ * architecture is extended let's limit our coverage to what is
+ * currently allowed, plus one extra to ensure we cover constraining
+ * the VL as expected.
+ */
+#define TEST_VQ_MAX 17
+
 struct vec_type {
        const char *name;
        unsigned long hwcap_type;
@@ -55,7 +65,7 @@ static const struct vec_type vec_types[] = {
        },
 };
 
-#define VL_TESTS (((SVE_VQ_MAX - SVE_VQ_MIN) + 1) * 4)
+#define VL_TESTS (((TEST_VQ_MAX - SVE_VQ_MIN) + 1) * 4)
 #define FLAG_TESTS 2
 #define FPSIMD_TESTS 2
 
@@ -689,7 +699,7 @@ static int do_parent(pid_t child)
                }
 
                /* Step through every possible VQ */
-               for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) {
+               for (vq = SVE_VQ_MIN; vq <= TEST_VQ_MAX; vq++) {
                        vl = sve_vl_from_vq(vq);
 
                        /* First, try to set this vector length */
index 2a18cb4..4328895 100644 (file)
@@ -378,7 +378,6 @@ endfunction
 // Main program entry point
 .globl _start
 function _start
-_start:
        mov     x23, #0         // Irritation signal count
 
        mov     w0, #SIGINT
index bf61586..ac27d87 100644 (file)
 #define NT_ARM_ZA 0x40c
 #endif
 
-#define EXPECTED_TESTS (((SVE_VQ_MAX - SVE_VQ_MIN) + 1) * 3)
+/*
+ * The architecture defines the maximum VQ as 16 but for extensibility
+ * the kernel specifies the SVE_VQ_MAX as 512 resulting in us running
+ * a *lot* more tests than are useful if we use it.  Until the
+ * architecture is extended let's limit our coverage to what is
+ * currently allowed, plus one extra to ensure we cover constraining
+ * the VL as expected.
+ */
+#define TEST_VQ_MAX 17
+
+#define EXPECTED_TESTS (((TEST_VQ_MAX - SVE_VQ_MIN) + 1) * 3)
 
 static void fill_buf(char *buf, size_t size)
 {
@@ -301,7 +311,7 @@ static int do_parent(pid_t child)
        ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
 
        /* Step through every possible VQ */
-       for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) {
+       for (vq = SVE_VQ_MIN; vq <= TEST_VQ_MAX; vq++) {
                vl = sve_vl_from_vq(vq);
 
                /* First, try to set this vector length */
index 53c54af..9dcd709 100644 (file)
@@ -231,7 +231,6 @@ endfunction
 // Main program entry point
 .globl _start
 function _start
-_start:
        mov     x23, #0         // signal count
 
        mov     w0, #SIGINT
diff --git a/tools/testing/selftests/arm64/fp/zt-ptrace.c b/tools/testing/selftests/arm64/fp/zt-ptrace.c
new file mode 100644 (file)
index 0000000..996d961
--- /dev/null
@@ -0,0 +1,365 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 ARM Limited.
+ */
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <asm/sigcontext.h>
+#include <asm/ptrace.h>
+
+#include "../../kselftest.h"
+
+/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
+#ifndef NT_ARM_ZA
+#define NT_ARM_ZA 0x40c
+#endif
+#ifndef NT_ARM_ZT
+#define NT_ARM_ZT 0x40d
+#endif
+
+#define EXPECTED_TESTS 3
+
+static int sme_vl;
+
+static void fill_buf(char *buf, size_t size)
+{
+       int i;
+
+       for (i = 0; i < size; i++)
+               buf[i] = random();
+}
+
+static int do_child(void)
+{
+       if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
+               ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno));
+
+       if (raise(SIGSTOP))
+               ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno));
+
+       return EXIT_SUCCESS;
+}
+
+static struct user_za_header *get_za(pid_t pid, void **buf, size_t *size)
+{
+       struct user_za_header *za;
+       void *p;
+       size_t sz = sizeof(*za);
+       struct iovec iov;
+
+       while (1) {
+               if (*size < sz) {
+                       p = realloc(*buf, sz);
+                       if (!p) {
+                               errno = ENOMEM;
+                               goto error;
+                       }
+
+                       *buf = p;
+                       *size = sz;
+               }
+
+               iov.iov_base = *buf;
+               iov.iov_len = sz;
+               if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_ZA, &iov))
+                       goto error;
+
+               za = *buf;
+               if (za->size <= sz)
+                       break;
+
+               sz = za->size;
+       }
+
+       return za;
+
+error:
+       return NULL;
+}
+
+static int set_za(pid_t pid, const struct user_za_header *za)
+{
+       struct iovec iov;
+
+       iov.iov_base = (void *)za;
+       iov.iov_len = za->size;
+       return ptrace(PTRACE_SETREGSET, pid, NT_ARM_ZA, &iov);
+}
+
+static int get_zt(pid_t pid, char zt[ZT_SIG_REG_BYTES])
+{
+       struct iovec iov;
+
+       iov.iov_base = zt;
+       iov.iov_len = ZT_SIG_REG_BYTES;
+       return ptrace(PTRACE_GETREGSET, pid, NT_ARM_ZT, &iov);
+}
+
+
+static int set_zt(pid_t pid, const char zt[ZT_SIG_REG_BYTES])
+{
+       struct iovec iov;
+
+       iov.iov_base = (void *)zt;
+       iov.iov_len = ZT_SIG_REG_BYTES;
+       return ptrace(PTRACE_SETREGSET, pid, NT_ARM_ZT, &iov);
+}
+
+/* Reading with ZA disabled returns all zeros */
+static void ptrace_za_disabled_read_zt(pid_t child)
+{
+       struct user_za_header za;
+       char zt[ZT_SIG_REG_BYTES];
+       int ret, i;
+       bool fail = false;
+
+       /* Disable PSTATE.ZA using the ZA interface */
+       memset(&za, 0, sizeof(za));
+       za.vl = sme_vl;
+       za.size = sizeof(za);
+
+       ret = set_za(child, &za);
+       if (ret != 0) {
+               ksft_print_msg("Failed to disable ZA\n");
+               fail = true;
+       }
+
+       /* Read back ZT */
+       ret = get_zt(child, zt);
+       if (ret != 0) {
+               ksft_print_msg("Failed to read ZT\n");
+               fail = true;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(zt); i++) {
+               if (zt[i]) {
+                       ksft_print_msg("zt[%d]: 0x%x != 0\n", i, zt[i]);
+                       fail = true;
+               }
+       }
+
+       ksft_test_result(!fail, "ptrace_za_disabled_read_zt\n");
+}
+
+/* Writing then reading ZT should return the data written */
+static void ptrace_set_get_zt(pid_t child)
+{
+       char zt_in[ZT_SIG_REG_BYTES];
+       char zt_out[ZT_SIG_REG_BYTES];
+       int ret, i;
+       bool fail = false;
+
+       fill_buf(zt_in, sizeof(zt_in));
+
+       ret = set_zt(child, zt_in);
+       if (ret != 0) {
+               ksft_print_msg("Failed to set ZT\n");
+               fail = true;
+       }
+
+       ret = get_zt(child, zt_out);
+       if (ret != 0) {
+               ksft_print_msg("Failed to read ZT\n");
+               fail = true;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(zt_in); i++) {
+               if (zt_in[i] != zt_out[i]) {
+                       ksft_print_msg("zt[%d]: 0x%x != 0x%x\n", i, 
+                                      zt_in[i], zt_out[i]);
+                       fail = true;
+               }
+       }
+
+       ksft_test_result(!fail, "ptrace_set_get_zt\n");
+}
+
+/* Writing ZT should set PSTATE.ZA */
+static void ptrace_enable_za_via_zt(pid_t child)
+{
+       struct user_za_header za_in;
+       struct user_za_header *za_out;
+       char zt[ZT_SIG_REG_BYTES];
+       char *za_data;
+       size_t za_out_size;
+       int ret, i, vq;
+       bool fail = false;
+
+       /* Disable PSTATE.ZA using the ZA interface */
+       memset(&za_in, 0, sizeof(za_in));
+       za_in.vl = sme_vl;
+       za_in.size = sizeof(za_in);
+
+       ret = set_za(child, &za_in);
+       if (ret != 0) {
+               ksft_print_msg("Failed to disable ZA\n");
+               fail = true;
+       }
+
+       /* Write ZT */
+       fill_buf(zt, sizeof(zt));
+       ret = set_zt(child, zt);
+       if (ret != 0) {
+               ksft_print_msg("Failed to set ZT\n");
+               fail = true;
+       }
+
+       /* Read back ZA and check for register data */
+       za_out = NULL;
+       za_out_size = 0;
+       if (get_za(child, (void **)&za_out, &za_out_size)) {
+               /* Should have an unchanged VL */
+               if (za_out->vl != sme_vl) {
+                       ksft_print_msg("VL changed from %d to %d\n",
+                                      sme_vl, za_out->vl);
+                       fail = true;
+               }
+               vq = __sve_vq_from_vl(za_out->vl);
+               za_data = (char *)za_out + ZA_PT_ZA_OFFSET;
+
+               /* Should have register data */
+               if (za_out->size < ZA_PT_SIZE(vq)) {
+                       ksft_print_msg("ZA data less than expected: %u < %u\n",
+                                      za_out->size, ZA_PT_SIZE(vq));
+                       fail = true;
+                       vq = 0;
+               }
+
+               /* That register data should be non-zero */
+               for (i = 0; i < ZA_PT_ZA_SIZE(vq); i++) {
+                       if (za_data[i]) {
+                               ksft_print_msg("ZA byte %d is %x\n",
+                                              i, za_data[i]);
+                               fail = true;
+                       }
+               }
+       } else {
+               ksft_print_msg("Failed to read ZA\n");
+               fail = true;
+       }
+
+       ksft_test_result(!fail, "ptrace_enable_za_via_zt\n");
+}
+
+static int do_parent(pid_t child)
+{
+       int ret = EXIT_FAILURE;
+       pid_t pid;
+       int status;
+       siginfo_t si;
+
+       /* Attach to the child */
+       while (1) {
+               int sig;
+
+               pid = wait(&status);
+               if (pid == -1) {
+                       perror("wait");
+                       goto error;
+               }
+
+               /*
+                * This should never happen but it's hard to flag in
+                * the framework.
+                */
+               if (pid != child)
+                       continue;
+
+               if (WIFEXITED(status) || WIFSIGNALED(status))
+                       ksft_exit_fail_msg("Child died unexpectedly\n");
+
+               if (!WIFSTOPPED(status))
+                       goto error;
+
+               sig = WSTOPSIG(status);
+
+               if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
+                       if (errno == ESRCH)
+                               goto disappeared;
+
+                       if (errno == EINVAL) {
+                               sig = 0; /* bust group-stop */
+                               goto cont;
+                       }
+
+                       ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
+                                             strerror(errno));
+                       goto error;
+               }
+
+               if (sig == SIGSTOP && si.si_code == SI_TKILL &&
+                   si.si_pid == pid)
+                       break;
+
+       cont:
+               if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
+                       if (errno == ESRCH)
+                               goto disappeared;
+
+                       ksft_test_result_fail("PTRACE_CONT: %s\n",
+                                             strerror(errno));
+                       goto error;
+               }
+       }
+
+       ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
+
+       ptrace_za_disabled_read_zt(child);
+       ptrace_set_get_zt(child);
+       ptrace_enable_za_via_zt(child);
+
+       ret = EXIT_SUCCESS;
+
+error:
+       kill(child, SIGKILL);
+
+disappeared:
+       return ret;
+}
+
+int main(void)
+{
+       int ret = EXIT_SUCCESS;
+       pid_t child;
+
+       srandom(getpid());
+
+       ksft_print_header();
+
+       if (!(getauxval(AT_HWCAP2) & HWCAP2_SME2)) {
+               ksft_set_plan(1);
+               ksft_exit_skip("SME2 not available\n");
+       }
+
+       /* We need a valid SME VL to enable/disable ZA */
+       sme_vl = prctl(PR_SME_GET_VL);
+       if (sme_vl == -1) {
+               ksft_set_plan(1);
+               ksft_exit_skip("Failed to read SME VL: %d (%s)\n",
+                              errno, strerror(errno));
+       }
+
+       ksft_set_plan(EXPECTED_TESTS);
+
+       child = fork();
+       if (!child)
+               return do_child();
+
+       if (do_parent(child))
+               ret = EXIT_FAILURE;
+
+       ksft_print_cnts();
+
+       return ret;
+}
diff --git a/tools/testing/selftests/arm64/fp/zt-test.S b/tools/testing/selftests/arm64/fp/zt-test.S
new file mode 100644 (file)
index 0000000..d632863
--- /dev/null
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2021-2 ARM Limited.
+// Original author: Mark Brown <broonie@kernel.org>
+//
+// Scalable Matrix Extension ZT context switch test
+// Repeatedly writes unique test patterns into ZT0
+// and reads them back to verify integrity.
+
+#include <asm/unistd.h>
+#include "assembler.h"
+#include "asm-offsets.h"
+#include "sme-inst.h"
+
+.arch_extension sve
+
+#define ZT_SZ  512
+#define ZT_B   (ZT_SZ / 8)
+
+// Declare some storage space to shadow ZT register contents and a
+// scratch buffer.
+.pushsection .text
+.data
+.align 4
+ztref:
+       .space  ZT_B
+scratch:
+       .space  ZT_B
+.popsection
+
+
+// Generate a test pattern for storage in ZT
+// x0: pid
+// x1: generation
+
+// These values are used to construct a 32-bit pattern that is repeated in the
+// scratch buffer as many times as will fit:
+// bits 31:24  generation number (increments once per test_loop)
+// bits 23: 8  pid
+// bits  7: 0  32-bit lane index
+
+function pattern
+       mov     w3, wzr
+       bfi     w3, w0, #8, #16         // PID
+       bfi     w3, w1, #24, #8         // Generation
+
+       ldr     x0, =scratch
+       mov     w1, #ZT_B / 4
+
+0:     str     w3, [x0], #4
+       add     w3, w3, #1              // Lane
+       subs    w1, w1, #1
+       b.ne    0b
+
+       ret
+endfunction
+
+// Set up test pattern in a ZT horizontal vector
+// x0: pid
+// x1: generation
+function setup_zt
+       mov     x4, x30
+
+       bl      pattern                 // Get pattern in scratch buffer
+       ldr     x0, =ztref
+       ldr     x1, =scratch
+       mov     x2, #ZT_B
+       bl      memcpy
+
+       ldr     x0, =ztref
+       _ldr_zt 0                       // load zt0 from pointer x0
+
+       ret     x4
+endfunction
+
+// Trivial memory compare: compare x2 bytes starting at address x0 with
+// bytes starting at address x1.
+// Returns only if all bytes match; otherwise, the program is aborted.
+// Clobbers x0-x5.
+function memcmp
+       cbz     x2, 2f
+
+       stp     x0, x1, [sp, #-0x20]!
+       str     x2, [sp, #0x10]
+
+       mov     x5, #0
+0:     ldrb    w3, [x0, x5]
+       ldrb    w4, [x1, x5]
+       add     x5, x5, #1
+       cmp     w3, w4
+       b.ne    1f
+       subs    x2, x2, #1
+       b.ne    0b
+
+1:     ldr     x2, [sp, #0x10]
+       ldp     x0, x1, [sp], #0x20
+       b.ne    barf
+
+2:     ret
+endfunction
+
+// Verify that a ZT vector matches its shadow in memory, else abort
+// Clobbers x0-x3
+function check_zt
+       mov     x3, x30
+
+       ldr     x0, =scratch            // Poison scratch
+       mov     x1, #ZT_B
+       bl      memfill_ae
+
+       ldr     x0, =scratch
+       _str_zt 0
+
+       ldr     x0, =ztref
+       ldr     x1, =scratch
+       mov     x2, #ZT_B
+       mov     x30, x3
+       b       memcmp
+endfunction
+
+// Any SME register modified here can cause corruption in the main
+// thread -- but *only* the locations modified here.
+function irritator_handler
+       // Increment the irritation signal count (x23):
+       ldr     x0, [x2, #ucontext_regs + 8 * 23]
+       add     x0, x0, #1
+       str     x0, [x2, #ucontext_regs + 8 * 23]
+
+       // Corrupt some random ZT data
+#if 0
+       adr     x0, .text + (irritator_handler - .text) / 16 * 16
+       movi    v0.8b, #1
+       movi    v9.16b, #2
+       movi    v31.8b, #3
+#endif
+
+       ret
+endfunction
+
+function tickle_handler
+       // Increment the signal count (x23):
+       ldr     x0, [x2, #ucontext_regs + 8 * 23]
+       add     x0, x0, #1
+       str     x0, [x2, #ucontext_regs + 8 * 23]
+
+       ret
+endfunction
+
+function terminate_handler
+       mov     w21, w0
+       mov     x20, x2
+
+       puts    "Terminated by signal "
+       mov     w0, w21
+       bl      putdec
+       puts    ", no error, iterations="
+       ldr     x0, [x20, #ucontext_regs + 8 * 22]
+       bl      putdec
+       puts    ", signals="
+       ldr     x0, [x20, #ucontext_regs + 8 * 23]
+       bl      putdecn
+
+       mov     x0, #0
+       mov     x8, #__NR_exit
+       svc     #0
+endfunction
+
+// w0: signal number
+// x1: sa_action
+// w2: sa_flags
+// Clobbers x0-x6,x8
+function setsignal
+       str     x30, [sp, #-((sa_sz + 15) / 16 * 16 + 16)]!
+
+       mov     w4, w0
+       mov     x5, x1
+       mov     w6, w2
+
+       add     x0, sp, #16
+       mov     x1, #sa_sz
+       bl      memclr
+
+       mov     w0, w4
+       add     x1, sp, #16
+       str     w6, [x1, #sa_flags]
+       str     x5, [x1, #sa_handler]
+       mov     x2, #0
+       mov     x3, #sa_mask_sz
+       mov     x8, #__NR_rt_sigaction
+       svc     #0
+
+       cbz     w0, 1f
+
+       puts    "sigaction failure\n"
+       b       .Labort
+
+1:     ldr     x30, [sp], #((sa_sz + 15) / 16 * 16 + 16)
+       ret
+endfunction
+
+// Main program entry point
+.globl _start
+function _start
+       mov     x23, #0         // signal count
+
+       mov     w0, #SIGINT
+       adr     x1, terminate_handler
+       mov     w2, #SA_SIGINFO
+       bl      setsignal
+
+       mov     w0, #SIGTERM
+       adr     x1, terminate_handler
+       mov     w2, #SA_SIGINFO
+       bl      setsignal
+
+       mov     w0, #SIGUSR1
+       adr     x1, irritator_handler
+       mov     w2, #SA_SIGINFO
+       orr     w2, w2, #SA_NODEFER
+       bl      setsignal
+
+       mov     w0, #SIGUSR2
+       adr     x1, tickle_handler
+       mov     w2, #SA_SIGINFO
+       orr     w2, w2, #SA_NODEFER
+       bl      setsignal
+
+       smstart_za
+
+       // Obtain our PID, to ensure test pattern uniqueness between processes
+       mov     x8, #__NR_getpid
+       svc     #0
+       mov     x20, x0
+
+       puts    "PID:\t"
+       mov     x0, x20
+       bl      putdecn
+
+       mov     x22, #0         // generation number, increments per iteration
+.Ltest_loop:
+       mov     x0, x20
+       mov     x1, x22
+       bl      setup_zt
+
+       mov     x8, #__NR_sched_yield   // Encourage preemption
+       svc     #0
+
+       mrs     x0, S3_3_C4_C2_2        // SVCR should have ZA=1,SM=0
+       and     x1, x0, #3
+       cmp     x1, #2
+       b.ne    svcr_barf
+
+       bl      check_zt
+
+       add     x22, x22, #1    // Everything still working
+       b       .Ltest_loop
+
+.Labort:
+       mov     x0, #0
+       mov     x1, #SIGABRT
+       mov     x8, #__NR_kill
+       svc     #0
+endfunction
+
+function barf
+// fpsimd.c acitivty log dump hack
+//     ldr     w0, =0xdeadc0de
+//     mov     w8, #__NR_exit
+//     svc     #0
+// end hack
+       smstop
+       mov     x10, x0 // expected data
+       mov     x11, x1 // actual data
+       mov     x12, x2 // data size
+
+       puts    "Mismatch: PID="
+       mov     x0, x20
+       bl      putdec
+       puts    ", iteration="
+       mov     x0, x22
+       bl      putdec
+       puts    "\tExpected ["
+       mov     x0, x10
+       mov     x1, x12
+       bl      dumphex
+       puts    "]\n\tGot      ["
+       mov     x0, x11
+       mov     x1, x12
+       bl      dumphex
+       puts    "]\n"
+
+       mov     x8, #__NR_getpid
+       svc     #0
+// fpsimd.c acitivty log dump hack
+//     ldr     w0, =0xdeadc0de
+//     mov     w8, #__NR_exit
+//     svc     #0
+// ^ end of hack
+       mov     x1, #SIGABRT
+       mov     x8, #__NR_kill
+       svc     #0
+//     mov     x8, #__NR_exit
+//     mov     x1, #1
+//     svc     #0
+endfunction
+
+function svcr_barf
+       mov     x10, x0
+
+       puts    "Bad SVCR: "
+       mov     x0, x10
+       bl      putdecn
+
+       mov     x8, #__NR_exit
+       mov     x1, #1
+       svc     #0
+endfunction
index 037046f..0d7ac3d 100644 (file)
@@ -1,24 +1,33 @@
 # SPDX-License-Identifier: GPL-2.0
 # Copyright (C) 2020 ARM Limited
 
-# preserve CC value from top level Makefile
-ifeq ($(CC),cc)
-CC := $(CROSS_COMPILE)gcc
-endif
-
 CFLAGS += -std=gnu99 -I. -pthread
 LDFLAGS += -pthread
 SRCS := $(filter-out mte_common_util.c,$(wildcard *.c))
 PROGS := $(patsubst %.c,%,$(SRCS))
 
+ifeq ($(LLVM),)
+# For GCC check that the toolchain has MTE support.
+
+# preserve CC value from top level Makefile
+ifeq ($(CC),cc)
+CC := $(CROSS_COMPILE)gcc
+endif
+
 #check if the compiler works well
 mte_cc_support := $(shell if ($(CC) $(CFLAGS) -march=armv8.5-a+memtag -E -x c /dev/null -o /dev/null 2>&1) then echo "1"; fi)
 
+else
+
+# All supported clang versions also support MTE.
+mte_cc_support := 1
+
+endif
+
 ifeq ($(mte_cc_support),1)
 # Generated binaries to be installed by top KSFT script
 TEST_GEN_PROGS := $(PROGS)
 
-# Get Kernel headers installed and use them.
 else
     $(warning compiler "$(CC)" does not support the ARMv8.5 MTE extension.)
     $(warning test program "mte" will not be created.)
index be7520a..8f5feba 100644 (file)
@@ -22,6 +22,10 @@ $(TEST_GEN_PROGS): $(PROGS)
 
 # Common test-unit targets to build common-layout test-cases executables
 # Needs secondary expansion to properly include the testcase c-file in pre-reqs
+COMMON_SOURCES := test_signals.c test_signals_utils.c testcases/testcases.c \
+       signals.S
+COMMON_HEADERS := test_signals.h test_signals_utils.h testcases/testcases.h
+
 .SECONDEXPANSION:
-$(PROGS): test_signals.c test_signals_utils.c testcases/testcases.c signals.S $$@.c test_signals.h test_signals_utils.h testcases/testcases.h
-       $(CC) $(CFLAGS) $^ -o $@
+$(PROGS): $$@.c ${COMMON_SOURCES} ${COMMON_HEADERS}
+       $(CC) $(CFLAGS) ${@}.c ${COMMON_SOURCES} -o $@
index 416b1ff..00051b4 100644 (file)
 #include "test_signals.h"
 #include "test_signals_utils.h"
 
-struct tdescr *current;
+struct tdescr *current = &tde;
 
 int main(int argc, char *argv[])
 {
-       current = &tde;
-
        ksft_print_msg("%s :: %s\n", current->name, current->descr);
        if (test_setup(current) && test_init(current)) {
                test_run(current);
index 0c64583..1e6273d 100644 (file)
@@ -34,6 +34,7 @@ enum {
        FSVE_BIT,
        FSME_BIT,
        FSME_FA64_BIT,
+       FSME2_BIT,
        FMAX_END
 };
 
@@ -41,6 +42,7 @@ enum {
 #define FEAT_SVE               (1UL << FSVE_BIT)
 #define FEAT_SME               (1UL << FSME_BIT)
 #define FEAT_SME_FA64          (1UL << FSME_FA64_BIT)
+#define FEAT_SME2              (1UL << FSME2_BIT)
 
 /*
  * A descriptor used to describe and configure a test case.
index 308e229..40be844 100644 (file)
@@ -29,6 +29,7 @@ static char const *const feats_names[FMAX_END] = {
        " SVE ",
        " SME ",
        " FA64 ",
+       " SME2 ",
 };
 
 #define MAX_FEATS_SZ   128
@@ -192,8 +193,10 @@ static bool handle_signal_copyctx(struct tdescr *td,
                 * in the copy, this was previously validated in
                 * ASSERT_GOOD_CONTEXT().
                 */
-               to_copy = offset + sizeof(struct extra_context) + 16 +
-                       extra->size;
+               to_copy = __builtin_offsetof(ucontext_t,
+                                            uc_mcontext.__reserved);
+               to_copy += offset + sizeof(struct extra_context) + 16;
+               to_copy += extra->size;
                copied_extra = (struct extra_context *)&(td->live_uc->uc_mcontext.__reserved[offset]);
        } else {
                copied_extra = NULL;
@@ -323,6 +326,8 @@ int test_init(struct tdescr *td)
                        td->feats_supported |= FEAT_SME;
                if (getauxval(AT_HWCAP2) & HWCAP2_SME_FA64)
                        td->feats_supported |= FEAT_SME_FA64;
+               if (getauxval(AT_HWCAP2) & HWCAP2_SME2)
+                       td->feats_supported |= FEAT_SME2;
                if (feats_ok(td)) {
                        if (td->feats_required & td->feats_supported)
                                fprintf(stderr,
index d0a1789..3d37daa 100644 (file)
@@ -34,6 +34,10 @@ static bool sme_get_vls(struct tdescr *td)
 
                vl &= PR_SME_VL_LEN_MASK;
 
+               /* Did we find the lowest supported VL? */
+               if (vq < sve_vq_from_vl(vl))
+                       break;
+
                /* Skip missing VLs */
                vq = sve_vq_from_vl(vl);
 
@@ -92,6 +96,11 @@ static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc,
                return 1;
        }
 
+       if (!(ssve->flags & SVE_SIG_FLAG_SM)) {
+               fprintf(stderr, "SVE_SIG_FLAG_SM not set in SVE record\n");
+               return 1;
+       }
+
        /* The actual size validation is done in get_current_context() */
        fprintf(stderr, "Got expected size %u and VL %d\n",
                head->size, ssve->vl);
@@ -116,12 +125,7 @@ static int sme_regs(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
 struct tdescr tde = {
        .name = "Streaming SVE registers",
        .descr = "Check that we get the right Streaming SVE registers reported",
-       /*
-        * We shouldn't require FA64 but things like memset() used in the
-        * helpers might use unsupported instructions so for now disable
-        * the test unless we've got the full instruction set.
-        */
-       .feats_required = FEAT_SME | FEAT_SME_FA64,
+       .feats_required = FEAT_SME,
        .timeout = 3,
        .init = sme_get_vls,
        .run = sme_regs,
diff --git a/tools/testing/selftests/arm64/signal/testcases/ssve_za_regs.c b/tools/testing/selftests/arm64/signal/testcases/ssve_za_regs.c
new file mode 100644 (file)
index 0000000..9dc5f12
--- /dev/null
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 ARM Limited
+ *
+ * Verify that both the streaming SVE and ZA register context in
+ * signal frames is set up as expected when enabled simultaneously.
+ */
+
+#include <signal.h>
+#include <ucontext.h>
+#include <sys/prctl.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static union {
+       ucontext_t uc;
+       char buf[1024 * 128];
+} context;
+static unsigned int vls[SVE_VQ_MAX];
+unsigned int nvls = 0;
+
+static bool sme_get_vls(struct tdescr *td)
+{
+       int vq, vl;
+
+       /*
+        * Enumerate up to SVE_VQ_MAX vector lengths
+        */
+       for (vq = SVE_VQ_MAX; vq > 0; --vq) {
+               vl = prctl(PR_SME_SET_VL, vq * 16);
+               if (vl == -1)
+                       return false;
+
+               vl &= PR_SME_VL_LEN_MASK;
+
+               /* Did we find the lowest supported VL? */
+               if (vq < sve_vq_from_vl(vl))
+                       break;
+
+               /* Skip missing VLs */
+               vq = sve_vq_from_vl(vl);
+
+               vls[nvls++] = vl;
+       }
+
+       /* We need at least one VL */
+       if (nvls < 1) {
+               fprintf(stderr, "Only %d VL supported\n", nvls);
+               return false;
+       }
+
+       return true;
+}
+
+static void setup_regs(void)
+{
+       /* smstart sm; real data is TODO */
+       asm volatile(".inst 0xd503437f" : : : );
+
+       /* smstart za; real data is TODO */
+       asm volatile(".inst 0xd503457f" : : : );
+}
+
+static char zeros[ZA_SIG_REGS_SIZE(SVE_VQ_MAX)];
+
+static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc,
+                        unsigned int vl)
+{
+       size_t offset;
+       struct _aarch64_ctx *head = GET_BUF_RESV_HEAD(context);
+       struct _aarch64_ctx *regs;
+       struct sve_context *ssve;
+       struct za_context *za;
+       int ret;
+
+       fprintf(stderr, "Testing VL %d\n", vl);
+
+       ret = prctl(PR_SME_SET_VL, vl);
+       if (ret != vl) {
+               fprintf(stderr, "Failed to set VL, got %d\n", ret);
+               return 1;
+       }
+
+       /*
+        * Get a signal context which should have the SVE and ZA
+        * frames in it.
+        */
+       setup_regs();
+       if (!get_current_context(td, &context.uc, sizeof(context)))
+               return 1;
+
+       regs = get_header(head, SVE_MAGIC, GET_BUF_RESV_SIZE(context),
+                         &offset);
+       if (!regs) {
+               fprintf(stderr, "No SVE context\n");
+               return 1;
+       }
+
+       ssve = (struct sve_context *)regs;
+       if (ssve->vl != vl) {
+               fprintf(stderr, "Got SSVE VL %d, expected %d\n", ssve->vl, vl);
+               return 1;
+       }
+
+       if (!(ssve->flags & SVE_SIG_FLAG_SM)) {
+               fprintf(stderr, "SVE_SIG_FLAG_SM not set in SVE record\n");
+               return 1;
+       }
+
+       fprintf(stderr, "Got expected SSVE size %u and VL %d\n",
+               regs->size, ssve->vl);
+
+       regs = get_header(head, ZA_MAGIC, GET_BUF_RESV_SIZE(context),
+                         &offset);
+       if (!regs) {
+               fprintf(stderr, "No ZA context\n");
+               return 1;
+       }
+
+       za = (struct za_context *)regs;
+       if (za->vl != vl) {
+               fprintf(stderr, "Got ZA VL %d, expected %d\n", za->vl, vl);
+               return 1;
+       }
+
+       fprintf(stderr, "Got expected ZA size %u and VL %d\n",
+               regs->size, za->vl);
+
+       /* We didn't load any data into ZA so it should be all zeros */
+       if (memcmp(zeros, (char *)za + ZA_SIG_REGS_OFFSET,
+                  ZA_SIG_REGS_SIZE(sve_vq_from_vl(za->vl))) != 0) {
+               fprintf(stderr, "ZA data invalid\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+static int sme_regs(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
+{
+       int i;
+
+       for (i = 0; i < nvls; i++) {
+               if (do_one_sme_vl(td, si, uc, vls[i]))
+                       return 1;
+       }
+
+       td->pass = 1;
+
+       return 0;
+}
+
+struct tdescr tde = {
+       .name = "Streaming SVE registers",
+       .descr = "Check that we get the right Streaming SVE registers reported",
+       .feats_required = FEAT_SME,
+       .timeout = 3,
+       .init = sme_get_vls,
+       .run = sme_regs,
+};
index d2eda7b..9f580b5 100644 (file)
@@ -108,6 +108,26 @@ bool validate_za_context(struct za_context *za, char **err)
        return true;
 }
 
+bool validate_zt_context(struct zt_context *zt, char **err)
+{
+       if (!zt || !err)
+               return false;
+
+       /* If the context is present there should be at least one register */
+       if (zt->nregs == 0) {
+               *err = "no registers";
+               return false;
+       }
+
+       /* Size should agree with the number of registers */
+       if (zt->head.size != ZT_SIG_CONTEXT_SIZE(zt->nregs)) {
+               *err = "register count does not match size";
+               return false;
+       }
+
+       return true;
+}
+
 bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
 {
        bool terminated = false;
@@ -117,6 +137,7 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
        struct extra_context *extra = NULL;
        struct sve_context *sve = NULL;
        struct za_context *za = NULL;
+       struct zt_context *zt = NULL;
        struct _aarch64_ctx *head =
                (struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
        void *extra_data = NULL;
@@ -163,6 +184,10 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
                        if (head->size != sizeof(struct esr_context))
                                *err = "Bad size for esr_context";
                        break;
+               case TPIDR2_MAGIC:
+                       if (head->size != sizeof(struct tpidr2_context))
+                               *err = "Bad size for tpidr2_context";
+                       break;
                case SVE_MAGIC:
                        if (flags & SVE_CTX)
                                *err = "Multiple SVE_MAGIC";
@@ -177,6 +202,13 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
                        za = (struct za_context *)head;
                        new_flags |= ZA_CTX;
                        break;
+               case ZT_MAGIC:
+                       if (flags & ZT_CTX)
+                               *err = "Multiple ZT_MAGIC";
+                       /* Size is validated in validate_za_context() */
+                       zt = (struct zt_context *)head;
+                       new_flags |= ZT_CTX;
+                       break;
                case EXTRA_MAGIC:
                        if (flags & EXTRA_CTX)
                                *err = "Multiple EXTRA_MAGIC";
@@ -234,6 +266,9 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
                if (new_flags & ZA_CTX)
                        if (!validate_za_context(za, err))
                                return false;
+               if (new_flags & ZT_CTX)
+                       if (!validate_zt_context(zt, err))
+                               return false;
 
                flags |= new_flags;
 
@@ -245,6 +280,11 @@ bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
                return false;
        }
 
+       if (terminated && (flags & ZT_CTX) && !(flags & ZA_CTX)) {
+               *err = "ZT context but no ZA context";
+               return false;
+       }
+
        return true;
 }
 
index 040afde..a08ab0d 100644 (file)
@@ -18,6 +18,7 @@
 #define SVE_CTX                (1 << 1)
 #define ZA_CTX         (1 << 2)
 #define EXTRA_CTX      (1 << 3)
+#define ZT_CTX         (1 << 4)
 
 #define KSFT_BAD_MAGIC 0xdeadbeef
 
diff --git a/tools/testing/selftests/arm64/signal/testcases/tpidr2_siginfo.c b/tools/testing/selftests/arm64/signal/testcases/tpidr2_siginfo.c
new file mode 100644 (file)
index 0000000..6a2c82b
--- /dev/null
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 ARM Limited
+ *
+ * Verify that the TPIDR2 register context in signal frames is set up as
+ * expected.
+ */
+
+#include <signal.h>
+#include <ucontext.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+#include <asm/sigcontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static union {
+       ucontext_t uc;
+       char buf[1024 * 128];
+} context;
+
+#define SYS_TPIDR2 "S3_3_C13_C0_5"
+
+static uint64_t get_tpidr2(void)
+{
+       uint64_t val;
+
+       asm volatile (
+               "mrs    %0, " SYS_TPIDR2 "\n"
+               : "=r"(val)
+               :
+               : "cc");
+
+       return val;
+}
+
+int tpidr2_present(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
+{
+       struct _aarch64_ctx *head = GET_BUF_RESV_HEAD(context);
+       struct tpidr2_context *tpidr2_ctx;
+       size_t offset;
+       bool in_sigframe;
+       bool have_sme;
+       __u64 orig_tpidr2;
+
+       have_sme = getauxval(AT_HWCAP2) & HWCAP2_SME;
+       if (have_sme)
+               orig_tpidr2 = get_tpidr2();
+
+       if (!get_current_context(td, &context.uc, sizeof(context)))
+               return 1;
+
+       tpidr2_ctx = (struct tpidr2_context *)
+               get_header(head, TPIDR2_MAGIC, td->live_sz, &offset);
+
+       in_sigframe = tpidr2_ctx != NULL;
+
+       fprintf(stderr, "TPIDR2 sigframe %s on system %s SME\n",
+               in_sigframe ? "present" : "absent",
+               have_sme ? "with" : "without");
+
+       td->pass = (in_sigframe == have_sme);
+
+       /*
+        * Check that the value we read back was the one present at
+        * the time that the signal was triggered.  TPIDR2 is owned by
+        * libc so we can't safely choose the value and it is possible
+        * that we may need to revisit this in future if something
+        * starts deciding to set a new TPIDR2 between us reading and
+        * the signal.
+        */
+       if (have_sme && tpidr2_ctx) {
+               if (tpidr2_ctx->tpidr2 != orig_tpidr2) {
+                       fprintf(stderr, "TPIDR2 in frame is %llx, was %llx\n",
+                               tpidr2_ctx->tpidr2, orig_tpidr2);
+                       td->pass = false;
+               }
+       }
+
+       return 0;
+}
+
+struct tdescr tde = {
+       .name = "TPIDR2",
+       .descr = "Validate that TPIDR2 is present as expected",
+       .timeout = 3,
+       .run = tpidr2_present,
+};
index ea45acb..174ad66 100644 (file)
@@ -34,6 +34,10 @@ static bool sme_get_vls(struct tdescr *td)
 
                vl &= PR_SME_VL_LEN_MASK;
 
+               /* Did we find the lowest supported VL? */
+               if (vq < sve_vq_from_vl(vl))
+                       break;
+
                /* Skip missing VLs */
                vq = sve_vq_from_vl(vl);
 
diff --git a/tools/testing/selftests/arm64/signal/testcases/zt_no_regs.c b/tools/testing/selftests/arm64/signal/testcases/zt_no_regs.c
new file mode 100644 (file)
index 0000000..34f69bc
--- /dev/null
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 ARM Limited
+ *
+ * Verify that using an instruction not supported in streaming mode
+ * traps when in streaming mode.
+ */
+
+#include <signal.h>
+#include <ucontext.h>
+#include <sys/prctl.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static union {
+       ucontext_t uc;
+       char buf[1024 * 128];
+} context;
+
+int zt_no_regs_run(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
+{
+       size_t offset;
+       struct _aarch64_ctx *head = GET_BUF_RESV_HEAD(context);
+
+       /*
+        * Get a signal context which should not have a ZT frame and
+        * registers in it.
+        */
+       if (!get_current_context(td, &context.uc, sizeof(context)))
+               return 1;
+
+       head = get_header(head, ZT_MAGIC, GET_BUF_RESV_SIZE(context), &offset);
+       if (head) {
+               fprintf(stderr, "Got unexpected ZT context\n");
+               return 1;
+       }
+
+       td->pass = 1;
+
+       return 0;
+}
+
+struct tdescr tde = {
+       .name = "ZT register data not present",
+       .descr = "Validate that ZT is not present when ZA is disabled",
+       .feats_required = FEAT_SME2,
+       .timeout = 3,
+       .sanity_disabled = true,
+       .run = zt_no_regs_run,
+};
diff --git a/tools/testing/selftests/arm64/signal/testcases/zt_regs.c b/tools/testing/selftests/arm64/signal/testcases/zt_regs.c
new file mode 100644 (file)
index 0000000..e1eb4d5
--- /dev/null
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 ARM Limited
+ *
+ * Verify that using an instruction not supported in streaming mode
+ * traps when in streaming mode.
+ */
+
+#include <signal.h>
+#include <ucontext.h>
+#include <sys/prctl.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static union {
+       ucontext_t uc;
+       char buf[1024 * 128];
+} context;
+
+static void enable_za(void)
+{
+       /* smstart za; real data is TODO */
+       asm volatile(".inst 0xd503457f" : : : );
+}
+
+int zt_regs_run(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
+{
+       size_t offset;
+       struct _aarch64_ctx *head = GET_BUF_RESV_HEAD(context);
+       struct zt_context *zt;
+       char *zeros;
+
+       /*
+        * Get a signal context which should have a ZT frame and registers
+        * in it.
+        */
+       enable_za();
+       if (!get_current_context(td, &context.uc, sizeof(context)))
+               return 1;
+
+       head = get_header(head, ZT_MAGIC, GET_BUF_RESV_SIZE(context), &offset);
+       if (!head) {
+               fprintf(stderr, "No ZT context\n");
+               return 1;
+       }
+
+       zt = (struct zt_context *)head;
+       if (zt->nregs == 0) {
+               fprintf(stderr, "Got context with no registers\n");
+               return 1;
+       }
+
+       fprintf(stderr, "Got expected size %u for %d registers\n",
+               head->size, zt->nregs);
+
+       /* We didn't load any data into ZT so it should be all zeros */
+       zeros = malloc(ZT_SIG_REGS_SIZE(zt->nregs));
+       if (!zeros) {
+               fprintf(stderr, "Out of memory, nregs=%u\n", zt->nregs);
+               return 1;
+       }
+       memset(zeros, 0, ZT_SIG_REGS_SIZE(zt->nregs));
+
+       if (memcmp(zeros, (char *)zt + ZT_SIG_REGS_OFFSET,
+                  ZT_SIG_REGS_SIZE(zt->nregs)) != 0) {
+               fprintf(stderr, "ZT data invalid\n");
+               return 1;
+       }
+
+       free(zeros);
+
+       td->pass = 1;
+
+       return 0;
+}
+
+struct tdescr tde = {
+       .name = "ZT register data",
+       .descr = "Validate that ZT is present and has data when ZA is enabled",
+       .feats_required = FEAT_SME2,
+       .timeout = 3,
+       .sanity_disabled = true,
+       .run = zt_regs_run,
+};