xref: /kvmtool/kvm.c (revision f5ab5f67ffc89c2adfd6c68a51820e331544dfaa)
16c7d8514SPekka Enberg #include <linux/kvm.h>
2*f5ab5f67SPekka Enberg 
3*f5ab5f67SPekka Enberg #include <asm/bootparam.h>
4*f5ab5f67SPekka Enberg 
51f9cff23SPekka Enberg #include <inttypes.h>
61f9cff23SPekka Enberg #include <sys/mman.h>
72da26a59SPekka Enberg #include <stdbool.h>
8*f5ab5f67SPekka Enberg #include <stdarg.h>
9b8f6afcdSPekka Enberg #include <stdlib.h>
10*f5ab5f67SPekka Enberg #include <string.h>
111f9cff23SPekka Enberg #include <stdio.h>
12b8f6afcdSPekka Enberg #include <fcntl.h>
13b8f6afcdSPekka Enberg 
141f9cff23SPekka Enberg /*
151f9cff23SPekka Enberg  * Compatibility code. Remove this when we move to tools/kvm.
161f9cff23SPekka Enberg  */
171f9cff23SPekka Enberg #ifndef KVM_EXIT_INTERNAL_ERROR
181f9cff23SPekka Enberg # define KVM_EXIT_INTERNAL_ERROR		17
191f9cff23SPekka Enberg #endif
201f9cff23SPekka Enberg 
219b1fb1c3SPekka Enberg struct kvm {
2273ac60e6SPekka Enberg 	int			sys_fd;		/* For system ioctls(), i.e. /dev/kvm */
2373ac60e6SPekka Enberg 	int			vm_fd;		/* For VM ioctls() */
2473ac60e6SPekka Enberg 	int			vcpu_fd;	/* For VCPU ioctls() */
251f9cff23SPekka Enberg 	struct kvm_run		*kvm_run;
269b1fb1c3SPekka Enberg };
279b1fb1c3SPekka Enberg 
28*f5ab5f67SPekka Enberg static void die_perror(const char *s)
29b8f6afcdSPekka Enberg {
30b8f6afcdSPekka Enberg 	perror(s);
31b8f6afcdSPekka Enberg 	exit(1);
32b8f6afcdSPekka Enberg }
33b8f6afcdSPekka Enberg 
34*f5ab5f67SPekka Enberg static void die(const char *format, ...)
35*f5ab5f67SPekka Enberg {
36*f5ab5f67SPekka Enberg         va_list ap;
37*f5ab5f67SPekka Enberg 
38*f5ab5f67SPekka Enberg         va_start(ap, format);
39*f5ab5f67SPekka Enberg         vprintf(format, ap);
40*f5ab5f67SPekka Enberg         va_end(ap);
41*f5ab5f67SPekka Enberg 
42*f5ab5f67SPekka Enberg         printf("\n");
43*f5ab5f67SPekka Enberg 	exit(1);
44*f5ab5f67SPekka Enberg }
45*f5ab5f67SPekka Enberg 
464076b041SPekka Enberg static inline bool kvm__supports_extension(struct kvm *self, unsigned int extension)
47b8f6afcdSPekka Enberg {
4828fa19c0SPekka Enberg 	int ret;
49b8f6afcdSPekka Enberg 
5073ac60e6SPekka Enberg 	ret = ioctl(self->sys_fd, KVM_CHECK_EXTENSION, extension);
514076b041SPekka Enberg 	if (ret < 0)
524076b041SPekka Enberg 		return false;
534076b041SPekka Enberg 
544076b041SPekka Enberg 	return ret;
554076b041SPekka Enberg }
564076b041SPekka Enberg 
574076b041SPekka Enberg static struct kvm *kvm__new(void)
584076b041SPekka Enberg {
594076b041SPekka Enberg 	struct kvm *self = calloc(1, sizeof *self);
604076b041SPekka Enberg 
614076b041SPekka Enberg 	if (!self)
624076b041SPekka Enberg 		die("out of memory");
634076b041SPekka Enberg 
644076b041SPekka Enberg 	return self;
654076b041SPekka Enberg }
664076b041SPekka Enberg 
674076b041SPekka Enberg static struct kvm *kvm__init(void)
684076b041SPekka Enberg {
692b0e3342SPekka Enberg 	struct kvm_userspace_memory_region mem;
704076b041SPekka Enberg 	struct kvm *self;
711f9cff23SPekka Enberg 	int mmap_size;
724076b041SPekka Enberg 	int ret;
734076b041SPekka Enberg 
744076b041SPekka Enberg 	self = kvm__new();
754076b041SPekka Enberg 
7673ac60e6SPekka Enberg 	self->sys_fd = open("/dev/kvm", O_RDWR);
7773ac60e6SPekka Enberg 	if (self->sys_fd < 0)
78*f5ab5f67SPekka Enberg 		die_perror("open");
79b8f6afcdSPekka Enberg 
8073ac60e6SPekka Enberg 	ret = ioctl(self->sys_fd, KVM_GET_API_VERSION, 0);
816c7d8514SPekka Enberg 	if (ret != KVM_API_VERSION)
82*f5ab5f67SPekka Enberg 		die_perror("KVM_API_VERSION ioctl");
836c7d8514SPekka Enberg 
8473ac60e6SPekka Enberg 	self->vm_fd = ioctl(self->sys_fd, KVM_CREATE_VM, 0);
8573ac60e6SPekka Enberg 	if (self->vm_fd < 0)
86*f5ab5f67SPekka Enberg 		die_perror("KVM_CREATE_VM ioctl");
8728fa19c0SPekka Enberg 
884076b041SPekka Enberg 	if (!kvm__supports_extension(self, KVM_CAP_USER_MEMORY))
89*f5ab5f67SPekka Enberg 		die("KVM_CAP_USER_MEMORY is not supported");
902da26a59SPekka Enberg 
912b0e3342SPekka Enberg 	mem = (struct kvm_userspace_memory_region) {
922b0e3342SPekka Enberg 		.slot			= 0,
932b0e3342SPekka Enberg 		.guest_phys_addr	= 0x0UL,
942b0e3342SPekka Enberg 		.memory_size		= 64UL * 1024UL * 1024UL,
952b0e3342SPekka Enberg 	};
962b0e3342SPekka Enberg 
9773ac60e6SPekka Enberg 	ret = ioctl(self->vm_fd, KVM_SET_USER_MEMORY_REGION, &mem, 1);
982b0e3342SPekka Enberg 	if (ret < 0)
99*f5ab5f67SPekka Enberg 		die_perror("KVM_SET_USER_MEMORY_REGION ioctl");
1002b0e3342SPekka Enberg 
101895c2fefSPekka Enberg 	if (!kvm__supports_extension(self, KVM_CAP_SET_TSS_ADDR))
102*f5ab5f67SPekka Enberg 		die("KVM_CAP_SET_TSS_ADDR is not supported");
103895c2fefSPekka Enberg 
10473ac60e6SPekka Enberg 	ret = ioctl(self->vm_fd, KVM_SET_TSS_ADDR, 0xfffbd000);
105895c2fefSPekka Enberg 	if (ret < 0)
106*f5ab5f67SPekka Enberg 		die_perror("KVM_SET_TSS_ADDR ioctl");
107895c2fefSPekka Enberg 
10873ac60e6SPekka Enberg 	self->vcpu_fd = ioctl(self->vm_fd, KVM_CREATE_VCPU, 0);
1092b0e3342SPekka Enberg 	if (self->vcpu_fd < 0)
110*f5ab5f67SPekka Enberg 		die_perror("KVM_CREATE_VCPU ioctl");
1112b0e3342SPekka Enberg 
1121f9cff23SPekka Enberg 	mmap_size = ioctl(self->sys_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
1131f9cff23SPekka Enberg 	if (mmap_size < 0)
114*f5ab5f67SPekka Enberg 		die_perror("KVM_GET_VCPU_MMAP_SIZE ioctl");
1151f9cff23SPekka Enberg 
1161f9cff23SPekka Enberg 	self->kvm_run = mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, self->vcpu_fd, 0);
1171f9cff23SPekka Enberg 	if (self->kvm_run == MAP_FAILED)
1181f9cff23SPekka Enberg 		die("unable to mmap vcpu fd");
1191f9cff23SPekka Enberg 
1204076b041SPekka Enberg 	return self;
1214076b041SPekka Enberg }
1224076b041SPekka Enberg 
1232b0e3342SPekka Enberg static void kvm__run(struct kvm *self)
1242b0e3342SPekka Enberg {
1252b0e3342SPekka Enberg 	int ret;
1262b0e3342SPekka Enberg 
1272b0e3342SPekka Enberg 	ret = ioctl(self->vcpu_fd, KVM_RUN, 0);
1282b0e3342SPekka Enberg 	if (ret < 0)
129*f5ab5f67SPekka Enberg 		die_perror("KVM_RUN ioctl");
130*f5ab5f67SPekka Enberg }
131*f5ab5f67SPekka Enberg 
132*f5ab5f67SPekka Enberg static const char *BZIMAGE_MAGIC	= "HdrS";
133*f5ab5f67SPekka Enberg 
134*f5ab5f67SPekka Enberg static int load_bzimage(struct kvm *kvm, int fd)
135*f5ab5f67SPekka Enberg {
136*f5ab5f67SPekka Enberg 	struct boot_params boot;
137*f5ab5f67SPekka Enberg 
138*f5ab5f67SPekka Enberg 	read(fd, &boot, sizeof(boot));
139*f5ab5f67SPekka Enberg 
140*f5ab5f67SPekka Enberg         if (memcmp(&boot.hdr.header, BZIMAGE_MAGIC, strlen(BZIMAGE_MAGIC)) != 0)
141*f5ab5f67SPekka Enberg 		return -1;
142*f5ab5f67SPekka Enberg 
143*f5ab5f67SPekka Enberg 	return 0;
1442b0e3342SPekka Enberg }
1452b0e3342SPekka Enberg 
146caf44df2SPekka Enberg static void kvm__load_kernel(struct kvm *kvm, const char *kernel_filename)
147caf44df2SPekka Enberg {
148*f5ab5f67SPekka Enberg 	int fd;
149*f5ab5f67SPekka Enberg 
150*f5ab5f67SPekka Enberg 	fd = open(kernel_filename, O_RDONLY);
151*f5ab5f67SPekka Enberg 	if (fd < 0)
152*f5ab5f67SPekka Enberg 		die("unable to open kernel");
153*f5ab5f67SPekka Enberg 
154*f5ab5f67SPekka Enberg 	if (load_bzimage(kvm, fd) < 0)
155*f5ab5f67SPekka Enberg 		die("%s is not a valid bzImage", kernel_filename);
156caf44df2SPekka Enberg }
157caf44df2SPekka Enberg 
1581f9cff23SPekka Enberg static const char *exit_reasons[] = {
1591f9cff23SPekka Enberg 	[KVM_EXIT_UNKNOWN]		= "unknown",
1601f9cff23SPekka Enberg 	[KVM_EXIT_EXCEPTION]		= "exception",
1611f9cff23SPekka Enberg 	[KVM_EXIT_IO]			= "io",
1621f9cff23SPekka Enberg 	[KVM_EXIT_HYPERCALL]		= "hypercall",
1631f9cff23SPekka Enberg 	[KVM_EXIT_DEBUG]		= "debug",
1641f9cff23SPekka Enberg 	[KVM_EXIT_HLT]			= "hlt",
1651f9cff23SPekka Enberg 	[KVM_EXIT_MMIO]			= "mmio",
1661f9cff23SPekka Enberg 	[KVM_EXIT_IRQ_WINDOW_OPEN]	= "irq window open",
1671f9cff23SPekka Enberg 	[KVM_EXIT_SHUTDOWN]		= "shutdown",
1681f9cff23SPekka Enberg 	[KVM_EXIT_FAIL_ENTRY]		= "fail entry",
1691f9cff23SPekka Enberg 	[KVM_EXIT_INTR]			= "intr",
1701f9cff23SPekka Enberg 	[KVM_EXIT_SET_TPR]		= "set tpr",
1711f9cff23SPekka Enberg 	[KVM_EXIT_TPR_ACCESS]		= "trp access",
1721f9cff23SPekka Enberg 	[KVM_EXIT_S390_SIEIC]		= "s390 sieic",
1731f9cff23SPekka Enberg 	[KVM_EXIT_S390_RESET]		= "s390 reset",
1741f9cff23SPekka Enberg 	[KVM_EXIT_DCR]			= "dcr",
1751f9cff23SPekka Enberg 	[KVM_EXIT_NMI]			= "dmi",
1761f9cff23SPekka Enberg 	[KVM_EXIT_INTERNAL_ERROR]	= "internal error",
1771f9cff23SPekka Enberg };
1781f9cff23SPekka Enberg 
179caf44df2SPekka Enberg static void usage(char *argv[])
180caf44df2SPekka Enberg {
181caf44df2SPekka Enberg 	fprintf(stderr, "  usage: %s <kernel-image>\n", argv[0]);
182caf44df2SPekka Enberg 	exit(1);
183caf44df2SPekka Enberg }
184caf44df2SPekka Enberg 
1854076b041SPekka Enberg int main(int argc, char *argv[])
1864076b041SPekka Enberg {
187caf44df2SPekka Enberg 	const char *kernel_filename;
1884076b041SPekka Enberg 	struct kvm *kvm;
1894076b041SPekka Enberg 	int ret;
1904076b041SPekka Enberg 
191caf44df2SPekka Enberg 	if (argc < 2)
192caf44df2SPekka Enberg 		usage(argv);
193caf44df2SPekka Enberg 
194caf44df2SPekka Enberg 	kernel_filename = argv[1];
195caf44df2SPekka Enberg 
1964076b041SPekka Enberg 	kvm = kvm__init();
1974076b041SPekka Enberg 
198caf44df2SPekka Enberg 	kvm__load_kernel(kvm, kernel_filename);
199b8f6afcdSPekka Enberg 
2002b0e3342SPekka Enberg 	kvm__run(kvm);
2012b0e3342SPekka Enberg 
2021f9cff23SPekka Enberg 	fprintf(stderr, "KVM exit reason: %" PRIu32 " (\"%s\")\n",
2031f9cff23SPekka Enberg 		kvm->kvm_run->exit_reason, exit_reasons[kvm->kvm_run->exit_reason]);
2041f9cff23SPekka Enberg 
205b8f6afcdSPekka Enberg 	return 0;
206b8f6afcdSPekka Enberg }
207