xref: /optee_os/core/arch/arm/mm/sp_mem.c (revision 5c1143a876a5da2804b7498e599e861539d6e068)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2021, Arm Limited. All rights reserved.
4  */
5 #include <assert.h>
6 #include <bitstring.h>
7 #include <ffa.h>
8 #include <kernel/spinlock.h>
9 #include <mm/fobj.h>
10 #include <mm/mobj.h>
11 #include <mm/sp_mem.h>
12 
13 #define NUM_SHARES	64
14 
15 static bitstr_t bit_decl(share_bits, NUM_SHARES);
16 static unsigned int sp_mem_lock = SPINLOCK_UNLOCK;
17 
18 /* mem_shares stores all active FF-A shares. */
19 SLIST_HEAD(sp_mem_head, sp_mem);
20 static struct sp_mem_head mem_shares = SLIST_HEAD_INITIALIZER(sp_mem_head);
21 
22 struct sp_mem *sp_mem_new(void)
23 {
24 	struct sp_mem *smem = NULL;
25 	uint32_t exceptions = 0;
26 	int i = 0;
27 
28 	smem = calloc(sizeof(*smem), 1);
29 	if (!smem)
30 		return NULL;
31 
32 	exceptions = cpu_spin_lock_xsave(&sp_mem_lock);
33 
34 	bit_ffc(share_bits, NUM_SHARES, &i);
35 	if (i == -1) {
36 		cpu_spin_unlock_xrestore(&sp_mem_lock, exceptions);
37 		free(smem);
38 		return NULL;
39 	}
40 
41 	bit_set(share_bits, i);
42 	/*
43 	 * OP-TEE SHAREs use bit 44 use bit 45 instead.
44 	 */
45 	smem->global_handle = i | FFA_MEMORY_HANDLE_SECURE_BIT;
46 	SLIST_INIT(&smem->regions);
47 	SLIST_INIT(&smem->receivers);
48 
49 	cpu_spin_unlock_xrestore(&sp_mem_lock, exceptions);
50 
51 	return smem;
52 }
53 
54 void sp_mem_add(struct sp_mem *smem)
55 {
56 	uint32_t exceptions = cpu_spin_lock_xsave(&sp_mem_lock);
57 
58 	SLIST_INSERT_HEAD(&mem_shares, smem, link);
59 
60 	cpu_spin_unlock_xrestore(&sp_mem_lock, exceptions);
61 }
62 
63 void sp_mem_remove(struct sp_mem *smem)
64 {
65 	uint32_t exceptions = 0;
66 	int i = 0;
67 	struct sp_mem *tsmem = NULL;
68 
69 	if (!smem)
70 		return;
71 
72 	/* Remove all receivers */
73 	while (!SLIST_EMPTY(&smem->receivers)) {
74 		struct sp_mem_receiver *receiver = NULL;
75 
76 		receiver = SLIST_FIRST(&smem->receivers);
77 		SLIST_REMOVE_HEAD(&smem->receivers, link);
78 		free(receiver);
79 	}
80 	/* Remove all regions */
81 	while (!SLIST_EMPTY(&smem->regions)) {
82 		struct sp_mem_map_region *region = SLIST_FIRST(&smem->regions);
83 
84 		mobj_put(region->mobj);
85 
86 		SLIST_REMOVE_HEAD(&smem->regions, link);
87 		free(region);
88 	}
89 
90 	exceptions = cpu_spin_lock_xsave(&sp_mem_lock);
91 
92 	i = smem->global_handle & ~FFA_MEMORY_HANDLE_SECURE_BIT;
93 	assert(i < NUM_SHARES);
94 
95 	bit_clear(share_bits, i);
96 
97 	SLIST_FOREACH(tsmem, &mem_shares, link) {
98 		if (tsmem == smem) {
99 			SLIST_REMOVE(&mem_shares, smem, sp_mem, link);
100 			break;
101 		}
102 	}
103 
104 	cpu_spin_unlock_xrestore(&sp_mem_lock, exceptions);
105 
106 	free(smem);
107 }
108