+#include "kvm/kvm.h"
+
#include <linux/kvm.h>
#include <asm/bootparam.h>
+#include <sys/ioctl.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <stdbool.h>
# define KVM_EXIT_INTERNAL_ERROR 17
#endif
-struct kvm {
- int sys_fd; /* For system ioctls(), i.e. /dev/kvm */
- int vm_fd; /* For VM ioctls() */
- int vcpu_fd; /* For VCPU ioctls() */
- struct kvm_run *kvm_run;
-
- uint64_t ram_size;
- void *ram_start;
+#define DEFINE_KVM_EXIT_REASON(reason) [reason] = #reason
- struct kvm_regs regs;
+const char *kvm_exit_reasons[] = {
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_UNKNOWN),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_EXCEPTION),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_IO),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_HYPERCALL),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_DEBUG),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_HLT),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_MMIO),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_IRQ_WINDOW_OPEN),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_SHUTDOWN),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_FAIL_ENTRY),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_INTR),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_SET_TPR),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_TPR_ACCESS),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_S390_SIEIC),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_S390_RESET),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_DCR),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_NMI),
+ DEFINE_KVM_EXIT_REASON(KVM_EXIT_INTERNAL_ERROR),
};
-static inline bool kvm__supports_extension(struct kvm *self, unsigned int extension)
+static inline void *guest_addr_to_host(struct kvm *self, unsigned long offset)
+{
+ return self->ram_start + offset;
+}
+
+static bool kvm__supports_extension(struct kvm *self, unsigned int extension)
{
int ret;
return self;
}
-static struct kvm *kvm__init(void)
+struct kvm *kvm__init(void)
{
struct kvm_userspace_memory_region mem;
struct kvm *self;
return self;
}
-static void kvm__run(struct kvm *self)
-{
- if (ioctl(self->vcpu_fd, KVM_RUN, 0) < 0)
- die_perror("KVM_RUN failed");
-}
-
-static void kvm__enable_singlestep(struct kvm *self)
+void kvm__enable_singlestep(struct kvm *self)
{
struct kvm_guest_debug debug = {
.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP,
warning("KVM_SET_GUEST_DEBUG failed");
}
-static void kvm__show_registers(struct kvm *self)
-{
- unsigned long rax, rbx, rcx;
- unsigned long rdx, rsi, rdi;
- unsigned long rbp, r8, r9;
- unsigned long r10, r11, r12;
- unsigned long r13, r14, r15;
- unsigned long rip, rsp;
- unsigned long rflags;
- struct kvm_regs regs;
-
- if (ioctl(self->vcpu_fd, KVM_GET_REGS, ®s) < 0)
- die("KVM_GET_REGS failed");
-
- rflags = regs.rflags;
-
- rip = regs.rip; rsp = regs.rsp;
- rax = regs.rax; rbx = regs.rbx; rcx = regs.rcx;
- rdx = regs.rdx; rsi = regs.rsi; rdi = regs.rdi;
- rbp = regs.rbp; r8 = regs.r8; r9 = regs.r9;
- r10 = regs.r10; r11 = regs.r11; r12 = regs.r12;
- r13 = regs.r13; r14 = regs.r14; r15 = regs.r15;
-
- printf("Registers:\n");
- printf(" rip: %016lx rsp: %016lx flags: %016lx\n", rip, rsp, rflags);
- printf(" rax: %016lx ebx: %016lx ecx: %016lx\n", rax, rbx, rcx);
- printf(" rdx: %016lx rsi: %016lx rdi: %016lx\n", rdx, rsi, rdi);
- printf(" rbp: %016lx r8: %016lx r9: %016lx\n", rbp, r8, r9);
- printf(" r10: %016lx r11: %016lx r12: %016lx\n", r10, r11, r12);
- printf(" r13: %016lx r14: %016lx r15: %016lx\n", r13, r14, r15);
-}
-
-static inline void *guest_addr_to_host(struct kvm *self, unsigned long offset)
-{
- return self->ram_start + offset;
-}
-
-static void kvm__show_code(struct kvm *self)
-{
- unsigned int code_bytes = 64;
- unsigned int code_prologue = code_bytes * 43 / 64;
- unsigned int code_len = code_bytes;
- unsigned char c;
- uint8_t *ip;
- int i;
-
- ip = guest_addr_to_host(self, self->regs.rip - code_prologue);
-
- printf("Code: ");
-
- for (i = 0; i < code_len; i++, ip++) {
- c = *ip;
-
- if (ip == guest_addr_to_host(self, self->regs.rip))
- printf("<%02x> ", c);
- else
- printf("%02x ", c);
- }
-
- printf("\n");
-}
-
/* bzImages are loaded at 1 MB by default. */
#define KERNEL_START_ADDR (1024ULL * 1024ULL)
return boot.hdr.code32_start;
}
-static uint32_t kvm__load_kernel(struct kvm *kvm, const char *kernel_filename)
+uint32_t kvm__load_kernel(struct kvm *kvm, const char *kernel_filename)
{
uint32_t ret;
int fd;
return ret;
}
-#define DEFINE_KVM_EXIT_REASON(reason) [reason] = #reason
-
-static const char *exit_reasons[] = {
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_UNKNOWN),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_EXCEPTION),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_IO),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_HYPERCALL),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_DEBUG),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_HLT),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_MMIO),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_IRQ_WINDOW_OPEN),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_SHUTDOWN),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_FAIL_ENTRY),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_INTR),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_SET_TPR),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_TPR_ACCESS),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_S390_SIEIC),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_S390_RESET),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_DCR),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_NMI),
- DEFINE_KVM_EXIT_REASON(KVM_EXIT_INTERNAL_ERROR),
-};
-
-static void usage(char *argv[])
-{
- fprintf(stderr, " usage: %s <kernel-image>\n", argv[0]);
- exit(1);
-}
-
-static void kvm__reset_vcpu(struct kvm *self, uint64_t rip)
+void kvm__reset_vcpu(struct kvm *self, uint64_t rip)
{
self->regs.rip = rip;
self->regs.rflags = 0x0000000000000002ULL;
die_perror("KVM_SET_REGS failed");
}
+void kvm__run(struct kvm *self)
+{
+ if (ioctl(self->vcpu_fd, KVM_RUN, 0) < 0)
+ die_perror("KVM_RUN failed");
+}
+
static void kvm__emulate_io_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
{
fprintf(stderr, "%s port=%x, size=%d, count=%" PRIu32 "\n", __func__, port, size, count);
fprintf(stderr, "%s port=%x, size=%d, count=%" PRIu32 "\n", __func__, port, size, count);
}
-static void kvm__emulate_io(struct kvm *self, uint16_t port, void *data, int direction, int size, uint32_t count)
+void kvm__emulate_io(struct kvm *self, uint16_t port, void *data, int direction, int size, uint32_t count)
{
if (direction == KVM_EXIT_IO_IN)
kvm__emulate_io_in(self, port, data, size, count);
kvm__emulate_io_out(self, port, data, size, count);
}
-int main(int argc, char *argv[])
+void kvm__show_registers(struct kvm *self)
{
- const char *kernel_filename;
- uint64_t kernel_start;
- struct kvm *kvm;
- int ret;
-
- if (argc < 2)
- usage(argv);
+ unsigned long rax, rbx, rcx;
+ unsigned long rdx, rsi, rdi;
+ unsigned long rbp, r8, r9;
+ unsigned long r10, r11, r12;
+ unsigned long r13, r14, r15;
+ unsigned long rip, rsp;
+ unsigned long rflags;
+ struct kvm_regs regs;
- kernel_filename = argv[1];
+ if (ioctl(self->vcpu_fd, KVM_GET_REGS, ®s) < 0)
+ die("KVM_GET_REGS failed");
- kvm = kvm__init();
+ rflags = regs.rflags;
- kernel_start = kvm__load_kernel(kvm, kernel_filename);
+ rip = regs.rip; rsp = regs.rsp;
+ rax = regs.rax; rbx = regs.rbx; rcx = regs.rcx;
+ rdx = regs.rdx; rsi = regs.rsi; rdi = regs.rdi;
+ rbp = regs.rbp; r8 = regs.r8; r9 = regs.r9;
+ r10 = regs.r10; r11 = regs.r11; r12 = regs.r12;
+ r13 = regs.r13; r14 = regs.r14; r15 = regs.r15;
- kvm__reset_vcpu(kvm, kernel_start);
+ printf("Registers:\n");
+ printf(" rip: %016lx rsp: %016lx flags: %016lx\n", rip, rsp, rflags);
+ printf(" rax: %016lx ebx: %016lx ecx: %016lx\n", rax, rbx, rcx);
+ printf(" rdx: %016lx rsi: %016lx rdi: %016lx\n", rdx, rsi, rdi);
+ printf(" rbp: %016lx r8: %016lx r9: %016lx\n", rbp, r8, r9);
+ printf(" r10: %016lx r11: %016lx r12: %016lx\n", r10, r11, r12);
+ printf(" r13: %016lx r14: %016lx r15: %016lx\n", r13, r14, r15);
+}
- kvm__enable_singlestep(kvm);
+void kvm__show_code(struct kvm *self)
+{
+ unsigned int code_bytes = 64;
+ unsigned int code_prologue = code_bytes * 43 / 64;
+ unsigned int code_len = code_bytes;
+ unsigned char c;
+ unsigned int i;
+ uint8_t *ip;
- for (;;) {
- kvm__run(kvm);
+ ip = guest_addr_to_host(self, self->regs.rip - code_prologue);
- switch (kvm->kvm_run->exit_reason) {
- case KVM_EXIT_IO:
- 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);
- goto exit_kvm;
- break;
- default:
- goto exit_kvm;
- }
- }
+ printf("Code: ");
-exit_kvm:
- fprintf(stderr, "KVM exit reason: %" PRIu32 " (\"%s\")\n",
- kvm->kvm_run->exit_reason, exit_reasons[kvm->kvm_run->exit_reason]);
+ for (i = 0; i < code_len; i++, ip++) {
+ c = *ip;
- kvm__show_registers(kvm);
- kvm__show_code(kvm);
+ if (ip == guest_addr_to_host(self, self->regs.rip))
+ printf("<%02x> ", c);
+ else
+ printf("%02x ", c);
+ }
- return 0;
+ printf("\n");
}