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