xref: /kvmtool/main.c (revision aa2c2691fbf0e258636db106f42da74f90f11424)
1ae1fae34SPekka Enberg #include "kvm/kvm.h"
2ae1fae34SPekka Enberg 
313a7760fSPekka Enberg #include "kvm/early_printk.h"
4f3150089SPekka Enberg #include "kvm/util.h"
57fb218bdSPekka Enberg 
6ae1fae34SPekka Enberg #include <inttypes.h>
70290405dSPekka Enberg #include <signal.h>
8ae1fae34SPekka Enberg #include <stdint.h>
9ae1fae34SPekka Enberg #include <stdlib.h>
10f3150089SPekka Enberg #include <string.h>
11ae1fae34SPekka Enberg #include <stdio.h>
12ae1fae34SPekka Enberg 
133db4f1beSCyrill Gorcunov unsigned int dbgtest_mode;
143db4f1beSCyrill Gorcunov 
15ae1fae34SPekka Enberg static void usage(char *argv[])
16ae1fae34SPekka Enberg {
173db4f1beSCyrill Gorcunov 	fprintf(stderr, "  usage: %s [--dbgtest] [--single-step] [--kernel=]<kernel-image>\n",
185645c7a9SCyrill Gorcunov 		argv[0]);
19ae1fae34SPekka Enberg 	exit(1);
20ae1fae34SPekka Enberg }
21ae1fae34SPekka Enberg 
220290405dSPekka Enberg static struct kvm *kvm;
230290405dSPekka Enberg 
240290405dSPekka Enberg static void handle_sigquit(int sig)
250290405dSPekka Enberg {
260290405dSPekka Enberg 	kvm__show_registers(kvm);
270290405dSPekka Enberg 	kvm__show_code(kvm);
280290405dSPekka Enberg 	kvm__show_page_tables(kvm);
290290405dSPekka Enberg 
300290405dSPekka Enberg 	kvm__delete(kvm);
310290405dSPekka Enberg 
320290405dSPekka Enberg 	exit(1);
330290405dSPekka Enberg }
340290405dSPekka Enberg 
356fd7308dSCyrill Gorcunov static char real_cmdline[2048];
366fd7308dSCyrill Gorcunov 
37*aa2c2691SPekka Enberg static bool option_matches(char *arg, const char *option)
38*aa2c2691SPekka Enberg {
39*aa2c2691SPekka Enberg 	return !strncmp(arg, option, strlen(option));
40*aa2c2691SPekka Enberg }
41*aa2c2691SPekka Enberg 
42ae1fae34SPekka Enberg int main(int argc, char *argv[])
43ae1fae34SPekka Enberg {
445645c7a9SCyrill Gorcunov 	const char *kernel_filename = NULL;
456d1f350dSCyrill Gorcunov 	const char *kernel_cmdline = NULL;
4664f06a2bSPekka Enberg 	bool single_step = false;
475645c7a9SCyrill Gorcunov 	int i;
48ae1fae34SPekka Enberg 
490290405dSPekka Enberg 	signal(SIGQUIT, handle_sigquit);
500290405dSPekka Enberg 
515645c7a9SCyrill Gorcunov 	for (i = 1; i < argc; i++) {
52*aa2c2691SPekka Enberg 		if (option_matches(argv[i], "--kernel=")) {
535645c7a9SCyrill Gorcunov 			kernel_filename = &argv[i][9];
545645c7a9SCyrill Gorcunov 			continue;
55*aa2c2691SPekka Enberg 		} else if (option_matches(argv[i], "--params=")) {
566d1f350dSCyrill Gorcunov 			kernel_cmdline = &argv[i][9];
576d1f350dSCyrill Gorcunov 			continue;
58*aa2c2691SPekka Enberg 		} else if (option_matches(argv[i], "--dbgtest")) {
593db4f1beSCyrill Gorcunov 			dbgtest_mode = 1;
603db4f1beSCyrill Gorcunov 			continue;
61*aa2c2691SPekka Enberg 		} else if (option_matches(argv[i], "--single-step")) {
6264f06a2bSPekka Enberg 			single_step = true;
6364f06a2bSPekka Enberg 			continue;
645645c7a9SCyrill Gorcunov 		} else {
655645c7a9SCyrill Gorcunov 			/* any unspecified arg is kernel image */
665645c7a9SCyrill Gorcunov 			if (argv[i][0] != '-')
675645c7a9SCyrill Gorcunov 				kernel_filename = argv[i];
685645c7a9SCyrill Gorcunov 			else
695645c7a9SCyrill Gorcunov 				warning("Unknown option: %s", argv[i]);
705645c7a9SCyrill Gorcunov 		}
715645c7a9SCyrill Gorcunov 	}
725645c7a9SCyrill Gorcunov 
735645c7a9SCyrill Gorcunov 	/* at least we should have kernel image passed */
745645c7a9SCyrill Gorcunov 	if (!kernel_filename)
75ae1fae34SPekka Enberg 		usage(argv);
76ae1fae34SPekka Enberg 
77ae1fae34SPekka Enberg 	kvm = kvm__init();
78ae1fae34SPekka Enberg 
79a1fe6bc5SPekka Enberg 	kvm__setup_cpuid(kvm);
80a1fe6bc5SPekka Enberg 
813a5c54b1SPekka Enberg 	strcpy(real_cmdline, "notsc nolapic nosmp noacpi nopci pci=off earlyprintk=serial,keep ");
82f28c0a02SCyrill Gorcunov 	if (kernel_cmdline) {
830b322d96SCyrill Gorcunov 		strlcat(real_cmdline, kernel_cmdline, sizeof(real_cmdline));
84f28c0a02SCyrill Gorcunov 		real_cmdline[sizeof(real_cmdline)-1] = '\0';
85f28c0a02SCyrill Gorcunov 	}
862525eb1fSPekka Enberg 
872525eb1fSPekka Enberg 	if (!kvm__load_kernel(kvm, kernel_filename, real_cmdline))
887fb218bdSPekka Enberg 		die("unable to load kernel %s", kernel_filename);
89ae1fae34SPekka Enberg 
907fb218bdSPekka Enberg 	kvm__reset_vcpu(kvm);
91ae1fae34SPekka Enberg 
9264f06a2bSPekka Enberg 	if (single_step)
93ae1fae34SPekka Enberg 		kvm__enable_singlestep(kvm);
94ae1fae34SPekka Enberg 
9513a7760fSPekka Enberg 	early_printk__init();
9613a7760fSPekka Enberg 
97ae1fae34SPekka Enberg 	for (;;) {
98ae1fae34SPekka Enberg 		kvm__run(kvm);
99ae1fae34SPekka Enberg 
100ae1fae34SPekka Enberg 		switch (kvm->kvm_run->exit_reason) {
101fe806d65SPekka Enberg 		case KVM_EXIT_DEBUG:
102fe806d65SPekka Enberg 			kvm__show_registers(kvm);
103fe806d65SPekka Enberg 			kvm__show_code(kvm);
104fe806d65SPekka Enberg 			break;
1052049569dSPekka Enberg 		case KVM_EXIT_IO: {
1062049569dSPekka Enberg 			bool ret;
1072049569dSPekka Enberg 
1082049569dSPekka Enberg 			ret = kvm__emulate_io(kvm,
109ae1fae34SPekka Enberg 					kvm->kvm_run->io.port,
110ae1fae34SPekka Enberg 					(uint8_t *)kvm->kvm_run + kvm->kvm_run->io.data_offset,
111ae1fae34SPekka Enberg 					kvm->kvm_run->io.direction,
112ae1fae34SPekka Enberg 					kvm->kvm_run->io.size,
113ae1fae34SPekka Enberg 					kvm->kvm_run->io.count);
1142049569dSPekka Enberg 
1152049569dSPekka Enberg 			if (!ret)
1162049569dSPekka Enberg 				goto exit_kvm;
117ae1fae34SPekka Enberg 			break;
1182049569dSPekka Enberg 		}
11929443dabSPekka Enberg 		case KVM_EXIT_MMIO: {
12029443dabSPekka Enberg 			bool ret;
12129443dabSPekka Enberg 
12229443dabSPekka Enberg 			ret = kvm__emulate_mmio(kvm,
12329443dabSPekka Enberg 					kvm->kvm_run->mmio.phys_addr,
12429443dabSPekka Enberg 					kvm->kvm_run->mmio.data,
12529443dabSPekka Enberg 					kvm->kvm_run->mmio.len,
12629443dabSPekka Enberg 					kvm->kvm_run->mmio.is_write);
12729443dabSPekka Enberg 
12829443dabSPekka Enberg 			if (!ret)
12929443dabSPekka Enberg 				goto exit_kvm;
13029443dabSPekka Enberg 			break;
13129443dabSPekka Enberg 
13229443dabSPekka Enberg 		}
133ae1fae34SPekka Enberg 		default:
134ae1fae34SPekka Enberg 			goto exit_kvm;
135ae1fae34SPekka Enberg 		}
136ae1fae34SPekka Enberg 	}
137ae1fae34SPekka Enberg 
138ae1fae34SPekka Enberg exit_kvm:
1393db4f1beSCyrill Gorcunov 
1403db4f1beSCyrill Gorcunov 	if (dbgtest_mode) {
1413db4f1beSCyrill Gorcunov 		if (kvm->kvm_run->exit_reason == KVM_EXIT_IO &&
14279241bb6SCyrill Gorcunov 			kvm->kvm_run->io.port == 0xe0)
1433db4f1beSCyrill Gorcunov 			fprintf(stderr, "KVM: this is an expected IO error\n");
1443db4f1beSCyrill Gorcunov 			goto out;
1453db4f1beSCyrill Gorcunov 	}
1463db4f1beSCyrill Gorcunov 
147ae1fae34SPekka Enberg 	fprintf(stderr, "KVM exit reason: %" PRIu32 " (\"%s\")\n",
148ae1fae34SPekka Enberg 		kvm->kvm_run->exit_reason, kvm_exit_reasons[kvm->kvm_run->exit_reason]);
149b9c0a0bcSCyrill Gorcunov 	if (kvm->kvm_run->exit_reason == KVM_EXIT_UNKNOWN)
150b9c0a0bcSCyrill Gorcunov 		fprintf(stderr, "KVM exit code: 0x%016llx\n",
151b9c0a0bcSCyrill Gorcunov 			kvm->kvm_run->hw.hardware_exit_reason);
152ae1fae34SPekka Enberg 
153ae1fae34SPekka Enberg 	kvm__show_registers(kvm);
154ae1fae34SPekka Enberg 	kvm__show_code(kvm);
155f01944c8SPekka Enberg 	kvm__show_page_tables(kvm);
1563db4f1beSCyrill Gorcunov out:
1579ef4c68eSPekka Enberg 	kvm__delete(kvm);
1589ef4c68eSPekka Enberg 
159ae1fae34SPekka Enberg 	return 0;
160ae1fae34SPekka Enberg }
161