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