xref: /openbmc/u-boot/drivers/tee/tee-uclass.c (revision 5c8fd32b)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2018 Linaro Limited
4  */
5 
6 #include <common.h>
7 #include <dm.h>
8 #include <dm/device-internal.h>
9 #include <dm/uclass-internal.h>
10 #include <tee.h>
11 
12 /**
13  * struct tee_uclass_priv - information of a TEE, stored by the uclass
14  *
15  * @list_shm:	list of structe tee_shm representing memory blocks shared
16  *		with the TEE.
17  */
18 struct tee_uclass_priv {
19 	struct list_head list_shm;
20 };
21 
22 static const struct tee_driver_ops *tee_get_ops(struct udevice *dev)
23 {
24 	return device_get_ops(dev);
25 }
26 
27 void tee_get_version(struct udevice *dev, struct tee_version_data *vers)
28 {
29 	tee_get_ops(dev)->get_version(dev, vers);
30 }
31 
32 int tee_open_session(struct udevice *dev, struct tee_open_session_arg *arg,
33 		     uint num_param, struct tee_param *param)
34 {
35 	return tee_get_ops(dev)->open_session(dev, arg, num_param, param);
36 }
37 
38 int tee_close_session(struct udevice *dev, u32 session)
39 {
40 	return tee_get_ops(dev)->close_session(dev, session);
41 }
42 
43 int tee_invoke_func(struct udevice *dev, struct tee_invoke_arg *arg,
44 		    uint num_param, struct tee_param *param)
45 {
46 	return tee_get_ops(dev)->invoke_func(dev, arg, num_param, param);
47 }
48 
49 int __tee_shm_add(struct udevice *dev, ulong align, void *addr, ulong size,
50 		  u32 flags, struct tee_shm **shmp)
51 {
52 	struct tee_shm *shm;
53 	void *p = addr;
54 	int rc;
55 
56 	if (flags & TEE_SHM_ALLOC) {
57 		if (align)
58 			p = memalign(align, size);
59 		else
60 			p = malloc(size);
61 	}
62 	if (!p)
63 		return -ENOMEM;
64 
65 	shm = calloc(1, sizeof(*shm));
66 	if (!shm) {
67 		rc = -ENOMEM;
68 		goto err;
69 	}
70 
71 	shm->dev = dev;
72 	shm->addr = p;
73 	shm->size = size;
74 	shm->flags = flags;
75 
76 	if (flags & TEE_SHM_SEC_REGISTER) {
77 		rc = tee_get_ops(dev)->shm_register(dev, shm);
78 		if (rc)
79 			goto err;
80 	}
81 
82 	if (flags & TEE_SHM_REGISTER) {
83 		struct tee_uclass_priv *priv = dev_get_uclass_priv(dev);
84 
85 		list_add(&shm->link, &priv->list_shm);
86 	}
87 
88 	*shmp = shm;
89 
90 	return 0;
91 err:
92 	free(shm);
93 	if (flags & TEE_SHM_ALLOC)
94 		free(p);
95 
96 	return rc;
97 }
98 
99 int tee_shm_alloc(struct udevice *dev, ulong size, u32 flags,
100 		  struct tee_shm **shmp)
101 {
102 	u32 f = flags;
103 
104 	f |= TEE_SHM_SEC_REGISTER | TEE_SHM_REGISTER | TEE_SHM_ALLOC;
105 
106 	return __tee_shm_add(dev, 0, NULL, size, f, shmp);
107 }
108 
109 int tee_shm_register(struct udevice *dev, void *addr, ulong size, u32 flags,
110 		     struct tee_shm **shmp)
111 {
112 	u32 f = flags & ~TEE_SHM_ALLOC;
113 
114 	f |= TEE_SHM_SEC_REGISTER | TEE_SHM_REGISTER;
115 
116 	return __tee_shm_add(dev, 0, addr, size, f, shmp);
117 }
118 
119 void tee_shm_free(struct tee_shm *shm)
120 {
121 	if (!shm)
122 		return;
123 
124 	if (shm->flags & TEE_SHM_SEC_REGISTER)
125 		tee_get_ops(shm->dev)->shm_unregister(shm->dev, shm);
126 
127 	if (shm->flags & TEE_SHM_REGISTER)
128 		list_del(&shm->link);
129 
130 	if (shm->flags & TEE_SHM_ALLOC)
131 		free(shm->addr);
132 
133 	free(shm);
134 }
135 
136 bool tee_shm_is_registered(struct tee_shm *shm, struct udevice *dev)
137 {
138 	struct tee_uclass_priv *priv = dev_get_uclass_priv(dev);
139 	struct tee_shm *s;
140 
141 	list_for_each_entry(s, &priv->list_shm, link)
142 		if (s == shm)
143 			return true;
144 
145 	return false;
146 }
147 
148 struct udevice *tee_find_device(struct udevice *start,
149 				int (*match)(struct tee_version_data *vers,
150 					     const void *data),
151 				const void *data,
152 				struct tee_version_data *vers)
153 {
154 	struct udevice *dev = start;
155 	struct tee_version_data lv;
156 	struct tee_version_data *v = vers ? vers : &lv;
157 
158 	if (!dev)
159 		uclass_find_first_device(UCLASS_TEE, &dev);
160 	else
161 		uclass_find_next_device(&dev);
162 
163 	for (; dev; uclass_find_next_device(&dev)) {
164 		if (device_probe(dev))
165 			continue;
166 		tee_get_ops(dev)->get_version(dev, v);
167 		if (!match || match(v, data))
168 			return dev;
169 	}
170 
171 	return NULL;
172 }
173 
174 static int tee_pre_probe(struct udevice *dev)
175 {
176 	struct tee_uclass_priv *priv = dev_get_uclass_priv(dev);
177 
178 	INIT_LIST_HEAD(&priv->list_shm);
179 
180 	return 0;
181 }
182 
183 static int tee_pre_remove(struct udevice *dev)
184 {
185 	struct tee_uclass_priv *priv = dev_get_uclass_priv(dev);
186 	struct tee_shm *shm;
187 
188 	/*
189 	 * Any remaining shared memory must be unregistered now as U-Boot
190 	 * is about to hand over to the next stage and that memory will be
191 	 * reused.
192 	 */
193 	while (!list_empty(&priv->list_shm)) {
194 		shm = list_first_entry(&priv->list_shm, struct tee_shm, link);
195 		debug("%s: freeing leftover shm %p (size %lu, flags %#x)\n",
196 		      __func__, (void *)shm, shm->size, shm->flags);
197 		tee_shm_free(shm);
198 	}
199 
200 	return 0;
201 }
202 
203 UCLASS_DRIVER(tee) = {
204 	.id = UCLASS_TEE,
205 	.name = "tee",
206 	.per_device_auto_alloc_size = sizeof(struct tee_uclass_priv),
207 	.pre_probe = tee_pre_probe,
208 	.pre_remove = tee_pre_remove,
209 };
210 
211 void tee_optee_ta_uuid_from_octets(struct tee_optee_ta_uuid *d,
212 				   const u8 s[TEE_UUID_LEN])
213 {
214 	d->time_low = ((u32)s[0] << 24) | ((u32)s[1] << 16) |
215 		      ((u32)s[2] << 8) | s[3],
216 	d->time_mid = ((u32)s[4] << 8) | s[5];
217 	d->time_hi_and_version = ((u32)s[6] << 8) | s[7];
218 	memcpy(d->clock_seq_and_node, s + 8, sizeof(d->clock_seq_and_node));
219 }
220 
221 void tee_optee_ta_uuid_to_octets(u8 d[TEE_UUID_LEN],
222 				 const struct tee_optee_ta_uuid *s)
223 {
224 	d[0] = s->time_low >> 24;
225 	d[1] = s->time_low >> 16;
226 	d[2] = s->time_low >> 8;
227 	d[3] = s->time_low;
228 	d[4] = s->time_mid >> 8;
229 	d[5] = s->time_mid;
230 	d[6] = s->time_hi_and_version >> 8;
231 	d[7] = s->time_hi_and_version;
232 	memcpy(d + 8, s->clock_seq_and_node, sizeof(s->clock_seq_and_node));
233 }
234