1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2011 NetApp, Inc. 5 * All rights reserved. 6 */ 7 8 #ifndef _DEV_VMM_VM_H_ 9 #define _DEV_VMM_VM_H_ 10 11 #ifdef _KERNEL 12 #include <sys/_cpuset.h> 13 14 #include <machine/vmm.h> 15 16 #include <dev/vmm/vmm_param.h> 17 #include <dev/vmm/vmm_mem.h> 18 19 struct vcpu; 20 21 enum vcpu_state { 22 VCPU_IDLE, 23 VCPU_FROZEN, 24 VCPU_RUNNING, 25 VCPU_SLEEPING, 26 }; 27 28 /* 29 * Initialization: 30 * (a) allocated when vcpu is created 31 * (i) initialized when vcpu is created and when it is reinitialized 32 * (o) initialized the first time the vcpu is created 33 * (x) initialized before use 34 */ 35 struct vcpu { 36 struct mtx mtx; /* (o) protects 'state' and 'hostcpu' */ 37 enum vcpu_state state; /* (o) vcpu state */ 38 int vcpuid; /* (o) */ 39 int hostcpu; /* (o) vcpu's host cpu */ 40 int reqidle; /* (i) request vcpu to idle */ 41 struct vm *vm; /* (o) */ 42 void *cookie; /* (i) cpu-specific data */ 43 void *stats; /* (a,i) statistics */ 44 45 VMM_VCPU_MD_FIELDS; 46 }; 47 48 #define vcpu_lock_init(v) mtx_init(&((v)->mtx), "vcpu lock", 0, MTX_SPIN) 49 #define vcpu_lock_destroy(v) mtx_destroy(&((v)->mtx)) 50 #define vcpu_lock(v) mtx_lock_spin(&((v)->mtx)) 51 #define vcpu_unlock(v) mtx_unlock_spin(&((v)->mtx)) 52 #define vcpu_assert_locked(v) mtx_assert(&((v)->mtx), MA_OWNED) 53 54 extern int vmm_ipinum; 55 56 int vcpu_set_state(struct vcpu *vcpu, enum vcpu_state state, bool from_idle); 57 int vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate, 58 bool from_idle); 59 int vcpu_set_state_all(struct vm *vm, enum vcpu_state state); 60 enum vcpu_state vcpu_get_state(struct vcpu *vcpu, int *hostcpu); 61 void vcpu_notify_event(struct vcpu *vcpu); 62 void vcpu_notify_event_locked(struct vcpu *vcpu); 63 int vcpu_debugged(struct vcpu *vcpu); 64 65 static inline void * 66 vcpu_stats(struct vcpu *vcpu) 67 { 68 return (vcpu->stats); 69 } 70 71 static inline struct vm * 72 vcpu_vm(struct vcpu *vcpu) 73 { 74 return (vcpu->vm); 75 } 76 77 static inline int 78 vcpu_vcpuid(struct vcpu *vcpu) 79 { 80 return (vcpu->vcpuid); 81 } 82 83 static int __inline 84 vcpu_is_running(struct vcpu *vcpu, int *hostcpu) 85 { 86 return (vcpu_get_state(vcpu, hostcpu) == VCPU_RUNNING); 87 } 88 89 #ifdef _SYS_PROC_H_ 90 static int __inline 91 vcpu_should_yield(struct vcpu *vcpu) 92 { 93 struct thread *td; 94 95 td = curthread; 96 return (td->td_ast != 0 || td->td_owepreempt != 0); 97 } 98 #endif 99 100 typedef void (*vm_rendezvous_func_t)(struct vcpu *vcpu, void *arg); 101 int vm_handle_rendezvous(struct vcpu *vcpu); 102 103 /* 104 * Rendezvous all vcpus specified in 'dest' and execute 'func(arg)'. 105 * The rendezvous 'func(arg)' is not allowed to do anything that will 106 * cause the thread to be put to sleep. 107 * 108 * The caller cannot hold any locks when initiating the rendezvous. 109 * 110 * The implementation of this API may cause vcpus other than those specified 111 * by 'dest' to be stalled. The caller should not rely on any vcpus making 112 * forward progress when the rendezvous is in progress. 113 */ 114 int vm_smp_rendezvous(struct vcpu *vcpu, cpuset_t dest, 115 vm_rendezvous_func_t func, void *arg); 116 117 /* 118 * Initialization: 119 * (o) initialized the first time the VM is created 120 * (i) initialized when VM is created and when it is reinitialized 121 * (x) initialized before use 122 * 123 * Locking: 124 * [m] mem_segs_lock 125 * [r] rendezvous_mtx 126 * [v] reads require one frozen vcpu, writes require freezing all vcpus 127 */ 128 struct vm { 129 void *cookie; /* (i) cpu-specific data */ 130 struct vcpu **vcpu; /* (o) guest vcpus */ 131 struct vm_mem mem; /* (i) [m+v] guest memory */ 132 133 char name[VM_MAX_NAMELEN + 1]; /* (o) virtual machine name */ 134 struct sx vcpus_init_lock; /* (o) */ 135 136 bool dying; /* (o) is dying */ 137 int suspend; /* (i) stop VM execution */ 138 139 volatile cpuset_t active_cpus; /* (i) active vcpus */ 140 volatile cpuset_t debug_cpus; /* (i) vcpus stopped for debug */ 141 volatile cpuset_t suspended_cpus; /* (i) suspended vcpus */ 142 volatile cpuset_t halted_cpus; /* (x) cpus in a hard halt */ 143 144 cpuset_t rendezvous_req_cpus; /* (x) [r] rendezvous requested */ 145 cpuset_t rendezvous_done_cpus; /* (x) [r] rendezvous finished */ 146 void *rendezvous_arg; /* (x) [r] rendezvous func/arg */ 147 vm_rendezvous_func_t rendezvous_func; 148 struct mtx rendezvous_mtx; /* (o) rendezvous lock */ 149 150 uint16_t sockets; /* (o) num of sockets */ 151 uint16_t cores; /* (o) num of cores/socket */ 152 uint16_t threads; /* (o) num of threads/core */ 153 uint16_t maxcpus; /* (o) max pluggable cpus */ 154 155 VMM_VM_MD_FIELDS; 156 }; 157 158 int vm_create(const char *name, struct vm **retvm); 159 struct vcpu *vm_alloc_vcpu(struct vm *vm, int vcpuid); 160 void vm_destroy(struct vm *vm); 161 int vm_reinit(struct vm *vm); 162 void vm_reset(struct vm *vm); 163 164 void vm_lock_vcpus(struct vm *vm); 165 void vm_unlock_vcpus(struct vm *vm); 166 void vm_disable_vcpu_creation(struct vm *vm); 167 168 int vm_suspend(struct vm *vm, enum vm_suspend_how how); 169 int vm_activate_cpu(struct vcpu *vcpu); 170 int vm_suspend_cpu(struct vm *vm, struct vcpu *vcpu); 171 int vm_resume_cpu(struct vm *vm, struct vcpu *vcpu); 172 173 cpuset_t vm_active_cpus(struct vm *vm); 174 cpuset_t vm_debug_cpus(struct vm *vm); 175 cpuset_t vm_suspended_cpus(struct vm *vm); 176 177 uint16_t vm_get_maxcpus(struct vm *vm); 178 void vm_get_topology(struct vm *vm, uint16_t *sockets, uint16_t *cores, 179 uint16_t *threads, uint16_t *maxcpus); 180 int vm_set_topology(struct vm *vm, uint16_t sockets, uint16_t cores, 181 uint16_t threads, uint16_t maxcpus); 182 183 static inline const char * 184 vm_name(struct vm *vm) 185 { 186 return (vm->name); 187 } 188 189 static inline struct vm_mem * 190 vm_mem(struct vm *vm) 191 { 192 return (&vm->mem); 193 } 194 195 static inline struct vcpu * 196 vm_vcpu(struct vm *vm, int vcpuid) 197 { 198 return (vm->vcpu[vcpuid]); 199 } 200 201 struct vm_eventinfo { 202 cpuset_t *rptr; /* rendezvous cookie */ 203 int *sptr; /* suspend cookie */ 204 int *iptr; /* reqidle cookie */ 205 }; 206 207 static inline int 208 vcpu_rendezvous_pending(struct vcpu *vcpu, struct vm_eventinfo *info) 209 { 210 /* 211 * This check isn't done with atomic operations or under a lock because 212 * there's no need to. If the vcpuid bit is set, the vcpu is part of a 213 * rendezvous and the bit won't be cleared until the vcpu enters the 214 * rendezvous. On rendezvous exit, the cpuset is cleared and the vcpu 215 * will see an empty cpuset. So, the races are harmless. 216 */ 217 return (CPU_ISSET(vcpu_vcpuid(vcpu), info->rptr)); 218 } 219 220 static inline int 221 vcpu_suspended(struct vm_eventinfo *info) 222 { 223 return (*info->sptr); 224 } 225 226 static inline int 227 vcpu_reqidle(struct vm_eventinfo *info) 228 { 229 return (*info->iptr); 230 } 231 #endif /* _KERNEL */ 232 233 #endif /* !_DEV_VMM_VM_H_ */ 234