xref: /kvmtool/kvm-cpu.c (revision 5f9b016e4e96429f9d076d4b31e5d309d14df17b)
15c3d55faSPekka Enberg #include "kvm/kvm-cpu.h"
25c3d55faSPekka Enberg 
3b0b42ba0SPekka Enberg #include "kvm/symbol.h"
45c3d55faSPekka Enberg #include "kvm/util.h"
55c3d55faSPekka Enberg #include "kvm/kvm.h"
619d98215SMarc Zyngier #include "kvm/virtio.h"
75c3d55faSPekka Enberg 
85c3d55faSPekka Enberg #include <sys/ioctl.h>
95c3d55faSPekka Enberg #include <sys/mman.h>
105ee154d1SPekka Enberg #include <signal.h>
115c3d55faSPekka Enberg #include <stdlib.h>
12b0b42ba0SPekka Enberg #include <string.h>
135c3d55faSPekka Enberg #include <errno.h>
145c3d55faSPekka Enberg #include <stdio.h>
155c3d55faSPekka Enberg 
16656be1b8SSasha Levin extern __thread struct kvm_cpu *current_kvm_cpu;
17656be1b8SSasha Levin 
1819d98215SMarc Zyngier int __attribute__((weak)) kvm_cpu__get_endianness(struct kvm_cpu *vcpu)
1919d98215SMarc Zyngier {
2019d98215SMarc Zyngier 	return VIRTIO_ENDIAN_HOST;
2119d98215SMarc Zyngier }
2219d98215SMarc Zyngier 
2343835ac9SSasha Levin void kvm_cpu__enable_singlestep(struct kvm_cpu *vcpu)
245c3d55faSPekka Enberg {
255c3d55faSPekka Enberg 	struct kvm_guest_debug debug = {
265c3d55faSPekka Enberg 		.control	= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP,
275c3d55faSPekka Enberg 	};
285c3d55faSPekka Enberg 
2943835ac9SSasha Levin 	if (ioctl(vcpu->vcpu_fd, KVM_SET_GUEST_DEBUG, &debug) < 0)
304542f276SCyrill Gorcunov 		pr_warning("KVM_SET_GUEST_DEBUG failed");
315c3d55faSPekka Enberg }
325c3d55faSPekka Enberg 
3343835ac9SSasha Levin void kvm_cpu__run(struct kvm_cpu *vcpu)
345c3d55faSPekka Enberg {
355c3d55faSPekka Enberg 	int err;
365c3d55faSPekka Enberg 
37f9fdf5cdSAsias He 	if (!vcpu->is_running)
38f9fdf5cdSAsias He 		return;
39f9fdf5cdSAsias He 
4043835ac9SSasha Levin 	err = ioctl(vcpu->vcpu_fd, KVM_RUN, 0);
4176b75d32SMatt Evans 	if (err < 0 && (errno != EINTR && errno != EAGAIN))
425c3d55faSPekka Enberg 		die_perror("KVM_RUN failed");
435c3d55faSPekka Enberg }
4465bab644SPekka Enberg 
454298ddadSSasha Levin static void kvm_cpu_signal_handler(int signum)
4649e5227dSSasha Levin {
474298ddadSSasha Levin 	if (signum == SIGKVMEXIT) {
48714e5b7fSSasha Levin 		if (current_kvm_cpu && current_kvm_cpu->is_running) {
49656be1b8SSasha Levin 			current_kvm_cpu->is_running = false;
504346fd8fSSasha Levin 			kvm__continue(current_kvm_cpu->kvm);
51656be1b8SSasha Levin 		}
524298ddadSSasha Levin 	} else if (signum == SIGKVMPAUSE) {
534298ddadSSasha Levin 		current_kvm_cpu->paused = 1;
544298ddadSSasha Levin 	}
5549e5227dSSasha Levin }
5649e5227dSSasha Levin 
5773f7e5b3SSasha Levin static void kvm_cpu__handle_coalesced_mmio(struct kvm_cpu *cpu)
5873f7e5b3SSasha Levin {
5973f7e5b3SSasha Levin 	if (cpu->ring) {
6073f7e5b3SSasha Levin 		while (cpu->ring->first != cpu->ring->last) {
6173f7e5b3SSasha Levin 			struct kvm_coalesced_mmio *m;
6273f7e5b3SSasha Levin 			m = &cpu->ring->coalesced_mmio[cpu->ring->first];
639b735910SMarc Zyngier 			kvm_cpu__emulate_mmio(cpu,
6473f7e5b3SSasha Levin 					      m->phys_addr,
6573f7e5b3SSasha Levin 					      m->data,
6673f7e5b3SSasha Levin 					      m->len,
6773f7e5b3SSasha Levin 					      1);
6873f7e5b3SSasha Levin 			cpu->ring->first = (cpu->ring->first + 1) % KVM_COALESCED_MMIO_MAX;
6973f7e5b3SSasha Levin 		}
7073f7e5b3SSasha Levin 	}
7173f7e5b3SSasha Levin }
7273f7e5b3SSasha Levin 
73df4239fbSSasha Levin void kvm_cpu__reboot(struct kvm *kvm)
74714e5b7fSSasha Levin {
75c23d9748SSasha Levin 	int i;
76c23d9748SSasha Levin 
77df4239fbSSasha Levin 	/* The kvm->cpus array contains a null pointer in the last location */
78e2077857SMatt Evans 	for (i = 0; ; i++) {
79df4239fbSSasha Levin 		if (kvm->cpus[i])
80df4239fbSSasha Levin 			pthread_kill(kvm->cpus[i]->thread, SIGKVMEXIT);
81e2077857SMatt Evans 		else
82e2077857SMatt Evans 			break;
83e2077857SMatt Evans 	}
84714e5b7fSSasha Levin }
85714e5b7fSSasha Levin 
8665bab644SPekka Enberg int kvm_cpu__start(struct kvm_cpu *cpu)
8765bab644SPekka Enberg {
885ee154d1SPekka Enberg 	sigset_t sigset;
895ee154d1SPekka Enberg 
905ee154d1SPekka Enberg 	sigemptyset(&sigset);
915ee154d1SPekka Enberg 	sigaddset(&sigset, SIGALRM);
925ee154d1SPekka Enberg 
935ee154d1SPekka Enberg 	pthread_sigmask(SIG_BLOCK, &sigset, NULL);
945ee154d1SPekka Enberg 
954298ddadSSasha Levin 	signal(SIGKVMEXIT, kvm_cpu_signal_handler);
964298ddadSSasha Levin 	signal(SIGKVMPAUSE, kvm_cpu_signal_handler);
9749e5227dSSasha Levin 
985d1a249cSPekka Enberg 	kvm_cpu__reset_vcpu(cpu);
995d1a249cSPekka Enberg 
100809f088bSSasha Levin 	if (cpu->kvm->cfg.single_step)
1016d6a4d41SPekka Enberg 		kvm_cpu__enable_singlestep(cpu);
1026d6a4d41SPekka Enberg 
103c23d9748SSasha Levin 	while (cpu->is_running) {
1044298ddadSSasha Levin 		if (cpu->paused) {
1054298ddadSSasha Levin 			kvm__notify_paused();
1064298ddadSSasha Levin 			cpu->paused = 0;
1074298ddadSSasha Levin 		}
1084298ddadSSasha Levin 
1094b1c6f6eSSasha Levin 		if (cpu->needs_nmi) {
1104b1c6f6eSSasha Levin 			kvm_cpu__arch_nmi(cpu);
1114b1c6f6eSSasha Levin 			cpu->needs_nmi = 0;
1124b1c6f6eSSasha Levin 		}
1134b1c6f6eSSasha Levin 
11465bab644SPekka Enberg 		kvm_cpu__run(cpu);
11565bab644SPekka Enberg 
11665bab644SPekka Enberg 		switch (cpu->kvm_run->exit_reason) {
1171621292eSSasha Levin 		case KVM_EXIT_UNKNOWN:
1181621292eSSasha Levin 			break;
11965bab644SPekka Enberg 		case KVM_EXIT_DEBUG:
12065bab644SPekka Enberg 			kvm_cpu__show_registers(cpu);
12165bab644SPekka Enberg 			kvm_cpu__show_code(cpu);
12265bab644SPekka Enberg 			break;
12365bab644SPekka Enberg 		case KVM_EXIT_IO: {
12465bab644SPekka Enberg 			bool ret;
12565bab644SPekka Enberg 
1264123ca55SMarc Zyngier 			ret = kvm_cpu__emulate_io(cpu,
12765bab644SPekka Enberg 						  cpu->kvm_run->io.port,
1283fdf659dSSasha Levin 						  (u8 *)cpu->kvm_run +
12965bab644SPekka Enberg 						  cpu->kvm_run->io.data_offset,
13065bab644SPekka Enberg 						  cpu->kvm_run->io.direction,
13165bab644SPekka Enberg 						  cpu->kvm_run->io.size,
13265bab644SPekka Enberg 						  cpu->kvm_run->io.count);
13365bab644SPekka Enberg 
13465bab644SPekka Enberg 			if (!ret)
13565bab644SPekka Enberg 				goto panic_kvm;
13665bab644SPekka Enberg 			break;
13765bab644SPekka Enberg 		}
13865bab644SPekka Enberg 		case KVM_EXIT_MMIO: {
13965bab644SPekka Enberg 			bool ret;
14065bab644SPekka Enberg 
141a7518f05SSasha Levin 			/*
142a7518f05SSasha Levin 			 * If we had MMIO exit, coalesced ring should be processed
143a7518f05SSasha Levin 			 * *before* processing the exit itself
144a7518f05SSasha Levin 			 */
145a7518f05SSasha Levin 			kvm_cpu__handle_coalesced_mmio(cpu);
146a7518f05SSasha Levin 
1479b735910SMarc Zyngier 			ret = kvm_cpu__emulate_mmio(cpu,
14865bab644SPekka Enberg 						    cpu->kvm_run->mmio.phys_addr,
14965bab644SPekka Enberg 						    cpu->kvm_run->mmio.data,
15065bab644SPekka Enberg 						    cpu->kvm_run->mmio.len,
15165bab644SPekka Enberg 						    cpu->kvm_run->mmio.is_write);
15265bab644SPekka Enberg 
15365bab644SPekka Enberg 			if (!ret)
15465bab644SPekka Enberg 				goto panic_kvm;
15565bab644SPekka Enberg 			break;
15665bab644SPekka Enberg 		}
1575ee154d1SPekka Enberg 		case KVM_EXIT_INTR:
158656be1b8SSasha Levin 			if (cpu->is_running)
159656be1b8SSasha Levin 				break;
16049e5227dSSasha Levin 			goto exit_kvm;
16165bab644SPekka Enberg 		case KVM_EXIT_SHUTDOWN:
16265bab644SPekka Enberg 			goto exit_kvm;
163*5f9b016eSAnup Patel 		case KVM_EXIT_SYSTEM_EVENT:
164*5f9b016eSAnup Patel 			/*
165*5f9b016eSAnup Patel 			 * Print the type of system event and
166*5f9b016eSAnup Patel 			 * treat all system events as shutdown request.
167*5f9b016eSAnup Patel 			 */
168*5f9b016eSAnup Patel 			switch (cpu->kvm_run->system_event.type) {
169*5f9b016eSAnup Patel 			case KVM_SYSTEM_EVENT_RESET:
170*5f9b016eSAnup Patel 				/* Fall through for now */
171*5f9b016eSAnup Patel 			case KVM_SYSTEM_EVENT_SHUTDOWN:
172*5f9b016eSAnup Patel 				goto exit_kvm;
173*5f9b016eSAnup Patel 			default:
174*5f9b016eSAnup Patel 				pr_warning("unknown system event type %d",
175*5f9b016eSAnup Patel 					   cpu->kvm_run->system_event.type);
176*5f9b016eSAnup Patel 				goto exit_kvm;
177*5f9b016eSAnup Patel 			};
178*5f9b016eSAnup Patel 			break;
179341ee0d4SMatt Evans 		default: {
180341ee0d4SMatt Evans 			bool ret;
181341ee0d4SMatt Evans 
182341ee0d4SMatt Evans 			ret = kvm_cpu__handle_exit(cpu);
183341ee0d4SMatt Evans 			if (!ret)
18465bab644SPekka Enberg 				goto panic_kvm;
185341ee0d4SMatt Evans 			break;
186341ee0d4SMatt Evans 		}
18765bab644SPekka Enberg 		}
18873f7e5b3SSasha Levin 		kvm_cpu__handle_coalesced_mmio(cpu);
18965bab644SPekka Enberg 	}
19065bab644SPekka Enberg 
19165bab644SPekka Enberg exit_kvm:
19265bab644SPekka Enberg 	return 0;
19365bab644SPekka Enberg 
19465bab644SPekka Enberg panic_kvm:
19565bab644SPekka Enberg 	return 1;
19665bab644SPekka Enberg }
197df4239fbSSasha Levin 
198df4239fbSSasha Levin int kvm_cpu__init(struct kvm *kvm)
199df4239fbSSasha Levin {
200df4239fbSSasha Levin 	int max_cpus, recommended_cpus, i;
201df4239fbSSasha Levin 
202df4239fbSSasha Levin 	max_cpus = kvm__max_cpus(kvm);
203df4239fbSSasha Levin 	recommended_cpus = kvm__recommended_cpus(kvm);
204df4239fbSSasha Levin 
205df4239fbSSasha Levin 	if (kvm->cfg.nrcpus > max_cpus) {
206df4239fbSSasha Levin 		printf("  # Limit the number of CPUs to %d\n", max_cpus);
207df4239fbSSasha Levin 		kvm->cfg.nrcpus = max_cpus;
208df4239fbSSasha Levin 	} else if (kvm->cfg.nrcpus > recommended_cpus) {
209df4239fbSSasha Levin 		printf("  # Warning: The maximum recommended amount of VCPUs"
210df4239fbSSasha Levin 			" is %d\n", recommended_cpus);
211df4239fbSSasha Levin 	}
212df4239fbSSasha Levin 
213df4239fbSSasha Levin 	kvm->nrcpus = kvm->cfg.nrcpus;
214df4239fbSSasha Levin 
215df4239fbSSasha Levin 	/* Alloc one pointer too many, so array ends up 0-terminated */
216df4239fbSSasha Levin 	kvm->cpus = calloc(kvm->nrcpus + 1, sizeof(void *));
217df4239fbSSasha Levin 	if (!kvm->cpus) {
218df4239fbSSasha Levin 		pr_warning("Couldn't allocate array for %d CPUs", kvm->nrcpus);
219df4239fbSSasha Levin 		return -ENOMEM;
220df4239fbSSasha Levin 	}
221df4239fbSSasha Levin 
222df4239fbSSasha Levin 	for (i = 0; i < kvm->nrcpus; i++) {
223df4239fbSSasha Levin 		kvm->cpus[i] = kvm_cpu__arch_init(kvm, i);
224df4239fbSSasha Levin 		if (!kvm->cpus[i]) {
225df4239fbSSasha Levin 			pr_warning("unable to initialize KVM VCPU");
226df4239fbSSasha Levin 			goto fail_alloc;
227df4239fbSSasha Levin 		}
228df4239fbSSasha Levin 	}
229df4239fbSSasha Levin 
230df4239fbSSasha Levin 	return 0;
231df4239fbSSasha Levin 
232df4239fbSSasha Levin fail_alloc:
233df4239fbSSasha Levin 	for (i = 0; i < kvm->nrcpus; i++)
234df4239fbSSasha Levin 		free(kvm->cpus[i]);
235df4239fbSSasha Levin 	return -ENOMEM;
236df4239fbSSasha Levin }
23749a8afd1SSasha Levin base_init(kvm_cpu__init);
238df4239fbSSasha Levin 
239df4239fbSSasha Levin int kvm_cpu__exit(struct kvm *kvm)
240df4239fbSSasha Levin {
241df4239fbSSasha Levin 	int i, r;
242df4239fbSSasha Levin 	void *ret = NULL;
243df4239fbSSasha Levin 
244df4239fbSSasha Levin 	kvm_cpu__delete(kvm->cpus[0]);
245df4239fbSSasha Levin 	kvm->cpus[0] = NULL;
246df4239fbSSasha Levin 
247df4239fbSSasha Levin 	for (i = 1; i < kvm->nrcpus; i++) {
248df4239fbSSasha Levin 		if (kvm->cpus[i]->is_running) {
249df4239fbSSasha Levin 			pthread_kill(kvm->cpus[i]->thread, SIGKVMEXIT);
250df4239fbSSasha Levin 			if (pthread_join(kvm->cpus[i]->thread, &ret) != 0)
251df4239fbSSasha Levin 				die("pthread_join");
252df4239fbSSasha Levin 			kvm_cpu__delete(kvm->cpus[i]);
253df4239fbSSasha Levin 		}
254df4239fbSSasha Levin 		if (ret == NULL)
255df4239fbSSasha Levin 			r = 0;
256df4239fbSSasha Levin 	}
257df4239fbSSasha Levin 
258df4239fbSSasha Levin 	free(kvm->cpus);
259df4239fbSSasha Levin 
260df4239fbSSasha Levin 	kvm->nrcpus = 0;
261df4239fbSSasha Levin 
262df4239fbSSasha Levin 	return r;
263df4239fbSSasha Levin }
26449a8afd1SSasha Levin late_exit(kvm_cpu__exit);
265