[PATCH v3 4/4] tests: check decoding of vcpu auxstr
Masatake YAMATO
yamato at redhat.com
Sat Jul 7 07:49:13 UTC 2018
* tests/ioctl_kvm_run_common.c: Rename from ioctl_kvm_run.c.
(run_kvm): Parametrize printing of KVM_RUN ioctl with print_KVM_RUN
invocation.
(main): Invoke optional KVM_NO_CPUID_CALLBACK macro when the old kernel
behavior is detected.
* tests/Makefile.am (EXTRA_DIST): Add ioctl_kvm_run_common.c.
* tests/ioctl_kvm_run.c: New file, a wrapper around
ioctl_kvm_run_common.c.
* ioctl_kvm_run_auxstr_vcpu.c: Likewise.
* tests/gen_tests.in (ioctl_kvm_run_auxstr_vcpu): New test.
* tests/pure_executables.list: Add ioctl_kvm_run_auxstr_vcpu.
* tests/.gitignore: Likewise.
Signed-off-by: Masatake YAMATO <yamato at redhat.com>
Co-Authored-by: Dmitry V. Levin <ldv at altlinux.org>
---
tests/.gitignore | 1 +
tests/Makefile.am | 1 +
tests/gen_tests.in | 1 +
tests/ioctl_kvm_run.c | 266 +---------------------------
tests/ioctl_kvm_run_auxstr_vcpu.c | 24 +++
tests/ioctl_kvm_run_common.c | 279 ++++++++++++++++++++++++++++++
tests/pure_executables.list | 1 +
7 files changed, 311 insertions(+), 262 deletions(-)
create mode 100644 tests/ioctl_kvm_run_auxstr_vcpu.c
create mode 100644 tests/ioctl_kvm_run_common.c
diff --git a/tests/.gitignore b/tests/.gitignore
index 2285a357..f15f5b03 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -145,6 +145,7 @@ ioctl_evdev
ioctl_evdev-v
ioctl_inotify
ioctl_kvm_run
+ioctl_kvm_run_auxstr_vcpu
ioctl_loop
ioctl_loop-nv
ioctl_loop-v
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 34b08a9f..41643f01 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -386,6 +386,7 @@ EXTRA_DIST = \
init.sh \
init_delete_module.h \
ipc.sh \
+ ioctl_kvm_run_common.c \
ksysent.sed \
lstatx.c \
match.awk \
diff --git a/tests/gen_tests.in b/tests/gen_tests.in
index 24e0510e..869c087e 100644
--- a/tests/gen_tests.in
+++ b/tests/gen_tests.in
@@ -140,6 +140,7 @@ ioctl_evdev +ioctl.test
ioctl_evdev-v +ioctl.test -v
ioctl_inotify +ioctl.test
ioctl_kvm_run +ioctl.test -a36 -y
+ioctl_kvm_run_auxstr_vcpu +ioctl.test -a36 -y -e kvm=vcpu
ioctl_loop +ioctl.test
ioctl_loop-nv +ioctl.test -a22 -e verbose=none
ioctl_loop-v +ioctl.test -v
diff --git a/tests/ioctl_kvm_run.c b/tests/ioctl_kvm_run.c
index e1bef579..602507fa 100644
--- a/tests/ioctl_kvm_run.c
+++ b/tests/ioctl_kvm_run.c
@@ -1,269 +1,11 @@
-/*
- * Check decoding of KVM_* commands of ioctl syscall using /dev/kvm API.
- * Based on kvmtest.c from https://lwn.net/Articles/658512/
- *
- * kvmtest.c author: Josh Triplett <josh at joshtriplett.org>
- * Copyright (c) 2015 Intel Corporation
- * Copyright (c) 2017-2018 The strace developers.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include "tests.h"
-
-#if defined HAVE_LINUX_KVM_H \
- && defined HAVE_STRUCT_KVM_REGS \
- && defined HAVE_STRUCT_KVM_SREGS \
- && defined HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION \
- &&(defined __x86_64__ || defined __i386__)
-
-# include <fcntl.h>
-# include <stdint.h>
-# include <stdio.h>
-# include <stdlib.h>
-# include <string.h>
-# include <sys/ioctl.h>
-# include <sys/mman.h>
-# include <unistd.h>
-# include <linux/kvm.h>
-
-static int
-kvm_ioctl(int fd, unsigned long cmd, const char *cmd_str, void *arg)
-{
- int rc = ioctl(fd, cmd, arg);
- if (rc < 0)
- perror_msg_and_skip("%s", cmd_str);
- return rc;
-}
-
-#define KVM_IOCTL(fd_, cmd_, arg_) \
- kvm_ioctl((fd_), (cmd_), #cmd_, (arg_))
-
-static const char dev[] = "/dev/kvm";
-static const char vm_dev[] = "anon_inode:kvm-vm";
-static char vcpu_dev[] = "anon_inode:kvm-vcpu:0";
-static size_t page_size;
-
-extern const char code[];
-extern const unsigned short code_size;
-
-__asm__(
- ".type code, @object \n"
- "code: \n"
- " mov $0xd80003f8, %edx \n"
- " mov $'\n', %al \n"
- " out %al, (%dx) \n"
- " hlt \n"
- ".size code, . - code \n"
- ".type code_size, @object \n"
- "code_size: \n"
- " .short . - code \n"
- ".size code_size, . - code_size \n"
- );
+#include "ioctl_kvm_run_common.c"
+#if need_print_KVM_RUN
static void
-run_kvm(const int vcpu_fd, struct kvm_run *const run, const size_t mmap_size,
- void *const mem)
-{
- /* Initialize CS to point at 0, via a read-modify-write of sregs. */
- struct kvm_sregs sregs;
- KVM_IOCTL(vcpu_fd, KVM_GET_SREGS, &sregs);
- printf("ioctl(%d<%s>, KVM_GET_SREGS, {cs={base=%#jx, limit=%u, selector=%u"
- ", type=%u, present=%u, dpl=%u, db=%u, s=%u, l=%u, g=%u, avl=%u}"
- ", ...}) = 0\n", vcpu_fd, vcpu_dev, (uintmax_t) sregs.cs.base,
- sregs.cs.limit, sregs.cs.selector, sregs.cs.type,
- sregs.cs.present, sregs.cs.dpl, sregs.cs.db, sregs.cs.s,
- sregs.cs.l, sregs.cs.g, sregs.cs.avl);
-
- sregs.cs.base = 0;
- sregs.cs.selector = 0;
- KVM_IOCTL(vcpu_fd, KVM_SET_SREGS, &sregs);
- printf("ioctl(%d<%s>, KVM_SET_SREGS, {cs={base=%#jx, limit=%u"
- ", selector=%u, type=%u, present=%u, dpl=%u, db=%u, s=%u"
- ", l=%u, g=%u, avl=%u}, ...}) = 0\n",
- vcpu_fd, vcpu_dev, (uintmax_t) sregs.cs.base,
- sregs.cs.limit, sregs.cs.selector, sregs.cs.type,
- sregs.cs.present, sregs.cs.dpl, sregs.cs.db, sregs.cs.s,
- sregs.cs.l, sregs.cs.g, sregs.cs.avl);
-
- /*
- * Initialize registers: instruction pointer for our code, addends,
- * and initial flags required by x86 architecture.
- */
- struct kvm_regs regs = {
- .rip = page_size,
- .rax = 2,
- .rbx = 2,
- .rflags = 0x2,
- };
- KVM_IOCTL(vcpu_fd, KVM_SET_REGS, ®s);
- printf("ioctl(%d<%s>, KVM_SET_REGS, {rax=%#jx, ..."
- ", rsp=%#jx, rbp=%#jx, ..., rip=%#jx, rflags=%#jx}) = 0\n",
- vcpu_fd, vcpu_dev, (uintmax_t) regs.rax,
- (uintmax_t) regs.rsp, (uintmax_t) regs.rbp,
- (uintmax_t) regs.rip, (uintmax_t) regs.rflags);
-
- /* Copy the code */
- memcpy(mem, code, code_size);
-
- const char *p = "\n";
-
- /* Repeatedly run code and handle VM exits. */
- for (;;) {
- KVM_IOCTL(vcpu_fd, KVM_RUN, NULL);
- printf("ioctl(%d<%s>, KVM_RUN, 0) = 0\n", vcpu_fd, vcpu_dev);
-
- switch (run->exit_reason) {
- case KVM_EXIT_HLT:
- if (p)
- error_msg_and_fail("premature KVM_EXIT_HLT");
- return;
- case KVM_EXIT_IO:
- if (run->io.direction == KVM_EXIT_IO_OUT
- && run->io.size == 1
- && run->io.port == 0x03f8
- && run->io.count == 1
- && run->io.data_offset < mmap_size
- && p && *p == ((char *) run)[run->io.data_offset])
- p = NULL;
- else
- error_msg_and_fail("unhandled KVM_EXIT_IO");
- break;
- case KVM_EXIT_MMIO:
- error_msg_and_fail("Got an unexpected MMIO exit:"
- " phys_addr %#llx,"
- " data %02x %02x %02x %02x"
- " %02x %02x %02x %02x,"
- " len %u, is_write %hhu",
- (unsigned long long) run->mmio.phys_addr,
- run->mmio.data[0], run->mmio.data[1],
- run->mmio.data[2], run->mmio.data[3],
- run->mmio.data[4], run->mmio.data[5],
- run->mmio.data[6], run->mmio.data[7],
- run->mmio.len, run->mmio.is_write);
-
- default:
- error_msg_and_fail("exit_reason = %#x",
- run->exit_reason);
- }
- }
-}
-
-static int
-vcpu_dev_should_have_cpuid(int fd)
+print_KVM_RUN(const int fd, const char *const dev, const unsigned int reason)
{
- int r = 0;
- char *filename = NULL;
- char buf[sizeof(vcpu_dev)];
-
- if (asprintf(&filename, "/proc/%d/fd/%d", getpid(), fd) < 0)
- error_msg_and_fail("asprintf");
-
- if (readlink(filename, buf, sizeof(buf)) == sizeof(buf) - 1
- && (memcmp(buf, vcpu_dev, sizeof(buf) - 1) == 0))
- r = 1;
- free(filename);
- return r;
+ printf("ioctl(%d<%s>, KVM_RUN, 0) = 0\n", fd, dev);
}
-int
-main(void)
-{
- skip_if_unavailable("/proc/self/fd/");
-
- int kvm = open(dev, O_RDWR);
- if (kvm < 0)
- perror_msg_and_skip("open: %s", dev);
-
- /* Make sure we have the stable version of the API */
- int ret = KVM_IOCTL(kvm, KVM_GET_API_VERSION, 0);
- if (ret != KVM_API_VERSION)
- error_msg_and_skip("KVM_GET_API_VERSION returned %d"
- ", KVM_API_VERSION is %d",
- kvm, KVM_API_VERSION);
- printf("ioctl(%d<%s>, KVM_GET_API_VERSION, 0) = %d\n",
- kvm, dev, ret);
-
- int vm_fd = KVM_IOCTL(kvm, KVM_CREATE_VM, 0);
- printf("ioctl(%d<%s>, KVM_CREATE_VM, 0) = %d<%s>\n",
- kvm, dev, vm_fd, vm_dev);
-
- /* Allocate one aligned page of guest memory to hold the code. */
- page_size = get_page_size();
- void *const mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_ANONYMOUS, -1, 0);
- if (mem == MAP_FAILED)
- perror_msg_and_fail("mmap page");
-
- /* Map it to the second page frame (to avoid the real-mode IDT at 0). */
- struct kvm_userspace_memory_region region = {
- .slot = 0,
- .guest_phys_addr = page_size,
- .memory_size = page_size,
- .userspace_addr = (uintptr_t) mem,
- };
- KVM_IOCTL(vm_fd, KVM_SET_USER_MEMORY_REGION, ®ion);
- printf("ioctl(%d<%s>, KVM_SET_USER_MEMORY_REGION"
- ", {slot=0, flags=0, guest_phys_addr=%#lx, memory_size=%lu"
- ", userspace_addr=%p}) = 0\n", vm_fd, vm_dev,
- (unsigned long) page_size, (unsigned long) page_size, mem);
-
- int vcpu_fd = KVM_IOCTL(vm_fd, KVM_CREATE_VCPU, NULL);
- if (!vcpu_dev_should_have_cpuid(vcpu_fd))
- /*
- * This is an older kernel that doesn't place a cpuid
- * at the end of the dentry associated with vcpu_fd.
- * Trim the cpuid part of vcpu_dev like:
- * "anon_inode:kvm-vcpu:0" -> "anon_inode:kvm-vcpu"
- */
- vcpu_dev[strlen (vcpu_dev) - 2] = '\0';
-
- printf("ioctl(%d<%s>, KVM_CREATE_VCPU, 0) = %d<%s>\n",
- vm_fd, vm_dev, vcpu_fd, vcpu_dev);
-
- /* Map the shared kvm_run structure and following data. */
- ret = KVM_IOCTL(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL);
- struct kvm_run *run;
- if (ret < (int) sizeof(*run))
- error_msg_and_fail("KVM_GET_VCPU_MMAP_SIZE returned %d < %d",
- ret, (int) sizeof(*run));
- printf("ioctl(%d<%s>, KVM_GET_VCPU_MMAP_SIZE, 0) = %d\n",
- kvm, dev, ret);
-
- const size_t mmap_size = (ret + page_size - 1) & -page_size;
- run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE,
- MAP_SHARED, vcpu_fd, 0);
- if (run == MAP_FAILED)
- perror_msg_and_fail("mmap vcpu");
-
- run_kvm(vcpu_fd, run, mmap_size, mem);
-
- puts("+++ exited with 0 +++");
- return 0;
-}
-
-#else /* !HAVE_LINUX_KVM_H */
-
-SKIP_MAIN_UNDEFINED("HAVE_LINUX_KVM_H && HAVE_STRUCT_KVM_REGS && "
- "HAVE_STRUCT_KVM_SREGS && "
- "HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION && "
- "(__x86_64__ || __i386__)")
-
#endif
diff --git a/tests/ioctl_kvm_run_auxstr_vcpu.c b/tests/ioctl_kvm_run_auxstr_vcpu.c
new file mode 100644
index 00000000..16af293f
--- /dev/null
+++ b/tests/ioctl_kvm_run_auxstr_vcpu.c
@@ -0,0 +1,24 @@
+#define KVM_NO_CPUID_CALLBACK \
+ error_msg_and_skip("newer kernel (>= 4.16) is needed")
+
+#include "ioctl_kvm_run_common.c"
+
+#if need_print_KVM_RUN
+
+static void
+print_KVM_RUN(const int fd, const char *const dev, const unsigned int reason)
+{
+ const char *str;
+
+# define CASE_ENTRY(R) case R: str = #R; break
+ switch (reason) {
+ CASE_ENTRY(KVM_EXIT_HLT);
+ CASE_ENTRY(KVM_EXIT_IO);
+ CASE_ENTRY(KVM_EXIT_MMIO);
+ default: str = "???";
+ }
+
+ printf("ioctl(%d<%s>, KVM_RUN, 0) = 0 (%s)\n", fd, dev, str);
+}
+
+#endif
diff --git a/tests/ioctl_kvm_run_common.c b/tests/ioctl_kvm_run_common.c
new file mode 100644
index 00000000..8925a677
--- /dev/null
+++ b/tests/ioctl_kvm_run_common.c
@@ -0,0 +1,279 @@
+/*
+ * Check decoding of KVM_* commands of ioctl syscall using /dev/kvm API.
+ * Based on kvmtest.c from https://lwn.net/Articles/658512/
+ *
+ * kvmtest.c author: Josh Triplett <josh at joshtriplett.org>
+ * Copyright (c) 2015 Intel Corporation
+ * Copyright (c) 2017-2018 The strace developers.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "tests.h"
+
+#if defined HAVE_LINUX_KVM_H \
+ && defined HAVE_STRUCT_KVM_REGS \
+ && defined HAVE_STRUCT_KVM_SREGS \
+ && defined HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION \
+ &&(defined __x86_64__ || defined __i386__)
+
+# include <fcntl.h>
+# include <stdint.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <sys/ioctl.h>
+# include <sys/mman.h>
+# include <unistd.h>
+# include <linux/kvm.h>
+
+static int
+kvm_ioctl(int fd, unsigned long cmd, const char *cmd_str, void *arg)
+{
+ int rc = ioctl(fd, cmd, arg);
+ if (rc < 0)
+ perror_msg_and_skip("%s", cmd_str);
+ return rc;
+}
+
+#define KVM_IOCTL(fd_, cmd_, arg_) \
+ kvm_ioctl((fd_), (cmd_), #cmd_, (arg_))
+
+static const char dev[] = "/dev/kvm";
+static const char vm_dev[] = "anon_inode:kvm-vm";
+static char vcpu_dev[] = "anon_inode:kvm-vcpu:0";
+static size_t page_size;
+
+extern const char code[];
+extern const unsigned short code_size;
+
+__asm__(
+ ".type code, @object \n"
+ "code: \n"
+ " mov $0xd80003f8, %edx \n"
+ " mov $'\n', %al \n"
+ " out %al, (%dx) \n"
+ " hlt \n"
+ ".size code, . - code \n"
+ ".type code_size, @object \n"
+ "code_size: \n"
+ " .short . - code \n"
+ ".size code_size, . - code_size \n"
+ );
+
+# define need_print_KVM_RUN 1
+
+static void
+print_KVM_RUN(const int fd, const char *const dev, const unsigned int reason);
+
+static void
+run_kvm(const int vcpu_fd, struct kvm_run *const run, const size_t mmap_size,
+ void *const mem)
+{
+ /* Initialize CS to point at 0, via a read-modify-write of sregs. */
+ struct kvm_sregs sregs;
+ KVM_IOCTL(vcpu_fd, KVM_GET_SREGS, &sregs);
+ printf("ioctl(%d<%s>, KVM_GET_SREGS, {cs={base=%#jx, limit=%u, selector=%u"
+ ", type=%u, present=%u, dpl=%u, db=%u, s=%u, l=%u, g=%u, avl=%u}"
+ ", ...}) = 0\n", vcpu_fd, vcpu_dev, (uintmax_t) sregs.cs.base,
+ sregs.cs.limit, sregs.cs.selector, sregs.cs.type,
+ sregs.cs.present, sregs.cs.dpl, sregs.cs.db, sregs.cs.s,
+ sregs.cs.l, sregs.cs.g, sregs.cs.avl);
+
+ sregs.cs.base = 0;
+ sregs.cs.selector = 0;
+ KVM_IOCTL(vcpu_fd, KVM_SET_SREGS, &sregs);
+ printf("ioctl(%d<%s>, KVM_SET_SREGS, {cs={base=%#jx, limit=%u"
+ ", selector=%u, type=%u, present=%u, dpl=%u, db=%u, s=%u"
+ ", l=%u, g=%u, avl=%u}, ...}) = 0\n",
+ vcpu_fd, vcpu_dev, (uintmax_t) sregs.cs.base,
+ sregs.cs.limit, sregs.cs.selector, sregs.cs.type,
+ sregs.cs.present, sregs.cs.dpl, sregs.cs.db, sregs.cs.s,
+ sregs.cs.l, sregs.cs.g, sregs.cs.avl);
+
+ /*
+ * Initialize registers: instruction pointer for our code, addends,
+ * and initial flags required by x86 architecture.
+ */
+ struct kvm_regs regs = {
+ .rip = page_size,
+ .rax = 2,
+ .rbx = 2,
+ .rflags = 0x2,
+ };
+ KVM_IOCTL(vcpu_fd, KVM_SET_REGS, ®s);
+ printf("ioctl(%d<%s>, KVM_SET_REGS, {rax=%#jx, ..."
+ ", rsp=%#jx, rbp=%#jx, ..., rip=%#jx, rflags=%#jx}) = 0\n",
+ vcpu_fd, vcpu_dev, (uintmax_t) regs.rax,
+ (uintmax_t) regs.rsp, (uintmax_t) regs.rbp,
+ (uintmax_t) regs.rip, (uintmax_t) regs.rflags);
+
+ /* Copy the code */
+ memcpy(mem, code, code_size);
+
+ const char *p = "\n";
+
+ /* Repeatedly run code and handle VM exits. */
+ for (;;) {
+ KVM_IOCTL(vcpu_fd, KVM_RUN, NULL);
+ print_KVM_RUN(vcpu_fd, vcpu_dev, run->exit_reason);
+
+ switch (run->exit_reason) {
+ case KVM_EXIT_HLT:
+ if (p)
+ error_msg_and_fail("premature KVM_EXIT_HLT");
+ return;
+ case KVM_EXIT_IO:
+ if (run->io.direction == KVM_EXIT_IO_OUT
+ && run->io.size == 1
+ && run->io.port == 0x03f8
+ && run->io.count == 1
+ && run->io.data_offset < mmap_size
+ && p && *p == ((char *) run)[run->io.data_offset])
+ p = NULL;
+ else
+ error_msg_and_fail("unhandled KVM_EXIT_IO");
+ break;
+ case KVM_EXIT_MMIO:
+ error_msg_and_fail("Got an unexpected MMIO exit:"
+ " phys_addr %#llx,"
+ " data %02x %02x %02x %02x"
+ " %02x %02x %02x %02x,"
+ " len %u, is_write %hhu",
+ (unsigned long long) run->mmio.phys_addr,
+ run->mmio.data[0], run->mmio.data[1],
+ run->mmio.data[2], run->mmio.data[3],
+ run->mmio.data[4], run->mmio.data[5],
+ run->mmio.data[6], run->mmio.data[7],
+ run->mmio.len, run->mmio.is_write);
+
+ default:
+ error_msg_and_fail("exit_reason = %#x",
+ run->exit_reason);
+ }
+ }
+}
+
+static int
+vcpu_dev_should_have_cpuid(int fd)
+{
+ int r = 0;
+ char *filename = NULL;
+ char buf[sizeof(vcpu_dev)];
+
+ if (asprintf(&filename, "/proc/%d/fd/%d", getpid(), fd) < 0)
+ error_msg_and_fail("asprintf");
+
+ if (readlink(filename, buf, sizeof(buf)) == sizeof(buf) - 1
+ && (memcmp(buf, vcpu_dev, sizeof(buf) - 1) == 0))
+ r = 1;
+ free(filename);
+ return r;
+}
+
+int
+main(void)
+{
+ skip_if_unavailable("/proc/self/fd/");
+
+ int kvm = open(dev, O_RDWR);
+ if (kvm < 0)
+ perror_msg_and_skip("open: %s", dev);
+
+ /* Make sure we have the stable version of the API */
+ int ret = KVM_IOCTL(kvm, KVM_GET_API_VERSION, 0);
+ if (ret != KVM_API_VERSION)
+ error_msg_and_skip("KVM_GET_API_VERSION returned %d"
+ ", KVM_API_VERSION is %d",
+ kvm, KVM_API_VERSION);
+ printf("ioctl(%d<%s>, KVM_GET_API_VERSION, 0) = %d\n",
+ kvm, dev, ret);
+
+ int vm_fd = KVM_IOCTL(kvm, KVM_CREATE_VM, 0);
+ printf("ioctl(%d<%s>, KVM_CREATE_VM, 0) = %d<%s>\n",
+ kvm, dev, vm_fd, vm_dev);
+
+ /* Allocate one aligned page of guest memory to hold the code. */
+ page_size = get_page_size();
+ void *const mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (mem == MAP_FAILED)
+ perror_msg_and_fail("mmap page");
+
+ /* Map it to the second page frame (to avoid the real-mode IDT at 0). */
+ struct kvm_userspace_memory_region region = {
+ .slot = 0,
+ .guest_phys_addr = page_size,
+ .memory_size = page_size,
+ .userspace_addr = (uintptr_t) mem,
+ };
+ KVM_IOCTL(vm_fd, KVM_SET_USER_MEMORY_REGION, ®ion);
+ printf("ioctl(%d<%s>, KVM_SET_USER_MEMORY_REGION"
+ ", {slot=0, flags=0, guest_phys_addr=%#lx, memory_size=%lu"
+ ", userspace_addr=%p}) = 0\n", vm_fd, vm_dev,
+ (unsigned long) page_size, (unsigned long) page_size, mem);
+
+ int vcpu_fd = KVM_IOCTL(vm_fd, KVM_CREATE_VCPU, NULL);
+ if (!vcpu_dev_should_have_cpuid(vcpu_fd)) {
+ /*
+ * This is an older kernel that doesn't place a cpuid
+ * at the end of the dentry associated with vcpu_fd.
+ * Trim the cpuid part of vcpu_dev like:
+ * "anon_inode:kvm-vcpu:0" -> "anon_inode:kvm-vcpu"
+ */
+ vcpu_dev[strlen (vcpu_dev) - 2] = '\0';
+#ifdef KVM_NO_CPUID_CALLBACK
+ KVM_NO_CPUID_CALLBACK;
+#endif
+ }
+
+ printf("ioctl(%d<%s>, KVM_CREATE_VCPU, 0) = %d<%s>\n",
+ vm_fd, vm_dev, vcpu_fd, vcpu_dev);
+
+ /* Map the shared kvm_run structure and following data. */
+ ret = KVM_IOCTL(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL);
+ struct kvm_run *run;
+ if (ret < (int) sizeof(*run))
+ error_msg_and_fail("KVM_GET_VCPU_MMAP_SIZE returned %d < %d",
+ ret, (int) sizeof(*run));
+ printf("ioctl(%d<%s>, KVM_GET_VCPU_MMAP_SIZE, 0) = %d\n",
+ kvm, dev, ret);
+
+ const size_t mmap_size = (ret + page_size - 1) & -page_size;
+ run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, vcpu_fd, 0);
+ if (run == MAP_FAILED)
+ perror_msg_and_fail("mmap vcpu");
+
+ run_kvm(vcpu_fd, run, mmap_size, mem);
+
+ puts("+++ exited with 0 +++");
+ return 0;
+}
+
+#else /* !HAVE_LINUX_KVM_H */
+
+SKIP_MAIN_UNDEFINED("HAVE_LINUX_KVM_H && HAVE_STRUCT_KVM_REGS && "
+ "HAVE_STRUCT_KVM_SREGS && "
+ "HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION && "
+ "(__x86_64__ || __i386__)")
+
+# define need_print_KVM_RUN 0
+
+#endif
diff --git a/tests/pure_executables.list b/tests/pure_executables.list
index 39565d0c..16efce7d 100755
--- a/tests/pure_executables.list
+++ b/tests/pure_executables.list
@@ -114,6 +114,7 @@ ioctl_dm
ioctl_evdev
ioctl_inotify
ioctl_kvm_run
+ioctl_kvm_run_auxstr_vcpu
ioctl_loop
ioctl_mtd
ioctl_rtc
--
2.17.1
More information about the Strace-devel
mailing list