19ff4a311SJens Wiklander // SPDX-License-Identifier: GPL-2.0+
29ff4a311SJens Wiklander /*
39ff4a311SJens Wiklander * Copyright (c) 2018 Linaro Limited
49ff4a311SJens Wiklander */
59ff4a311SJens Wiklander
69ff4a311SJens Wiklander #include <common.h>
79ff4a311SJens Wiklander #include <dm.h>
89ff4a311SJens Wiklander #include <dm/device-internal.h>
99ff4a311SJens Wiklander #include <dm/uclass-internal.h>
109ff4a311SJens Wiklander #include <tee.h>
119ff4a311SJens Wiklander
129ff4a311SJens Wiklander /**
139ff4a311SJens Wiklander * struct tee_uclass_priv - information of a TEE, stored by the uclass
149ff4a311SJens Wiklander *
159ff4a311SJens Wiklander * @list_shm: list of structe tee_shm representing memory blocks shared
169ff4a311SJens Wiklander * with the TEE.
179ff4a311SJens Wiklander */
189ff4a311SJens Wiklander struct tee_uclass_priv {
199ff4a311SJens Wiklander struct list_head list_shm;
209ff4a311SJens Wiklander };
219ff4a311SJens Wiklander
tee_get_ops(struct udevice * dev)229ff4a311SJens Wiklander static const struct tee_driver_ops *tee_get_ops(struct udevice *dev)
239ff4a311SJens Wiklander {
249ff4a311SJens Wiklander return device_get_ops(dev);
259ff4a311SJens Wiklander }
269ff4a311SJens Wiklander
tee_get_version(struct udevice * dev,struct tee_version_data * vers)279ff4a311SJens Wiklander void tee_get_version(struct udevice *dev, struct tee_version_data *vers)
289ff4a311SJens Wiklander {
299ff4a311SJens Wiklander tee_get_ops(dev)->get_version(dev, vers);
309ff4a311SJens Wiklander }
319ff4a311SJens Wiklander
tee_open_session(struct udevice * dev,struct tee_open_session_arg * arg,uint num_param,struct tee_param * param)329ff4a311SJens Wiklander int tee_open_session(struct udevice *dev, struct tee_open_session_arg *arg,
339ff4a311SJens Wiklander uint num_param, struct tee_param *param)
349ff4a311SJens Wiklander {
359ff4a311SJens Wiklander return tee_get_ops(dev)->open_session(dev, arg, num_param, param);
369ff4a311SJens Wiklander }
379ff4a311SJens Wiklander
tee_close_session(struct udevice * dev,u32 session)389ff4a311SJens Wiklander int tee_close_session(struct udevice *dev, u32 session)
399ff4a311SJens Wiklander {
409ff4a311SJens Wiklander return tee_get_ops(dev)->close_session(dev, session);
419ff4a311SJens Wiklander }
429ff4a311SJens Wiklander
tee_invoke_func(struct udevice * dev,struct tee_invoke_arg * arg,uint num_param,struct tee_param * param)439ff4a311SJens Wiklander int tee_invoke_func(struct udevice *dev, struct tee_invoke_arg *arg,
449ff4a311SJens Wiklander uint num_param, struct tee_param *param)
459ff4a311SJens Wiklander {
469ff4a311SJens Wiklander return tee_get_ops(dev)->invoke_func(dev, arg, num_param, param);
479ff4a311SJens Wiklander }
489ff4a311SJens Wiklander
__tee_shm_add(struct udevice * dev,ulong align,void * addr,ulong size,u32 flags,struct tee_shm ** shmp)499ff4a311SJens Wiklander int __tee_shm_add(struct udevice *dev, ulong align, void *addr, ulong size,
509ff4a311SJens Wiklander u32 flags, struct tee_shm **shmp)
519ff4a311SJens Wiklander {
529ff4a311SJens Wiklander struct tee_shm *shm;
539ff4a311SJens Wiklander void *p = addr;
549ff4a311SJens Wiklander int rc;
559ff4a311SJens Wiklander
569ff4a311SJens Wiklander if (flags & TEE_SHM_ALLOC) {
579ff4a311SJens Wiklander if (align)
589ff4a311SJens Wiklander p = memalign(align, size);
599ff4a311SJens Wiklander else
609ff4a311SJens Wiklander p = malloc(size);
619ff4a311SJens Wiklander }
629ff4a311SJens Wiklander if (!p)
639ff4a311SJens Wiklander return -ENOMEM;
649ff4a311SJens Wiklander
659ff4a311SJens Wiklander shm = calloc(1, sizeof(*shm));
669ff4a311SJens Wiklander if (!shm) {
679ff4a311SJens Wiklander rc = -ENOMEM;
689ff4a311SJens Wiklander goto err;
699ff4a311SJens Wiklander }
709ff4a311SJens Wiklander
719ff4a311SJens Wiklander shm->dev = dev;
729ff4a311SJens Wiklander shm->addr = p;
739ff4a311SJens Wiklander shm->size = size;
749ff4a311SJens Wiklander shm->flags = flags;
759ff4a311SJens Wiklander
769ff4a311SJens Wiklander if (flags & TEE_SHM_SEC_REGISTER) {
779ff4a311SJens Wiklander rc = tee_get_ops(dev)->shm_register(dev, shm);
789ff4a311SJens Wiklander if (rc)
799ff4a311SJens Wiklander goto err;
809ff4a311SJens Wiklander }
819ff4a311SJens Wiklander
829ff4a311SJens Wiklander if (flags & TEE_SHM_REGISTER) {
839ff4a311SJens Wiklander struct tee_uclass_priv *priv = dev_get_uclass_priv(dev);
849ff4a311SJens Wiklander
859ff4a311SJens Wiklander list_add(&shm->link, &priv->list_shm);
869ff4a311SJens Wiklander }
879ff4a311SJens Wiklander
889ff4a311SJens Wiklander *shmp = shm;
899ff4a311SJens Wiklander
909ff4a311SJens Wiklander return 0;
919ff4a311SJens Wiklander err:
929ff4a311SJens Wiklander free(shm);
939ff4a311SJens Wiklander if (flags & TEE_SHM_ALLOC)
949ff4a311SJens Wiklander free(p);
959ff4a311SJens Wiklander
969ff4a311SJens Wiklander return rc;
979ff4a311SJens Wiklander }
989ff4a311SJens Wiklander
tee_shm_alloc(struct udevice * dev,ulong size,u32 flags,struct tee_shm ** shmp)999ff4a311SJens Wiklander int tee_shm_alloc(struct udevice *dev, ulong size, u32 flags,
1009ff4a311SJens Wiklander struct tee_shm **shmp)
1019ff4a311SJens Wiklander {
1029ff4a311SJens Wiklander u32 f = flags;
1039ff4a311SJens Wiklander
1049ff4a311SJens Wiklander f |= TEE_SHM_SEC_REGISTER | TEE_SHM_REGISTER | TEE_SHM_ALLOC;
1059ff4a311SJens Wiklander
1069ff4a311SJens Wiklander return __tee_shm_add(dev, 0, NULL, size, f, shmp);
1079ff4a311SJens Wiklander }
1089ff4a311SJens Wiklander
tee_shm_register(struct udevice * dev,void * addr,ulong size,u32 flags,struct tee_shm ** shmp)1099ff4a311SJens Wiklander int tee_shm_register(struct udevice *dev, void *addr, ulong size, u32 flags,
1109ff4a311SJens Wiklander struct tee_shm **shmp)
1119ff4a311SJens Wiklander {
1129ff4a311SJens Wiklander u32 f = flags & ~TEE_SHM_ALLOC;
1139ff4a311SJens Wiklander
1149ff4a311SJens Wiklander f |= TEE_SHM_SEC_REGISTER | TEE_SHM_REGISTER;
1159ff4a311SJens Wiklander
1169ff4a311SJens Wiklander return __tee_shm_add(dev, 0, addr, size, f, shmp);
1179ff4a311SJens Wiklander }
1189ff4a311SJens Wiklander
tee_shm_free(struct tee_shm * shm)1199ff4a311SJens Wiklander void tee_shm_free(struct tee_shm *shm)
1209ff4a311SJens Wiklander {
1219ff4a311SJens Wiklander if (!shm)
1229ff4a311SJens Wiklander return;
1239ff4a311SJens Wiklander
1249ff4a311SJens Wiklander if (shm->flags & TEE_SHM_SEC_REGISTER)
1259ff4a311SJens Wiklander tee_get_ops(shm->dev)->shm_unregister(shm->dev, shm);
1269ff4a311SJens Wiklander
1279ff4a311SJens Wiklander if (shm->flags & TEE_SHM_REGISTER)
1289ff4a311SJens Wiklander list_del(&shm->link);
1299ff4a311SJens Wiklander
1309ff4a311SJens Wiklander if (shm->flags & TEE_SHM_ALLOC)
1319ff4a311SJens Wiklander free(shm->addr);
1329ff4a311SJens Wiklander
1339ff4a311SJens Wiklander free(shm);
1349ff4a311SJens Wiklander }
1359ff4a311SJens Wiklander
tee_shm_is_registered(struct tee_shm * shm,struct udevice * dev)1369ff4a311SJens Wiklander bool tee_shm_is_registered(struct tee_shm *shm, struct udevice *dev)
1379ff4a311SJens Wiklander {
1389ff4a311SJens Wiklander struct tee_uclass_priv *priv = dev_get_uclass_priv(dev);
1399ff4a311SJens Wiklander struct tee_shm *s;
1409ff4a311SJens Wiklander
1419ff4a311SJens Wiklander list_for_each_entry(s, &priv->list_shm, link)
1429ff4a311SJens Wiklander if (s == shm)
1439ff4a311SJens Wiklander return true;
1449ff4a311SJens Wiklander
1459ff4a311SJens Wiklander return false;
1469ff4a311SJens Wiklander }
1479ff4a311SJens Wiklander
tee_find_device(struct udevice * start,int (* match)(struct tee_version_data * vers,const void * data),const void * data,struct tee_version_data * vers)1489ff4a311SJens Wiklander struct udevice *tee_find_device(struct udevice *start,
1499ff4a311SJens Wiklander int (*match)(struct tee_version_data *vers,
1509ff4a311SJens Wiklander const void *data),
1519ff4a311SJens Wiklander const void *data,
1529ff4a311SJens Wiklander struct tee_version_data *vers)
1539ff4a311SJens Wiklander {
1549ff4a311SJens Wiklander struct udevice *dev = start;
1559ff4a311SJens Wiklander struct tee_version_data lv;
1569ff4a311SJens Wiklander struct tee_version_data *v = vers ? vers : &lv;
1579ff4a311SJens Wiklander
1589ff4a311SJens Wiklander if (!dev)
1599ff4a311SJens Wiklander uclass_find_first_device(UCLASS_TEE, &dev);
1609ff4a311SJens Wiklander else
1619ff4a311SJens Wiklander uclass_find_next_device(&dev);
1629ff4a311SJens Wiklander
1639ff4a311SJens Wiklander for (; dev; uclass_find_next_device(&dev)) {
1649ff4a311SJens Wiklander if (device_probe(dev))
1659ff4a311SJens Wiklander continue;
1669ff4a311SJens Wiklander tee_get_ops(dev)->get_version(dev, v);
1679ff4a311SJens Wiklander if (!match || match(v, data))
1689ff4a311SJens Wiklander return dev;
1699ff4a311SJens Wiklander }
1709ff4a311SJens Wiklander
1719ff4a311SJens Wiklander return NULL;
1729ff4a311SJens Wiklander }
1739ff4a311SJens Wiklander
tee_pre_probe(struct udevice * dev)1749ff4a311SJens Wiklander static int tee_pre_probe(struct udevice *dev)
1759ff4a311SJens Wiklander {
1769ff4a311SJens Wiklander struct tee_uclass_priv *priv = dev_get_uclass_priv(dev);
1779ff4a311SJens Wiklander
1789ff4a311SJens Wiklander INIT_LIST_HEAD(&priv->list_shm);
1799ff4a311SJens Wiklander
1809ff4a311SJens Wiklander return 0;
1819ff4a311SJens Wiklander }
1829ff4a311SJens Wiklander
tee_pre_remove(struct udevice * dev)1839ff4a311SJens Wiklander static int tee_pre_remove(struct udevice *dev)
1849ff4a311SJens Wiklander {
1859ff4a311SJens Wiklander struct tee_uclass_priv *priv = dev_get_uclass_priv(dev);
1869ff4a311SJens Wiklander struct tee_shm *shm;
1879ff4a311SJens Wiklander
1889ff4a311SJens Wiklander /*
1899ff4a311SJens Wiklander * Any remaining shared memory must be unregistered now as U-Boot
1909ff4a311SJens Wiklander * is about to hand over to the next stage and that memory will be
1919ff4a311SJens Wiklander * reused.
1929ff4a311SJens Wiklander */
1939ff4a311SJens Wiklander while (!list_empty(&priv->list_shm)) {
1949ff4a311SJens Wiklander shm = list_first_entry(&priv->list_shm, struct tee_shm, link);
1959ff4a311SJens Wiklander debug("%s: freeing leftover shm %p (size %lu, flags %#x)\n",
1969ff4a311SJens Wiklander __func__, (void *)shm, shm->size, shm->flags);
1979ff4a311SJens Wiklander tee_shm_free(shm);
1989ff4a311SJens Wiklander }
1999ff4a311SJens Wiklander
2009ff4a311SJens Wiklander return 0;
2019ff4a311SJens Wiklander }
2029ff4a311SJens Wiklander
2039ff4a311SJens Wiklander UCLASS_DRIVER(tee) = {
2049ff4a311SJens Wiklander .id = UCLASS_TEE,
2059ff4a311SJens Wiklander .name = "tee",
2069ff4a311SJens Wiklander .per_device_auto_alloc_size = sizeof(struct tee_uclass_priv),
2079ff4a311SJens Wiklander .pre_probe = tee_pre_probe,
2089ff4a311SJens Wiklander .pre_remove = tee_pre_remove,
2099ff4a311SJens Wiklander };
210*1cc8cc4eSJens Wiklander
tee_optee_ta_uuid_from_octets(struct tee_optee_ta_uuid * d,const u8 s[TEE_UUID_LEN])211*1cc8cc4eSJens Wiklander void tee_optee_ta_uuid_from_octets(struct tee_optee_ta_uuid *d,
212*1cc8cc4eSJens Wiklander const u8 s[TEE_UUID_LEN])
213*1cc8cc4eSJens Wiklander {
214*1cc8cc4eSJens Wiklander d->time_low = ((u32)s[0] << 24) | ((u32)s[1] << 16) |
215*1cc8cc4eSJens Wiklander ((u32)s[2] << 8) | s[3],
216*1cc8cc4eSJens Wiklander d->time_mid = ((u32)s[4] << 8) | s[5];
217*1cc8cc4eSJens Wiklander d->time_hi_and_version = ((u32)s[6] << 8) | s[7];
218*1cc8cc4eSJens Wiklander memcpy(d->clock_seq_and_node, s + 8, sizeof(d->clock_seq_and_node));
219*1cc8cc4eSJens Wiklander }
220*1cc8cc4eSJens Wiklander
tee_optee_ta_uuid_to_octets(u8 d[TEE_UUID_LEN],const struct tee_optee_ta_uuid * s)221*1cc8cc4eSJens Wiklander void tee_optee_ta_uuid_to_octets(u8 d[TEE_UUID_LEN],
222*1cc8cc4eSJens Wiklander const struct tee_optee_ta_uuid *s)
223*1cc8cc4eSJens Wiklander {
224*1cc8cc4eSJens Wiklander d[0] = s->time_low >> 24;
225*1cc8cc4eSJens Wiklander d[1] = s->time_low >> 16;
226*1cc8cc4eSJens Wiklander d[2] = s->time_low >> 8;
227*1cc8cc4eSJens Wiklander d[3] = s->time_low;
228*1cc8cc4eSJens Wiklander d[4] = s->time_mid >> 8;
229*1cc8cc4eSJens Wiklander d[5] = s->time_mid;
230*1cc8cc4eSJens Wiklander d[6] = s->time_hi_and_version >> 8;
231*1cc8cc4eSJens Wiklander d[7] = s->time_hi_and_version;
232*1cc8cc4eSJens Wiklander memcpy(d + 8, s->clock_seq_and_node, sizeof(s->clock_seq_and_node));
233*1cc8cc4eSJens Wiklander }
234