xref: /optee_os/core/arch/arm/kernel/virtualization.c (revision 11d8578d93f0aee793b28221b06187f62bb7b24b)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2018, EPAM Systems. All rights reserved.
4  * Copyright (c) 2023-2024, Linaro Limited
5  */
6 
7 #include <bitstring.h>
8 #include <compiler.h>
9 #include <kernel/boot.h>
10 #include <kernel/linker.h>
11 #include <kernel/misc.h>
12 #include <kernel/mutex.h>
13 #include <kernel/notif.h>
14 #include <kernel/panic.h>
15 #include <kernel/refcount.h>
16 #include <kernel/spinlock.h>
17 #include <kernel/thread_spmc.h>
18 #include <kernel/virtualization.h>
19 #include <mm/core_memprot.h>
20 #include <mm/core_mmu.h>
21 #include <mm/tee_mm.h>
22 #include <platform_config.h>
23 #include <sm/optee_smc.h>
24 #include <string.h>
25 #include <string_ext.h>
26 #include <util.h>
27 
28 LIST_HEAD(prtn_list_head, guest_partition);
29 
30 static unsigned int prtn_list_lock __nex_data = SPINLOCK_UNLOCK;
31 
32 static struct prtn_list_head prtn_list __nex_data =
33 	LIST_HEAD_INITIALIZER(prtn_list);
34 static struct prtn_list_head prtn_destroy_list __nex_data =
35 	LIST_HEAD_INITIALIZER(prtn_destroy_list);
36 
37 /* Free pages used for guest partitions */
38 tee_mm_pool_t virt_mapper_pool __nex_bss;
39 
40 /* Memory used by OP-TEE core */
41 struct memory_map *kmem_map __nex_bss;
42 
43 struct guest_spec_data {
44 	size_t size;
45 	void (*destroy)(void *data);
46 };
47 
48 static bool add_disabled __nex_bss;
49 static unsigned gsd_count __nex_bss;
50 static struct guest_spec_data *gsd_array __nex_bss;
51 
52 struct guest_partition {
53 	LIST_ENTRY(guest_partition) link;
54 	struct mmu_partition *mmu_prtn;
55 	struct memory_map mem_map;
56 	struct mutex mutex;
57 	void *tables_va;
58 	tee_mm_entry_t *tee_ram;
59 	tee_mm_entry_t *ta_ram;
60 	tee_mm_entry_t *tables;
61 	bool runtime_initialized;
62 	bool got_guest_destroyed;
63 	bool shutting_down;
64 	uint16_t id;
65 	struct refcount refc;
66 #ifdef CFG_CORE_SEL1_SPMC
67 	uint64_t cookies[SPMC_CORE_SEL1_MAX_SHM_COUNT];
68 	uint8_t cookie_count;
69 	bitstr_t bit_decl(shm_bits, SPMC_CORE_SEL1_MAX_SHM_COUNT);
70 #endif
71 	void **data_array;
72 };
73 
74 struct guest_partition *current_partition[CFG_TEE_CORE_NB_CORE] __nex_bss;
75 
76 static struct guest_partition *get_current_prtn(void)
77 {
78 	struct guest_partition *ret;
79 	uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_FOREIGN_INTR);
80 
81 	ret = current_partition[get_core_pos()];
82 
83 	thread_unmask_exceptions(exceptions);
84 
85 	return ret;
86 }
87 
88 uint16_t virt_get_current_guest_id(void)
89 {
90 	struct guest_partition *prtn = get_current_prtn();
91 
92 	if (!prtn)
93 		return 0;
94 	return prtn->id;
95 }
96 
97 static void set_current_prtn(struct guest_partition *prtn)
98 {
99 	uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_FOREIGN_INTR);
100 
101 	current_partition[get_core_pos()] = prtn;
102 
103 	thread_unmask_exceptions(exceptions);
104 }
105 
106 static size_t get_ta_ram_size(void)
107 {
108 	size_t ta_size = 0;
109 
110 	core_mmu_get_ta_range(NULL, &ta_size);
111 	return ROUNDDOWN(ta_size / CFG_VIRT_GUEST_COUNT - VCORE_UNPG_RW_SZ -
112 			 core_mmu_get_total_pages_size(), SMALL_PAGE_SIZE);
113 }
114 
115 static TEE_Result prepare_memory_map(struct memory_map *mem_map,
116 				     paddr_t tee_data, paddr_t ta_ram)
117 {
118 	struct tee_mmap_region *map = NULL;
119 	vaddr_t max_va = 0;
120 	size_t n = 0;
121 	/*
122 	 * This function assumes that at time of operation,
123 	 * kmemory_map (aka static_memory_map from core_mmu.c)
124 	 * will not be altered. This is true, because all
125 	 * changes to static_memory_map are done during
126 	 * OP-TEE initialization, while this function will
127 	 * called when hypervisor creates a guest.
128 	 */
129 
130 	/* Allocate entries for virtual guest map */
131 	mem_map->map = nex_calloc(kmem_map->count + 1, sizeof(*mem_map->map));
132 	if (!mem_map->map)
133 		return TEE_ERROR_OUT_OF_MEMORY;
134 	mem_map->count = kmem_map->count;
135 	mem_map->alloc_count = kmem_map->count + 1;
136 
137 	memcpy(mem_map->map, kmem_map->map,
138 	       sizeof(*mem_map->map) * mem_map->count);
139 
140 	/* Map TEE .data and .bss sections */
141 	for (n = 0; n < mem_map->count; n++) {
142 		map = mem_map->map + n;
143 		if (map->va == (vaddr_t)(VCORE_UNPG_RW_PA)) {
144 			map->type = MEM_AREA_TEE_RAM_RW;
145 			map->attr = core_mmu_type_to_attr(map->type);
146 			map->pa = tee_data;
147 		}
148 		if (map->va + map->size > max_va)
149 			max_va = map->va + map->size;
150 	}
151 
152 	/* Map TA_RAM */
153 	mem_map->count++;
154 	map = ins_array_elem(mem_map->map, mem_map->count,
155 			     sizeof(*mem_map->map), n, NULL);
156 	map->region_size = SMALL_PAGE_SIZE;
157 	map->va = ROUNDUP(max_va, map->region_size);
158 	map->va += (ta_ram - map->va) & CORE_MMU_PGDIR_MASK;
159 	map->pa = ta_ram;
160 	map->size = get_ta_ram_size();
161 	map->type = MEM_AREA_TA_RAM;
162 	map->attr = core_mmu_type_to_attr(map->type);
163 
164 	DMSG("New map (%08lx):",  (vaddr_t)(VCORE_UNPG_RW_PA));
165 
166 	for (n = 0; n < mem_map->count; n++)
167 		DMSG("T: %-16s rsz: %08x, pa: %08lx, va: %08lx, sz: %08lx attr: %x",
168 		     teecore_memtype_name(mem_map->map[n].type),
169 		     mem_map->map[n].region_size, mem_map->map[n].pa,
170 		     mem_map->map[n].va, mem_map->map[n].size,
171 		     mem_map->map[n].attr);
172 	return TEE_SUCCESS;
173 }
174 
175 void virt_init_memory(struct memory_map *mem_map, paddr_t secmem0_base,
176 		      paddr_size_t secmem0_size, paddr_t secmem1_base,
177 		      paddr_size_t secmem1_size)
178 {
179 	paddr_size_t size = secmem0_size;
180 	paddr_t base = secmem0_base;
181 	size_t n = 0;
182 
183 	if (secmem1_size) {
184 		assert(secmem0_base + secmem0_size <= secmem1_base);
185 		size = secmem1_base + secmem1_size - base;
186 	}
187 
188 	/* Init page pool that covers all secure RAM */
189 	if (!tee_mm_init(&virt_mapper_pool, base, size,
190 			 SMALL_PAGE_SHIFT, TEE_MM_POOL_NEX_MALLOC))
191 		panic("Can't create pool with free pages");
192 	DMSG("Created virtual mapper pool from %"PRIxPA" to %"PRIxPA,
193 	     base, base + size);
194 
195 	if (secmem1_size) {
196 		/* Carve out an eventual gap between secmem0 and secmem1 */
197 		base = secmem0_base + secmem0_size;
198 		size = secmem1_base - base;
199 		if (size) {
200 			DMSG("Carving out gap between secmem0 and secmem1 (0x%"PRIxPA":0x%"PRIxPASZ")",
201 			     base, size);
202 			if (!tee_mm_alloc2(&virt_mapper_pool, base, size))
203 				panic("Can't carve out secmem gap");
204 		}
205 	}
206 
207 
208 	/* Carve out areas that are used by OP-TEE core */
209 	for (n = 0; n < mem_map->count; n++) {
210 		struct tee_mmap_region *map = mem_map->map + n;
211 
212 		switch (map->type) {
213 		case MEM_AREA_TEE_RAM_RX:
214 		case MEM_AREA_TEE_RAM_RO:
215 		case MEM_AREA_NEX_RAM_RO:
216 		case MEM_AREA_NEX_RAM_RW:
217 			DMSG("Carving out area of type %d (0x%08lx-0x%08lx)",
218 			     map->type, map->pa, map->pa + map->size);
219 			if (!tee_mm_alloc2(&virt_mapper_pool, map->pa,
220 					   map->size))
221 				panic("Can't carve out used area");
222 			break;
223 		default:
224 			continue;
225 		}
226 	}
227 
228 	kmem_map = mem_map;
229 }
230 
231 
232 static TEE_Result configure_guest_prtn_mem(struct guest_partition *prtn)
233 {
234 	TEE_Result res = TEE_SUCCESS;
235 	paddr_t original_data_pa = 0;
236 
237 	prtn->tee_ram = tee_mm_alloc(&virt_mapper_pool, VCORE_UNPG_RW_SZ);
238 	if (!prtn->tee_ram) {
239 		EMSG("Can't allocate memory for TEE runtime context");
240 		res = TEE_ERROR_OUT_OF_MEMORY;
241 		goto err;
242 	}
243 	DMSG("TEE RAM: %08" PRIxPA, tee_mm_get_smem(prtn->tee_ram));
244 
245 	prtn->ta_ram = tee_mm_alloc(&virt_mapper_pool, get_ta_ram_size());
246 	if (!prtn->ta_ram) {
247 		EMSG("Can't allocate memory for TA data");
248 		res = TEE_ERROR_OUT_OF_MEMORY;
249 		goto err;
250 	}
251 	DMSG("TA RAM: %08" PRIxPA, tee_mm_get_smem(prtn->ta_ram));
252 
253 	prtn->tables = tee_mm_alloc(&virt_mapper_pool,
254 				   core_mmu_get_total_pages_size());
255 	if (!prtn->tables) {
256 		EMSG("Can't allocate memory for page tables");
257 		res = TEE_ERROR_OUT_OF_MEMORY;
258 		goto err;
259 	}
260 
261 	prtn->tables_va = phys_to_virt(tee_mm_get_smem(prtn->tables),
262 				      MEM_AREA_SEC_RAM_OVERALL,
263 				      core_mmu_get_total_pages_size());
264 	assert(prtn->tables_va);
265 
266 	prtn->mmu_prtn = core_alloc_mmu_prtn(prtn->tables_va);
267 	if (!prtn->mmu_prtn) {
268 		res = TEE_ERROR_OUT_OF_MEMORY;
269 		goto err;
270 	}
271 
272 	res = prepare_memory_map(&prtn->mem_map, tee_mm_get_smem(prtn->tee_ram),
273 				 tee_mm_get_smem(prtn->ta_ram));
274 	if (res)
275 		goto err;
276 
277 	core_init_mmu_prtn(prtn->mmu_prtn, &prtn->mem_map);
278 
279 	original_data_pa = virt_to_phys(__data_start);
280 	/* Switch to guest's mappings */
281 	core_mmu_set_prtn(prtn->mmu_prtn);
282 
283 	/* clear .bss */
284 	memset((void *)(VCORE_UNPG_RW_PA), 0, VCORE_UNPG_RW_SZ);
285 
286 	/* copy .data section from R/O original */
287 	memcpy(__data_start,
288 	       phys_to_virt(original_data_pa, MEM_AREA_SEC_RAM_OVERALL,
289 			    __data_end - __data_start),
290 	       __data_end - __data_start);
291 
292 	return TEE_SUCCESS;
293 
294 err:
295 	if (prtn->tee_ram)
296 		tee_mm_free(prtn->tee_ram);
297 	if (prtn->ta_ram)
298 		tee_mm_free(prtn->ta_ram);
299 	if (prtn->tables)
300 		tee_mm_free(prtn->tables);
301 	nex_free(prtn->mmu_prtn);
302 	nex_free(prtn->mem_map.map);
303 
304 	return res;
305 }
306 
307 static void destroy_gsd(struct guest_partition *prtn, bool free_only)
308 {
309 	size_t n = 0;
310 
311 	for (n = 0; n < gsd_count; n++) {
312 		if (!free_only && prtn->data_array[n] && gsd_array[n].destroy)
313 			gsd_array[n].destroy(prtn->data_array[n]);
314 		nex_free(prtn->data_array[n]);
315 	}
316 	nex_free(prtn->data_array);
317 	prtn->data_array = NULL;
318 }
319 
320 static TEE_Result alloc_gsd(struct guest_partition *prtn)
321 {
322 	unsigned int n = 0;
323 
324 	if (!gsd_count)
325 		return TEE_SUCCESS;
326 
327 	prtn->data_array = nex_calloc(gsd_count, sizeof(void *));
328 	if (!prtn->data_array)
329 		return TEE_ERROR_OUT_OF_MEMORY;
330 
331 	for (n = 0; n < gsd_count; n++) {
332 		prtn->data_array[n] = nex_calloc(1, gsd_array[n].size);
333 		if (!prtn->data_array[n]) {
334 			destroy_gsd(prtn, true /*free_only*/);
335 			return TEE_ERROR_OUT_OF_MEMORY;
336 		}
337 	}
338 
339 	return TEE_SUCCESS;
340 }
341 TEE_Result virt_guest_created(uint16_t guest_id)
342 {
343 	struct guest_partition *prtn = NULL;
344 	TEE_Result res = TEE_SUCCESS;
345 	uint32_t exceptions = 0;
346 
347 	prtn = nex_calloc(1, sizeof(*prtn));
348 	if (!prtn)
349 		return TEE_ERROR_OUT_OF_MEMORY;
350 
351 	res = alloc_gsd(prtn);
352 	if (res)
353 		goto err_free_prtn;
354 
355 	prtn->id = guest_id;
356 	mutex_init(&prtn->mutex);
357 	refcount_set(&prtn->refc, 1);
358 	res = configure_guest_prtn_mem(prtn);
359 	if (res)
360 		goto err_free_gsd;
361 
362 	set_current_prtn(prtn);
363 
364 	/* Initialize threads */
365 	thread_init_threads();
366 	/* Do the preinitcalls */
367 	call_preinitcalls();
368 
369 	exceptions = cpu_spin_lock_xsave(&prtn_list_lock);
370 	LIST_INSERT_HEAD(&prtn_list, prtn, link);
371 	cpu_spin_unlock_xrestore(&prtn_list_lock, exceptions);
372 
373 	IMSG("Added guest %d", guest_id);
374 
375 	set_current_prtn(NULL);
376 	core_mmu_set_default_prtn();
377 
378 	return TEE_SUCCESS;
379 
380 err_free_gsd:
381 	destroy_gsd(prtn, true /*free_only*/);
382 err_free_prtn:
383 	nex_free(prtn);
384 	return res;
385 }
386 
387 static bool
388 prtn_have_remaining_resources(struct guest_partition *prtn __maybe_unused)
389 {
390 #ifdef CFG_CORE_SEL1_SPMC
391 	int i = 0;
392 
393 	if (prtn->cookie_count)
394 		return true;
395 	bit_ffs(prtn->shm_bits, SPMC_CORE_SEL1_MAX_SHM_COUNT, &i);
396 	return i >= 0;
397 #else
398 	return false;
399 #endif
400 }
401 
402 static void get_prtn(struct guest_partition *prtn)
403 {
404 	if (!refcount_inc(&prtn->refc))
405 		panic();
406 }
407 
408 uint16_t virt_get_guest_id(struct guest_partition *prtn)
409 {
410 	if (!prtn)
411 		return 0;
412 	return prtn->id;
413 }
414 
415 static struct guest_partition *find_guest_by_id_unlocked(uint16_t guest_id)
416 {
417 	struct guest_partition *prtn = NULL;
418 
419 	LIST_FOREACH(prtn, &prtn_list, link)
420 		if (!prtn->shutting_down && prtn->id == guest_id)
421 			return prtn;
422 
423 	return NULL;
424 }
425 
426 struct guest_partition *virt_next_guest(struct guest_partition *prtn)
427 {
428 	struct guest_partition *ret = NULL;
429 	uint32_t exceptions = 0;
430 
431 	exceptions = cpu_spin_lock_xsave(&prtn_list_lock);
432 	if (prtn)
433 		ret = LIST_NEXT(prtn, link);
434 	else
435 		ret = LIST_FIRST(&prtn_list);
436 
437 	while (ret && ret->shutting_down)
438 		ret = LIST_NEXT(prtn, link);
439 	if (ret)
440 		get_prtn(ret);
441 	cpu_spin_unlock_xrestore(&prtn_list_lock, exceptions);
442 
443 	virt_put_guest(prtn);
444 
445 	return ret;
446 }
447 
448 struct guest_partition *virt_get_current_guest(void)
449 {
450 	struct guest_partition *prtn = get_current_prtn();
451 
452 	if (prtn)
453 		get_prtn(prtn);
454 	return prtn;
455 }
456 
457 struct guest_partition *virt_get_guest(uint16_t guest_id)
458 {
459 	struct guest_partition *prtn = NULL;
460 	uint32_t exceptions = 0;
461 
462 	exceptions = cpu_spin_lock_xsave(&prtn_list_lock);
463 	prtn = find_guest_by_id_unlocked(guest_id);
464 	if (prtn)
465 		get_prtn(prtn);
466 	cpu_spin_unlock_xrestore(&prtn_list_lock, exceptions);
467 
468 	return prtn;
469 }
470 
471 void virt_put_guest(struct guest_partition *prtn)
472 {
473 	if (prtn && refcount_dec(&prtn->refc)) {
474 		uint32_t exceptions = 0;
475 		bool do_free = true;
476 
477 		assert(prtn->shutting_down);
478 
479 		exceptions = cpu_spin_lock_xsave(&prtn_list_lock);
480 		LIST_REMOVE(prtn, link);
481 		if (prtn_have_remaining_resources(prtn)) {
482 			LIST_INSERT_HEAD(&prtn_destroy_list, prtn, link);
483 			/*
484 			 * Delay the nex_free() until
485 			 * virt_reclaim_cookie_from_destroyed_guest()
486 			 * is done with this partition.
487 			 */
488 			do_free = false;
489 		}
490 		cpu_spin_unlock_xrestore(&prtn_list_lock, exceptions);
491 
492 		destroy_gsd(prtn, false /*!free_only*/);
493 		tee_mm_free(prtn->tee_ram);
494 		prtn->tee_ram = NULL;
495 		tee_mm_free(prtn->ta_ram);
496 		prtn->ta_ram = NULL;
497 		tee_mm_free(prtn->tables);
498 		prtn->tables = NULL;
499 		core_free_mmu_prtn(prtn->mmu_prtn);
500 		prtn->mmu_prtn = NULL;
501 		nex_free(prtn->mem_map.map);
502 		prtn->mem_map.map = NULL;
503 		if (do_free)
504 			nex_free(prtn);
505 	}
506 }
507 
508 TEE_Result virt_guest_destroyed(uint16_t guest_id)
509 {
510 	struct guest_partition *prtn = NULL;
511 	uint32_t exceptions = 0;
512 
513 	IMSG("Removing guest %"PRId16, guest_id);
514 
515 	exceptions = cpu_spin_lock_xsave(&prtn_list_lock);
516 
517 	prtn = find_guest_by_id_unlocked(guest_id);
518 	if (prtn && !prtn->got_guest_destroyed)
519 		prtn->got_guest_destroyed = true;
520 	else
521 		prtn = NULL;
522 
523 	cpu_spin_unlock_xrestore(&prtn_list_lock, exceptions);
524 
525 	if (prtn) {
526 		notif_deliver_atomic_event(NOTIF_EVENT_SHUTDOWN, prtn->id);
527 
528 		exceptions = cpu_spin_lock_xsave(&prtn_list_lock);
529 		prtn->shutting_down = true;
530 		cpu_spin_unlock_xrestore(&prtn_list_lock, exceptions);
531 
532 		virt_put_guest(prtn);
533 	} else {
534 		EMSG("Client with id %d is not found", guest_id);
535 	}
536 
537 	return TEE_SUCCESS;
538 }
539 
540 TEE_Result virt_set_guest(uint16_t guest_id)
541 {
542 	struct guest_partition *prtn = get_current_prtn();
543 
544 	/* This can be true only if we return from IRQ RPC */
545 	if (prtn && prtn->id == guest_id)
546 		return TEE_SUCCESS;
547 
548 	if (prtn)
549 		panic("Virtual guest partition is already set");
550 
551 	prtn = virt_get_guest(guest_id);
552 	if (!prtn)
553 		return TEE_ERROR_ITEM_NOT_FOUND;
554 
555 	set_current_prtn(prtn);
556 	core_mmu_set_prtn(prtn->mmu_prtn);
557 
558 	return TEE_SUCCESS;
559 }
560 
561 void virt_unset_guest(void)
562 {
563 	struct guest_partition *prtn = get_current_prtn();
564 
565 	if (!prtn)
566 		return;
567 
568 	set_current_prtn(NULL);
569 	core_mmu_set_default_prtn();
570 	virt_put_guest(prtn);
571 }
572 
573 void virt_on_stdcall(void)
574 {
575 	struct guest_partition *prtn = get_current_prtn();
576 
577 	/* Initialize runtime on first std call */
578 	if (!prtn->runtime_initialized) {
579 		mutex_lock(&prtn->mutex);
580 		if (!prtn->runtime_initialized) {
581 			init_tee_runtime();
582 			call_driver_initcalls();
583 			prtn->runtime_initialized = true;
584 		}
585 		mutex_unlock(&prtn->mutex);
586 	}
587 }
588 
589 struct memory_map *virt_get_memory_map(void)
590 {
591 	struct guest_partition *prtn;
592 
593 	prtn = get_current_prtn();
594 
595 	if (!prtn)
596 		return NULL;
597 
598 	return &prtn->mem_map;
599 }
600 
601 void virt_get_ta_ram(vaddr_t *start, vaddr_t *end)
602 {
603 	struct guest_partition *prtn = get_current_prtn();
604 
605 	*start = (vaddr_t)phys_to_virt(tee_mm_get_smem(prtn->ta_ram),
606 				       MEM_AREA_TA_RAM,
607 				       tee_mm_get_bytes(prtn->ta_ram));
608 	*end = *start + tee_mm_get_bytes(prtn->ta_ram);
609 }
610 
611 #ifdef CFG_CORE_SEL1_SPMC
612 static int find_cookie(struct guest_partition *prtn, uint64_t cookie)
613 {
614 	int i = 0;
615 
616 	for (i = 0; i < prtn->cookie_count; i++)
617 		if (prtn->cookies[i] == cookie)
618 			return i;
619 	return -1;
620 }
621 
622 static struct guest_partition *find_prtn_cookie(uint64_t cookie, int *idx)
623 {
624 	struct guest_partition *prtn = NULL;
625 	int i = 0;
626 
627 	LIST_FOREACH(prtn, &prtn_list, link) {
628 		i = find_cookie(prtn, cookie);
629 		if (i >= 0) {
630 			if (idx)
631 				*idx = i;
632 			return prtn;
633 		}
634 	}
635 
636 	return NULL;
637 }
638 
639 TEE_Result virt_add_cookie_to_current_guest(uint64_t cookie)
640 {
641 	TEE_Result res = TEE_ERROR_ACCESS_DENIED;
642 	struct guest_partition *prtn = NULL;
643 	uint32_t exceptions = 0;
644 
645 	exceptions = cpu_spin_lock_xsave(&prtn_list_lock);
646 	if (find_prtn_cookie(cookie, NULL))
647 		goto out;
648 
649 	prtn = current_partition[get_core_pos()];
650 	if (prtn->cookie_count < ARRAY_SIZE(prtn->cookies)) {
651 		prtn->cookies[prtn->cookie_count] = cookie;
652 		prtn->cookie_count++;
653 		res = TEE_SUCCESS;
654 	}
655 out:
656 	cpu_spin_unlock_xrestore(&prtn_list_lock, exceptions);
657 
658 	return res;
659 }
660 
661 void virt_remove_cookie(uint64_t cookie)
662 {
663 	struct guest_partition *prtn = NULL;
664 	uint32_t exceptions = 0;
665 	int i = 0;
666 
667 	exceptions = cpu_spin_lock_xsave(&prtn_list_lock);
668 	prtn = find_prtn_cookie(cookie, &i);
669 	if (prtn) {
670 		memmove(prtn->cookies + i, prtn->cookies + i + 1,
671 			sizeof(uint64_t) * (prtn->cookie_count - i - 1));
672 		prtn->cookie_count--;
673 	}
674 	cpu_spin_unlock_xrestore(&prtn_list_lock, exceptions);
675 }
676 
677 uint16_t virt_find_guest_by_cookie(uint64_t cookie)
678 {
679 	struct guest_partition *prtn = NULL;
680 	uint32_t exceptions = 0;
681 	uint16_t ret = 0;
682 
683 	exceptions = cpu_spin_lock_xsave(&prtn_list_lock);
684 	prtn = find_prtn_cookie(cookie, NULL);
685 	if (prtn)
686 		ret = prtn->id;
687 
688 	cpu_spin_unlock_xrestore(&prtn_list_lock, exceptions);
689 
690 	return ret;
691 }
692 
693 bitstr_t *virt_get_shm_bits(void)
694 {
695 	return get_current_prtn()->shm_bits;
696 }
697 
698 static TEE_Result reclaim_cookie(struct guest_partition *prtn, uint64_t cookie)
699 {
700 	if (cookie & FFA_MEMORY_HANDLE_HYPERVISOR_BIT) {
701 		size_t n = 0;
702 
703 		for (n = 0; n < prtn->cookie_count; n++) {
704 			if (prtn->cookies[n] == cookie) {
705 				memmove(prtn->cookies + n,
706 					prtn->cookies + n + 1,
707 					sizeof(uint64_t) *
708 						(prtn->cookie_count - n - 1));
709 				prtn->cookie_count--;
710 				return TEE_SUCCESS;
711 			}
712 		}
713 	} else {
714 		uint64_t mask = FFA_MEMORY_HANDLE_NON_SECURE_BIT |
715 				SHIFT_U64(FFA_MEMORY_HANDLE_PRTN_MASK,
716 					  FFA_MEMORY_HANDLE_PRTN_SHIFT);
717 		int64_t i = cookie & ~mask;
718 
719 		if (i >= 0 && i < SPMC_CORE_SEL1_MAX_SHM_COUNT &&
720 		    bit_test(prtn->shm_bits, i)) {
721 			bit_clear(prtn->shm_bits, i);
722 			return TEE_SUCCESS;
723 		}
724 	}
725 
726 	return TEE_ERROR_ITEM_NOT_FOUND;
727 }
728 
729 TEE_Result virt_reclaim_cookie_from_destroyed_guest(uint16_t guest_id,
730 						    uint64_t cookie)
731 
732 {
733 	struct guest_partition *prtn = NULL;
734 	TEE_Result res = TEE_ERROR_ITEM_NOT_FOUND;
735 	uint32_t exceptions = 0;
736 
737 	exceptions = cpu_spin_lock_xsave(&prtn_list_lock);
738 	LIST_FOREACH(prtn, &prtn_destroy_list, link) {
739 		if (prtn->id == guest_id) {
740 			res = reclaim_cookie(prtn, cookie);
741 			if (prtn_have_remaining_resources(prtn))
742 				prtn = NULL;
743 			else
744 				LIST_REMOVE(prtn, link);
745 			break;
746 		}
747 	}
748 	cpu_spin_unlock_xrestore(&prtn_list_lock, exceptions);
749 
750 	nex_free(prtn);
751 
752 	return res;
753 }
754 #endif /*CFG_CORE_SEL1_SPMC*/
755 
756 TEE_Result virt_add_guest_spec_data(unsigned int *data_id, size_t data_size,
757 				    void (*data_destroy)(void *data))
758 {
759 	void *p = NULL;
760 
761 	/*
762 	 * This function only executes successfully in a single threaded
763 	 * environment before exiting to the normal world the first time.
764 	 * If add_disabled is true, it means we're not in this environment
765 	 * any longer.
766 	 */
767 
768 	if (add_disabled)
769 		return TEE_ERROR_BAD_PARAMETERS;
770 
771 	p = nex_realloc(gsd_array, sizeof(*gsd_array) * (gsd_count + 1));
772 	if (!p)
773 		return TEE_ERROR_OUT_OF_MEMORY;
774 	gsd_array = p;
775 
776 	gsd_array[gsd_count] = (struct guest_spec_data){
777 		.size = data_size,
778 		.destroy = data_destroy,
779 	};
780 	*data_id = gsd_count + 1;
781 	gsd_count++;
782 	return TEE_SUCCESS;
783 }
784 
785 void *virt_get_guest_spec_data(struct guest_partition *prtn,
786 			       unsigned int data_id)
787 {
788 	assert(data_id);
789 	if (!data_id || !prtn || data_id > gsd_count)
790 		return NULL;
791 	return prtn->data_array[data_id - 1];
792 }
793 
794 static TEE_Result virt_disable_add(void)
795 {
796 	add_disabled = true;
797 
798 	return TEE_SUCCESS;
799 }
800 nex_release_init_resource(virt_disable_add);
801