On Thu, 7 Dec 2017 17:18:50 +0300, "Dmitry V. Levin" <l...@altlinux.org> wrote: > On Thu, Dec 07, 2017 at 11:14:34PM +0900, Masatake YAMATO wrote: >> On Thu, 7 Dec 2017 17:04:05 +0300, "Dmitry V. Levin" <l...@altlinux.org> >> wrote: >> > On Mon, Dec 04, 2017 at 10:08:17PM +0900, Masatake YAMATO wrote: >> >> * tests/Makefile.am (check_PROGRAMS): Add ioctl_kvm. >> >> (DECODER_TESTS): Add ioctl_kvm.test. >> >> (EXTRA_DIST): Add ioctl_kvm.expected. >> >> * tests/ioctl_kvm.c: New test target file. >> >> Taken from https://lwn.net/Articles/658512/. >> >> * tests/ioctl_kvm.expected: New expected file. >> >> * tests/ioctl_kvm.test: New test driver. >> >> >> >> Changes in v2: >> >> * Skip the test case if kvm.h is not available. >> >> * Skip the test case if opening /dev/kvm is failed. >> >> * Include sys/typtes.h first. >> >> >> >> All items are suggested by ldv. >> >> >> >> Highlights in v3: >> >> * Build the new test case when __x86_64__ is defined. >> >> * Don't use macros/functions in err.h. >> >> Use macros/functions in tests.h instead. >> >> * Remove redundant inclusion of header files. >> >> >> >> All above items are suggested by ldv. >> >> >> >> * Add .test and .expected file to Makefile.am. >> >> >> >> No Change in v4. >> > >> > Yet the test doesn't quite fit the test suite, so I took the liberty >> > to tweak it here and there, please have a look. >> > >> > I also renamed it to make room for more formal KVM_* ioctl tests like >> > those we already have (tests/ioctl_*.c) for other ioctl decoders. >> > >> > * tests/ioctl_kvm_run.c: New file. >> > * tests/ioctl_kvm_run.test: New test. >> > * tests/Makefile.am (DECODER_TESTS): Add ioctl_kvm_run.test. >> > * tests/pure_executables.list: Add ioctl_kvm_run. >> > * tests/.gitignore: Likewise. >> > >> > Co-authored-by: Dmitry V. Levin <l...@altlinux.org> >> > --- >> > tests/.gitignore | 1 + >> > tests/Makefile.am | 1 + >> > tests/ioctl_kvm_run.c | 220 >> > ++++++++++++++++++++++++++++++++++++++++++++ >> > tests/ioctl_kvm_run.test | 11 +++ >> > tests/pure_executables.list | 1 + >> > 5 files changed, 234 insertions(+) >> > create mode 100644 tests/ioctl_kvm_run.c >> > create mode 100755 tests/ioctl_kvm_run.test >> > >> > diff --git a/tests/.gitignore b/tests/.gitignore >> > index 93c980f..7838a5b 100644 >> > --- a/tests/.gitignore >> > +++ b/tests/.gitignore >> > @@ -128,6 +128,7 @@ ioctl_dm >> > ioctl_dm-v >> > ioctl_evdev >> > ioctl_evdev-v >> > +ioctl_kvm_run >> > ioctl_loop >> > ioctl_loop-nv >> > ioctl_loop-v >> > diff --git a/tests/Makefile.am b/tests/Makefile.am >> > index 7bc2872..22a39d7 100644 >> > --- a/tests/Makefile.am >> > +++ b/tests/Makefile.am >> > @@ -206,6 +206,7 @@ DECODER_TESTS = \ >> > ioctl.test \ >> > ioctl_dm-v.test \ >> > ioctl_dm.test \ >> > + ioctl_kvm_run.test \ >> > ioctl_loop-nv.test \ >> > ioctl_nsfs.test \ >> > ioctl_sock_gifconf.test \ >> > diff --git a/tests/ioctl_kvm_run.c b/tests/ioctl_kvm_run.c >> > new file mode 100644 >> > index 0000000..90fffba >> > --- /dev/null >> > +++ b/tests/ioctl_kvm_run.c >> > @@ -0,0 +1,220 @@ >> > +/* >> > + * 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 <j...@joshtriplett.org> >> > + * Copyright (c) 2015 Intel Corporation >> > + * Copyright (c) 2017 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 <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 const char vcpu_dev[] = "anon_inode:kvm-vcpu"; >> > +static size_t page_size; >> > + >> > +static void >> > +code(void) >> > +{ >> > + __asm__("mov $0xd80003f8, %edx; mov $'\n', %al; out %al, (%dx); hlt"); >> > +} >> > + >> > +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 till the end of page */ >> > + size_t code_size = page_size - ((uintptr_t) code & (page_size - 1)); >> > + if (code_size < 16) >> > + code_size = 16; >> > + 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; >> > + default: >> > + error_msg_and_fail("exit_reason = %#x", >> > + run->exit_reason); >> > + } >> > + } >> > +} >> > + >> > +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, >> >> Please, look at [PATCH v5 1/4] and [PATCH v5 4/4]. I found I missed >> printing '}' at the end. I added the last '}' in the above patch. > > Yes, I missed it, too. Thanks, fixed locally. > >> > + (unsigned long) page_size, (unsigned long) page_size, mem); >> > + >> > + int vcpu_fd = KVM_IOCTL(vm_fd, KVM_CREATE_VCPU, NULL); >> > + 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.test b/tests/ioctl_kvm_run.test >> > new file mode 100755 >> > index 0000000..a23cbeb >> > --- /dev/null >> > +++ b/tests/ioctl_kvm_run.test >> > @@ -0,0 +1,11 @@ >> > +#!/bin/sh >> > + >> > +# Check decoding of KVM_* ioctl commands. >> > + >> > +. "${srcdir=.}/init.sh" >> > + >> > +check_prog grep >> > +run_prog > /dev/null >> > +run_strace -a36 -y -eioctl $args > "$EXP" >> > +grep -v '^ioctl([012],' < "$LOG" > "$OUT" >> > +match_diff "$OUT" "$EXP" >> > diff --git a/tests/pure_executables.list b/tests/pure_executables.list >> > index 7ab52ef..0d1964d 100755 >> > --- a/tests/pure_executables.list >> > +++ b/tests/pure_executables.list >> > @@ -103,6 +103,7 @@ ioctl >> > ioctl_block >> > ioctl_dm >> > ioctl_evdev >> > +ioctl_kvm_run >> > ioctl_loop >> > ioctl_mtd >> > ioctl_rtc > > What about the patch itself? Are you OK with the changes?
I read this through. Other than assembly language code in code(), it looks good for me. I don't understand what is done in code(). I compiled .c file having only code() and run objdump -d: What I got is 0000000000000000 <code>: 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: ba f8 03 00 d8 mov $0xd80003f8,%edx 9: b0 0a mov $0xa,%al b: ee out %al,(%dx) c: f4 hlt d: 90 nop e: 5d pop %rbp f: c3 retq I find no add operator in the output. So I guess what this code does is different fron what the original code does: const uint8_t code[] = { 0xba, 0xf8, 0x03, /* mov $0x3f8, %dx */ 0x00, 0xd8, /* add %bl, %al */ 0x04, '0', /* add $'0', %al */ The code executed by kvm is not important here. However, I wondher what the intent is. Masatake YAMATO > > -- > ldv ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel