1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4 */
5
6 #ifndef _LINUX_GUNYAH_H
7 #define _LINUX_GUNYAH_H
8
9 #include <linux/bitfield.h>
10 #include <linux/errno.h>
11 #include <linux/interrupt.h>
12 #include <linux/limits.h>
13 #include <linux/list.h>
14 #include <linux/mod_devicetable.h>
15 #include <linux/types.h>
16
17 #include <uapi/linux/gunyah.h>
18
19 struct gunyah_vm;
20
21 int __must_check gunyah_vm_get(struct gunyah_vm *ghvm);
22 void gunyah_vm_put(struct gunyah_vm *ghvm);
23
24 /**
25 * struct gunyah_auth_vm_mgr_ops - Auth VM Mgr helper ops
26 * auth_vm_mgr driver will add the specific ops to setup the VM before
27 * the VM starts
28 * @pre_alloc_vmid: QTVMs have predetermined vmids. This callback can be
29 * used by the auth vm mgr to request RM to assign the
30 * same vmid for the VM. (Optional)
31 * @pre_vm_configure: Fill in the arguments of VM_CONFIGURE RM call. Most of
32 * the auth vm mgrs would need this, as different AUTH has
33 * a different layout of image or metadata or dtb offsets.
34 * @vm_authenticate: Callback to make an RM call if it is a qtvm. (Optional)
35 * @pre_vm_init: Callback before RM sets up all the objects/resources
36 * needed by the VM. For ex, this would be when you can
37 * choose to setup if you want demand paged VM or not. (Optional)
38 * @pre_vm_start: Callback for any setup before VM start where client
39 * drivers can share/lend memory. (Optional)
40 * @pre_vm_reset: Callback for any cleanup before VM reset. All resources
41 * tracked by RM will be cleaned at this stage (Optional)
42 * @post_vm_reset: Callback for any cleanup after VM reset (Optional)
43 * @start_fail: Needed when roll back is needed before auth_mgr can
44 * clean up at a later stage.
45 **/
46 struct gunyah_auth_vm_mgr_ops {
47 u16 (*pre_alloc_vmid)(struct gunyah_vm *ghvm);
48 int (*pre_vm_configure)(struct gunyah_vm *ghvm);
49 int (*vm_authenticate)(struct gunyah_vm *ghvm);
50 int (*pre_vm_init)(struct gunyah_vm *ghvm);
51 int (*pre_vm_start)(struct gunyah_vm *ghvm);
52 int (*pre_vm_reset)(struct gunyah_vm *ghvm);
53 int (*post_vm_reset)(struct gunyah_vm *ghvm);
54 void (*vm_start_fail)(struct gunyah_vm *ghvm);
55 };
56
57 /**
58 * struct gunyah_auth_vm - Represents an authentication type handler
59 * @type: value from &enum gunyah_auth_type
60 * @name: friendly name for debug purposes
61 * @mod: owner of the auth type
62 * @vm_attach: attach ops/private_data with the VM.
63 * @vm_detach: detach ops/private_data with the VM.
64 */
65 struct gunyah_auth_vm_mgr {
66 u32 type;
67 const char *name;
68 struct module *mod;
69 long (*vm_attach)(struct gunyah_vm *ghvm, struct gunyah_auth_desc *d);
70 void (*vm_detach)(struct gunyah_vm *ghvm);
71 };
72 int gunyah_auth_vm_mgr_register(struct gunyah_auth_vm_mgr *auth_vm);
73 void gunyah_auth_vm_mgr_unregister(struct gunyah_auth_vm_mgr *auth_vm);
74
75 struct gunyah_vm_function_instance;
76 /**
77 * struct gunyah_vm_function - Represents a function type
78 * @type: value from &enum gunyah_fn_type
79 * @name: friendly name for debug purposes
80 * @mod: owner of the function type
81 * @bind: Called when a new function of this type has been allocated.
82 * @unbind: Called when the function instance is being destroyed.
83 * @compare: Compare function instance @f's argument to the provided arg.
84 * Return true if they are equivalent. Used on GUNYAH_VM_REMOVE_FUNCTION.
85 */
86 struct gunyah_vm_function {
87 u32 type;
88 const char *name;
89 struct module *mod;
90 long (*bind)(struct gunyah_vm_function_instance *f);
91 void (*unbind)(struct gunyah_vm_function_instance *f);
92 bool (*compare)(const struct gunyah_vm_function_instance *f,
93 const void *arg, size_t size);
94 };
95
96 /**
97 * struct gunyah_vm_function_instance - Represents one function instance
98 * @arg_size: size of user argument
99 * @argp: pointer to user argument
100 * @ghvm: Pointer to VM instance
101 * @rm: Pointer to resource manager for the VM instance
102 * @fn: The ops for the function
103 * @data: Private data for function
104 * @vm_list: for gunyah_vm's functions list
105 */
106 struct gunyah_vm_function_instance {
107 size_t arg_size;
108 void *argp;
109 struct gunyah_vm *ghvm;
110 struct gunyah_rm *rm;
111 struct gunyah_vm_function *fn;
112 void *data;
113 struct list_head vm_list;
114 };
115
116 int gunyah_vm_function_register(struct gunyah_vm_function *f);
117 void gunyah_vm_function_unregister(struct gunyah_vm_function *f);
118
119 /* Since the function identifiers were setup in a uapi header as an
120 * enum and we do no want to change that, the user must supply the expanded
121 * constant as well and the compiler checks they are the same.
122 * See also MODULE_ALIAS_RDMA_NETLINK.
123 */
124 #define MODULE_ALIAS_GUNYAH_VM_FUNCTION(_type, _idx) \
125 static inline void __maybe_unused __chk##_idx(void) \
126 { \
127 BUILD_BUG_ON(_type != _idx); \
128 } \
129 MODULE_ALIAS("ghfunc:" __stringify(_idx))
130
131 #define DECLARE_GUNYAH_VM_FUNCTION(_name, _type, _bind, _unbind, _compare) \
132 static struct gunyah_vm_function _name = { \
133 .type = _type, \
134 .name = __stringify(_name), \
135 .mod = THIS_MODULE, \
136 .bind = _bind, \
137 .unbind = _unbind, \
138 .compare = _compare, \
139 }
140
141 #define module_gunyah_vm_function(__gf) \
142 module_driver(__gf, gunyah_vm_function_register, \
143 gunyah_vm_function_unregister)
144
145 #define DECLARE_GUNYAH_VM_FUNCTION_INIT(_name, _type, _idx, _bind, _unbind, \
146 _compare) \
147 DECLARE_GUNYAH_VM_FUNCTION(_name, _type, _bind, _unbind, _compare); \
148 module_gunyah_vm_function(_name); \
149 MODULE_ALIAS_GUNYAH_VM_FUNCTION(_type, _idx)
150
151 /* Matches resource manager's resource types for VM_GET_HYP_RESOURCES RPC */
152 enum gunyah_resource_type {
153 /* clang-format off */
154 GUNYAH_RESOURCE_TYPE_BELL_TX = 0,
155 GUNYAH_RESOURCE_TYPE_BELL_RX = 1,
156 GUNYAH_RESOURCE_TYPE_MSGQ_TX = 2,
157 GUNYAH_RESOURCE_TYPE_MSGQ_RX = 3,
158 GUNYAH_RESOURCE_TYPE_VCPU = 4,
159 GUNYAH_RESOURCE_TYPE_MEM_EXTENT = 9,
160 GUNYAH_RESOURCE_TYPE_ADDR_SPACE = 10,
161 /* clang-format on */
162 };
163
164 struct gunyah_resource {
165 enum gunyah_resource_type type;
166 u64 capid;
167 unsigned int irq;
168
169 struct list_head list;
170 u32 rm_label;
171 };
172
173 /**
174 * struct gunyah_vm_resource_ticket - Represents a ticket to reserve access to VM resource(s)
175 * @vm_list: for @gunyah_vm->resource_tickets
176 * @resources: List of resource(s) associated with this ticket
177 * (members are from @gunyah_resource->list)
178 * @resource_type: Type of resource this ticket reserves
179 * @label: Label of the resource from resource manager this ticket reserves.
180 * @owner: owner of the ticket
181 * @populate: callback provided by the ticket owner and called when a resource is found that
182 * matches @resource_type and @label. Note that this callback could be called
183 * multiple times if userspace created mutliple resources with the same type/label.
184 * This callback may also have significant delay after gunyah_vm_add_resource_ticket()
185 * since gunyah_vm_add_resource_ticket() could be called before the VM starts.
186 * @unpopulate: callback provided by the ticket owner and called when the ticket owner should no
187 * longer use the resource provided in the argument. When unpopulate() returns,
188 * the ticket owner should not be able to use the resource any more as the resource
189 * might being freed.
190 */
191 struct gunyah_vm_resource_ticket {
192 struct list_head vm_list;
193 struct list_head resources;
194 enum gunyah_resource_type resource_type;
195 u32 label;
196
197 struct module *owner;
198 bool (*populate)(struct gunyah_vm_resource_ticket *ticket,
199 struct gunyah_resource *ghrsc);
200 void (*unpopulate)(struct gunyah_vm_resource_ticket *ticket,
201 struct gunyah_resource *ghrsc);
202 };
203
204 int gunyah_vm_add_resource_ticket(struct gunyah_vm *ghvm,
205 struct gunyah_vm_resource_ticket *ticket);
206 void gunyah_vm_remove_resource_ticket(struct gunyah_vm *ghvm,
207 struct gunyah_vm_resource_ticket *ticket);
208
209 /*
210 * gunyah_vm_io_handler contains the info about an io device and its associated
211 * addr and the ops associated with the io device.
212 */
213 struct gunyah_vm_io_handler {
214 struct rb_node node;
215 u64 addr;
216
217 bool datamatch;
218 u8 len;
219 u64 data;
220 struct gunyah_vm_io_handler_ops *ops;
221 };
222
223 /*
224 * gunyah_vm_io_handler_ops contains function pointers associated with an iodevice.
225 */
226 struct gunyah_vm_io_handler_ops {
227 int (*read)(struct gunyah_vm_io_handler *io_dev, u64 addr, u32 len,
228 u64 data);
229 int (*write)(struct gunyah_vm_io_handler *io_dev, u64 addr, u32 len,
230 u64 data);
231 };
232
233 int gunyah_vm_add_io_handler(struct gunyah_vm *ghvm,
234 struct gunyah_vm_io_handler *io_dev);
235 void gunyah_vm_remove_io_handler(struct gunyah_vm *ghvm,
236 struct gunyah_vm_io_handler *io_dev);
237
238 #define GUNYAH_RM_ACL_X BIT(0)
239 #define GUNYAH_RM_ACL_W BIT(1)
240 #define GUNYAH_RM_ACL_R BIT(2)
241
242 struct gunyah_rm_mem_acl_entry {
243 __le16 vmid;
244 u8 perms;
245 u8 reserved;
246 } __packed;
247
248 struct gunyah_rm_mem_entry {
249 __le64 phys_addr;
250 __le64 size;
251 } __packed;
252
253 enum gunyah_rm_mem_type {
254 GUNYAH_RM_MEM_TYPE_NORMAL = 0,
255 GUNYAH_RM_MEM_TYPE_IO = 1,
256 };
257
258 /*
259 * struct gunyah_rm_mem_parcel - Info about memory to be lent/shared/donated/reclaimed
260 * @mem_type: The type of memory: normal (DDR) or IO
261 * @label: An client-specified identifier which can be used by the other VMs to identify the purpose
262 * of the memory parcel.
263 * @n_acl_entries: Count of the number of entries in the @acl_entries array.
264 * @acl_entries: An array of access control entries. Each entry specifies a VM and what access
265 * is allowed for the memory parcel.
266 * @n_mem_entries: Count of the number of entries in the @mem_entries array.
267 * @mem_entries: An array of regions to be associated with the memory parcel. Addresses should be
268 * (intermediate) physical addresses from Linux's perspective.
269 * @mem_handle: On success, filled with memory handle that RM allocates for this memory parcel
270 */
271 struct gunyah_rm_mem_parcel {
272 enum gunyah_rm_mem_type mem_type;
273 u32 label;
274 size_t n_acl_entries;
275 struct gunyah_rm_mem_acl_entry *acl_entries;
276 size_t n_mem_entries;
277 struct gunyah_rm_mem_entry *mem_entries;
278 u32 mem_handle;
279 };
280
281 enum gunyah_pagetable_access {
282 /* clang-format off */
283 GUNYAH_PAGETABLE_ACCESS_NONE = 0,
284 GUNYAH_PAGETABLE_ACCESS_X = 1,
285 GUNYAH_PAGETABLE_ACCESS_W = 2,
286 GUNYAH_PAGETABLE_ACCESS_R = 4,
287 GUNYAH_PAGETABLE_ACCESS_RX = 5,
288 GUNYAH_PAGETABLE_ACCESS_RW = 6,
289 GUNYAH_PAGETABLE_ACCESS_RWX = 7,
290 /* clang-format on */
291 };
292
293 struct gunyah_rm_platform_ops {
294 int (*pre_mem_share)(struct gunyah_rm *rm,
295 struct gunyah_rm_mem_parcel *mem_parcel);
296 int (*post_mem_reclaim)(struct gunyah_rm *rm,
297 struct gunyah_rm_mem_parcel *mem_parcel);
298
299 int (*pre_demand_page)(struct gunyah_rm *rm, u16 vmid,
300 enum gunyah_pagetable_access access,
301 struct folio *folio);
302 int (*release_demand_page)(struct gunyah_rm *rm, u16 vmid,
303 enum gunyah_pagetable_access access,
304 struct folio *folio);
305 };
306
307 #if IS_ENABLED(CONFIG_GUNYAH_PLATFORM_HOOKS)
308 int gunyah_rm_register_platform_ops(
309 const struct gunyah_rm_platform_ops *platform_ops);
310 void gunyah_rm_unregister_platform_ops(
311 const struct gunyah_rm_platform_ops *platform_ops);
312 int devm_gunyah_rm_register_platform_ops(
313 struct device *dev, const struct gunyah_rm_platform_ops *ops);
314 #else
gunyah_rm_register_platform_ops(const struct gunyah_rm_platform_ops * platform_ops)315 static inline int gunyah_rm_register_platform_ops(
316 const struct gunyah_rm_platform_ops *platform_ops)
317 {
318 return 0;
319 }
gunyah_rm_unregister_platform_ops(const struct gunyah_rm_platform_ops * platform_ops)320 static inline void gunyah_rm_unregister_platform_ops(
321 const struct gunyah_rm_platform_ops *platform_ops)
322 {
323 }
324 static inline int
devm_gunyah_rm_register_platform_ops(struct device * dev,const struct gunyah_rm_platform_ops * ops)325 devm_gunyah_rm_register_platform_ops(struct device *dev,
326 const struct gunyah_rm_platform_ops *ops)
327 {
328 return 0;
329 }
330 #endif
331
332 /******************************************************************************/
333 /* Common arch-independent definitions for Gunyah hypercalls */
334 #define GUNYAH_CAPID_INVAL U64_MAX
335 #define GUNYAH_VMID_ROOT_VM 0xff
336
337 enum gunyah_error {
338 /* clang-format off */
339 GUNYAH_ERROR_OK = 0,
340 GUNYAH_ERROR_UNIMPLEMENTED = -1,
341 GUNYAH_ERROR_RETRY = -2,
342
343 GUNYAH_ERROR_ARG_INVAL = 1,
344 GUNYAH_ERROR_ARG_SIZE = 2,
345 GUNYAH_ERROR_ARG_ALIGN = 3,
346
347 GUNYAH_ERROR_NOMEM = 10,
348
349 GUNYAH_ERROR_ADDR_OVFL = 20,
350 GUNYAH_ERROR_ADDR_UNFL = 21,
351 GUNYAH_ERROR_ADDR_INVAL = 22,
352
353 GUNYAH_ERROR_DENIED = 30,
354 GUNYAH_ERROR_BUSY = 31,
355 GUNYAH_ERROR_IDLE = 32,
356
357 GUNYAH_ERROR_IRQ_BOUND = 40,
358 GUNYAH_ERROR_IRQ_UNBOUND = 41,
359
360 GUNYAH_ERROR_CSPACE_CAP_NULL = 50,
361 GUNYAH_ERROR_CSPACE_CAP_REVOKED = 51,
362 GUNYAH_ERROR_CSPACE_WRONG_OBJ_TYPE = 52,
363 GUNYAH_ERROR_CSPACE_INSUF_RIGHTS = 53,
364 GUNYAH_ERROR_CSPACE_FULL = 54,
365
366 GUNYAH_ERROR_MSGQUEUE_EMPTY = 60,
367 GUNYAH_ERROR_MSGQUEUE_FULL = 61,
368 /* clang-format on */
369 };
370
371 /**
372 * gunyah_error_remap() - Remap Gunyah hypervisor errors into a Linux error code
373 * @gunyah_error: Gunyah hypercall return value
374 */
gunyah_error_remap(enum gunyah_error gunyah_error)375 static inline int gunyah_error_remap(enum gunyah_error gunyah_error)
376 {
377 switch (gunyah_error) {
378 case GUNYAH_ERROR_OK:
379 return 0;
380 case GUNYAH_ERROR_NOMEM:
381 return -ENOMEM;
382 case GUNYAH_ERROR_DENIED:
383 case GUNYAH_ERROR_CSPACE_CAP_NULL:
384 case GUNYAH_ERROR_CSPACE_CAP_REVOKED:
385 case GUNYAH_ERROR_CSPACE_WRONG_OBJ_TYPE:
386 case GUNYAH_ERROR_CSPACE_INSUF_RIGHTS:
387 return -EACCES;
388 case GUNYAH_ERROR_CSPACE_FULL:
389 case GUNYAH_ERROR_BUSY:
390 case GUNYAH_ERROR_IDLE:
391 return -EBUSY;
392 case GUNYAH_ERROR_IRQ_BOUND:
393 case GUNYAH_ERROR_IRQ_UNBOUND:
394 case GUNYAH_ERROR_MSGQUEUE_FULL:
395 case GUNYAH_ERROR_MSGQUEUE_EMPTY:
396 return -EIO;
397 case GUNYAH_ERROR_UNIMPLEMENTED:
398 return -EOPNOTSUPP;
399 case GUNYAH_ERROR_RETRY:
400 return -EAGAIN;
401 default:
402 return -EINVAL;
403 }
404 }
405
406 enum gunyah_api_feature {
407 /* clang-format off */
408 GUNYAH_FEATURE_DOORBELL = 1,
409 GUNYAH_FEATURE_MSGQUEUE = 2,
410 GUNYAH_FEATURE_VCPU = 5,
411 GUNYAH_FEATURE_MEMEXTENT = 6,
412 /* clang-format on */
413 };
414
415 bool arch_is_gunyah_guest(void);
416
417 enum gunyah_info_owner {
418 /* clang-format off */
419 GUNYAH_INFO_OWNER_INVALID = 0,
420 GUNYAH_INFO_OWNER_HYP = 1,
421 GUNYAH_INFO_OWNER_ROOTVM = 2,
422 GUNYAH_INFO_OWNER_RM = 3,
423 GUNYAH_INFO_OWNER_QCRM = 16,
424 /* clang-format on */
425 };
426
427 void *gunyah_get_info(u16 owner, u16 id, size_t *size);
428
429 #define GUNYAH_API_V1 1
430
431 /* Other bits reserved for future use and will be zero */
432 /* clang-format off */
433 #define GUNYAH_API_INFO_API_VERSION_MASK GENMASK_ULL(13, 0)
434 #define GUNYAH_API_INFO_BIG_ENDIAN BIT_ULL(14)
435 #define GUNYAH_API_INFO_IS_64BIT BIT_ULL(15)
436 #define GUNYAH_API_INFO_VARIANT_MASK GENMASK_ULL(63, 56)
437 /* clang-format on */
438
439 struct gunyah_hypercall_hyp_identify_resp {
440 u64 api_info;
441 u64 flags[3];
442 };
443
444 static inline u16
gunyah_api_version(const struct gunyah_hypercall_hyp_identify_resp * gunyah_api)445 gunyah_api_version(const struct gunyah_hypercall_hyp_identify_resp *gunyah_api)
446 {
447 return FIELD_GET(GUNYAH_API_INFO_API_VERSION_MASK,
448 gunyah_api->api_info);
449 }
450
451 void gunyah_hypercall_hyp_identify(
452 struct gunyah_hypercall_hyp_identify_resp *hyp_identity);
453
454 enum gunyah_error gunyah_hypercall_bell_send(u64 capid, u64 new_flags,
455 u64 *old_flags);
456 enum gunyah_error gunyah_hypercall_bell_set_mask(u64 capid, u64 enable_mask,
457 u64 ack_mask);
458
459 /* Immediately raise RX vIRQ on receiver VM */
460 #define GUNYAH_HYPERCALL_MSGQ_TX_FLAGS_PUSH BIT(0)
461
462 enum gunyah_error gunyah_hypercall_msgq_send(u64 capid, size_t size, void *buff,
463 u64 tx_flags, bool *ready);
464 enum gunyah_error gunyah_hypercall_msgq_recv(u64 capid, void *buff, size_t size,
465 size_t *recv_size, bool *ready);
466
467 #define GUNYAH_ADDRSPACE_SELF_CAP 0
468
469 /* clang-format off */
470 #define GUNYAH_MEMEXTENT_MAPPING_USER_ACCESS GENMASK_ULL(2, 0)
471 #define GUNYAH_MEMEXTENT_MAPPING_KERNEL_ACCESS GENMASK_ULL(6, 4)
472 #define GUNYAH_MEMEXTENT_MAPPING_TYPE GENMASK_ULL(23, 16)
473 /* clang-format on */
474
475 enum gunyah_memextent_donate_type {
476 /* clang-format off */
477 GUNYAH_MEMEXTENT_DONATE_TO_CHILD = 0,
478 GUNYAH_MEMEXTENT_DONATE_TO_PARENT = 1,
479 GUNYAH_MEMEXTENT_DONATE_TO_SIBLING = 2,
480 GUNYAH_MEMEXTENT_DONATE_TO_PROTECTED = 3,
481 GUNYAH_MEMEXTENT_DONATE_FROM_PROTECTED = 4,
482 /* clang-format on */
483 };
484
485 enum gunyah_addrspace_map_flag_bits {
486 /* clang-format off */
487 GUNYAH_ADDRSPACE_MAP_FLAG_PARTIAL = 0,
488 GUNYAH_ADDRSPACE_MAP_FLAG_PRIVATE = 1,
489 GUNYAH_ADDRSPACE_MAP_FLAG_VMMIO = 2,
490 GUNYAH_ADDRSPACE_MAP_FLAG_NOSYNC = 31,
491 /* clang-format on */
492 };
493
494 enum gunyah_error gunyah_hypercall_addrspace_map(u64 capid, u64 extent_capid,
495 u64 vbase, u32 extent_attrs,
496 u32 flags, u64 offset,
497 u64 size);
498 enum gunyah_error gunyah_hypercall_addrspace_unmap(u64 capid, u64 extent_capid,
499 u64 vbase, u32 flags,
500 u64 offset, u64 size);
501
502 /* clang-format off */
503 #define GUNYAH_MEMEXTENT_OPTION_TYPE_MASK GENMASK_ULL(7, 0)
504 #define GUNYAH_MEMEXTENT_OPTION_NOSYNC BIT(31)
505 /* clang-format on */
506
507 enum gunyah_error gunyah_hypercall_memextent_donate(u32 options, u64 from_capid,
508 u64 to_capid, u64 offset,
509 u64 size);
510
511 struct gunyah_hypercall_vcpu_run_resp {
512 union {
513 enum {
514 /* clang-format off */
515 /* VCPU is ready to run */
516 GUNYAH_VCPU_STATE_READY = 0,
517 /* VCPU is sleeping until an interrupt arrives */
518 GUNYAH_VCPU_STATE_EXPECTS_WAKEUP = 1,
519 /* VCPU is powered off */
520 GUNYAH_VCPU_STATE_POWERED_OFF = 2,
521 /* VCPU is blocked in EL2 for unspecified reason */
522 GUNYAH_VCPU_STATE_BLOCKED = 3,
523 /* VCPU has returned for MMIO READ */
524 GUNYAH_VCPU_ADDRSPACE_VMMIO_READ = 4,
525 /* VCPU has returned for MMIO WRITE */
526 GUNYAH_VCPU_ADDRSPACE_VMMIO_WRITE = 5,
527 /* VCPU blocked on fault where we can demand page */
528 GUNYAH_VCPU_ADDRSPACE_PAGE_FAULT = 7,
529 /* VCPU is powered off due to some system event/reset */
530 GUNYAH_VCPU_STATE_SYSTEM_OFF = 0x100,
531 /* clang-format on */
532 } state;
533 u64 sized_state;
534 };
535 u64 state_data[3];
536 };
537
538 enum {
539 GUNYAH_ADDRSPACE_VMMIO_ACTION_EMULATE = 0,
540 GUNYAH_ADDRSPACE_VMMIO_ACTION_RETRY = 1,
541 GUNYAH_ADDRSPACE_VMMIO_ACTION_FAULT = 2,
542 };
543
544 /**
545 * struct gunyah_vcpu - Track an instance of gunyah vCPU
546 * @f: Function instance (how we get associated with the main VM)
547 * @rsc: Pointer to the Gunyah vCPU resource, will be NULL until VM starts
548 * @run_lock: One userspace thread at a time should run the vCPU
549 * @ghvm: Pointer to the main VM struct; quicker look up than going through
550 * @f->ghvm
551 * @vcpu_run: Pointer to page shared with userspace to communicate vCPU state
552 * @state: Our copy of the state of the vCPU, since userspace could trick
553 * kernel to behave incorrectly if we relied on @vcpu_run
554 * @mmio_read_len: Our copy of @vcpu_run->mmio.len; see also @state
555 * @mmio_addr: Our copy of @vcpu_run->mmio.phys_addr; see also @state
556 * @ready: if vCPU goes to sleep, hypervisor reports to us that it's sleeping
557 * and will signal interrupt (from @rsc) when it's time to wake up.
558 * This completion signals that we can run vCPU again.
559 * @nb: When VM exits, the status of VM is reported via @vcpu_run->status.
560 * We need to track overall VM status, and the nb gives us the updates from
561 * Resource Manager.
562 * @ticket: resource ticket to claim vCPU# for the VM
563 * @kref: Reference counter
564 */
565 struct gunyah_vcpu {
566 struct gunyah_vm_function_instance *f;
567 struct gunyah_resource *rsc;
568 struct mutex run_lock;
569 struct gunyah_vm *ghvm;
570
571 struct gunyah_vcpu_run *vcpu_run;
572
573 /**
574 * Track why the vcpu_run hypercall returned. This mirrors the vcpu_run
575 * structure shared with userspace, except is used internally to avoid
576 * trusting userspace to not modify the vcpu_run structure.
577 */
578 enum {
579 GUNYAH_VCPU_RUN_STATE_UNKNOWN = 0,
580 GUNYAH_VCPU_RUN_STATE_READY,
581 GUNYAH_VCPU_RUN_STATE_MMIO_READ,
582 GUNYAH_VCPU_RUN_STATE_MMIO_WRITE,
583 GUNYAH_VCPU_RUN_STATE_SYSTEM_DOWN,
584 } state;
585 u8 mmio_read_len;
586 u64 mmio_addr;
587
588 struct completion ready;
589
590 struct notifier_block nb;
591 struct gunyah_vm_resource_ticket ticket;
592 struct kref kref;
593 };
594
595 enum gunyah_error
596 gunyah_hypercall_vcpu_run(u64 capid, unsigned long *resume_data,
597 struct gunyah_hypercall_vcpu_run_resp *resp);
598
599 #define GUNYAH_ADDRSPC_MODIFY_FLAG_UNLOCK_BIT 0
600 #define GUNYAH_ADDRSPC_MODIFY_FLAG_SANITIZE_BIT 1
601 enum gunyah_error
602 gunyah_hypercall_addrspc_modify_pages(u64 capid, u64 addr, u64 size, u64 flags);
603 enum gunyah_error
604 gunyah_hypercall_addrspace_find_info_area(unsigned long *ipa, unsigned long *size);
605 enum gunyah_error
606 #define GUNYAH_ADDRSPACE_VMMIO_CONFIGURE_OP_ADD_RANGE 0
607 gunyah_hypercall_addrspc_configure_vmmio_range(u64 capid, u64 base, u64 size, u64 op);
608 #endif
609