1 // SPDX-License-Identifier: GPL-2.0
11 #include "processor.h"
13 static void guest_ins_port80(uint8_t *buffer
, unsigned int count
)
18 end
= (unsigned long)buffer
+ 1;
20 end
= (unsigned long)buffer
+ 8192;
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
);
27 static void guest_code(void)
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.
39 guest_ins_port80(buffer
, 2);
40 guest_ins_port80(buffer
, 3);
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]",
53 int main(int argc
, char *argv
[])
55 struct kvm_vcpu
*vcpu
;
61 vm
= vm_create_with_one_vcpu(&vcpu
, guest_code
);
64 memset(®s
, 0, sizeof(regs
));
68 TEST_ASSERT_KVM_EXIT_REASON(vcpu
, KVM_EXIT_IO
);
70 if (get_ucall(vcpu
, &uc
))
73 TEST_ASSERT(run
->io
.port
== 0x80,
74 "Expected I/O at port 0x80, got port 0x%x", run
->io
.port
);
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.
83 vcpu_regs_get(vcpu
, ®s
);
88 memset((void *)run
+ run
->io
.data_offset
, 0xaa, 4096);
89 vcpu_regs_set(vcpu
, ®s
);
96 REPORT_GUEST_ASSERT(uc
);
98 TEST_FAIL("Unknown ucall %lu", uc
.cmd
);