ioctl_kvm_run.c revision b755614143ce6aab5265ed32c1bb6c8f748e7898
14ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor/*
24ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor * Check decoding of KVM_* commands of ioctl syscall using /dev/kvm API.
39f1e3ff3b3095967e2b92b57a53524e2d6bb141cDouglas Gregor * Based on kvmtest.c from https://lwn.net/Articles/658512/
44807231938d8aff28de09f78f301f9ba5845e5e4Douglas Gregor *
54ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor * kvmtest.c author: Josh Triplett <josh@joshtriplett.org>
64ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor * Copyright (c) 2015 Intel Corporation
79f1e3ff3b3095967e2b92b57a53524e2d6bb141cDouglas Gregor * Copyright (c) 2017-2018 The strace developers.
84ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor *
99f1e3ff3b3095967e2b92b57a53524e2d6bb141cDouglas Gregor * Permission is hereby granted, free of charge, to any person obtaining a copy
103f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek * of this software and associated documentation files (the "Software"), to
113f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek * deal in the Software without restriction, including without limitation the
123f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
133f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek * sell copies of the Software, and to permit persons to whom the Software is
143f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek * furnished to do so, subject to the following conditions:
153f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek *
163f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek * The above copyright notice and this permission notice shall be included in
173f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek * all copies or substantial portions of the Software.
183f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek *
193f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
203f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2123bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2223bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2323bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2423bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2523bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek * IN THE SOFTWARE.
2623bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek */
2723bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek
28dd3e5549e3c11e217078938aacf72f042eea5343Douglas Gregor#include "tests.h"
29dd3e5549e3c11e217078938aacf72f042eea5343Douglas Gregor
30dd3e5549e3c11e217078938aacf72f042eea5343Douglas Gregor#if defined HAVE_LINUX_KVM_H				\
318f7c540ac42370c40ebcdc4b69018c938faf94ecArgyrios Kyrtzidis && defined HAVE_STRUCT_KVM_REGS			\
328f7c540ac42370c40ebcdc4b69018c938faf94ecArgyrios Kyrtzidis && defined HAVE_STRUCT_KVM_SREGS			\
33b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis && defined HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION	\
34b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis &&(defined __x86_64__ || defined __i386__)
35b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis
36b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis# include <fcntl.h>
37b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis# include <stdint.h>
38b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis# include <stdio.h>
39b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis# include <stdlib.h>
40b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis# include <string.h>
41b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis# include <sys/ioctl.h>
42b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis# include <sys/mman.h>
43b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis# include <linux/kvm.h>
44b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis
45b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidisstatic int
46b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidiskvm_ioctl(int fd, unsigned long cmd, const char *cmd_str, void *arg)
479f1e3ff3b3095967e2b92b57a53524e2d6bb141cDouglas Gregor{
489f1e3ff3b3095967e2b92b57a53524e2d6bb141cDouglas Gregor	int rc = ioctl(fd, cmd, arg);
49572feb2a190b5e8b04fb06c4ac50ee0f61e93ff0Douglas Gregor	if (rc < 0)
503453bf7da9ac88cd2421b7fdccebf5cd2b8a9d87Argyrios Kyrtzidis		perror_msg_and_skip("%s", cmd_str);
514419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	return rc;
524419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor}
534419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor
544419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor#define KVM_IOCTL(fd_, cmd_, arg_)	\
554419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	kvm_ioctl((fd_), (cmd_), #cmd_, (arg_))
564ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor
574ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregorstatic const char dev[] = "/dev/kvm";
58572feb2a190b5e8b04fb06c4ac50ee0f61e93ff0Douglas Gregorstatic const char vm_dev[] = "anon_inode:kvm-vm";
594419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregorstatic const char vcpu_dev[] = "anon_inode:kvm-vcpu";
604ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregorstatic size_t page_size;
614ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor
62572feb2a190b5e8b04fb06c4ac50ee0f61e93ff0Douglas Gregorextern const char code[];
634419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregorextern const unsigned short code_size;
644419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor
654419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor__asm__(
664419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	".type code, @object		\n"
674419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	"code:				\n"
684419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	"	mov $0xd80003f8, %edx	\n"
694419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	"	mov $'\n', %al		\n"
704419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	"	out %al, (%dx)		\n"
719b2a0ac970a077bdc0bf08c6c682f80ad733c892Chandler Carruth	"	hlt			\n"
724ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor	".size code, . - code		\n"
734ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor	".type code_size, @object	\n"
744ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor	"code_size:			\n"
754ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor	"	.short . - code		\n"
764ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor	".size code_size, . - code_size	\n"
774ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor	);
789b2a0ac970a077bdc0bf08c6c682f80ad733c892Chandler Carruth
794ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor
804ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregorstatic void
814ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregorrun_kvm(const int vcpu_fd, struct kvm_run *const run, const size_t mmap_size,
824ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor	void *const mem)
834ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor{
844ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor	/* Initialize CS to point at 0, via a read-modify-write of sregs. */
854ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor	struct kvm_sregs sregs;
869b2a0ac970a077bdc0bf08c6c682f80ad733c892Chandler Carruth	KVM_IOCTL(vcpu_fd, KVM_GET_SREGS, &sregs);
879b2a0ac970a077bdc0bf08c6c682f80ad733c892Chandler Carruth	printf("ioctl(%d<%s>, KVM_GET_SREGS, {cs={base=%#jx, limit=%u, selector=%u"
884ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor	       ", type=%u, present=%u, dpl=%u, db=%u, s=%u, l=%u, g=%u, avl=%u}"
89ecdcb883cbc6bb4a2445dc6f02d58d9bdb54a0edDouglas Gregor	       ", ...}) = 0\n", vcpu_fd, vcpu_dev, (uintmax_t) sregs.cs.base,
904419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	       sregs.cs.limit, sregs.cs.selector, sregs.cs.type,
914419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	       sregs.cs.present, sregs.cs.dpl, sregs.cs.db, sregs.cs.s,
924ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor	       sregs.cs.l, sregs.cs.g, sregs.cs.avl);
934ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor
944ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor	sregs.cs.base = 0;
953f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek	sregs.cs.selector = 0;
963f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek	KVM_IOCTL(vcpu_fd, KVM_SET_SREGS, &sregs);
973f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek	printf("ioctl(%d<%s>, KVM_SET_SREGS, {cs={base=%#jx, limit=%u"
984419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	       ", selector=%u, type=%u, present=%u, dpl=%u, db=%u, s=%u"
994419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	       ", l=%u, g=%u, avl=%u}, ...}) = 0\n",
1004419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	       vcpu_fd, vcpu_dev, (uintmax_t) sregs.cs.base,
1014419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	       sregs.cs.limit, sregs.cs.selector, sregs.cs.type,
1024419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	       sregs.cs.present, sregs.cs.dpl, sregs.cs.db, sregs.cs.s,
1034419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	       sregs.cs.l, sregs.cs.g, sregs.cs.avl);
1044419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor
1054419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	/*
1063f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek	 * Initialize registers: instruction pointer for our code, addends,
1073f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek	 * and initial flags required by x86 architecture.
1083f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek	 */
1094419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	struct kvm_regs regs = {
1104419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor		.rip = page_size,
1114419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor		.rax = 2,
1124419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor		.rbx = 2,
1134419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor		.rflags = 0x2,
1144419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	};
1153f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek	KVM_IOCTL(vcpu_fd, KVM_SET_REGS, &regs);
1163f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek	printf("ioctl(%d<%s>, KVM_SET_REGS, {rax=%#jx, ..."
1173f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek	       ", rsp=%#jx, rbp=%#jx, ..., rip=%#jx, rflags=%#jx}) = 0\n",
1183f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek	       vcpu_fd, vcpu_dev, (uintmax_t) regs.rax,
11942b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor	       (uintmax_t) regs.rsp, (uintmax_t) regs.rbp,
1203f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek	       (uintmax_t) regs.rip, (uintmax_t) regs.rflags);
1213f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek
1223f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek	/* Copy the code */
12342b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor	memcpy(mem, code, code_size);
12442b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor
1253f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek	const char *p = "\n";
1263f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek
1273f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek	/* Repeatedly run code and handle VM exits. */
12842b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor	for (;;) {
12942b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor		KVM_IOCTL(vcpu_fd, KVM_RUN, NULL);
1303f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek		printf("ioctl(%d<%s>, KVM_RUN, 0) = 0\n", vcpu_fd, vcpu_dev);
1313f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek
1323f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek		switch (run->exit_reason) {
1339b2a0ac970a077bdc0bf08c6c682f80ad733c892Chandler Carruth		case KVM_EXIT_HLT:
134a676379b26edc959193f9f919ba9c6d296a57824Argyrios Kyrtzidis			if (p)
1353f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek				error_msg_and_fail("premature KVM_EXIT_HLT");
136a676379b26edc959193f9f919ba9c6d296a57824Argyrios Kyrtzidis			return;
1373f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek		case KVM_EXIT_IO:
13850402470f07f720c509c8797f40a106a0d4af6a7Argyrios Kyrtzidis			if (run->io.direction == KVM_EXIT_IO_OUT
139d7711ec430fde5706f85ba6c4b85283a8e743ff7Argyrios Kyrtzidis			    && run->io.size == 1
14042b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor			    && run->io.port == 0x03f8
1413f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek			    && run->io.count == 1
1423f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek			    && run->io.data_offset < mmap_size
1433f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek			    && p && *p == ((char *) run)[run->io.data_offset])
1449b2a0ac970a077bdc0bf08c6c682f80ad733c892Chandler Carruth				p = NULL;
145a676379b26edc959193f9f919ba9c6d296a57824Argyrios Kyrtzidis			else
1463f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek				error_msg_and_fail("unhandled KVM_EXIT_IO");
14742b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor			break;
1483f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek		case KVM_EXIT_MMIO:
14950402470f07f720c509c8797f40a106a0d4af6a7Argyrios Kyrtzidis			error_msg_and_fail("Got an unexpected MMIO exit:"
150d7711ec430fde5706f85ba6c4b85283a8e743ff7Argyrios Kyrtzidis					   " phys_addr %#llx,"
15142b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor					   " data %02x %02x %02x %02x"
1523f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek						" %02x %02x %02x %02x,"
1533f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek					   " len %u, is_write %hhu",
1543f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek					   (unsigned long long) run->mmio.phys_addr,
1553f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek					   run->mmio.data[0], run->mmio.data[1],
15642b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor					   run->mmio.data[2], run->mmio.data[3],
1573f4046004be223b03f1f895bb934e44921ccf805Ted Kremenek					   run->mmio.data[4], run->mmio.data[5],
15842b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor					   run->mmio.data[6], run->mmio.data[7],
15942b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor					   run->mmio.len, run->mmio.is_write);
16023bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek
16123bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek		default:
16223bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek			error_msg_and_fail("exit_reason = %#x",
1634419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor					   run->exit_reason);
1644419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor		}
1654419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	}
1664419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor}
1674419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor
1684419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregorint
1694419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregormain(void)
1704419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor{
1714419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	skip_if_unavailable("/proc/self/fd/");
1724419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor
1734419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	int kvm = open(dev, O_RDWR);
1744419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	if (kvm < 0)
1754419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor		perror_msg_and_skip("open: %s", dev);
1764419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor
1774419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	/* Make sure we have the stable version of the API */
1784419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	int ret = KVM_IOCTL(kvm, KVM_GET_API_VERSION, 0);
1794419b675577d7c281a659fab1fec10e1bfbe04c5Douglas Gregor	if (ret != KVM_API_VERSION)
18023bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek		error_msg_and_skip("KVM_GET_API_VERSION returned %d"
18123bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek				   ", KVM_API_VERSION is %d",
18223bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek				   kvm, KVM_API_VERSION);
18323bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek	printf("ioctl(%d<%s>, KVM_GET_API_VERSION, 0) = %d\n",
18442b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor	       kvm, dev, ret);
18523bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek
18623bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek	int vm_fd = KVM_IOCTL(kvm, KVM_CREATE_VM, 0);
18723bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek	printf("ioctl(%d<%s>, KVM_CREATE_VM, 0) = %d<%s>\n",
18842b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor	       kvm, dev, vm_fd, vm_dev);
18942b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor
1909b2a0ac970a077bdc0bf08c6c682f80ad733c892Chandler Carruth	/* Allocate one aligned page of guest memory to hold the code. */
19142b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor	page_size = get_page_size();
19223bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek	void *const mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
193a676379b26edc959193f9f919ba9c6d296a57824Argyrios Kyrtzidis				  MAP_SHARED | MAP_ANONYMOUS, -1, 0);
19442b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor	if (mem == MAP_FAILED)
195c059f89d888cd214e18ed09a7b47339201526381Argyrios Kyrtzidis		perror_msg_and_fail("mmap page");
196a9b06d4c246d6c301e3dd1844f5dba669ed9c631Douglas Gregor
197a676379b26edc959193f9f919ba9c6d296a57824Argyrios Kyrtzidis	/* Map it to the second page frame (to avoid the real-mode IDT at 0). */
19823bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek	struct kvm_userspace_memory_region region = {
19942b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor		.slot = 0,
20042b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor		.guest_phys_addr = page_size,
20123bc11ff1874f8875426c9a8a29fe1e6894c3503Ted Kremenek		.memory_size = page_size,
20242b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor		.userspace_addr = (uintptr_t) mem,
20342b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor	};
204d7711ec430fde5706f85ba6c4b85283a8e743ff7Argyrios Kyrtzidis	KVM_IOCTL(vm_fd, KVM_SET_USER_MEMORY_REGION, &region);
205d7711ec430fde5706f85ba6c4b85283a8e743ff7Argyrios Kyrtzidis	printf("ioctl(%d<%s>, KVM_SET_USER_MEMORY_REGION"
20642b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor	       ", {slot=0, flags=0, guest_phys_addr=%#lx, memory_size=%lu"
20742b2984771a7fd1b17c78bbb2c59fed3db2f1960Douglas Gregor	       ", userspace_addr=%p}) = 0\n", vm_fd, vm_dev,
208dd3e5549e3c11e217078938aacf72f042eea5343Douglas Gregor	       (unsigned long) page_size, (unsigned long) page_size, mem);
209dd3e5549e3c11e217078938aacf72f042eea5343Douglas Gregor
2108f7c540ac42370c40ebcdc4b69018c938faf94ecArgyrios Kyrtzidis	int vcpu_fd = KVM_IOCTL(vm_fd, KVM_CREATE_VCPU, NULL);
211b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis	printf("ioctl(%d<%s>, KVM_CREATE_VCPU, 0) = %d<%s>\n",
212b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis	       vm_fd, vm_dev, vcpu_fd, vcpu_dev);
213b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis
214b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis	/* Map the shared kvm_run structure and following data. */
215b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis	ret = KVM_IOCTL(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL);
216b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis	struct kvm_run *run;
217b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis	if (ret < (int) sizeof(*run))
218b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis		error_msg_and_fail("KVM_GET_VCPU_MMAP_SIZE returned %d < %d",
219b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis				   ret, (int) sizeof(*run));
220b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis	printf("ioctl(%d<%s>, KVM_GET_VCPU_MMAP_SIZE, 0) = %d\n",
221b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis	       kvm, dev, ret);
222b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis
223b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis	const size_t mmap_size = (ret + page_size - 1) & -page_size;
224b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis	run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE,
225b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis		   MAP_SHARED, vcpu_fd, 0);
226b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis	if (run == MAP_FAILED)
227b94b62c3b15967d29f63165e834fa4f12944394cArgyrios Kyrtzidis		perror_msg_and_fail("mmap vcpu");
228
229	run_kvm(vcpu_fd, run, mmap_size, mem);
230
231	puts("+++ exited with 0 +++");
232	return 0;
233}
234
235#else /* !HAVE_LINUX_KVM_H */
236
237SKIP_MAIN_UNDEFINED("HAVE_LINUX_KVM_H && HAVE_STRUCT_KVM_REGS && "
238		    "HAVE_STRUCT_KVM_SREGS && "
239		    "HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION && "
240		    "(__x86_64__ || __i386__)")
241
242#endif
243