xref: /kvmtool/kvm-cpu.c (revision e300a5eef43ed25dc415b47d67cdf8d8987a9bf8)
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"
7*e300a5eeSMichael Ellerman #include "kvm/mutex.h"
8*e300a5eeSMichael Ellerman #include "kvm/barrier.h"
95c3d55faSPekka Enberg 
105c3d55faSPekka Enberg #include <sys/ioctl.h>
115c3d55faSPekka Enberg #include <sys/mman.h>
12*e300a5eeSMichael Ellerman #include <sys/eventfd.h>
135ee154d1SPekka Enberg #include <signal.h>
145c3d55faSPekka Enberg #include <stdlib.h>
15b0b42ba0SPekka Enberg #include <string.h>
165c3d55faSPekka Enberg #include <errno.h>
175c3d55faSPekka Enberg #include <stdio.h>
185c3d55faSPekka Enberg 
19656be1b8SSasha Levin extern __thread struct kvm_cpu *current_kvm_cpu;
20656be1b8SSasha Levin 
2119d98215SMarc Zyngier int __attribute__((weak)) kvm_cpu__get_endianness(struct kvm_cpu *vcpu)
2219d98215SMarc Zyngier {
2319d98215SMarc Zyngier 	return VIRTIO_ENDIAN_HOST;
2419d98215SMarc Zyngier }
2519d98215SMarc Zyngier 
2643835ac9SSasha Levin void kvm_cpu__enable_singlestep(struct kvm_cpu *vcpu)
275c3d55faSPekka Enberg {
285c3d55faSPekka Enberg 	struct kvm_guest_debug debug = {
295c3d55faSPekka Enberg 		.control	= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP,
305c3d55faSPekka Enberg 	};
315c3d55faSPekka Enberg 
3243835ac9SSasha Levin 	if (ioctl(vcpu->vcpu_fd, KVM_SET_GUEST_DEBUG, &debug) < 0)
334542f276SCyrill Gorcunov 		pr_warning("KVM_SET_GUEST_DEBUG failed");
345c3d55faSPekka Enberg }
355c3d55faSPekka Enberg 
3643835ac9SSasha Levin void kvm_cpu__run(struct kvm_cpu *vcpu)
375c3d55faSPekka Enberg {
385c3d55faSPekka Enberg 	int err;
395c3d55faSPekka Enberg 
40f9fdf5cdSAsias He 	if (!vcpu->is_running)
41f9fdf5cdSAsias He 		return;
42f9fdf5cdSAsias He 
4343835ac9SSasha Levin 	err = ioctl(vcpu->vcpu_fd, KVM_RUN, 0);
4476b75d32SMatt Evans 	if (err < 0 && (errno != EINTR && errno != EAGAIN))
455c3d55faSPekka Enberg 		die_perror("KVM_RUN failed");
465c3d55faSPekka Enberg }
4765bab644SPekka Enberg 
484298ddadSSasha Levin static void kvm_cpu_signal_handler(int signum)
4949e5227dSSasha Levin {
504298ddadSSasha Levin 	if (signum == SIGKVMEXIT) {
512aa76b26SWill Deacon 		if (current_kvm_cpu && current_kvm_cpu->is_running)
52656be1b8SSasha Levin 			current_kvm_cpu->is_running = false;
534298ddadSSasha Levin 	} else if (signum == SIGKVMPAUSE) {
544298ddadSSasha Levin 		current_kvm_cpu->paused = 1;
554298ddadSSasha Levin 	}
56*e300a5eeSMichael Ellerman 
57*e300a5eeSMichael Ellerman 	/* For SIGKVMTASK cpu->task is already set */
5849e5227dSSasha Levin }
5949e5227dSSasha Levin 
6073f7e5b3SSasha Levin static void kvm_cpu__handle_coalesced_mmio(struct kvm_cpu *cpu)
6173f7e5b3SSasha Levin {
6273f7e5b3SSasha Levin 	if (cpu->ring) {
6373f7e5b3SSasha Levin 		while (cpu->ring->first != cpu->ring->last) {
6473f7e5b3SSasha Levin 			struct kvm_coalesced_mmio *m;
6573f7e5b3SSasha Levin 			m = &cpu->ring->coalesced_mmio[cpu->ring->first];
669b735910SMarc Zyngier 			kvm_cpu__emulate_mmio(cpu,
6773f7e5b3SSasha Levin 					      m->phys_addr,
6873f7e5b3SSasha Levin 					      m->data,
6973f7e5b3SSasha Levin 					      m->len,
7073f7e5b3SSasha Levin 					      1);
7173f7e5b3SSasha Levin 			cpu->ring->first = (cpu->ring->first + 1) % KVM_COALESCED_MMIO_MAX;
7273f7e5b3SSasha Levin 		}
7373f7e5b3SSasha Levin 	}
7473f7e5b3SSasha Levin }
7573f7e5b3SSasha Levin 
76*e300a5eeSMichael Ellerman static DEFINE_MUTEX(task_lock);
77*e300a5eeSMichael Ellerman static int task_eventfd;
78*e300a5eeSMichael Ellerman 
79*e300a5eeSMichael Ellerman static void kvm_cpu__run_task(struct kvm_cpu *cpu)
80*e300a5eeSMichael Ellerman {
81*e300a5eeSMichael Ellerman 	u64 inc = 1;
82*e300a5eeSMichael Ellerman 
83*e300a5eeSMichael Ellerman 	pr_debug("Running task %p on cpu %lu", cpu->task, cpu->cpu_id);
84*e300a5eeSMichael Ellerman 
85*e300a5eeSMichael Ellerman 	/* Make sure we see the store to cpu->task */
86*e300a5eeSMichael Ellerman 	rmb();
87*e300a5eeSMichael Ellerman 	cpu->task->func(cpu, cpu->task->data);
88*e300a5eeSMichael Ellerman 
89*e300a5eeSMichael Ellerman 	/* Clear task before we signal completion */
90*e300a5eeSMichael Ellerman 	cpu->task = NULL;
91*e300a5eeSMichael Ellerman 	wmb();
92*e300a5eeSMichael Ellerman 
93*e300a5eeSMichael Ellerman 	if (write(task_eventfd, &inc, sizeof(inc)) < 0)
94*e300a5eeSMichael Ellerman 		die("Failed notifying of completed task.");
95*e300a5eeSMichael Ellerman }
96*e300a5eeSMichael Ellerman 
97*e300a5eeSMichael Ellerman void kvm_cpu__run_on_all_cpus(struct kvm *kvm, struct kvm_cpu_task *task)
98*e300a5eeSMichael Ellerman {
99*e300a5eeSMichael Ellerman 	int i, done = 0;
100*e300a5eeSMichael Ellerman 
101*e300a5eeSMichael Ellerman 	pr_debug("Running task %p on all cpus", task);
102*e300a5eeSMichael Ellerman 
103*e300a5eeSMichael Ellerman 	mutex_lock(&task_lock);
104*e300a5eeSMichael Ellerman 
105*e300a5eeSMichael Ellerman 	for (i = 0; i < kvm->nrcpus; i++) {
106*e300a5eeSMichael Ellerman 		if (kvm->cpus[i]->task) {
107*e300a5eeSMichael Ellerman 			/* Should never happen */
108*e300a5eeSMichael Ellerman 			die("CPU %d already has a task pending!", i);
109*e300a5eeSMichael Ellerman 		}
110*e300a5eeSMichael Ellerman 
111*e300a5eeSMichael Ellerman 		kvm->cpus[i]->task = task;
112*e300a5eeSMichael Ellerman 		wmb();
113*e300a5eeSMichael Ellerman 
114*e300a5eeSMichael Ellerman 		if (kvm->cpus[i] == current_kvm_cpu)
115*e300a5eeSMichael Ellerman 			kvm_cpu__run_task(current_kvm_cpu);
116*e300a5eeSMichael Ellerman 		else
117*e300a5eeSMichael Ellerman 			pthread_kill(kvm->cpus[i]->thread, SIGKVMTASK);
118*e300a5eeSMichael Ellerman 	}
119*e300a5eeSMichael Ellerman 
120*e300a5eeSMichael Ellerman 	while (done < kvm->nrcpus) {
121*e300a5eeSMichael Ellerman 		u64 count;
122*e300a5eeSMichael Ellerman 
123*e300a5eeSMichael Ellerman 		if (read(task_eventfd, &count, sizeof(count)) < 0)
124*e300a5eeSMichael Ellerman 			die("Failed reading task eventfd");
125*e300a5eeSMichael Ellerman 
126*e300a5eeSMichael Ellerman 		done += count;
127*e300a5eeSMichael Ellerman 	}
128*e300a5eeSMichael Ellerman 
129*e300a5eeSMichael Ellerman 	mutex_unlock(&task_lock);
130*e300a5eeSMichael Ellerman }
131*e300a5eeSMichael Ellerman 
13265bab644SPekka Enberg int kvm_cpu__start(struct kvm_cpu *cpu)
13365bab644SPekka Enberg {
1345ee154d1SPekka Enberg 	sigset_t sigset;
1355ee154d1SPekka Enberg 
1365ee154d1SPekka Enberg 	sigemptyset(&sigset);
1375ee154d1SPekka Enberg 	sigaddset(&sigset, SIGALRM);
1385ee154d1SPekka Enberg 
1395ee154d1SPekka Enberg 	pthread_sigmask(SIG_BLOCK, &sigset, NULL);
1405ee154d1SPekka Enberg 
1414298ddadSSasha Levin 	signal(SIGKVMEXIT, kvm_cpu_signal_handler);
1424298ddadSSasha Levin 	signal(SIGKVMPAUSE, kvm_cpu_signal_handler);
143*e300a5eeSMichael Ellerman 	signal(SIGKVMTASK, kvm_cpu_signal_handler);
14449e5227dSSasha Levin 
1455d1a249cSPekka Enberg 	kvm_cpu__reset_vcpu(cpu);
1465d1a249cSPekka Enberg 
147809f088bSSasha Levin 	if (cpu->kvm->cfg.single_step)
1486d6a4d41SPekka Enberg 		kvm_cpu__enable_singlestep(cpu);
1496d6a4d41SPekka Enberg 
150c23d9748SSasha Levin 	while (cpu->is_running) {
1514298ddadSSasha Levin 		if (cpu->paused) {
1524298ddadSSasha Levin 			kvm__notify_paused();
1534298ddadSSasha Levin 			cpu->paused = 0;
1544298ddadSSasha Levin 		}
1554298ddadSSasha Levin 
1564b1c6f6eSSasha Levin 		if (cpu->needs_nmi) {
1574b1c6f6eSSasha Levin 			kvm_cpu__arch_nmi(cpu);
1584b1c6f6eSSasha Levin 			cpu->needs_nmi = 0;
1594b1c6f6eSSasha Levin 		}
1604b1c6f6eSSasha Levin 
161*e300a5eeSMichael Ellerman 		if (cpu->task)
162*e300a5eeSMichael Ellerman 			kvm_cpu__run_task(cpu);
163*e300a5eeSMichael Ellerman 
16465bab644SPekka Enberg 		kvm_cpu__run(cpu);
16565bab644SPekka Enberg 
16665bab644SPekka Enberg 		switch (cpu->kvm_run->exit_reason) {
1671621292eSSasha Levin 		case KVM_EXIT_UNKNOWN:
1681621292eSSasha Levin 			break;
16965bab644SPekka Enberg 		case KVM_EXIT_DEBUG:
17065bab644SPekka Enberg 			kvm_cpu__show_registers(cpu);
17165bab644SPekka Enberg 			kvm_cpu__show_code(cpu);
17265bab644SPekka Enberg 			break;
17365bab644SPekka Enberg 		case KVM_EXIT_IO: {
17465bab644SPekka Enberg 			bool ret;
17565bab644SPekka Enberg 
1764123ca55SMarc Zyngier 			ret = kvm_cpu__emulate_io(cpu,
17765bab644SPekka Enberg 						  cpu->kvm_run->io.port,
1783fdf659dSSasha Levin 						  (u8 *)cpu->kvm_run +
17965bab644SPekka Enberg 						  cpu->kvm_run->io.data_offset,
18065bab644SPekka Enberg 						  cpu->kvm_run->io.direction,
18165bab644SPekka Enberg 						  cpu->kvm_run->io.size,
18265bab644SPekka Enberg 						  cpu->kvm_run->io.count);
18365bab644SPekka Enberg 
18465bab644SPekka Enberg 			if (!ret)
18565bab644SPekka Enberg 				goto panic_kvm;
18665bab644SPekka Enberg 			break;
18765bab644SPekka Enberg 		}
18865bab644SPekka Enberg 		case KVM_EXIT_MMIO: {
18965bab644SPekka Enberg 			bool ret;
19065bab644SPekka Enberg 
191a7518f05SSasha Levin 			/*
192a7518f05SSasha Levin 			 * If we had MMIO exit, coalesced ring should be processed
193a7518f05SSasha Levin 			 * *before* processing the exit itself
194a7518f05SSasha Levin 			 */
195a7518f05SSasha Levin 			kvm_cpu__handle_coalesced_mmio(cpu);
196a7518f05SSasha Levin 
1979b735910SMarc Zyngier 			ret = kvm_cpu__emulate_mmio(cpu,
19865bab644SPekka Enberg 						    cpu->kvm_run->mmio.phys_addr,
19965bab644SPekka Enberg 						    cpu->kvm_run->mmio.data,
20065bab644SPekka Enberg 						    cpu->kvm_run->mmio.len,
20165bab644SPekka Enberg 						    cpu->kvm_run->mmio.is_write);
20265bab644SPekka Enberg 
20365bab644SPekka Enberg 			if (!ret)
20465bab644SPekka Enberg 				goto panic_kvm;
20565bab644SPekka Enberg 			break;
20665bab644SPekka Enberg 		}
2075ee154d1SPekka Enberg 		case KVM_EXIT_INTR:
208656be1b8SSasha Levin 			if (cpu->is_running)
209656be1b8SSasha Levin 				break;
21049e5227dSSasha Levin 			goto exit_kvm;
21165bab644SPekka Enberg 		case KVM_EXIT_SHUTDOWN:
21265bab644SPekka Enberg 			goto exit_kvm;
2135f9b016eSAnup Patel 		case KVM_EXIT_SYSTEM_EVENT:
2145f9b016eSAnup Patel 			/*
2155f9b016eSAnup Patel 			 * Print the type of system event and
2165f9b016eSAnup Patel 			 * treat all system events as shutdown request.
2175f9b016eSAnup Patel 			 */
2185f9b016eSAnup Patel 			switch (cpu->kvm_run->system_event.type) {
2195f9b016eSAnup Patel 			default:
2205f9b016eSAnup Patel 				pr_warning("unknown system event type %d",
2215f9b016eSAnup Patel 					   cpu->kvm_run->system_event.type);
2220161ed77SMark Rutland 				/* fall through for now */
2230161ed77SMark Rutland 			case KVM_SYSTEM_EVENT_RESET:
2240161ed77SMark Rutland 				/* Fall through for now */
2250161ed77SMark Rutland 			case KVM_SYSTEM_EVENT_SHUTDOWN:
2260161ed77SMark Rutland 				/*
2270161ed77SMark Rutland 				 * Ensure that all VCPUs are torn down,
2280161ed77SMark Rutland 				 * regardless of which CPU generated the event.
2290161ed77SMark Rutland 				 */
2302aa76b26SWill Deacon 				kvm__reboot(cpu->kvm);
2315f9b016eSAnup Patel 				goto exit_kvm;
2325f9b016eSAnup Patel 			};
2335f9b016eSAnup Patel 			break;
234341ee0d4SMatt Evans 		default: {
235341ee0d4SMatt Evans 			bool ret;
236341ee0d4SMatt Evans 
237341ee0d4SMatt Evans 			ret = kvm_cpu__handle_exit(cpu);
238341ee0d4SMatt Evans 			if (!ret)
23965bab644SPekka Enberg 				goto panic_kvm;
240341ee0d4SMatt Evans 			break;
241341ee0d4SMatt Evans 		}
24265bab644SPekka Enberg 		}
24373f7e5b3SSasha Levin 		kvm_cpu__handle_coalesced_mmio(cpu);
24465bab644SPekka Enberg 	}
24565bab644SPekka Enberg 
24665bab644SPekka Enberg exit_kvm:
24765bab644SPekka Enberg 	return 0;
24865bab644SPekka Enberg 
24965bab644SPekka Enberg panic_kvm:
25065bab644SPekka Enberg 	return 1;
25165bab644SPekka Enberg }
252df4239fbSSasha Levin 
253df4239fbSSasha Levin int kvm_cpu__init(struct kvm *kvm)
254df4239fbSSasha Levin {
255df4239fbSSasha Levin 	int max_cpus, recommended_cpus, i;
256df4239fbSSasha Levin 
257df4239fbSSasha Levin 	max_cpus = kvm__max_cpus(kvm);
258df4239fbSSasha Levin 	recommended_cpus = kvm__recommended_cpus(kvm);
259df4239fbSSasha Levin 
260df4239fbSSasha Levin 	if (kvm->cfg.nrcpus > max_cpus) {
261df4239fbSSasha Levin 		printf("  # Limit the number of CPUs to %d\n", max_cpus);
262df4239fbSSasha Levin 		kvm->cfg.nrcpus = max_cpus;
263df4239fbSSasha Levin 	} else if (kvm->cfg.nrcpus > recommended_cpus) {
264df4239fbSSasha Levin 		printf("  # Warning: The maximum recommended amount of VCPUs"
265df4239fbSSasha Levin 			" is %d\n", recommended_cpus);
266df4239fbSSasha Levin 	}
267df4239fbSSasha Levin 
268df4239fbSSasha Levin 	kvm->nrcpus = kvm->cfg.nrcpus;
269df4239fbSSasha Levin 
270*e300a5eeSMichael Ellerman 	task_eventfd = eventfd(0, 0);
271*e300a5eeSMichael Ellerman 	if (task_eventfd < 0) {
272*e300a5eeSMichael Ellerman 		pr_warning("Couldn't create task_eventfd");
273*e300a5eeSMichael Ellerman 		return task_eventfd;
274*e300a5eeSMichael Ellerman 	}
275*e300a5eeSMichael Ellerman 
276df4239fbSSasha Levin 	/* Alloc one pointer too many, so array ends up 0-terminated */
277df4239fbSSasha Levin 	kvm->cpus = calloc(kvm->nrcpus + 1, sizeof(void *));
278df4239fbSSasha Levin 	if (!kvm->cpus) {
279df4239fbSSasha Levin 		pr_warning("Couldn't allocate array for %d CPUs", kvm->nrcpus);
280df4239fbSSasha Levin 		return -ENOMEM;
281df4239fbSSasha Levin 	}
282df4239fbSSasha Levin 
283df4239fbSSasha Levin 	for (i = 0; i < kvm->nrcpus; i++) {
284df4239fbSSasha Levin 		kvm->cpus[i] = kvm_cpu__arch_init(kvm, i);
285df4239fbSSasha Levin 		if (!kvm->cpus[i]) {
286df4239fbSSasha Levin 			pr_warning("unable to initialize KVM VCPU");
287df4239fbSSasha Levin 			goto fail_alloc;
288df4239fbSSasha Levin 		}
289df4239fbSSasha Levin 	}
290df4239fbSSasha Levin 
291df4239fbSSasha Levin 	return 0;
292df4239fbSSasha Levin 
293df4239fbSSasha Levin fail_alloc:
294df4239fbSSasha Levin 	for (i = 0; i < kvm->nrcpus; i++)
295df4239fbSSasha Levin 		free(kvm->cpus[i]);
296df4239fbSSasha Levin 	return -ENOMEM;
297df4239fbSSasha Levin }
29849a8afd1SSasha Levin base_init(kvm_cpu__init);
299df4239fbSSasha Levin 
300df4239fbSSasha Levin int kvm_cpu__exit(struct kvm *kvm)
301df4239fbSSasha Levin {
302df4239fbSSasha Levin 	int i, r;
303df4239fbSSasha Levin 	void *ret = NULL;
304df4239fbSSasha Levin 
305df4239fbSSasha Levin 	kvm_cpu__delete(kvm->cpus[0]);
306df4239fbSSasha Levin 	kvm->cpus[0] = NULL;
307df4239fbSSasha Levin 
308df4239fbSSasha Levin 	for (i = 1; i < kvm->nrcpus; i++) {
309df4239fbSSasha Levin 		if (kvm->cpus[i]->is_running) {
310df4239fbSSasha Levin 			pthread_kill(kvm->cpus[i]->thread, SIGKVMEXIT);
311df4239fbSSasha Levin 			if (pthread_join(kvm->cpus[i]->thread, &ret) != 0)
312df4239fbSSasha Levin 				die("pthread_join");
313df4239fbSSasha Levin 			kvm_cpu__delete(kvm->cpus[i]);
314df4239fbSSasha Levin 		}
315df4239fbSSasha Levin 		if (ret == NULL)
316df4239fbSSasha Levin 			r = 0;
317df4239fbSSasha Levin 	}
318df4239fbSSasha Levin 
319df4239fbSSasha Levin 	free(kvm->cpus);
320df4239fbSSasha Levin 
321df4239fbSSasha Levin 	kvm->nrcpus = 0;
322df4239fbSSasha Levin 
323*e300a5eeSMichael Ellerman 	close(task_eventfd);
324*e300a5eeSMichael Ellerman 
325df4239fbSSasha Levin 	return r;
326df4239fbSSasha Levin }
327a44c3293SSasha Levin core_exit(kvm_cpu__exit);
328