Ignore -p
[kvm-minippc.git] / main.c
diff --git a/main.c b/main.c
index 5012602b756c5ffd7bca90933be29543386ae2d4..86181fb7a7d738fe240977ffd0b5f7ce0da316d0 100644 (file)
--- a/main.c
+++ b/main.c
@@ -16,6 +16,7 @@
 
 #define _GNU_SOURCE
 
+#include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <getopt.h>
@@ -37,6 +38,7 @@
 #define PROGSTART 0x20000000
 
 #define MSR_64 (1UL<<63)
+#define MSR_FP (1UL<<13)
 #define MSR_LE (1UL<<0)
 
 enum {
@@ -197,6 +199,43 @@ static void load(const char arg[], uint8_t *ram) {
        fclose(f);
 }
 
+static void dump(const char src[], const uint8_t ram[]) {
+       const char *ptr = strchr(src, ':');
+       if (!ptr) {
+               printf("Invalid dump\n");
+               exit(1);
+       }
+
+       char name[PATH_MAX];
+       memcpy(name, src, ptr - src);
+       name[ptr - src] = '\0';
+
+       ptr++;
+       const uint32_t addr = strtol(ptr, NULL, 0);
+
+       ptr = strchr(ptr, ':');
+       if (!ptr) {
+               printf("Invalid dump\n");
+               exit(1);
+       }
+
+       ptr++;
+       const uint32_t len = strtol(ptr, NULL, 0);
+
+       //printf("Saving to %s, from %x, len %u\n", name, addr, len);
+
+       FILE *f = fopen(name, "w");
+       if (!f) {
+               printf("Can't open %s\n", name);
+               exit(1);
+       }
+
+       if (fwrite(&ram[addr], len, 1, f) != 1)
+               abort();
+
+       fclose(f);
+}
+
 static void setfpregs(const int vcpu, struct kvm_fpu *fpregs) {
        // KVM_[SG]ET_FPU isn't supported on PPC, we have to move individual regs...
        unsigned i;
@@ -225,6 +264,43 @@ static void getfpregs(const int vcpu, struct kvm_fpu *fpregs) {
        }
 }
 
+static void disassemble(const char binpath[], char *disasm, const unsigned len) {
+
+       char buf[PATH_MAX];
+       snprintf(buf, PATH_MAX,
+               "objdump -b binary -m powerpc --no-show-raw-insn -D %s",
+               binpath);
+       buf[PATH_MAX - 1] = '\0';
+
+       FILE *f = popen(buf, "r");
+       if (!f) {
+               printf("Disassembly failed, trace won't have disas\n");
+               return;
+       }
+
+       while (fgets(buf, PATH_MAX, f)) {
+               if (buf[0] != ' ')
+                       continue;
+               const char *ptr = strchr(buf, ':');
+               if (!ptr)
+                       continue;
+               nukenewline(buf);
+
+               const unsigned addr = strtol(buf, NULL, 16) / 4 * 32;
+               if (addr / 32 + 1 >= len)
+                       abort();
+
+               ptr++;
+               while (isspace(*ptr))
+                       ptr++;
+
+               strncpy(&disasm[addr], ptr, 32);
+               disasm[addr + 31] = '\0';
+       }
+
+       pclose(f);
+}
+
 int main(int argc, char **argv) {
 
        const struct option longopts[] = {
@@ -238,7 +314,7 @@ int main(int argc, char **argv) {
                { "help", 0, NULL, 'h' },
                { NULL, 0, NULL, 0 }
        };
-       const char opts[] = "i:g:f:s:l:d:t:h";
+       const char opts[] = "i:g:f:s:l:d:t:hp:";
 
        struct kvm_run *run;
        struct kvm_regs regs;
@@ -249,7 +325,8 @@ int main(int argc, char **argv) {
        char dumps[MAXDUMPS][PATH_MAX];
        unsigned num_dumps = 0;
        uint8_t *ram, *progmem;
-       const char *binpath;
+       const char *binpath = NULL;
+       const char *disasm = NULL;
 
        // Yes, we're frugal
        if (posix_memalign((void **) &ram, 64 * 1024, RAMSIZE))
@@ -261,7 +338,8 @@ int main(int argc, char **argv) {
 
        regs.lr = -1;
        regs.pc = PROGSTART;
-       regs.msr = MSR_64 | MSR_LE;
+       regs.msr = MSR_64 | MSR_FP | MSR_LE;
+       regs.gpr[1] = 0x8000; // Default stack pointer at 32kb, 20kb free space before vecs
 
        while (1) {
                const int c = getopt_long(argc, argv, opts, longopts, NULL);
@@ -317,6 +395,8 @@ int main(int argc, char **argv) {
                                        return 1;
                                }
                        break;
+                       case 'p': // ignored
+                       break;
                        case 'h':
                        default:
                                help(argv[0]);
@@ -343,6 +423,14 @@ int main(int argc, char **argv) {
                abort();
        fclose(binary);
 
+
+       if (trace) {
+               const unsigned disaslen = binlen / 4 + 64;
+               disasm = calloc(disaslen, 32);
+
+               disassemble(binpath, (char *) disasm, disaslen);
+       }
+
        kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
        if (kvm < 0) {
                printf("Failed to open kvm, perhaps you lack permissions?\n");
@@ -401,15 +489,59 @@ int main(int argc, char **argv) {
                abort();
 
        // Runtime
+       uint64_t pc = PROGSTART;
+       unsigned i;
        while (1) {
                if (ioctl(vcpu, KVM_RUN, NULL) == -1)
                        abort();
-               printf("Exited because %u\n", run->exit_reason);
+
+               if (ioctl(vcpu, KVM_GET_REGS, &regs) == -1)
+                       abort();
+               //printf("PC %lx LR %lx\n", regs.pc, regs.lr);
+
+               if (run->exit_reason == KVM_EXIT_DEBUG) {
+                       if (trace) {
+                               getfpregs(vcpu, &fpregs);
+
+                               fprintf(trace, "%lx: %s\n", pc, &disasm[(pc - PROGSTART) / 4 * 32]);
+                               for (i = 0; i < 32; i++) {
+                                       if (i % 8 == 0)
+                                               fprintf(trace, "GPR: ");
+                                       fprintf(trace, "%08lx", regs.gpr[i]);
+                                       if (i % 8 == 7)
+                                               fprintf(trace, "\n");
+                                       else
+                                               fprintf(trace, " ");
+                               }
+                               for (i = 0; i < 32; i++) {
+                                       if (i % 8 == 0)
+                                               fprintf(trace, "FPR: ");
+                                       fprintf(trace, "%08lx", fpregs.fpr[i]);
+                                       if (i % 8 == 7)
+                                               fprintf(trace, "\n");
+                                       else
+                                               fprintf(trace, " ");
+                               }
+                       }
+               } else if (regs.pc < PROGSTART || regs.pc > PROGSTART + binlen) {
+                       // Normal exit by blr
+                       break;
+               } else {
+                       printf("Unexpected exit because %u\n", run->exit_reason);
+                       break;
+               }
+
+               pc = regs.pc;
+       }
+
+       for (i = 0; i < num_dumps; i++) {
+               dump(dumps[i], ram);
        }
 
        close(kvm);
        free(progmem);
        free(ram);
        free((char *) binpath);
+       free((char *) disasm);
        return 0;
 }