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 13 static 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_1(count == 0, count); 24 GUEST_ASSERT_2((unsigned long)buffer == end, buffer, end); 25 } 26 27 static 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_2(buffer[i] == 0xaa, i, buffer[i]); 47 48 GUEST_DONE(); 49 } 50 51 int main(int argc, char *argv[]) 52 { 53 struct kvm_vcpu *vcpu; 54 struct kvm_regs regs; 55 struct kvm_run *run; 56 struct kvm_vm *vm; 57 struct ucall uc; 58 59 /* Tell stdout not to buffer its content */ 60 setbuf(stdout, NULL); 61 62 vm = vm_create_with_one_vcpu(&vcpu, guest_code); 63 run = vcpu->run; 64 65 memset(®s, 0, sizeof(regs)); 66 67 while (1) { 68 vcpu_run(vcpu); 69 70 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, 71 "Unexpected exit reason: %u (%s),\n", 72 run->exit_reason, 73 exit_reason_str(run->exit_reason)); 74 75 if (get_ucall(vcpu, &uc)) 76 break; 77 78 TEST_ASSERT(run->io.port == 0x80, 79 "Expected I/O at port 0x80, got port 0x%x\n", run->io.port); 80 81 /* 82 * Modify the rep string count in RCX: 2 => 1 and 3 => 8192. 83 * Note, this abuses KVM's batching of rep string I/O to avoid 84 * getting stuck in an infinite loop. That behavior isn't in 85 * scope from a testing perspective as it's not ABI in any way, 86 * i.e. it really is abusing internal KVM knowledge. 87 */ 88 vcpu_regs_get(vcpu, ®s); 89 if (regs.rcx == 2) 90 regs.rcx = 1; 91 if (regs.rcx == 3) 92 regs.rcx = 8192; 93 memset((void *)run + run->io.data_offset, 0xaa, 4096); 94 vcpu_regs_set(vcpu, ®s); 95 } 96 97 switch (uc.cmd) { 98 case UCALL_DONE: 99 break; 100 case UCALL_ABORT: 101 REPORT_GUEST_ASSERT_2(uc, "argN+1 = 0x%lx, argN+2 = 0x%lx"); 102 default: 103 TEST_FAIL("Unknown ucall %lu", uc.cmd); 104 } 105 106 kvm_vm_free(vm); 107 return 0; 108 } 109