xref: /kvmtool/main.c (revision f28c0a02f8baed175104cc41a778e307ba50ba58)
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>
7ae1fae34SPekka Enberg #include <stdint.h>
8ae1fae34SPekka Enberg #include <stdlib.h>
9f3150089SPekka Enberg #include <string.h>
10ae1fae34SPekka Enberg #include <stdio.h>
11ae1fae34SPekka Enberg 
12ae1fae34SPekka Enberg static void usage(char *argv[])
13ae1fae34SPekka Enberg {
1464f06a2bSPekka Enberg 	fprintf(stderr, "  usage: %s [--single-step] [--kernel=]<kernel-image>\n",
155645c7a9SCyrill Gorcunov 		argv[0]);
16ae1fae34SPekka Enberg 	exit(1);
17ae1fae34SPekka Enberg }
18ae1fae34SPekka Enberg 
19ae1fae34SPekka Enberg int main(int argc, char *argv[])
20ae1fae34SPekka Enberg {
215645c7a9SCyrill Gorcunov 	const char *kernel_filename = NULL;
226d1f350dSCyrill Gorcunov 	const char *kernel_cmdline = NULL;
2364f06a2bSPekka Enberg 	bool single_step = false;
242525eb1fSPekka Enberg 	char real_cmdline[128];
25ae1fae34SPekka Enberg 	struct kvm *kvm;
265645c7a9SCyrill Gorcunov 	int i;
27ae1fae34SPekka Enberg 
285645c7a9SCyrill Gorcunov 	for (i = 1; i < argc; i++) {
295645c7a9SCyrill Gorcunov 		if (!strncmp("--kernel=", argv[i], 9)) {
305645c7a9SCyrill Gorcunov 			kernel_filename = &argv[i][9];
315645c7a9SCyrill Gorcunov 			continue;
326d1f350dSCyrill Gorcunov 		} else if (!strncmp("--params=", argv[i], 9)) {
336d1f350dSCyrill Gorcunov 			kernel_cmdline = &argv[i][9];
346d1f350dSCyrill Gorcunov 			continue;
3564f06a2bSPekka Enberg 		} else if (!strncmp("--single-step", argv[i], 13)) {
3664f06a2bSPekka Enberg 			single_step = true;
3764f06a2bSPekka Enberg 			continue;
385645c7a9SCyrill Gorcunov 		} else {
395645c7a9SCyrill Gorcunov 			/* any unspecified arg is kernel image */
405645c7a9SCyrill Gorcunov 			if (argv[i][0] != '-')
415645c7a9SCyrill Gorcunov 				kernel_filename = argv[i];
425645c7a9SCyrill Gorcunov 			else
435645c7a9SCyrill Gorcunov 				warning("Unknown option: %s", argv[i]);
445645c7a9SCyrill Gorcunov 		}
455645c7a9SCyrill Gorcunov 	}
465645c7a9SCyrill Gorcunov 
475645c7a9SCyrill Gorcunov 	/* at least we should have kernel image passed */
485645c7a9SCyrill Gorcunov 	if (!kernel_filename)
49ae1fae34SPekka Enberg 		usage(argv);
50ae1fae34SPekka Enberg 
51ae1fae34SPekka Enberg 	kvm = kvm__init();
52ae1fae34SPekka Enberg 
53a1fe6bc5SPekka Enberg 	kvm__setup_cpuid(kvm);
54a1fe6bc5SPekka Enberg 
55*f28c0a02SCyrill Gorcunov 	strcpy(real_cmdline, "notsc nolapic nosmp noacpi earlyprintk=serial,keep");
56*f28c0a02SCyrill Gorcunov 	if (kernel_cmdline) {
57*f28c0a02SCyrill Gorcunov 		strncat(real_cmdline, kernel_cmdline, sizeof(real_cmdline));
58*f28c0a02SCyrill Gorcunov 		real_cmdline[sizeof(real_cmdline)-1] = '\0';
59*f28c0a02SCyrill Gorcunov 	}
602525eb1fSPekka Enberg 
612525eb1fSPekka Enberg 	if (!kvm__load_kernel(kvm, kernel_filename, real_cmdline))
627fb218bdSPekka Enberg 		die("unable to load kernel %s", kernel_filename);
63ae1fae34SPekka Enberg 
647fb218bdSPekka Enberg 	kvm__reset_vcpu(kvm);
65ae1fae34SPekka Enberg 
6664f06a2bSPekka Enberg 	if (single_step)
67ae1fae34SPekka Enberg 		kvm__enable_singlestep(kvm);
68ae1fae34SPekka Enberg 
6913a7760fSPekka Enberg 	early_printk__init();
7013a7760fSPekka Enberg 
71ae1fae34SPekka Enberg 	for (;;) {
72ae1fae34SPekka Enberg 		kvm__run(kvm);
73ae1fae34SPekka Enberg 
74ae1fae34SPekka Enberg 		switch (kvm->kvm_run->exit_reason) {
75fe806d65SPekka Enberg 		case KVM_EXIT_DEBUG:
76fe806d65SPekka Enberg 			kvm__show_registers(kvm);
77fe806d65SPekka Enberg 			kvm__show_code(kvm);
78fe806d65SPekka Enberg 			break;
792049569dSPekka Enberg 		case KVM_EXIT_IO: {
802049569dSPekka Enberg 			bool ret;
812049569dSPekka Enberg 
822049569dSPekka Enberg 			ret = kvm__emulate_io(kvm,
83ae1fae34SPekka Enberg 					kvm->kvm_run->io.port,
84ae1fae34SPekka Enberg 					(uint8_t *)kvm->kvm_run + kvm->kvm_run->io.data_offset,
85ae1fae34SPekka Enberg 					kvm->kvm_run->io.direction,
86ae1fae34SPekka Enberg 					kvm->kvm_run->io.size,
87ae1fae34SPekka Enberg 					kvm->kvm_run->io.count);
882049569dSPekka Enberg 
892049569dSPekka Enberg 			if (!ret)
902049569dSPekka Enberg 				goto exit_kvm;
91ae1fae34SPekka Enberg 			break;
922049569dSPekka Enberg 		}
9329443dabSPekka Enberg 		case KVM_EXIT_MMIO: {
9429443dabSPekka Enberg 			bool ret;
9529443dabSPekka Enberg 
9629443dabSPekka Enberg 			ret = kvm__emulate_mmio(kvm,
9729443dabSPekka Enberg 					kvm->kvm_run->mmio.phys_addr,
9829443dabSPekka Enberg 					kvm->kvm_run->mmio.data,
9929443dabSPekka Enberg 					kvm->kvm_run->mmio.len,
10029443dabSPekka Enberg 					kvm->kvm_run->mmio.is_write);
10129443dabSPekka Enberg 
10229443dabSPekka Enberg 			if (!ret)
10329443dabSPekka Enberg 				goto exit_kvm;
10429443dabSPekka Enberg 			break;
10529443dabSPekka Enberg 
10629443dabSPekka Enberg 		}
107ae1fae34SPekka Enberg 		default:
108ae1fae34SPekka Enberg 			goto exit_kvm;
109ae1fae34SPekka Enberg 		}
110ae1fae34SPekka Enberg 	}
111ae1fae34SPekka Enberg 
112ae1fae34SPekka Enberg exit_kvm:
113ae1fae34SPekka Enberg 	fprintf(stderr, "KVM exit reason: %" PRIu32 " (\"%s\")\n",
114ae1fae34SPekka Enberg 		kvm->kvm_run->exit_reason, kvm_exit_reasons[kvm->kvm_run->exit_reason]);
115ae1fae34SPekka Enberg 
116ae1fae34SPekka Enberg 	kvm__show_registers(kvm);
117ae1fae34SPekka Enberg 	kvm__show_code(kvm);
118f01944c8SPekka Enberg 	kvm__show_page_tables(kvm);
119ae1fae34SPekka Enberg 
1209ef4c68eSPekka Enberg 	kvm__delete(kvm);
1219ef4c68eSPekka Enberg 
122ae1fae34SPekka Enberg 	return 0;
123ae1fae34SPekka Enberg }
124