Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'tee-sysfs-for-6.20' of git://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee into soc/drivers

TEE sysfs for 6.20

- Add an optional generic sysfs attribute for TEE revision
- Implement revision reporting for OP-TEE using both SMC and FF-A ABIs

* tag 'tee-sysfs-for-6.20' of git://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee:
tee: optee: store OS revision for TEE core
tee: add revision sysfs attribute

Signed-off-by: Arnd Bergmann <arnd@arndb.de>

+163 -18
+10
Documentation/ABI/testing/sysfs-class-tee
··· 13 13 space if the variable is absent. The primary purpose 14 14 of this variable is to let systemd know whether 15 15 tee-supplicant is needed in the early boot with initramfs. 16 + 17 + What: /sys/class/tee/tee{,priv}X/revision 18 + Date: Jan 2026 19 + KernelVersion: 6.19 20 + Contact: op-tee@lists.trustedfirmware.org 21 + Description: 22 + Read-only revision string reported by the TEE driver. This is 23 + for diagnostics only and must not be used to infer feature 24 + support. Use TEE_IOC_VERSION for capability and compatibility 25 + checks.
+23
drivers/tee/optee/core.c
··· 63 63 return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask); 64 64 } 65 65 66 + int optee_get_revision(struct tee_device *teedev, char *buf, size_t len) 67 + { 68 + struct optee *optee = tee_get_drvdata(teedev); 69 + u64 build_id; 70 + 71 + if (!optee) 72 + return -ENODEV; 73 + if (!buf || !len) 74 + return -EINVAL; 75 + 76 + build_id = optee->revision.os_build_id; 77 + if (build_id) 78 + scnprintf(buf, len, "%u.%u (%016llx)", 79 + optee->revision.os_major, 80 + optee->revision.os_minor, 81 + (unsigned long long)build_id); 82 + else 83 + scnprintf(buf, len, "%u.%u", optee->revision.os_major, 84 + optee->revision.os_minor); 85 + 86 + return 0; 87 + } 88 + 66 89 static void optee_bus_scan(struct work_struct *work) 67 90 { 68 91 WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
+40 -14
drivers/tee/optee/ffa_abi.c
··· 775 775 * with a matching configuration. 776 776 */ 777 777 778 + static bool optee_ffa_get_os_revision(struct ffa_device *ffa_dev, 779 + const struct ffa_ops *ops, 780 + struct optee_revision *revision) 781 + { 782 + const struct ffa_msg_ops *msg_ops = ops->msg_ops; 783 + struct ffa_send_direct_data data = { 784 + .data0 = OPTEE_FFA_GET_OS_VERSION, 785 + }; 786 + int rc; 787 + 788 + msg_ops->mode_32bit_set(ffa_dev); 789 + 790 + rc = msg_ops->sync_send_receive(ffa_dev, &data); 791 + if (rc) { 792 + pr_err("Unexpected error %d\n", rc); 793 + return false; 794 + } 795 + 796 + if (revision) { 797 + revision->os_major = data.data0; 798 + revision->os_minor = data.data1; 799 + revision->os_build_id = data.data2; 800 + } 801 + 802 + if (data.data2) 803 + pr_info("revision %lu.%lu (%08lx)", 804 + data.data0, data.data1, data.data2); 805 + else 806 + pr_info("revision %lu.%lu", data.data0, data.data1); 807 + 808 + return true; 809 + } 810 + 778 811 static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev, 779 812 const struct ffa_ops *ops) 780 813 { ··· 830 797 data.data0, data.data1); 831 798 return false; 832 799 } 833 - 834 - data = (struct ffa_send_direct_data){ 835 - .data0 = OPTEE_FFA_GET_OS_VERSION, 836 - }; 837 - rc = msg_ops->sync_send_receive(ffa_dev, &data); 838 - if (rc) { 839 - pr_err("Unexpected error %d\n", rc); 840 - return false; 841 - } 842 - if (data.data2) 843 - pr_info("revision %lu.%lu (%08lx)", 844 - data.data0, data.data1, data.data2); 845 - else 846 - pr_info("revision %lu.%lu", data.data0, data.data1); 847 800 848 801 return true; 849 802 } ··· 919 900 920 901 static const struct tee_driver_ops optee_ffa_clnt_ops = { 921 902 .get_version = optee_ffa_get_version, 903 + .get_tee_revision = optee_get_revision, 922 904 .open = optee_ffa_open, 923 905 .release = optee_release, 924 906 .open_session = optee_open_session, ··· 938 918 939 919 static const struct tee_driver_ops optee_ffa_supp_ops = { 940 920 .get_version = optee_ffa_get_version, 921 + .get_tee_revision = optee_get_revision, 941 922 .open = optee_ffa_open, 942 923 .release = optee_release_supp, 943 924 .supp_recv = optee_supp_recv, ··· 1080 1059 optee = kzalloc(sizeof(*optee), GFP_KERNEL); 1081 1060 if (!optee) 1082 1061 return -ENOMEM; 1062 + 1063 + if (!optee_ffa_get_os_revision(ffa_dev, ffa_ops, &optee->revision)) { 1064 + rc = -EINVAL; 1065 + goto err_free_optee; 1066 + } 1083 1067 1084 1068 pool = optee_ffa_shm_pool_alloc_pages(); 1085 1069 if (IS_ERR(pool)) {
+19
drivers/tee/optee/optee_private.h
··· 172 172 struct optee; 173 173 174 174 /** 175 + * struct optee_revision - OP-TEE OS revision reported by secure world 176 + * @os_major: OP-TEE OS major version 177 + * @os_minor: OP-TEE OS minor version 178 + * @os_build_id: OP-TEE OS build identifier (0 if unspecified) 179 + * 180 + * Values come from OPTEE_SMC_CALL_GET_OS_REVISION (SMC ABI) or 181 + * OPTEE_FFA_GET_OS_VERSION (FF-A ABI); this is the trusted OS revision, not an 182 + * FF-A ABI version. 183 + */ 184 + struct optee_revision { 185 + u32 os_major; 186 + u32 os_minor; 187 + u64 os_build_id; 188 + }; 189 + 190 + int optee_get_revision(struct tee_device *teedev, char *buf, size_t len); 191 + 192 + /** 175 193 * struct optee_ops - OP-TEE driver internal operations 176 194 * @do_call_with_arg: enters OP-TEE in secure world 177 195 * @to_msg_param: converts from struct tee_param to OPTEE_MSG parameters ··· 267 249 bool in_kernel_rpmb_routing; 268 250 struct work_struct scan_bus_work; 269 251 struct work_struct rpmb_scan_bus_work; 252 + struct optee_revision revision; 270 253 }; 271 254 272 255 struct optee_session {
+12 -3
drivers/tee/optee/smc_abi.c
··· 1242 1242 1243 1243 static const struct tee_driver_ops optee_clnt_ops = { 1244 1244 .get_version = optee_get_version, 1245 + .get_tee_revision = optee_get_revision, 1245 1246 .open = optee_smc_open, 1246 1247 .release = optee_release, 1247 1248 .open_session = optee_open_session, ··· 1262 1261 1263 1262 static const struct tee_driver_ops optee_supp_ops = { 1264 1263 .get_version = optee_get_version, 1264 + .get_tee_revision = optee_get_revision, 1265 1265 .open = optee_smc_open, 1266 1266 .release = optee_release_supp, 1267 1267 .supp_recv = optee_supp_recv, ··· 1325 1323 } 1326 1324 #endif 1327 1325 1328 - static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn) 1326 + static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn, 1327 + struct optee_revision *revision) 1329 1328 { 1330 1329 union { 1331 1330 struct arm_smccc_res smccc; ··· 1339 1336 1340 1337 invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0, 1341 1338 &res.smccc); 1339 + 1340 + if (revision) { 1341 + revision->os_major = res.result.major; 1342 + revision->os_minor = res.result.minor; 1343 + revision->os_build_id = res.result.build_id; 1344 + } 1342 1345 1343 1346 if (res.result.build_id) 1344 1347 pr_info("revision %lu.%lu (%0*lx)", res.result.major, ··· 1754 1745 return -EINVAL; 1755 1746 } 1756 1747 1757 - optee_msg_get_os_revision(invoke_fn); 1758 - 1759 1748 if (!optee_msg_api_revision_is_compatible(invoke_fn)) { 1760 1749 pr_warn("api revision mismatch\n"); 1761 1750 return -EINVAL; ··· 1821 1814 rc = -ENOMEM; 1822 1815 goto err_free_shm_pool; 1823 1816 } 1817 + 1818 + optee_msg_get_os_revision(invoke_fn, &optee->revision); 1824 1819 1825 1820 optee->ops = &optee_ops; 1826 1821 optee->smc.invoke_fn = invoke_fn;
+50 -1
drivers/tee/tee_core.c
··· 1146 1146 NULL 1147 1147 }; 1148 1148 1149 - ATTRIBUTE_GROUPS(tee_dev); 1149 + static const struct attribute_group tee_dev_group = { 1150 + .attrs = tee_dev_attrs, 1151 + }; 1152 + 1153 + static ssize_t revision_show(struct device *dev, 1154 + struct device_attribute *attr, char *buf) 1155 + { 1156 + struct tee_device *teedev = container_of(dev, struct tee_device, dev); 1157 + char version[TEE_REVISION_STR_SIZE]; 1158 + int ret; 1159 + 1160 + if (!teedev->desc->ops->get_tee_revision) 1161 + return -ENODEV; 1162 + 1163 + ret = teedev->desc->ops->get_tee_revision(teedev, version, 1164 + sizeof(version)); 1165 + if (ret) 1166 + return ret; 1167 + 1168 + return sysfs_emit(buf, "%s\n", version); 1169 + } 1170 + static DEVICE_ATTR_RO(revision); 1171 + 1172 + static struct attribute *tee_revision_attrs[] = { 1173 + &dev_attr_revision.attr, 1174 + NULL 1175 + }; 1176 + 1177 + static umode_t tee_revision_attr_is_visible(struct kobject *kobj, 1178 + struct attribute *attr, int n) 1179 + { 1180 + struct device *dev = kobj_to_dev(kobj); 1181 + struct tee_device *teedev = container_of(dev, struct tee_device, dev); 1182 + 1183 + if (teedev->desc->ops->get_tee_revision) 1184 + return attr->mode; 1185 + 1186 + return 0; 1187 + } 1188 + 1189 + static const struct attribute_group tee_revision_group = { 1190 + .attrs = tee_revision_attrs, 1191 + .is_visible = tee_revision_attr_is_visible, 1192 + }; 1193 + 1194 + static const struct attribute_group *tee_dev_groups[] = { 1195 + &tee_dev_group, 1196 + &tee_revision_group, 1197 + NULL 1198 + }; 1150 1199 1151 1200 static const struct class tee_class = { 1152 1201 .name = "tee",
+9
include/linux/tee_core.h
··· 76 76 /** 77 77 * struct tee_driver_ops - driver operations vtable 78 78 * @get_version: returns version of driver 79 + * @get_tee_revision: returns revision string (diagnostic only); 80 + * do not infer feature support from this, use 81 + * TEE_IOC_VERSION instead 79 82 * @open: called for a context when the device file is opened 80 83 * @close_context: called when the device file is closed 81 84 * @release: called to release the context ··· 98 95 * client closes the device file, even if there are existing references to the 99 96 * context. The TEE driver can use @close_context to start cleaning up. 100 97 */ 98 + 101 99 struct tee_driver_ops { 102 100 void (*get_version)(struct tee_device *teedev, 103 101 struct tee_ioctl_version_data *vers); 102 + int (*get_tee_revision)(struct tee_device *teedev, 103 + char *buf, size_t len); 104 104 int (*open)(struct tee_context *ctx); 105 105 void (*close_context)(struct tee_context *ctx); 106 106 void (*release)(struct tee_context *ctx); ··· 128 122 unsigned long start); 129 123 int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm); 130 124 }; 125 + 126 + /* Size for TEE revision string buffer used by get_tee_revision(). */ 127 + #define TEE_REVISION_STR_SIZE 128 131 128 132 129 /** 133 130 * struct tee_desc - Describes the TEE driver to the subsystem