#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/io.h> #include <sys/mman.h> #include <fcntl.h> #include <getopt.h> #include <string.h> #define die(x) { perror(x); exit(1); } #define warn(x) { perror(x); } #include <x86emu/x86emu.h> #include "helper_exec.h" #include "test.h" #include "pci-userspace.h" void x86emu_dump_xregs(void); int int15_handler(void); int int16_handler(void); int int1A_handler(void); #ifndef _PC int int42_handler(void); #endif int intE6_handler(void); void pushw(u16 val); unsigned short get_device(char *arg_val); extern int teststart, testend; _ptr p; ptr current = 0; unsigned char biosmem[1024 * 1024]; int verbose = 0; /* Interrupt multiplexer */ void do_int(int num) { int ret = 0; printf("int%x vector at %x\n", num, getIntVect(num)); /* This is a pInt leftover */ current->num = num; switch (num) { #ifndef _PC case 0x10: case 0x42: case 0x6D: if (getIntVect(num) == 0xFF065) { ret = int42_handler(); } break; #endif case 0x15: ret = int15_handler(); break; case 0x16: ret = int16_handler(); break; case 0x1A: ret = int1A_handler(); break; case 0xe6: ret = intE6_handler(); break; default: break; } if (!ret) ret = run_bios_int(num); if (!ret) { printf("\nint%x: not implemented\n", num); //x86emu_dump_xregs(); } } unsigned char *mapitin(char *file, off_t where, size_t size) { void *z; int fd = open(file, O_RDWR, 0); if (fd < 0) die(file); z = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, where); if (z == (void *) -1) die("mmap"); close(fd); return z; } u8 x_inb(u16 port); u16 x_inw(u16 port); void x_outb(u16 port, u8 val); void x_outw(u16 port, u16 val); u32 x_inl(u16 port); void x_outl(u16 port, u32 val); X86EMU_pioFuncs myfuncs = { x_inb, x_inw, x_inl, x_outb, x_outw, x_outl }; void usage(char *name) { printf ("Usage: %s [-c codesegment] [-s size] [-b base] [-i ip] [-t] <filename> ... \n", name); } int main(int argc, char **argv) { char *absegname = 0; void *abseg = 0; int i, c, trace = 0; unsigned char *cp; char *filename; size_t size = 0; int base = 0; int have_size = 0, have_base = 0, have_ip = 0, have_cs = 0; int have_devfn = 0; int parse_rom = 0; char *fsegname = 0; unsigned char *fsegptr; unsigned short initialip = 0, initialcs = 0, devfn = 0; X86EMU_intrFuncs intFuncs[256]; void X86EMU_setMemBase(void *base, size_t size); void x86emu_dump_xregs(void); int X86EMU_set_debug(int debug); int debugflag = 0; const char *optstring = "vh?b:i:c:s:tpd:"; while (1) { int option_index = 0; static struct option long_options[] = { {"verbose", 0, 0, 'v'}, {"help", 0, 0, 'h'}, {"trace", 0, 0, 't'}, {"base", 1, 0, 'b'}, {"fseg", 1, 0, 'f'}, {"instructionpointer", 1, 0, 'i'}, {"codesegment", 1, 0, 'c'}, {"absegment", 1, 0, 'a'}, {"size", 1, 0, 's'}, {"parserom", 0, 0, 'p'}, {"device", 1, 0, 'd'}, {"debug", 1, 0, 'D'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, optstring, long_options, &option_index); if (c == -1) break; switch (c) { case 'v': verbose = 1; break; case 'h': case '?': usage(argv[0]); return 0; case 't': trace = 1; break; case 'b': base = strtol(optarg, 0, 0); have_base = 1; break; case 'i': initialip = strtol(optarg, 0, 0); have_ip = 1; break; case 'c': initialcs = strtol(optarg, 0, 0); have_cs = 1; break; case 's': size = strtol(optarg, 0, 0); have_size = 1; break; case 'p': printf("Parsing rom images not implemented.\n"); parse_rom = 1; break; case 'f': fsegname = optarg; break; case 'a': absegname = optarg; break; case 'd': devfn = get_device(optarg); have_devfn = 1; break; case 'D': debugflag = strtol(optarg, 0, 0); break; default: printf("Unknown option \n"); usage(argv[0]); return 1; } } if (optind >= argc) { printf("Filename missing.\n"); usage(argv[0]); return 1; } while (optind < argc) { printf("running file %s\n", argv[optind]); filename = argv[optind]; optind++; /* normally we would do continue, but for * now only one filename is supported. */ /* continue; */ break; } if (!have_size) { printf("No size specified. defaulting to 32k\n"); size = 32 * 1024; } if (!have_base) { printf("No base specified. defaulting to 0xc0000\n"); base = 0xc0000; } if (!have_cs) { printf("No initial code segment specified. defaulting to 0xc000\n"); initialcs = 0xc000; } if (!have_ip) { printf ("No initial instruction pointer specified. defaulting to 0x0003\n"); initialip = 0x0003; } //printf("Point 1 int%x vector at %x\n", 0x42, getIntVect(0x42)); if (initialip == 0x0003) { if ((devfn == 0) || (have_devfn == 0)) { printf("WARNING! It appears you are trying to run an option ROM.\n"); printf(" (initial ip = 0x0003)\n"); if (have_devfn) { printf(" However, the device you have specified is 0x00\n"); printf(" It is very unlikely that your device is at this address\n"); printf(" Please check your -d option\n"); } else { printf(" Please specify a device with -d\n"); printf(" The default is not likely to work\n"); } } } if (absegname) { abseg = mapitin(absegname, (off_t) 0xa0000, 0x20000); if (!abseg) die(absegname); } current = &p; X86EMU_setMemBase(biosmem, sizeof(biosmem)); M.abseg = (unsigned long)abseg; X86EMU_setupPioFuncs(&myfuncs); ioperm(0, 0x400, 1); if (iopl(3) < 0) { warn("iopl failed, continuing anyway"); } /* Emergency sync ;-) */ sync(); sync(); /* Setting up interrupt environment. * basically this means initializing PCI and * intXX handlers. */ pciInit(); for (i = 0; i < 256; i++) intFuncs[i] = do_int; X86EMU_setupIntrFuncs(intFuncs); cp = mapitin(filename, (off_t) 0, size); if (devfn) { printf("Loading ax with BusDevFn = %x\n",devfn); } current->ax = devfn ? devfn : 0xff; current->dx = 0x80; // current->ip = 0; for (i = 0; i < size; i++) wrb(base + i, cp[i]); if (fsegname) { fsegptr = mapitin(fsegname, (off_t) 0, 0x10000); for (i = 0; i < 0x10000; i++) wrb(0xf0000 + i, fsegptr[i]); } else { char *date = "01/01/99"; for (i = i; date[i]; i++) wrb(0xffff5 + i, date[i]); wrb(0xffff7, '/'); wrb(0xffffa, '/'); } /* cpu setup */ X86_AX = devfn ? devfn : 0xff; X86_DX = 0x80; X86_EIP = initialip; X86_CS = initialcs; /* Initialize stack and data segment */ X86_SS = 0x0030; X86_DS = 0x0040; X86_SP = 0xfffe; /* We need a sane way to return from bios * execution. A hlt instruction and a pointer * to it, both kept on the stack, will do. */ pushw(0xf4f4); /* hlt; hlt */ pushw(X86_SS); pushw(X86_SP + 2); X86_ES = 0x0000; if (trace) { printf("Switching to single step mode.\n"); //X86EMU_trace_on(); } if (debugflag) { //X86EMU_set_debug(debugflag); } X86EMU_exec(); /* Cleaning up */ pciExit(); return 0; } unsigned short get_device(char *arg_val) { unsigned short devfn=0; long bus=0,dev=0,fn=0,need_pack=0; char *tok; tok = strsep(&arg_val,":"); if (arg_val != NULL) { bus = strtol(tok,0,16); need_pack = 1; } else { arg_val = tok; } tok = strsep(&arg_val,"."); if (arg_val != NULL) { dev = strtol(tok,0,16); fn = strtol(arg_val,0,16); need_pack = 1; } else { if (need_pack ==1 && (strlen(tok))) { dev = strtol(tok,0,16); } } if ( need_pack == 1) { devfn = bus<<8 | (dev<<3) | fn; } else { devfn = strtol(tok, 0, 0); } return devfn; }