// SPDX-License-Identifier: GPL-2.0
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include "test_util.h"
#include "kvm_util.h"
#include "processor.h"
static void guest_ins_port80(uint8_t *buffer, unsigned int count)
{
unsigned long end;
if (count == 2 )
end = (unsigned long )buffer + 1 ;
else
end = (unsigned long )buffer + 8192 ;
asm volatile ("cld; rep; insb" : "+D" (buffer), "+c" (count) : "d" (0 x80) : "memory" );
GUEST_ASSERT_EQ(count, 0 );
GUEST_ASSERT_EQ((unsigned long )buffer, end);
}
static void guest_code(void )
{
uint8_t buffer[8192 ];
int i;
/*
* Special case tests . main ( ) will adjust RCX 2 = > 1 and 3 = > 8192 to
* test that KVM doesn ' t explode when userspace modifies the " count " on
* a userspace I / O exit . KVM isn ' t required to play nice with the I / O
* itself as KVM doesn ' t support manipulating the count , it just needs
* to not explode or overflow a buffer .
*/
guest_ins_port80(buffer, 2 );
guest_ins_port80(buffer, 3 );
/* Verify KVM fills the buffer correctly when not stuffing RCX. */
memset(buffer, 0 , sizeof (buffer));
guest_ins_port80(buffer, 8192 );
for (i = 0 ; i < 8192 ; i++)
__GUEST_ASSERT(buffer[i] == 0 xaa,
"Expected '0xaa', got '0x%x' at buffer[%u]" ,
buffer[i], i);
GUEST_DONE();
}
int main(int argc, char *argv[])
{
struct kvm_vcpu *vcpu;
struct kvm_regs regs;
struct kvm_run *run;
struct kvm_vm *vm;
struct ucall uc;
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
run = vcpu->run;
memset(®s, 0 , sizeof (regs));
while (1 ) {
vcpu_run(vcpu);
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
if (get_ucall(vcpu, &uc))
break ;
TEST_ASSERT(run->io.port == 0 x80,
"Expected I/O at port 0x80, got port 0x%x" , run->io.port);
/*
* Modify the rep string count in RCX : 2 = > 1 and 3 = > 8192 .
* Note , this abuses KVM ' s batching of rep string I / O to avoid
* getting stuck in an infinite loop . That behavior isn ' t in
* scope from a testing perspective as it ' s not ABI in any way ,
* i . e . it really is abusing internal KVM knowledge .
*/
vcpu_regs_get(vcpu, ®s);
if (regs.rcx == 2 )
regs.rcx = 1 ;
if (regs.rcx == 3 )
regs.rcx = 8192 ;
memset((void *)run + run->io.data_offset, 0 xaa, 4096 );
vcpu_regs_set(vcpu, ®s);
}
switch (uc.cmd) {
case UCALL_DONE:
break ;
case UCALL_ABORT:
REPORT_GUEST_ASSERT(uc);
default :
TEST_FAIL("Unknown ucall %lu" , uc.cmd);
}
kvm_vm_free(vm);
return 0 ;
}
Messung V0.5 in Prozent C=93 H=94 G=93
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet am 2026-10-12)
¤
*© Formatika GbR, Deutschland