kvm: Add simple NMI enable/disable support

This patch adds simple NMI I/O port emulation.

Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
This commit is contained in:
Pekka Enberg
2015-06-01 16:39:39 +01:00
committed by Will Deacon
parent 6a26200aa4
commit 2049569d3d
4 changed files with 75 additions and 16 deletions
+3 -1
View File
@@ -17,6 +17,8 @@ struct kvm {
uint64_t ram_size;
void *ram_start;
bool nmi_disabled;
uint16_t boot_selector;
uint16_t boot_ip;
uint16_t boot_sp;
@@ -33,7 +35,7 @@ void kvm__enable_singlestep(struct kvm *self);
bool kvm__load_kernel(struct kvm *kvm, const char *kernel_filename, const char *kernel_cmdline);
void kvm__reset_vcpu(struct kvm *self);
void kvm__run(struct kvm *self);
void kvm__emulate_io(struct kvm *self, uint16_t port, void *data, int direction, int size, uint32_t count);
bool kvm__emulate_io(struct kvm *self, uint16_t port, void *data, int direction, int size, uint32_t count);
/*
* Debugging
+62 -12
View File
@@ -1,27 +1,77 @@
#include "kvm/kvm.h"
#include <limits.h>
#include <stdio.h>
static void kvm__emulate_io_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
{
fprintf(stderr, "IO error: OUT port=%x, size=%d, count=%" PRIu32 "\n", port, size, count);
struct ioport_operations {
bool (*io_in)(struct kvm *self, uint16_t port, void *data, int size, uint32_t count);
bool (*io_out)(struct kvm *self, uint16_t port, void *data, int size, uint32_t count);
};
kvm__show_registers(self);
kvm__show_code(self);
static uint8_t ioport_to_uint8(void *data)
{
uint8_t *p = data;
return *p;
}
static void kvm__emulate_io_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
static bool cmos_ram_rtc_io_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
{
fprintf(stderr, "IO error: IN port=%x, size=%d, count=%" PRIu32 "\n", port, size, count);
uint8_t value;
kvm__show_registers(self);
kvm__show_code(self);
value = ioport_to_uint8(data);
self->nmi_disabled = value & (1UL << 7);
return true;
}
void kvm__emulate_io(struct kvm *self, uint16_t port, void *data, int direction, int size, uint32_t count)
static struct ioport_operations cmos_ram_rtc_ops = {
.io_out = cmos_ram_rtc_io_out,
};
static struct ioport_operations *ioport_ops[USHRT_MAX] = {
[0x70] = &cmos_ram_rtc_ops,
};
static const char *to_direction(int direction)
{
if (direction == KVM_EXIT_IO_IN)
kvm__emulate_io_in(self, port, data, size, count);
return "IN";
else
kvm__emulate_io_out(self, port, data, size, count);
return "OUT";
}
static void ioport_error(uint16_t port, void *data, int direction, int size, uint32_t count)
{
fprintf(stderr, "IO error: %s port=%x, size=%d, count=%" PRIu32 "\n", to_direction(direction), port, size, count);
}
bool kvm__emulate_io(struct kvm *self, uint16_t port, void *data, int direction, int size, uint32_t count)
{
struct ioport_operations *ops = ioport_ops[port];
bool ret;
if (!ops)
goto error;
if (direction == KVM_EXIT_IO_IN) {
if (!ops->io_in)
goto error;
ret = ops->io_in(self, port, data, size, count);
if (!ret)
goto error;
} else {
if (!ops->io_out)
goto error;
ret = ops->io_out(self, port, data, size, count);
if (!ret)
goto error;
}
return true;
error:
ioport_error(port, data, direction, size, count);
return false;
}
+2 -1
View File
@@ -473,7 +473,8 @@ void kvm__show_registers(struct kvm *self)
print_segment("gs ", &sregs.gs);
print_segment("tr ", &sregs.tr);
print_segment("ldt", &sregs.ldt);
printf(" [ efer: %016lx apic base: %016lx ]\n", (uint64_t) sregs.efer, (uint64_t) sregs.apic_base);
printf(" [ efer: %016lx apic base: %016lx nmi: %s ]\n", (uint64_t) sregs.efer, (uint64_t) sregs.apic_base,
(self->nmi_disabled ? "disabled" : "enabled"));
printf("Interrupt bitmap:\n");
printf(" ");
for (i = 0; i < (KVM_NR_INTERRUPTS + 63) / 64; i++)
+8 -2
View File
@@ -66,14 +66,20 @@ int main(int argc, char *argv[])
kvm__show_registers(kvm);
kvm__show_code(kvm);
break;
case KVM_EXIT_IO:
kvm__emulate_io(kvm,
case KVM_EXIT_IO: {
bool ret;
ret = kvm__emulate_io(kvm,
kvm->kvm_run->io.port,
(uint8_t *)kvm->kvm_run + kvm->kvm_run->io.data_offset,
kvm->kvm_run->io.direction,
kvm->kvm_run->io.size,
kvm->kvm_run->io.count);
if (!ret)
goto exit_kvm;
break;
}
default:
goto exit_kvm;
}