Revert "arm64: smccc: Remove broken support for SMCCCv1.3 SVE discard hint"

This reverts commit bfcaffd4cc which is
commit 8c462d56487e3abdbf8a61cedfe7c795a54f4a78 upstream.

It breaks the Android kernel abi and can be brought back in the future
in an abi-safe way if it is really needed.

Bug: 161946584
Change-Id: I8936edc25779838c941ebaf55f267f386d876403
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2025-01-03 07:40:38 +00:00
parent 4cf1dd1184
commit 115fd6611e
3 changed files with 64 additions and 5 deletions

View File

@@ -7,19 +7,48 @@
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
#include <asm/assembler.h> #include <asm/assembler.h>
#include <asm/thread_info.h>
/*
* If we have SMCCC v1.3 and (as is likely) no SVE state in
* the registers then set the SMCCC hint bit to say there's no
* need to preserve it. Do this by directly adjusting the SMCCC
* function value which is already stored in x0 ready to be called.
*/
SYM_FUNC_START(__arm_smccc_sve_check)
ldr_l x16, smccc_has_sve_hint
cbz x16, 2f
get_current_task x16
ldr x16, [x16, #TSK_TI_FLAGS]
tbnz x16, #TIF_FOREIGN_FPSTATE, 1f // Any live FP state?
tbnz x16, #TIF_SVE, 2f // Does that state include SVE?
1: orr x0, x0, ARM_SMCCC_1_3_SVE_HINT
2: ret
SYM_FUNC_END(__arm_smccc_sve_check)
EXPORT_SYMBOL(__arm_smccc_sve_check)
.macro SMCCC instr .macro SMCCC instr
stp x29, x30, [sp, #-16]!
mov x29, sp
alternative_if ARM64_SVE
bl __arm_smccc_sve_check
alternative_else_nop_endif
\instr #0 \instr #0
ldr x4, [sp] ldr x4, [sp, #16]
stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS] stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS] stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
ldr x4, [sp, #8] ldr x4, [sp, #24]
cbz x4, 1f /* no quirk structure */ cbz x4, 1f /* no quirk structure */
ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS] ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS]
cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6 cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6
b.ne 1f b.ne 1f
str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS] str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]
1: ret 1: ldp x29, x30, [sp], #16
ret
.endm .endm
/* /*

View File

@@ -16,6 +16,7 @@ static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE; static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE;
bool __ro_after_init smccc_trng_available = false; bool __ro_after_init smccc_trng_available = false;
u64 __ro_after_init smccc_has_sve_hint = false;
void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit) void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
{ {
@@ -23,6 +24,9 @@ void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
smccc_conduit = conduit; smccc_conduit = conduit;
smccc_trng_available = smccc_probe_trng(); smccc_trng_available = smccc_probe_trng();
if (IS_ENABLED(CONFIG_ARM64_SVE) &&
smccc_version >= ARM_SMCCC_VERSION_1_3)
smccc_has_sve_hint = true;
} }
enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void) enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void)

View File

@@ -280,6 +280,8 @@ u32 arm_smccc_get_version(void);
void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit); void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit);
extern u64 smccc_has_sve_hint;
/** /**
* struct arm_smccc_res - Result from SMC/HVC call * struct arm_smccc_res - Result from SMC/HVC call
* @a0-a3 result values from registers 0 to 3 * @a0-a3 result values from registers 0 to 3
@@ -359,6 +361,15 @@ struct arm_smccc_quirk {
} state; } state;
}; };
/**
* __arm_smccc_sve_check() - Set the SVE hint bit when doing SMC calls
*
* Sets the SMCCC hint bit to indicate if there is live state in the SVE
* registers, this modifies x0 in place and should never be called from C
* code.
*/
asmlinkage unsigned long __arm_smccc_sve_check(unsigned long x0);
/** /**
* __arm_smccc_smc() - make SMC calls * __arm_smccc_smc() - make SMC calls
* @a0-a7: arguments passed in registers 0 to 7 * @a0-a7: arguments passed in registers 0 to 7
@@ -426,6 +437,20 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
#endif #endif
/* nVHE hypervisor doesn't have a current thread so needs separate checks */
#if defined(CONFIG_ARM64_SVE) && !defined(__KVM_NVHE_HYPERVISOR__)
#define SMCCC_SVE_CHECK ALTERNATIVE("nop \n", "bl __arm_smccc_sve_check \n", \
ARM64_SVE)
#define smccc_sve_clobbers "x16", "x30", "cc",
#else
#define SMCCC_SVE_CHECK
#define smccc_sve_clobbers
#endif
#define ___count_args(_0, _1, _2, _3, _4, _5, _6, _7, _8, x, ...) x #define ___count_args(_0, _1, _2, _3, _4, _5, _6, _7, _8, x, ...) x
#define __count_args(...) \ #define __count_args(...) \
@@ -493,7 +518,7 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
#define ___constraints(count) \ #define ___constraints(count) \
: __constraint_read_ ## count \ : __constraint_read_ ## count \
: "memory" : smccc_sve_clobbers "memory"
#define __constraints(count) ___constraints(count) #define __constraints(count) ___constraints(count)
/* /*
@@ -508,7 +533,8 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
register unsigned long r2 asm("r2"); \ register unsigned long r2 asm("r2"); \
register unsigned long r3 asm("r3"); \ register unsigned long r3 asm("r3"); \
__declare_args(__count_args(__VA_ARGS__), __VA_ARGS__); \ __declare_args(__count_args(__VA_ARGS__), __VA_ARGS__); \
asm volatile(inst "\n" : \ asm volatile(SMCCC_SVE_CHECK \
inst "\n" : \
"=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3) \ "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3) \
__constraints(__count_args(__VA_ARGS__))); \ __constraints(__count_args(__VA_ARGS__))); \
if (___res) \ if (___res) \