1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * Copyright (c) 2018, EPAM Systems. All rights reserved.
4 * Copyright (c) 2024, Linaro Limited
5 */
6
7 #ifndef __KERNEL_VIRTUALIZATION_H
8 #define __KERNEL_VIRTUALIZATION_H
9
10 #include <bitstring.h>
11 #include <mm/core_mmu.h>
12 #include <stdbool.h>
13 #include <stdint.h>
14 #include <tee_api_types.h>
15
16 #define HYP_CLNT_ID 0
17
18 struct guest_partition;
19
20 #if defined(CFG_NS_VIRTUALIZATION)
21 /**
22 * virt_guest_created() - create new VM partition
23 * @guest_id: VM id provided by hypervisor
24 *
25 * This function is called by hypervisor (via fast SMC)
26 * when hypervisor creates new guest VM, so OP-TEE
27 * can prepare partition for that VM
28 */
29 TEE_Result virt_guest_created(uint16_t guest_id);
30
31 /**
32 * virt_guest_destroyed() - destroy existing VM partition
33 * @guest_id: VM id provided by hypervisor
34 *
35 * This function is called by hypervisor (via fast SMC)
36 * when hypervisor is ready to destroy guest VM. Hypervisor
37 * must ensure that there are no ongoing calls from this
38 * VM right now.
39 */
40 TEE_Result virt_guest_destroyed(uint16_t guest_id);
41
42 /**
43 * virt_set_guest() - set guest VM context for current core
44 * @guest_id: VM id provided by hypervisor
45 *
46 * This function switches memory partitions, so TEE part of
47 * OP-TEE will see memory associated with current guest.
48 * It should be called on entry to OP-TEE
49 */
50 TEE_Result virt_set_guest(uint16_t guest_id);
51
52 /**
53 * virt_unset_guest() - set default memory partition
54 *
55 * This function should be called upon leaving OP-TEE,
56 * to switch to default memory partition, so all TEE-specific
57 * memory will be unmapped. This is safety measure to ensure
58 * that TEE memory is untouched when there is no active VM.
59 */
60 void virt_unset_guest(void);
61
62 /**
63 * virt_on_stdcall() - std call hook
64 *
65 * This hook is called on every std call, but really is needed
66 * only once: to initialize TEE runtime for current guest VM
67 */
68 void virt_on_stdcall(void);
69
70 /*
71 * Next function are needed because virtualization subsystem manages
72 * memory in own way. There is no one static memory map, instead
73 * every guest gets own memory map.
74 */
75
76 /**
77 * virt_init_memory() - initialize memory for virtualization subsystem
78 * @mem_map: current OP-TEE memory map
79 * @secmem0_base: base of first secure memory range
80 * @secmem0_size: size of first secure memory range
81 * @secmem1_base: base of an eventual second secure memory range, 0 if unused
82 * @secmem1_size: size of an eventual second secure memory range, 0 if unused
83 */
84 void virt_init_memory(struct memory_map *mem_map, paddr_t secmem0_base,
85 paddr_size_t secmem0_size, paddr_t secmem1_base,
86 paddr_size_t secmem1_size);
87
88 /**
89 * virt_get_memory_map() - get current memory map
90 */
91 struct memory_map *virt_get_memory_map(void);
92
93 /**
94 * virt_get_current_guest_id() - return current guest ID
95 *
96 * Returns current guest ID or 0 if none is set.
97 */
98 uint16_t virt_get_current_guest_id(void);
99
100 /**
101 * virt_get_guest_id() - return guest ID of a guest partition
102 * @prtn: Guest partition
103 *
104 * Returns guest ID or 0 if @prtn is NULL
105 */
106 uint16_t virt_get_guest_id(struct guest_partition *prtn);
107
108 /*
109 * virt_next_guest() - iterate over guest partitions
110 * @prtn: Guest partition to start from
111 *
112 * Iterates of the guest partitions, if @prtn is NULL the first partition
113 * is returned. If there are none or no next partition NULL is returned.
114 *
115 * The supplied @prtn has its reference counter decreased with
116 * virt_put_guest() before returning the next partition. A returned
117 * partition has its reference counter increased before being returned.
118 *
119 * If virt_next_guest() is called in sequence until it returns NULL, all
120 * reference counters are restored, but if the sequence is stopped earlier
121 * it's the callers responsibility to call virt_put_guest() on the last
122 * returned partition.
123 */
124 struct guest_partition *virt_next_guest(struct guest_partition *prtn);
125
126 /**
127 * virt_get_current_guest() - increase reference to current guest partition
128 *
129 * Each successful call to this function must be matched by a call to
130 * virt_put_guest() in order to decrease the reference counter again.
131 *
132 * Return a pointer to the guest partition on success or NULL on failure
133 */
134 struct guest_partition *virt_get_current_guest(void);
135
136 /**
137 * virt_get_guest() - increase reference to a guest partition
138 * @guest_id: ID of the guest partition to find
139 *
140 * Each successful call to this function must be matched by a call to
141 * virt_put_guest() in order to decrease the reference counter again.
142 *
143 * Return a pointer to the guest partition on success or NULL on failure
144 */
145 struct guest_partition *virt_get_guest(uint16_t guest_id);
146
147 /**
148 * virt_put_guest() - decrease reference to a guest partition
149 * @prtn: Guest partition
150 *
151 * Does nothing if @prtn is NULL.
152 */
153 void virt_put_guest(struct guest_partition *prtn);
154
155 /**
156 * virt_add_guest_spec_data() - add guest specific data
157 * @data_id: assigned id for the guest specific data
158 * @data_size: size of the guest specific data
159 * @data_destroy: function to destroy the guest specific data when the
160 * guest is destroyed, does not free the data itself
161 *
162 * Assigns a new data ID returned in @data_id and records the associated
163 * @data_size size and destructor function @data_destroy.
164 *
165 * To keep things simple, this function is only to be called before exiting
166 * to the normal world for the first time, that is, while we're single
167 * threaded and only have one partition.
168 */
169 TEE_Result virt_add_guest_spec_data(unsigned int *data_id, size_t data_size,
170 void (*data_destroy)(void *data));
171
172 /*
173 * virt_get_guest_spec_data() - get guest specific data
174 * @prtn: guest partition
175 * @data_id: previously assigned ID for the data
176 *
177 * Returns the preallocated guest specific data of the partition with the
178 * ID of @guest_id, will only return NULL for an unrecognized @data_id or
179 * NULL @prtn.
180 */
181 void *virt_get_guest_spec_data(struct guest_partition *prtn,
182 unsigned int data_id);
183
184 #else
virt_guest_created(uint16_t guest_id __unused)185 static inline TEE_Result virt_guest_created(uint16_t guest_id __unused)
186 { return TEE_ERROR_NOT_SUPPORTED; }
187
virt_guest_destroyed(uint16_t guest_id __unused)188 static inline TEE_Result virt_guest_destroyed(uint16_t guest_id __unused)
189 { return TEE_ERROR_NOT_SUPPORTED; }
190
virt_set_guest(uint16_t guest_id __unused)191 static inline TEE_Result virt_set_guest(uint16_t guest_id __unused)
192 { return TEE_ERROR_NOT_SUPPORTED; }
193
virt_unset_guest(void)194 static inline void virt_unset_guest(void) { }
virt_on_stdcall(void)195 static inline void virt_on_stdcall(void) { }
virt_get_memory_map(void)196 static inline struct memory_map *virt_get_memory_map(void) { return NULL; }
virt_init_memory(struct memory_map * mem_map __unused,paddr_t secmem0_base __unused,paddr_size_t secmem0_size __unused,paddr_t secmem1_base __unused,paddr_size_t secmem1_size __unused)197 static inline void virt_init_memory(struct memory_map *mem_map __unused,
198 paddr_t secmem0_base __unused,
199 paddr_size_t secmem0_size __unused,
200 paddr_t secmem1_base __unused,
201 paddr_size_t secmem1_size __unused) { }
virt_get_current_guest_id(void)202 static inline uint16_t virt_get_current_guest_id(void) { return 0; }
virt_get_guest_id(struct guest_partition * prtn __unused)203 static inline uint16_t virt_get_guest_id(struct guest_partition *prtn __unused)
204 {
205 return 0;
206 }
virt_get_current_guest(void)207 static inline struct guest_partition *virt_get_current_guest(void)
208 {
209 return NULL;
210 }
virt_get_guest(uint16_t guest_id __unused)211 static inline struct guest_partition *virt_get_guest(uint16_t guest_id __unused)
212 {
213 return NULL;
214 }
215 static inline struct guest_partition *
virt_next_guest(struct guest_partition * prtn __unused)216 virt_next_guest(struct guest_partition *prtn __unused)
217 {
218 return NULL;
219 }
virt_put_guest(struct guest_partition * prtn __unused)220 static inline void virt_put_guest(struct guest_partition *prtn __unused) { }
221 static inline TEE_Result
virt_add_guest_spec_data(unsigned int * data_id __unused,size_t data_size __unused,void (* data_destroy)(void * data)__unused)222 virt_add_guest_spec_data(unsigned int *data_id __unused,
223 size_t data_size __unused,
224 void (*data_destroy)(void *data) __unused)
225 {
226 return TEE_ERROR_NOT_SUPPORTED;
227 }
228
229 static inline void *
virt_get_guest_spec_data(struct guest_partition * prtn __unused,unsigned int data_id __unused)230 virt_get_guest_spec_data(struct guest_partition *prtn __unused,
231 unsigned int data_id __unused)
232 {
233 return NULL;
234 }
235
236 #endif /*CFG_NS_VIRTUALIZATION*/
237
238 #if defined(CFG_CORE_SEL1_SPMC) && defined(CFG_NS_VIRTUALIZATION)
239 TEE_Result virt_add_cookie_to_current_guest(uint64_t cookie);
240 void virt_remove_cookie(uint64_t cookie);
241 uint16_t virt_find_guest_by_cookie(uint64_t cookie);
242 bitstr_t *virt_get_shm_bits(void);
243
244 TEE_Result virt_reclaim_cookie_from_destroyed_guest(uint16_t guest_id,
245 uint64_t cookie);
246 #else
247 static inline TEE_Result
virt_add_cookie_to_current_guest(uint64_t cookie __unused)248 virt_add_cookie_to_current_guest(uint64_t cookie __unused)
249 { return TEE_ERROR_NOT_SUPPORTED; }
virt_remove_cookie(uint64_t cookie __unused)250 static inline void virt_remove_cookie(uint64_t cookie __unused) { }
virt_find_guest_by_cookie(uint64_t cookie __unused)251 static inline uint16_t virt_find_guest_by_cookie(uint64_t cookie __unused)
252 { return 0; }
virt_get_shm_bits(void)253 static inline bitstr_t *virt_get_shm_bits(void) { return NULL; }
254 static inline TEE_Result
virt_reclaim_cookie_from_destroyed_guest(uint16_t guest_id __unused,uint64_t cookie __unused)255 virt_reclaim_cookie_from_destroyed_guest(uint16_t guest_id __unused,
256 uint64_t cookie __unused)
257 { return TEE_ERROR_NOT_SUPPORTED; }
258 #endif
259
260 #endif /* __KERNEL_VIRTUALIZATION_H */
261