Home | History | Annotate | Download | only in tests-m32
      1 /*
      2  * Check decoding of KVM_* commands of ioctl syscall using /dev/kvm API.
      3  * Based on kvmtest.c from https://lwn.net/Articles/658512/
      4  *
      5  * kvmtest.c author: Josh Triplett <josh (at) joshtriplett.org>
      6  * Copyright (c) 2015 Intel Corporation
      7  * Copyright (c) 2017-2018 The strace developers.
      8  *
      9  * Permission is hereby granted, free of charge, to any person obtaining a copy
     10  * of this software and associated documentation files (the "Software"), to
     11  * deal in the Software without restriction, including without limitation the
     12  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
     13  * sell copies of the Software, and to permit persons to whom the Software is
     14  * furnished to do so, subject to the following conditions:
     15  *
     16  * The above copyright notice and this permission notice shall be included in
     17  * all copies or substantial portions of the Software.
     18  *
     19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     25  * IN THE SOFTWARE.
     26  */
     27 
     28 #include "tests.h"
     29 
     30 #if defined HAVE_LINUX_KVM_H				\
     31  && defined HAVE_STRUCT_KVM_CPUID2			\
     32  && defined HAVE_STRUCT_KVM_REGS			\
     33  && defined HAVE_STRUCT_KVM_SREGS			\
     34  && defined HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION	\
     35  &&(defined __x86_64__ || defined __i386__)
     36 
     37 # include <fcntl.h>
     38 # include <stdint.h>
     39 # include <stdio.h>
     40 # include <stdlib.h>
     41 # include <string.h>
     42 # include <sys/ioctl.h>
     43 # include <sys/mman.h>
     44 # include <unistd.h>
     45 # include <linux/kvm.h>
     46 
     47 # ifndef KVM_MAX_CPUID_ENTRIES
     48 #  define KVM_MAX_CPUID_ENTRIES 80
     49 # endif
     50 
     51 #include "xlat.h"
     52 #include "xlat/kvm_cpuid_flags.h"
     53 
     54 static int
     55 kvm_ioctl(int fd, unsigned long cmd, const char *cmd_str, void *arg)
     56 {
     57 	int rc = ioctl(fd, cmd, arg);
     58 	if (rc < 0)
     59 		perror_msg_and_skip("%s", cmd_str);
     60 	return rc;
     61 }
     62 
     63 #define KVM_IOCTL(fd_, cmd_, arg_)	\
     64 	kvm_ioctl((fd_), (cmd_), #cmd_, (arg_))
     65 
     66 static const char dev[] = "/dev/kvm";
     67 static const char vm_dev[] = "anon_inode:kvm-vm";
     68 static char vcpu_dev[] = "anon_inode:kvm-vcpu:0";
     69 static size_t page_size;
     70 
     71 extern const char code[];
     72 extern const unsigned short code_size;
     73 
     74 __asm__(
     75 	".type code, @object		\n"
     76 	"code:				\n"
     77 	"	mov $0xd80003f8, %edx	\n"
     78 	"	mov $'\n', %al		\n"
     79 	"	out %al, (%dx)		\n"
     80 	"	hlt			\n"
     81 	".size code, . - code		\n"
     82 	".type code_size, @object	\n"
     83 	"code_size:			\n"
     84 	"	.short . - code		\n"
     85 	".size code_size, . - code_size	\n"
     86 	);
     87 
     88 static void
     89 print_kvm_segment(const struct kvm_segment *seg)
     90 {
     91 	printf("{base=%#jx, limit=%u, selector=%u, type=%u, present=%u, "
     92 	       "dpl=%u, db=%u, s=%u, l=%u, g=%u, avl=%u}",
     93 	       (uintmax_t) seg->base, seg->limit, seg->selector, seg->type,
     94 	       seg->present, seg->dpl, seg->db, seg->s, seg->l, seg->g,
     95 	       seg->avl);
     96 }
     97 
     98 static void
     99 print_kvm_sregs(const struct kvm_sregs *sregs)
    100 {
    101 	printf("{cs=");
    102 	print_kvm_segment(&sregs->cs);
    103 #if VERBOSE
    104 	printf(", ds=");
    105 	print_kvm_segment(&sregs->ds);
    106 	printf(", es=");
    107 	print_kvm_segment(&sregs->es);
    108 	printf(", fs=");
    109 	print_kvm_segment(&sregs->fs);
    110 	printf(", gs=");
    111 	print_kvm_segment(&sregs->gs);
    112 	printf(", ss=");
    113 	print_kvm_segment(&sregs->ss);
    114 	printf(", tr=");
    115 	print_kvm_segment(&sregs->tr);
    116 	printf(", ldt=");
    117 	print_kvm_segment(&sregs->ldt);
    118 	printf(", gdt={base=%#jx, limit=%u}, idt={base=%#jx, limit=%u}, "
    119 	      "cr0=%llu, cr2=%llu, cr3=%llu, cr4=%llu, cr8=%llu, efer=%llu, "
    120 	      "apic_base=%#jx", (uintmax_t) sregs->gdt.base, sregs->gdt.limit,
    121 	      (uintmax_t) sregs->idt.base, sregs->idt.limit, sregs->cr0,
    122 	      sregs->cr2, sregs->cr3, sregs->cr4, sregs->cr8, sregs->efer,
    123 	      (uintmax_t)sregs->apic_base);
    124 	printf(", interrupt_bitmap=[");
    125 	for (size_t i = 0; i < ARRAY_SIZE(sregs->interrupt_bitmap); i++) {
    126 		if (i)
    127 			printf(", ");
    128 		printf("%#jx", (uintmax_t) sregs->interrupt_bitmap[i]);
    129 	}
    130 	printf("]");
    131 #else
    132 	printf(", ...");
    133 #endif
    134 	printf("}");
    135 }
    136 
    137 static void
    138 print_kvm_regs(const struct kvm_regs *regs)
    139 {
    140 	printf("{rax=%#jx", (uintmax_t) regs->rax);
    141 #if VERBOSE
    142 	printf(", rbx=%#jx, rcx=%#jx, rdx=%#jx, rsi=%#jx, rdi=%#jx",
    143 	       (uintmax_t) regs->rbx, (uintmax_t) regs->rcx,
    144 	       (uintmax_t) regs->rdx, (uintmax_t) regs->rsi,
    145 	       (uintmax_t) regs->rdi);
    146 #else
    147 	printf(", ...");
    148 #endif
    149 	printf(", rsp=%#jx, rbp=%#jx", (uintmax_t) regs->rsp,
    150 	       (uintmax_t) regs->rbp);
    151 #if VERBOSE
    152 	printf(", r8=%#jx, r9=%#jx, r10=%#jx, r11=%#jx, r12=%#jx, r13=%#jx"
    153 	       ", r14=%#jx, r15=%#jx",
    154 	       (uintmax_t) regs->r8, (uintmax_t) regs->r9,
    155 	       (uintmax_t) regs->r10, (uintmax_t) regs->r11,
    156 	       (uintmax_t) regs->r12, (uintmax_t) regs->r13,
    157 	       (uintmax_t) regs->r14, (uintmax_t) regs->r15);
    158 #else
    159 	printf(", ...");
    160 #endif
    161 	printf(", rip=%#jx, rflags=%#jx}", (uintmax_t) regs->rip,
    162 	       (uintmax_t) regs->rflags);
    163 }
    164 
    165 # define need_print_KVM_RUN 1
    166 
    167 static void
    168 print_KVM_RUN(const int fd, const char *const dev, const unsigned int reason);
    169 
    170 static void
    171 run_kvm(const int vcpu_fd, struct kvm_run *const run, const size_t mmap_size,
    172 	void *const mem)
    173 {
    174 	/* Initialize CS to point at 0, via a read-modify-write of sregs. */
    175 	struct kvm_sregs sregs;
    176 	KVM_IOCTL(vcpu_fd, KVM_GET_SREGS, &sregs);
    177 	printf("ioctl(%d<%s>, KVM_GET_SREGS, ", vcpu_fd, vcpu_dev);
    178 	print_kvm_sregs(&sregs);
    179 	printf(") = 0\n");
    180 
    181 	sregs.cs.base = 0;
    182 	sregs.cs.selector = 0;
    183 	KVM_IOCTL(vcpu_fd, KVM_SET_SREGS, &sregs);
    184 	printf("ioctl(%d<%s>, KVM_SET_SREGS, ", vcpu_fd, vcpu_dev);
    185 	print_kvm_sregs(&sregs);
    186 	printf(") = 0\n");
    187 
    188 	/*
    189 	 * Initialize registers: instruction pointer for our code, addends,
    190 	 * and initial flags required by x86 architecture.
    191 	 */
    192 	struct kvm_regs regs = {
    193 		.rip = page_size,
    194 		.rax = 2,
    195 		.rbx = 2,
    196 		.rflags = 0x2,
    197 	};
    198 	KVM_IOCTL(vcpu_fd, KVM_SET_REGS, &regs);
    199 	printf("ioctl(%d<%s>, KVM_SET_REGS, ", vcpu_fd, vcpu_dev);
    200 	print_kvm_regs(&regs);
    201 	printf(") = 0\n");
    202 
    203 	/* Copy the code */
    204 	memcpy(mem, code, code_size);
    205 
    206 	const char *p = "\n";
    207 
    208 	/* Repeatedly run code and handle VM exits. */
    209 	for (;;) {
    210 		KVM_IOCTL(vcpu_fd, KVM_RUN, NULL);
    211 		print_KVM_RUN(vcpu_fd, vcpu_dev, run->exit_reason);
    212 
    213 		switch (run->exit_reason) {
    214 		case KVM_EXIT_HLT:
    215 			if (p)
    216 				error_msg_and_fail("premature KVM_EXIT_HLT");
    217 			return;
    218 		case KVM_EXIT_IO:
    219 			if (run->io.direction == KVM_EXIT_IO_OUT
    220 			    && run->io.size == 1
    221 			    && run->io.port == 0x03f8
    222 			    && run->io.count == 1
    223 			    && run->io.data_offset < mmap_size
    224 			    && p && *p == ((char *) run)[run->io.data_offset])
    225 				p = NULL;
    226 			else
    227 				error_msg_and_fail("unhandled KVM_EXIT_IO");
    228 			break;
    229 		case KVM_EXIT_MMIO:
    230 			error_msg_and_fail("Got an unexpected MMIO exit:"
    231 					   " phys_addr %#llx,"
    232 					   " data %02x %02x %02x %02x"
    233 						" %02x %02x %02x %02x,"
    234 					   " len %u, is_write %hhu",
    235 					   (unsigned long long) run->mmio.phys_addr,
    236 					   run->mmio.data[0], run->mmio.data[1],
    237 					   run->mmio.data[2], run->mmio.data[3],
    238 					   run->mmio.data[4], run->mmio.data[5],
    239 					   run->mmio.data[6], run->mmio.data[7],
    240 					   run->mmio.len, run->mmio.is_write);
    241 
    242 		default:
    243 			error_msg_and_fail("exit_reason = %#x",
    244 					   run->exit_reason);
    245 		}
    246 	}
    247 }
    248 
    249 static int
    250 vcpu_dev_should_have_cpuid(int fd)
    251 {
    252 	int r = 0;
    253 	char *filename = NULL;
    254 	char buf[sizeof(vcpu_dev)];
    255 
    256 	if (asprintf(&filename, "/proc/%d/fd/%d", getpid(), fd) < 0)
    257 		error_msg_and_fail("asprintf");
    258 
    259 	if (readlink(filename, buf, sizeof(buf)) == sizeof(buf) - 1
    260 	    && (memcmp(buf, vcpu_dev, sizeof(buf) - 1) == 0))
    261 		r = 1;
    262 	free(filename);
    263 	return r;
    264 }
    265 
    266 static void
    267 print_cpuid_ioctl(int fd, const char *fd_dev,
    268 		  const char *ioctl_name, const struct kvm_cpuid2 *cpuid)
    269 {
    270 	printf("ioctl(%d<%s>, %s, {nent=%u, entries=[",
    271 	       fd, fd_dev, ioctl_name, cpuid->nent);
    272 #if VERBOSE
    273 	for (size_t i = 0; i < cpuid->nent; i++) {
    274 		if (i)
    275 			printf(", ");
    276 		printf("{function=%#x, index=%#x, flags=",
    277 		       cpuid->entries[i].function, cpuid->entries[i].index);
    278 		printflags(kvm_cpuid_flags, cpuid->entries[i].flags,
    279 			   "KVM_CPUID_FLAG_???");
    280 		printf(", eax=%#x, ebx=%#x, ecx=%#x, edx=%#x}",
    281 		       cpuid->entries[i].eax, cpuid->entries[i].ebx,
    282 		       cpuid->entries[i].ecx, cpuid->entries[i].edx);
    283 	}
    284 #else
    285 	if (cpuid->nent)
    286 		printf("...");
    287 #endif
    288 	printf("]}) = 0\n");
    289 }
    290 
    291 int
    292 main(void)
    293 {
    294 	skip_if_unavailable("/proc/self/fd/");
    295 
    296 	int kvm = open(dev, O_RDWR);
    297 	if (kvm < 0)
    298 		perror_msg_and_skip("open: %s", dev);
    299 
    300 	/* Make sure we have the stable version of the API */
    301 	int ret = KVM_IOCTL(kvm, KVM_GET_API_VERSION, 0);
    302 	if (ret != KVM_API_VERSION)
    303 		error_msg_and_skip("KVM_GET_API_VERSION returned %d"
    304 				   ", KVM_API_VERSION is %d",
    305 				   kvm, KVM_API_VERSION);
    306 	printf("ioctl(%d<%s>, KVM_GET_API_VERSION, 0) = %d\n",
    307 	       kvm, dev, ret);
    308 
    309 	ret = KVM_IOCTL(kvm, KVM_CHECK_EXTENSION,
    310 			(void *) (uintptr_t) KVM_CAP_USER_MEMORY);
    311 	printf("ioctl(%d<%s>, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY) = %d\n",
    312 	       kvm, dev, ret);
    313 
    314 	int vm_fd = KVM_IOCTL(kvm, KVM_CREATE_VM, 0);
    315 	printf("ioctl(%d<%s>, KVM_CREATE_VM, 0) = %d<%s>\n",
    316 	       kvm, dev, vm_fd, vm_dev);
    317 
    318 	/* Allocate one aligned page of guest memory to hold the code. */
    319 	page_size = get_page_size();
    320 	void *const mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
    321 				  MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    322 	if (mem == MAP_FAILED)
    323 		perror_msg_and_fail("mmap page");
    324 
    325 	/* Map it to the second page frame (to avoid the real-mode IDT at 0). */
    326 	struct kvm_userspace_memory_region region = {
    327 		.slot = 0,
    328 		.guest_phys_addr = page_size,
    329 		.memory_size = page_size,
    330 		.userspace_addr = (uintptr_t) mem,
    331 	};
    332 	KVM_IOCTL(vm_fd, KVM_SET_USER_MEMORY_REGION, &region);
    333 	printf("ioctl(%d<%s>, KVM_SET_USER_MEMORY_REGION"
    334 	       ", {slot=0, flags=0, guest_phys_addr=%#lx, memory_size=%lu"
    335 	       ", userspace_addr=%p}) = 0\n", vm_fd, vm_dev,
    336 	       (unsigned long) page_size, (unsigned long) page_size, mem);
    337 
    338 	int vcpu_fd = KVM_IOCTL(vm_fd, KVM_CREATE_VCPU, NULL);
    339 	if (!vcpu_dev_should_have_cpuid(vcpu_fd)) {
    340 		/*
    341 		 * This is an older kernel that doesn't place a cpuid
    342 		 * at the end of the dentry associated with vcpu_fd.
    343 		 * Trim the cpuid part of vcpu_dev like:
    344 		 * "anon_inode:kvm-vcpu:0" -> "anon_inode:kvm-vcpu"
    345 		 */
    346 		vcpu_dev[strlen (vcpu_dev) - 2] = '\0';
    347 #ifdef KVM_NO_CPUID_CALLBACK
    348 		KVM_NO_CPUID_CALLBACK;
    349 #endif
    350 	}
    351 
    352 	printf("ioctl(%d<%s>, KVM_CREATE_VCPU, 0) = %d<%s>\n",
    353 	       vm_fd, vm_dev, vcpu_fd, vcpu_dev);
    354 
    355 	/* Map the shared kvm_run structure and following data. */
    356 	ret = KVM_IOCTL(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL);
    357 	struct kvm_run *run;
    358 	if (ret < (int) sizeof(*run))
    359 		error_msg_and_fail("KVM_GET_VCPU_MMAP_SIZE returned %d < %d",
    360 				   ret, (int) sizeof(*run));
    361 	printf("ioctl(%d<%s>, KVM_GET_VCPU_MMAP_SIZE, 0) = %d\n",
    362 	       kvm, dev, ret);
    363 
    364 	const size_t mmap_size = (ret + page_size - 1) & -page_size;
    365 	run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE,
    366 		   MAP_SHARED, vcpu_fd, 0);
    367 	if (run == MAP_FAILED)
    368 		perror_msg_and_fail("mmap vcpu");
    369 
    370 	size_t cpuid_nent = KVM_MAX_CPUID_ENTRIES;
    371 	struct kvm_cpuid2 *cpuid = tail_alloc(sizeof(*cpuid) +
    372 					      cpuid_nent *
    373 					      sizeof(*cpuid->entries));
    374 
    375 	cpuid->nent = 0;
    376 	ioctl(kvm, KVM_GET_SUPPORTED_CPUID, cpuid);
    377 	printf("ioctl(%d<%s>, KVM_GET_SUPPORTED_CPUID, %p) = -1 E2BIG (%m)\n",
    378 	       kvm, dev, cpuid);
    379 
    380 	cpuid->nent = cpuid_nent;
    381 
    382 	KVM_IOCTL(kvm, KVM_GET_SUPPORTED_CPUID, cpuid);
    383 	print_cpuid_ioctl(kvm, dev, "KVM_GET_SUPPORTED_CPUID", cpuid);
    384 
    385 	struct kvm_cpuid2 cpuid_tmp = { .nent = 0 };
    386 	KVM_IOCTL(vcpu_fd, KVM_SET_CPUID2, &cpuid_tmp);
    387 	printf("ioctl(%d<%s>, KVM_SET_CPUID2, {nent=%u, entries=[]}) = 0\n",
    388 	       vcpu_fd, vcpu_dev, cpuid_tmp.nent);
    389 
    390 	KVM_IOCTL(vcpu_fd, KVM_SET_CPUID2, cpuid);
    391 	print_cpuid_ioctl(vcpu_fd, vcpu_dev, "KVM_SET_CPUID2", cpuid);
    392 
    393 	ioctl(vcpu_fd, KVM_SET_CPUID2, NULL);
    394 	printf("ioctl(%d<%s>, KVM_SET_CPUID2, NULL) = -1 EFAULT (%m)\n",
    395 	       vcpu_fd, vcpu_dev);
    396 
    397 	run_kvm(vcpu_fd, run, mmap_size, mem);
    398 
    399 	puts("+++ exited with 0 +++");
    400 	return 0;
    401 }
    402 
    403 #else /* !HAVE_LINUX_KVM_H */
    404 
    405 SKIP_MAIN_UNDEFINED("HAVE_LINUX_KVM_H && HAVE_STRUCT_KVM_CPUID2 && "
    406 		    "HAVE_STRUCT_KVM_REGS && HAVE_STRUCT_KVM_SREGS && "
    407 		    "HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION && "
    408 		    "(__x86_64__ || __i386__)")
    409 
    410 # define need_print_KVM_RUN 0
    411 
    412 #endif
    413