I'm currently experimenting with KVM, and trying to get US (userspace) I/O working. Currently, output (i.e. out dx, eax
) works, and the US code can see the written value, but input (in eax, dx
) does not seem to work - the VM doesn't receive the value written by the US code.
if (run->io.port == 0xface && run->io.direction == KVM_EXIT_IO_IN)
{
printf("Port 0xface read\n");
*(volatile uint32_t *)((uintptr_t)run + run->io.data_offset) = 0xdeadbeefu;
continue;
}
run
is a pointer to a struct kvm_run
that was mmap
ed earlier and has enough space (i.e. run->io.data_offset
is a valid offset from the pointer). The continue
statement eventually causes the VM to restart, and the code continues normally. However, when I try to get the VM's rax
register (which should be 0xdeadbeef
), I get zero. From what I read in the docs (kvm/Documentation/api.txt
), this is how I should be doing it. Am I missing something?
On a semi-related note, if I precede the continue
statement with run->io.count = run->io.count;
, the I/O is triggered again (even though count
isn't changed). Is this expected behavior? Or am I triggering undefined behavior?
The issue is with the actual mmap
call:
run = mmap(NULL, mapSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, vcpuFD, 0);
The flags
parameter should be MAP_SHARED
instead of MAP_PRIVATE
:
run = mmap(NULL, mapSize, PROT_READ | PROT_WRITE, MAP_SHARED, vcpuFD, 0);
^^^^^^^^^^
The virtual machine will see the updated values when KVM_RUN
is issued to restart it.