From: Pekka Enberg Date: Wed, 31 Mar 2010 18:35:27 +0000 (+0300) Subject: kvm: Add simple NMI enable/disable support X-Git-Tag: next-20110824~3^2~528^2~199 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=05c00c5368d20e50d47b6421faa54c4522b63d45;p=karo-tx-linux.git kvm: Add simple NMI enable/disable support This patch adds simple NMI I/O port emulation. Signed-off-by: Pekka Enberg --- diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h index d89a3f26fd5b..73d3c857871a 100644 --- a/tools/kvm/include/kvm/kvm.h +++ b/tools/kvm/include/kvm/kvm.h @@ -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 diff --git a/tools/kvm/ioport.c b/tools/kvm/ioport.c index e77a663d724b..f78674dcfb3d 100644 --- a/tools/kvm/ioport.c +++ b/tools/kvm/ioport.c @@ -1,27 +1,77 @@ #include "kvm/kvm.h" +#include #include -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; } diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c index c651004edd6d..5c0089caa533 100644 --- a/tools/kvm/kvm.c +++ b/tools/kvm/kvm.c @@ -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++) diff --git a/tools/kvm/main.c b/tools/kvm/main.c index 9a6817b96dde..402d76940c8b 100644 --- a/tools/kvm/main.c +++ b/tools/kvm/main.c @@ -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; }