| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| #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> |
| #include <stdarg.h> |
| #include <stdtypes.h> |
| #define die(x) { perror(x); exit(1); } |
| #define warn(x) { perror(x); } |
| |
| #include <x86emu/x86emu.h> |
| #include <console/console.h> |
| #include <arch/byteorder.h> |
| #include "device.h" |
| |
| #include "testbios.h" |
| #include "pci-userspace.h" |
| int X86EMU_set_debug(int debug); |
| |
| biosemu_device_t bios_device; |
| |
| extern int teststart, testend; |
| |
| #define BIOSMEM_SIZE (1024 * 1024) |
| unsigned char biosmem[BIOSMEM_SIZE]; |
| |
| int verbose = 0; |
| |
| static 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; |
| } |
| |
| static 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; |
| } |
| |
| int printk(int msg_level, const char *fmt, ...) |
| { |
| va_list args; |
| int i; |
| |
| putchar('<'); |
| putchar('0' + msg_level); |
| putchar('>'); |
| putchar(' '); |
| va_start(args, fmt); |
| i = vprintf(fmt, args); |
| va_end(args); |
| |
| return i; |
| } |
| |
| static void usage(char *name) |
| { |
| printf |
| ("Usage: %s [-c codesegment] [-s size] [-b base] [-i ip] [-t] " |
| "<filename> ...\n", name); |
| } |
| |
| /* main entry into YABEL biosemu, arguments are: |
| * *biosmem = pointer to virtual memory |
| * biosmem_size = size of the virtual memory |
| * *dev = pointer to the device to be initialised |
| * rom_addr = address of the OptionROM to be executed, if this is = 0, YABEL |
| * will look for an ExpansionROM BAR and use the code from there. |
| */ |
| u32 |
| biosemu(u8 *biosmem, u32 biosmem_size, struct device * dev, unsigned long |
| rom_addr); |
| |
| |
| int main(int argc, char **argv) |
| { |
| int ret; |
| char *absegname = NULL; |
| void *abseg = NULL; |
| int c, trace = 0; |
| unsigned char *cp; |
| char *filename; |
| ssize_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]; |
| int debugflag = 0; |
| struct device *dev; |
| |
| //const char *optstring = "vh?b:i:c:s:tpd:"; |
| 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': |
| 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; |
| } |
| |
| if (parse_rom) |
| printf("Parsing rom images not implemented.\n"); |
| |
| //printf("Point 1 int%x vector at %x\n", 0x42, getIntVect(0x42)); |
| #if 0 |
| 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"); |
| } |
| } |
| } |
| #endif |
| |
| if (absegname) { |
| abseg = mapitin(absegname, (off_t) 0xa0000, 0x20000); |
| if (!abseg) |
| die(absegname); |
| } |
| |
| 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. |
| */ |
| pci_initialize(); |
| |
| #if 0 |
| for (i = 0; i < 256; i++) |
| intFuncs[i] = do_int; |
| X86EMU_setupIntrFuncs(intFuncs); |
| #endif |
| cp = mapitin(filename, (off_t) 0, size); |
| |
| if (devfn) { |
| printf("Loading ax with BusDevFn = %x\n",devfn); |
| } |
| |
| #if 0 |
| 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 { |
| const 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; |
| #endif |
| |
| if (trace) { |
| printf("Switching to single step mode.\n"); |
| //X86EMU_trace_on(); |
| } |
| if (debugflag) { |
| printf("Enable Debug = %x.\n",debugflag); |
| //X86EMU_set_debug(debugflag); |
| } |
| #if 0 |
| X86EMU_exec(); |
| #endif |
| |
| ret = biosemu(biosmem, BIOSMEM_SIZE, dev, base); |
| |
| #if 0 |
| current = &p; |
| X86EMU_setMemBase(biosmem, sizeof(biosmem)); |
| M.abseg = (unsigned long)abseg; |
| X86EMU_setupPioFuncs(&myfuncs); |
| #endif |
| |
| /* Cleaning up */ |
| pci_exit(); |
| |
| return 0; |
| } |