]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
kvm: Add simple NMI enable/disable support
authorPekka Enberg <penberg@cs.helsinki.fi>
Wed, 31 Mar 2010 18:35:27 +0000 (21:35 +0300)
committerPekka Enberg <penberg@cs.helsinki.fi>
Wed, 31 Mar 2010 18:37:40 +0000 (21:37 +0300)
This patch adds simple NMI I/O port emulation.

Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
tools/kvm/include/kvm/kvm.h
tools/kvm/ioport.c
tools/kvm/kvm.c
tools/kvm/main.c

index d89a3f26fd5bfd8639ae311621a47070d6794eba..73d3c857871a93fdc6c9b7d1636267d403f7ec87 100644 (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
index e77a663d724b06587be06600b9783ae38c83d26b..f78674dcfb3dfb0cea19bf15728402f072f3e271 100644 (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)
+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);
+};
+
+static uint8_t ioport_to_uint8(void *data)
 {
-       fprintf(stderr, "IO error: OUT port=%x, size=%d, count=%" PRIu32 "\n", port, size, count);
+       uint8_t *p = data;
 
-       kvm__show_registers(self);
-       kvm__show_code(self);
+       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;
+
+       value   = ioport_to_uint8(data);
 
-       kvm__show_registers(self);
-       kvm__show_code(self);
+       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;
 }
index c651004edd6db5874cd9625625f3dbda783174aa..5c0089caa5331aa9169a344fc913f2aa34c84d63 100644 (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++)
index 9a6817b96ddedb8f6dec16c896e857e3ff97eb4b..402d76940c8b4541ab5cf3dbc4adeeb150d41868 100644 (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;
                }