Start on kvm side
authorLauri Kasanen <cand@gmx.com>
Thu, 27 May 2021 12:05:38 +0000 (15:05 +0300)
committerLauri Kasanen <cand@gmx.com>
Thu, 27 May 2021 12:05:38 +0000 (15:05 +0300)
main.c

diff --git a/main.c b/main.c
index daa48ee640cb37bc7d538adeb0023b1de166ecc5..8550e4e133f1ababc46f46c1fee696aac5f657c4 100644 (file)
--- a/main.c
+++ b/main.c
@@ -16,6 +16,7 @@
 
 #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;
@@ -184,10 +188,15 @@ int main(int argc, char **argv) {
        };
        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);
@@ -206,6 +215,8 @@ int main(int argc, char **argv) {
                                        printf("Failed to open %s\n", optarg);
                                        return 1;
                                }
+
+                               binpath = strdup(optarg);
                        break;
                        case 'g':
                                parseregs(optarg, 1);
@@ -252,12 +263,24 @@ int main(int argc, char **argv) {
                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");
@@ -268,6 +291,59 @@ int main(int argc, char **argv) {
        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, &region);
+
+       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, &region);
+
+       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, &regs) == -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;
 }