mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-09-04 20:51:28 +00:00
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:
committed by
Will Deacon
parent
6a26200aa4
commit
2049569d3d
+3
-1
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user