1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2020 Arm Limited 4 */ 5 6 #define pr_fmt(fmt) "smccc: " fmt 7 8 #include <linux/cache.h> 9 #include <linux/init.h> 10 #include <linux/arm-smccc.h> 11 #include <linux/kernel.h> 12 #include <linux/arm-smccc-bus.h> 13 #include <linux/arm-smccc-rsi.h> 14 15 #include <asm/archrandom.h> 16 17 static u32 smccc_version = ARM_SMCCC_VERSION_1_0; 18 static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE; 19 20 bool __ro_after_init smccc_trng_available = false; 21 s32 __ro_after_init smccc_soc_id_version = SMCCC_RET_NOT_SUPPORTED; 22 s32 __ro_after_init smccc_soc_id_revision = SMCCC_RET_NOT_SUPPORTED; 23 24 void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit) 25 { 26 struct arm_smccc_res res; 27 28 smccc_version = version; 29 smccc_conduit = conduit; 30 31 smccc_trng_available = smccc_probe_trng(); 32 33 if ((smccc_version >= ARM_SMCCC_VERSION_1_2) && 34 (smccc_conduit != SMCCC_CONDUIT_NONE)) { 35 arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, 36 ARM_SMCCC_ARCH_SOC_ID, &res); 37 if ((s32)res.a0 >= 0) { 38 arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 0, &res); 39 smccc_soc_id_version = (s32)res.a0; 40 arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 1, &res); 41 smccc_soc_id_revision = (s32)res.a0; 42 } 43 } 44 } 45 46 enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void) 47 { 48 if (smccc_version < ARM_SMCCC_VERSION_1_1) 49 return SMCCC_CONDUIT_NONE; 50 51 return smccc_conduit; 52 } 53 EXPORT_SYMBOL_GPL(arm_smccc_1_1_get_conduit); 54 55 u32 arm_smccc_get_version(void) 56 { 57 return smccc_version; 58 } 59 EXPORT_SYMBOL_GPL(arm_smccc_get_version); 60 61 s32 arm_smccc_get_soc_id_version(void) 62 { 63 return smccc_soc_id_version; 64 } 65 66 s32 arm_smccc_get_soc_id_revision(void) 67 { 68 return smccc_soc_id_revision; 69 } 70 EXPORT_SYMBOL_GPL(arm_smccc_get_soc_id_revision); 71 72 bool arm_smccc_hypervisor_has_uuid(const uuid_t *hyp_uuid) 73 { 74 struct arm_smccc_res res = {}; 75 uuid_t uuid; 76 77 arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, &res); 78 if (res.a0 == SMCCC_RET_NOT_SUPPORTED) 79 return false; 80 81 uuid = smccc_res_to_uuid(res.a0, res.a1, res.a2, res.a3); 82 return uuid_equal(&uuid, hyp_uuid); 83 } 84 EXPORT_SYMBOL_GPL(arm_smccc_hypervisor_has_uuid); 85 86 struct smccc_device_info { 87 u32 func_id; 88 bool requires_smc; 89 const char *device_name; 90 }; 91 92 static const struct smccc_device_info smccc_devices[] __initconst = { 93 { 94 .func_id = ARM_SMCCC_TRNG_VERSION, 95 .requires_smc = false, 96 .device_name = "arm-smccc-trng", 97 }, 98 { 99 .func_id = SMC_RSI_ABI_VERSION, 100 .requires_smc = true, 101 .device_name = "arm-rsi", 102 }, 103 }; 104 105 static bool __init smccc_probe_smccc_device(const struct smccc_device_info *smccc_dev) 106 { 107 int ret; 108 struct arm_smccc_res res = {}; 109 110 if (smccc_conduit == SMCCC_CONDUIT_NONE) 111 return false; 112 113 if (smccc_dev->requires_smc && smccc_conduit != SMCCC_CONDUIT_SMC) 114 return false; 115 116 if (IS_ENABLED(CONFIG_ARM) && ARM_SMCCC_IS_64(smccc_dev->func_id)) 117 return false; 118 119 arm_smccc_1_1_invoke(smccc_dev->func_id, 0, &res); 120 ret = res.a0; 121 122 if (ret == SMCCC_RET_NOT_SUPPORTED) 123 return false; 124 125 return true; 126 } 127 128 static int __init smccc_devices_init(void) 129 { 130 struct arm_smccc_device *sdev; 131 const struct smccc_device_info *smccc_dev; 132 133 for (int i = 0; i < ARRAY_SIZE(smccc_devices); i++) { 134 smccc_dev = &smccc_devices[i]; 135 136 if (!smccc_probe_smccc_device(smccc_dev)) 137 continue; 138 139 sdev = arm_smccc_device_register(smccc_dev->device_name, smccc_dev->func_id); 140 if (IS_ERR(sdev)) 141 pr_err("%s: could not register device: %pe\n", 142 smccc_dev->device_name, sdev); 143 } 144 145 return 0; 146 } 147 device_initcall(smccc_devices_init); 148