#define _GNU_SOURCE
+#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <linux/kvm.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
+#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define MAXDUMPS 10
+#define RAMSIZE (64 * 1024 * 1024)
+#define PROGSTART 0x20000000
static void nukenewline(char buf[]) {
unsigned i;
};
const char opts[] = "i:g:f:s:l:d:t:h";
- int kvm;
+ struct kvm_run *run;
+ struct kvm_regs regs;
+ struct kvm_sregs sregs;
+ int kvm, vmfd, vcpu;
FILE *binary = NULL, *trace = NULL;
char dumps[MAXDUMPS][PATH_MAX];
unsigned num_dumps = 0;
+ uint8_t *ram, *progmem;
+ const char *binpath;
while (1) {
const int c = getopt_long(argc, argv, opts, longopts, NULL);
printf("Failed to open %s\n", optarg);
return 1;
}
+
+ binpath = strdup(optarg);
break;
case 'g':
parseregs(optarg, 1);
help(argv[0]);
}
+ // Yes, we're frugal
+ if (posix_memalign(&ram, 64 * 1024, RAMSIZE))
+ abort();
+ memset(ram, 0, RAMSIZE);
+
fseek(binary, 0, SEEK_END);
const unsigned binlen = ftell(binary);
rewind(binary);
printf("Loading binary %u bytes\n", binlen); // TODO
+ if (posix_memalign(&progmem, 64 * 1024, binlen))
+ abort();
+
+ if (fread(progmem, binlen, 1, binary) != 1)
+ abort();
+ fclose(binary);
+
kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
if (kvm < 0) {
printf("Failed to open kvm, perhaps you lack permissions?\n");
ret = ioctl(kvm, KVM_GET_API_VERSION, NULL);
if (ret == -1 || ret != 12) abort();
+ ret = ioctl(kvm, KVM_CHECK_EXTENSION, KVM_CAP_PPC_GUEST_DEBUG_SSTEP);
+ if (ret == -1 || !ret) {
+ printf("This system lacks single-stepping!\n");
+ return 1;
+ }
+
+ vmfd = ioctl(kvm, KVM_CREATE_VM, (unsigned long)0);
+
+ struct kvm_userspace_memory_region region = {
+ .slot = 0,
+ .guest_phys_addr = 0,
+ .memory_size = RAMSIZE,
+ .userspace_addr = ram,
+ .flags = 0
+ };
+ ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, ®ion);
+
+ region.slot = 1;
+ region.guest_phys_addr = PROGSTART;
+ region.memory_size = binlen;
+ region.userspace_addr = progmem;
+ region.flags = KVM_MEM_READONLY;
+ ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, ®ion);
+
+ vcpu = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long)0);
+ const unsigned vcpulen = ioctl(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL);
+
+ run = mmap(NULL, vcpulen, PROT_READ | PROT_WRITE, MAP_SHARED, vcpu, 0);
+
+ if (ioctl(vcpu, KVM_GET_SREGS, &sregs) == -1)
+ abort();
+ if (ioctl(vcpu, KVM_SET_SREGS, &sregs) == -1)
+ abort();
+
+ if (ioctl(vcpu, KVM_SET_REGS, ®s) == -1)
+ abort();
+
+ const struct kvm_guest_debug dbg = {
+ .control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
+ };
+ if (ioctl(vcpu, KVM_SET_GUEST_DEBUG, &dbg) == -1)
+ abort();
+
+ // Runtime
+ while (1) {
+ if (ioctl(vcpu, KVM_RUN, NULL) == -1)
+ abort();
+ printf("Exited because %u\n", run->exit_reason);
+ }
+
close(kvm);
+ free(progmem);
+ free(ram);
+ free((char *) binpath);
return 0;
}