File Index
Files and directories
Sign in
FILE

userspace_io_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/kvm/x86/userspace_io_test.c C
  1// SPDX-License-Identifier: GPL-2.0
  2#include <fcntl.h>
  3#include <stdio.h>
  4#include <stdlib.h>
  5#include <string.h>
  6#include <sys/ioctl.h>
  7
  8#include "test_util.h"
  9
 10#include "kvm_util.h"
 11#include "processor.h"
 12
 13static void guest_ins_port80(uint8_t *buffer, unsigned int count)
 14{
 15	unsigned long end;
 16
 17	if (count == 2)
 18		end = (unsigned long)buffer + 1;
 19	else
 20		end = (unsigned long)buffer + 8192;
 21
 22	asm volatile("cld; rep; insb" : "+D"(buffer), "+c"(count) : "d"(0x80) : "memory");
 23	GUEST_ASSERT_EQ(count, 0);
 24	GUEST_ASSERT_EQ((unsigned long)buffer, end);
 25}
 26
 27static void guest_code(void)
 28{
 29	uint8_t buffer[8192];
 30	int i;
 31
 32	/*
 33	 * Special case tests.  main() will adjust RCX 2 => 1 and 3 => 8192 to
 34	 * test that KVM doesn't explode when userspace modifies the "count" on
 35	 * a userspace I/O exit.  KVM isn't required to play nice with the I/O
 36	 * itself as KVM doesn't support manipulating the count, it just needs
 37	 * to not explode or overflow a buffer.
 38	 */
 39	guest_ins_port80(buffer, 2);
 40	guest_ins_port80(buffer, 3);
 41
 42	/* Verify KVM fills the buffer correctly when not stuffing RCX. */
 43	memset(buffer, 0, sizeof(buffer));
 44	guest_ins_port80(buffer, 8192);
 45	for (i = 0; i < 8192; i++)
 46		__GUEST_ASSERT(buffer[i] == 0xaa,
 47			       "Expected '0xaa', got '0x%x' at buffer[%u]",
 48			       buffer[i], i);
 49
 50	GUEST_DONE();
 51}
 52
 53int main(int argc, char *argv[])
 54{
 55	struct kvm_vcpu *vcpu;
 56	struct kvm_regs regs;
 57	struct kvm_run *run;
 58	struct kvm_vm *vm;
 59	struct ucall uc;
 60
 61	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
 62	run = vcpu->run;
 63
 64	memset(&regs, 0, sizeof(regs));
 65
 66	while (1) {
 67		vcpu_run(vcpu);
 68		TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
 69
 70		if (get_ucall(vcpu, &uc))
 71			break;
 72
 73		TEST_ASSERT(run->io.port == 0x80,
 74			    "Expected I/O at port 0x80, got port 0x%x", run->io.port);
 75
 76		/*
 77		 * Modify the rep string count in RCX: 2 => 1 and 3 => 8192.
 78		 * Note, this abuses KVM's batching of rep string I/O to avoid
 79		 * getting stuck in an infinite loop.  That behavior isn't in
 80		 * scope from a testing perspective as it's not ABI in any way,
 81		 * i.e. it really is abusing internal KVM knowledge.
 82		 */
 83		vcpu_regs_get(vcpu, &regs);
 84		if (regs.rcx == 2)
 85			regs.rcx = 1;
 86		if (regs.rcx == 3)
 87			regs.rcx = 8192;
 88		memset((void *)run + run->io.data_offset, 0xaa, PAGE_SIZE);
 89		vcpu_regs_set(vcpu, &regs);
 90	}
 91
 92	switch (uc.cmd) {
 93	case UCALL_DONE:
 94		break;
 95	case UCALL_ABORT:
 96		REPORT_GUEST_ASSERT(uc);
 97	default:
 98		TEST_FAIL("Unknown ucall %lu", uc.cmd);
 99	}
100
101	kvm_vm_free(vm);
102	return 0;
103}
~/ Read-only file preview.