xref: /kvmtool/kvm-cpu.c (revision 809f088b1d9fc4223c19a2f500e33adee5739ccc)
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"
65c3d55faSPekka Enberg 
75c3d55faSPekka Enberg #include <sys/ioctl.h>
85c3d55faSPekka Enberg #include <sys/mman.h>
95ee154d1SPekka Enberg #include <signal.h>
105c3d55faSPekka Enberg #include <stdlib.h>
11b0b42ba0SPekka Enberg #include <string.h>
125c3d55faSPekka Enberg #include <errno.h>
135c3d55faSPekka Enberg #include <stdio.h>
145c3d55faSPekka Enberg 
15e2077857SMatt Evans extern struct kvm_cpu **kvm_cpus;
16656be1b8SSasha Levin extern __thread struct kvm_cpu *current_kvm_cpu;
17656be1b8SSasha Levin 
1843835ac9SSasha Levin void kvm_cpu__enable_singlestep(struct kvm_cpu *vcpu)
195c3d55faSPekka Enberg {
205c3d55faSPekka Enberg 	struct kvm_guest_debug debug = {
215c3d55faSPekka Enberg 		.control	= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP,
225c3d55faSPekka Enberg 	};
235c3d55faSPekka Enberg 
2443835ac9SSasha Levin 	if (ioctl(vcpu->vcpu_fd, KVM_SET_GUEST_DEBUG, &debug) < 0)
254542f276SCyrill Gorcunov 		pr_warning("KVM_SET_GUEST_DEBUG failed");
265c3d55faSPekka Enberg }
275c3d55faSPekka Enberg 
2843835ac9SSasha Levin void kvm_cpu__run(struct kvm_cpu *vcpu)
295c3d55faSPekka Enberg {
305c3d55faSPekka Enberg 	int err;
315c3d55faSPekka Enberg 
32f9fdf5cdSAsias He 	if (!vcpu->is_running)
33f9fdf5cdSAsias He 		return;
34f9fdf5cdSAsias He 
3543835ac9SSasha Levin 	err = ioctl(vcpu->vcpu_fd, KVM_RUN, 0);
3676b75d32SMatt Evans 	if (err < 0 && (errno != EINTR && errno != EAGAIN))
375c3d55faSPekka Enberg 		die_perror("KVM_RUN failed");
385c3d55faSPekka Enberg }
3965bab644SPekka Enberg 
404298ddadSSasha Levin static void kvm_cpu_signal_handler(int signum)
4149e5227dSSasha Levin {
424298ddadSSasha Levin 	if (signum == SIGKVMEXIT) {
43714e5b7fSSasha Levin 		if (current_kvm_cpu && current_kvm_cpu->is_running) {
44656be1b8SSasha Levin 			current_kvm_cpu->is_running = false;
458dd576f5SAsias He 			kvm__continue();
46656be1b8SSasha Levin 		}
474298ddadSSasha Levin 	} else if (signum == SIGKVMPAUSE) {
484298ddadSSasha Levin 		current_kvm_cpu->paused = 1;
494298ddadSSasha Levin 	}
5049e5227dSSasha Levin }
5149e5227dSSasha Levin 
5273f7e5b3SSasha Levin static void kvm_cpu__handle_coalesced_mmio(struct kvm_cpu *cpu)
5373f7e5b3SSasha Levin {
5473f7e5b3SSasha Levin 	if (cpu->ring) {
5573f7e5b3SSasha Levin 		while (cpu->ring->first != cpu->ring->last) {
5673f7e5b3SSasha Levin 			struct kvm_coalesced_mmio *m;
5773f7e5b3SSasha Levin 			m = &cpu->ring->coalesced_mmio[cpu->ring->first];
5817edd536SMatt Evans 			kvm_cpu__emulate_mmio(cpu->kvm,
5973f7e5b3SSasha Levin 					      m->phys_addr,
6073f7e5b3SSasha Levin 					      m->data,
6173f7e5b3SSasha Levin 					      m->len,
6273f7e5b3SSasha Levin 					      1);
6373f7e5b3SSasha Levin 			cpu->ring->first = (cpu->ring->first + 1) % KVM_COALESCED_MMIO_MAX;
6473f7e5b3SSasha Levin 		}
6573f7e5b3SSasha Levin 	}
6673f7e5b3SSasha Levin }
6773f7e5b3SSasha Levin 
68714e5b7fSSasha Levin void kvm_cpu__reboot(void)
69714e5b7fSSasha Levin {
70c23d9748SSasha Levin 	int i;
71c23d9748SSasha Levin 
72e2077857SMatt Evans 	/* The kvm_cpus array contains a null pointer in the last location */
73e2077857SMatt Evans 	for (i = 0; ; i++) {
74c23d9748SSasha Levin 		if (kvm_cpus[i])
75c23d9748SSasha Levin 			pthread_kill(kvm_cpus[i]->thread, SIGKVMEXIT);
76e2077857SMatt Evans 		else
77e2077857SMatt Evans 			break;
78e2077857SMatt Evans 	}
79714e5b7fSSasha Levin }
80714e5b7fSSasha Levin 
8165bab644SPekka Enberg int kvm_cpu__start(struct kvm_cpu *cpu)
8265bab644SPekka Enberg {
835ee154d1SPekka Enberg 	sigset_t sigset;
845ee154d1SPekka Enberg 
855ee154d1SPekka Enberg 	sigemptyset(&sigset);
865ee154d1SPekka Enberg 	sigaddset(&sigset, SIGALRM);
875ee154d1SPekka Enberg 
885ee154d1SPekka Enberg 	pthread_sigmask(SIG_BLOCK, &sigset, NULL);
895ee154d1SPekka Enberg 
904298ddadSSasha Levin 	signal(SIGKVMEXIT, kvm_cpu_signal_handler);
914298ddadSSasha Levin 	signal(SIGKVMPAUSE, kvm_cpu_signal_handler);
9249e5227dSSasha Levin 
935d1a249cSPekka Enberg 	kvm_cpu__reset_vcpu(cpu);
945d1a249cSPekka Enberg 
95*809f088bSSasha Levin 	if (cpu->kvm->cfg.single_step)
966d6a4d41SPekka Enberg 		kvm_cpu__enable_singlestep(cpu);
976d6a4d41SPekka Enberg 
98c23d9748SSasha Levin 	while (cpu->is_running) {
994298ddadSSasha Levin 		if (cpu->paused) {
1004298ddadSSasha Levin 			kvm__notify_paused();
1014298ddadSSasha Levin 			cpu->paused = 0;
1024298ddadSSasha Levin 		}
1034298ddadSSasha Levin 
1044b1c6f6eSSasha Levin 		if (cpu->needs_nmi) {
1054b1c6f6eSSasha Levin 			kvm_cpu__arch_nmi(cpu);
1064b1c6f6eSSasha Levin 			cpu->needs_nmi = 0;
1074b1c6f6eSSasha Levin 		}
1084b1c6f6eSSasha Levin 
10965bab644SPekka Enberg 		kvm_cpu__run(cpu);
11065bab644SPekka Enberg 
11165bab644SPekka Enberg 		switch (cpu->kvm_run->exit_reason) {
1121621292eSSasha Levin 		case KVM_EXIT_UNKNOWN:
1131621292eSSasha Levin 			break;
11465bab644SPekka Enberg 		case KVM_EXIT_DEBUG:
11565bab644SPekka Enberg 			kvm_cpu__show_registers(cpu);
11665bab644SPekka Enberg 			kvm_cpu__show_code(cpu);
11765bab644SPekka Enberg 			break;
11865bab644SPekka Enberg 		case KVM_EXIT_IO: {
11965bab644SPekka Enberg 			bool ret;
12065bab644SPekka Enberg 
12117edd536SMatt Evans 			ret = kvm_cpu__emulate_io(cpu->kvm,
12265bab644SPekka Enberg 						  cpu->kvm_run->io.port,
1233fdf659dSSasha Levin 						  (u8 *)cpu->kvm_run +
12465bab644SPekka Enberg 						  cpu->kvm_run->io.data_offset,
12565bab644SPekka Enberg 						  cpu->kvm_run->io.direction,
12665bab644SPekka Enberg 						  cpu->kvm_run->io.size,
12765bab644SPekka Enberg 						  cpu->kvm_run->io.count);
12865bab644SPekka Enberg 
12965bab644SPekka Enberg 			if (!ret)
13065bab644SPekka Enberg 				goto panic_kvm;
13165bab644SPekka Enberg 			break;
13265bab644SPekka Enberg 		}
13365bab644SPekka Enberg 		case KVM_EXIT_MMIO: {
13465bab644SPekka Enberg 			bool ret;
13565bab644SPekka Enberg 
136a7518f05SSasha Levin 			/*
137a7518f05SSasha Levin 			 * If we had MMIO exit, coalesced ring should be processed
138a7518f05SSasha Levin 			 * *before* processing the exit itself
139a7518f05SSasha Levin 			 */
140a7518f05SSasha Levin 			kvm_cpu__handle_coalesced_mmio(cpu);
141a7518f05SSasha Levin 
14217edd536SMatt Evans 			ret = kvm_cpu__emulate_mmio(cpu->kvm,
14365bab644SPekka Enberg 						    cpu->kvm_run->mmio.phys_addr,
14465bab644SPekka Enberg 						    cpu->kvm_run->mmio.data,
14565bab644SPekka Enberg 						    cpu->kvm_run->mmio.len,
14665bab644SPekka Enberg 						    cpu->kvm_run->mmio.is_write);
14765bab644SPekka Enberg 
14865bab644SPekka Enberg 			if (!ret)
14965bab644SPekka Enberg 				goto panic_kvm;
15065bab644SPekka Enberg 			break;
15165bab644SPekka Enberg 		}
1525ee154d1SPekka Enberg 		case KVM_EXIT_INTR:
153656be1b8SSasha Levin 			if (cpu->is_running)
154656be1b8SSasha Levin 				break;
15549e5227dSSasha Levin 			goto exit_kvm;
15665bab644SPekka Enberg 		case KVM_EXIT_SHUTDOWN:
15765bab644SPekka Enberg 			goto exit_kvm;
158341ee0d4SMatt Evans 		default: {
159341ee0d4SMatt Evans 			bool ret;
160341ee0d4SMatt Evans 
161341ee0d4SMatt Evans 			ret = kvm_cpu__handle_exit(cpu);
162341ee0d4SMatt Evans 			if (!ret)
16365bab644SPekka Enberg 				goto panic_kvm;
164341ee0d4SMatt Evans 			break;
165341ee0d4SMatt Evans 		}
16665bab644SPekka Enberg 		}
16773f7e5b3SSasha Levin 		kvm_cpu__handle_coalesced_mmio(cpu);
16865bab644SPekka Enberg 	}
16965bab644SPekka Enberg 
17065bab644SPekka Enberg exit_kvm:
17165bab644SPekka Enberg 	return 0;
17265bab644SPekka Enberg 
17365bab644SPekka Enberg panic_kvm:
17465bab644SPekka Enberg 	return 1;
17565bab644SPekka Enberg }
176