#define _GNU_SOURCE
+#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#define PROGSTART 0x20000000
#define MSR_64 (1UL<<63)
+#define MSR_FP (1UL<<13)
#define MSR_LE (1UL<<0)
enum {
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;
}
}
+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[] = {
{ "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;
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))
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);
return 1;
}
break;
+ case 'p': // ignored
+ break;
case 'h':
default:
help(argv[0]);
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");
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, ®s) == -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;
}