| #include <unistd.h> |
| #include <fcntl.h> |
| #include <stdio.h> |
| #include <sys/mman.h> |
| #include <sys/types.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <signal.h> |
| #include <sys/stat.h> |
| #include <getopt.h> |
| #if defined(__alpha__) || defined (__ia64__) |
| #include <sys/io.h> |
| #elif defined(HAVE_SYS_PERM) |
| #include <sys/perm.h> |
| #endif |
| #include "debug.h" |
| #include "v86bios.h" |
| #include "pci.h" |
| #include "AsmMacros.h" |
| |
| #define SIZE 0x100000 |
| #define VRAM_START 0xA0000 |
| #define VRAM_SIZE 0x1FFFF |
| #define V_BIOS_SIZE 0x1FFFF |
| #define BIOS_START 0x7C00 /* default BIOS entry */ |
| #define BIOS_MEM 0x600 |
| |
| CARD8 code[] = { 0xcd, 0x10, 0xf4 }; |
| struct config Config; |
| |
| static int map(void); |
| static void unmap(void); |
| static void runBIOS(int argc, char **argv); |
| static int map_vram(void); |
| static void unmap_vram(void); |
| static int copy_vbios(memType base); |
| static int copy_sys_bios(void); |
| static CARD32 setup_int_vect(void); |
| static void update_bios_vars(void); |
| static int chksum(CARD8 *start); |
| static void setup_bios_regs(i86biosRegsPtr regs, int argc, char **argv); |
| static void print_regs(i86biosRegsPtr regs); |
| void dprint(unsigned long start, unsigned long size); |
| |
| void loadCodeToMem(unsigned char *ptr, CARD8 *code); |
| |
| static int vram_mapped = 0; |
| static char* bios_var; |
| |
| |
| int |
| main(int argc,char **argv) |
| { |
| CARD32 vbios_base; |
| |
| Config.PrintPort = PRINT_PORT; |
| Config.IoStatistics = IO_STATISTICS; |
| Config.PrintIrq = PRINT_IRQ; |
| Config.PrintPci = PRINT_PCI; |
| Config.ShowAllDev = SHOW_ALL_DEV; |
| Config.PrintIp = PRINT_IP; |
| Config.SaveBios = SAVE_BIOS; |
| Config.Trace = TRACE; |
| Config.ConfigActiveOnly = CONFIG_ACTIVE_ONLY; |
| Config.ConfigActiveDevice = CONFIG_ACTIVE_DEVICE; |
| Config.MapSysBios = MAP_SYS_BIOS; |
| Config.Resort = RESORT; |
| Config.FixRom = FIX_ROM; |
| Config.NoConsole = NO_CONSOLE; |
| Config.Verbose = VERBOSE; |
| |
| if (!map()) |
| exit(1); |
| if (!copy_sys_bios()) |
| exit(1); |
| if (!(vbios_base = setup_int_vect())) |
| exit(1); |
| if (!map_vram()) |
| exit(1); |
| if (!copy_vbios(vbios_base)) |
| exit(1); |
| |
| iopl(3); |
| setup_io(); |
| runBIOS(argc,argv); |
| update_bios_vars(); |
| unmap_vram(); |
| iopl(0); |
| unmap(); |
| printf("done !\n"); |
| exit (1); |
| } |
| |
| int |
| map(void) |
| { |
| void* mem; |
| |
| mem = mmap(0, (size_t)SIZE, |
| PROT_EXEC | PROT_READ | PROT_WRITE, |
| MAP_FIXED | MAP_PRIVATE | MAP_ANON, |
| -1, 0 ); |
| if (mem != 0) { |
| perror("anonymous map"); |
| return (0); |
| } |
| memset(mem,0,SIZE); |
| |
| loadCodeToMem((unsigned char *) BIOS_START, code); |
| return (1); |
| } |
| |
| static int |
| copy_sys_bios(void) |
| { |
| #define SYS_BIOS 0xF0000 |
| int mem_fd; |
| |
| if ((mem_fd = open(MEM_FILE,O_RDONLY))<0) { |
| perror("opening memory"); |
| return (0); |
| } |
| |
| if (lseek(mem_fd,(off_t) SYS_BIOS,SEEK_SET) != (off_t) SYS_BIOS) |
| goto Error; |
| if (read(mem_fd, (char *)SYS_BIOS, (size_t) 0xFFFF) != (size_t) 0xFFFF) |
| goto Error; |
| |
| close(mem_fd); |
| return (1); |
| |
| Error: |
| perror("sys_bios"); |
| close(mem_fd); |
| return (0); |
| } |
| |
| static int |
| map_vram(void) |
| { |
| int mem_fd; |
| |
| #ifdef __ia64__ |
| if ((mem_fd = open(MEM_FILE,O_RDWR | O_SYNC))<0) |
| #else |
| if ((mem_fd = open(MEM_FILE,O_RDWR))<0) |
| #endif |
| { |
| perror("opening memory"); |
| return 0; |
| } |
| |
| #ifndef __alpha__ |
| if (mmap((void *) VRAM_START, (size_t) VRAM_SIZE, |
| PROT_EXEC | PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, |
| mem_fd, VRAM_START) == (void *) -1) |
| #else |
| if (!_bus_base()) sparse_shift = 7; /* Uh, oh, JENSEN... */ |
| if (!_bus_base_sparse()) sparse_shift = 0; |
| if ((vram_map = mmap(0,(size_t) (VRAM_SIZE << sparse_shift), |
| PROT_READ | PROT_WRITE, |
| MAP_SHARED, |
| mem_fd, (VRAM_START << sparse_shift) |
| | _bus_base_sparse())) == (void *) -1) |
| #endif |
| { |
| perror("mmap error in map_hardware_ram"); |
| close(mem_fd); |
| return (0); |
| } |
| vram_mapped = 1; |
| close(mem_fd); |
| return (1); |
| } |
| |
| static int |
| copy_vbios(memType v_base) |
| { |
| int mem_fd; |
| unsigned char *tmp; |
| int size; |
| |
| if ((mem_fd = open(MEM_FILE,O_RDONLY))<0) { |
| perror("opening memory"); |
| return (0); |
| } |
| |
| if (lseek(mem_fd,(off_t) v_base, SEEK_SET) != (off_t) v_base) { |
| fprintf(stderr,"Cannot lseek\n"); |
| goto Error; |
| } |
| tmp = (unsigned char *)malloc(3); |
| if (read(mem_fd, (char *)tmp, (size_t) 3) != (size_t) 3) { |
| fprintf(stderr,"Cannot read\n"); |
| goto Error; |
| } |
| if (lseek(mem_fd,(off_t) v_base,SEEK_SET) != (off_t) v_base) |
| goto Error; |
| |
| if (*tmp != 0x55 || *(tmp+1) != 0xAA ) { |
| fprintf(stderr,"No bios found at: 0x%lx\n",v_base); |
| goto Error; |
| } |
| #ifdef DEBUG |
| dprint((unsigned long)tmp,0x100); |
| #endif |
| size = *(tmp+2) * 512; |
| |
| if (read(mem_fd, (char *)v_base, (size_t) size) != (size_t) size) { |
| fprintf(stderr,"Cannot read\n"); |
| goto Error; |
| } |
| free(tmp); |
| close(mem_fd); |
| if (!chksum((CARD8*)v_base)) |
| return (0); |
| |
| return (1); |
| |
| Error: |
| perror("v_bios"); |
| close(mem_fd); |
| return (0); |
| } |
| |
| static void |
| unmap(void) |
| { |
| munmap(0,SIZE); |
| } |
| |
| static void |
| unmap_vram(void) |
| { |
| if (!vram_mapped) return; |
| |
| munmap((void*)VRAM_START,VRAM_SIZE); |
| vram_mapped = 0; |
| } |
| |
| static void |
| runBIOS(int argc, char ** argv) |
| { |
| i86biosRegs bRegs; |
| #ifdef V86BIOS_DEBUG |
| printf("starting BIOS\n"); |
| #endif |
| setup_bios_regs(&bRegs, argc, argv); |
| do_x86(BIOS_START,&bRegs); |
| print_regs(&bRegs); |
| #ifdef V86BIOS_DEBUG |
| printf("done\n"); |
| #endif |
| } |
| |
| static CARD32 |
| setup_int_vect(void) |
| { |
| int mem_fd; |
| CARD32 vbase; |
| void *map; |
| |
| if ((mem_fd = open(MEM_FILE,O_RDONLY))<0) { |
| perror("opening memory"); |
| return (0); |
| } |
| |
| if ((map = mmap((void *) 0, (size_t) 0x2000, |
| PROT_EXEC | PROT_READ | PROT_WRITE, MAP_SHARED, |
| mem_fd, 0)) == (void *)-1) { |
| perror("mmap error in map_hardware_ram"); |
| close(mem_fd); |
| return (0); |
| } |
| |
| close(mem_fd); |
| memcpy(0,map,BIOS_MEM); |
| munmap(map,0x2000); |
| /* |
| * create a backup copy of the bios variables to write back the |
| * modified values |
| */ |
| bios_var = (char *)malloc(BIOS_MEM); |
| memcpy(bios_var,0,BIOS_MEM); |
| |
| vbase = (*((CARD16*)(0x10 << 2) + 1)) << 4; |
| fprintf(stderr,"vbase: 0x%x\n",vbase); |
| return vbase; |
| } |
| |
| static void |
| update_bios_vars(void) |
| { |
| int mem_fd; |
| void *map; |
| memType i; |
| |
| #ifdef __ia64__ |
| if ((mem_fd = open(MEM_FILE,O_RDWR | O_SYNC))<0) |
| #else |
| if ((mem_fd = open(MEM_FILE,O_RDWR))<0) |
| #endif |
| { |
| perror("opening memory"); |
| return; |
| } |
| |
| if ((map = mmap((void *) 0, (size_t) 0x2000, |
| PROT_EXEC | PROT_READ | PROT_WRITE, MAP_SHARED, |
| mem_fd, 0)) == (void *)-1) { |
| perror("mmap error in map_hardware_ram"); |
| close(mem_fd); |
| return; |
| } |
| |
| for (i = 0; i < BIOS_MEM; i++) { |
| if (bios_var[i] != *(CARD8*)i) |
| *((CARD8*)map + i) = *(CARD8*)i; |
| } |
| |
| munmap(map,0x2000); |
| close(mem_fd); |
| } |
| |
| |
| static void |
| setup_bios_regs(i86biosRegsPtr regs, int argc, char **argv) |
| { |
| int c; |
| |
| regs->ax = 0; |
| regs->bx = 0; |
| regs->cx = 0; |
| regs->dx = 0; |
| regs->es = 0; |
| regs->di = 0; |
| opterr = 0; |
| while ((c = getopt(argc,argv,"a:b:c:d:e:i:")) != EOF) { |
| switch (c) { |
| case 'a': |
| regs->ax = strtol(optarg,NULL,0); |
| break; |
| case 'b': |
| regs->bx = strtol(optarg,NULL,0); |
| break; |
| case 'c': |
| regs->cx = strtol(optarg,NULL,0); |
| break; |
| case 'd': |
| regs->dx = strtol(optarg,NULL,0); |
| break; |
| case 'e': |
| regs->es = strtol(optarg,NULL,0); |
| break; |
| case 'i': |
| regs->di = strtol(optarg,NULL,0); |
| break; |
| } |
| } |
| } |
| |
| |
| static int |
| chksum(CARD8 *start) |
| { |
| CARD16 size; |
| CARD8 val = 0; |
| int i; |
| |
| size = *(start+2) * 512; |
| for (i = 0; i<size; i++) |
| val += *(start + i); |
| |
| if (!val) |
| return 1; |
| |
| fprintf(stderr,"BIOS cksum wrong!\n"); |
| return 0; |
| } |
| |
| static void |
| print_regs(i86biosRegsPtr regs) |
| { |
| printf("ax=%x bx=%x cx=%x dx=%x es=%x di=%x\n",(CARD16)regs->ax, |
| (CARD16)regs->bx,(CARD16)regs->cx,(CARD16)regs->dx, |
| (CARD16)regs->es,(CARD16)regs->di); |
| } |
| |
| void |
| loadCodeToMem(unsigned char *ptr, CARD8 code[]) |
| { |
| int i; |
| CARD8 val; |
| |
| for ( i=0;;i++) { |
| val = code[i]; |
| *ptr++ = val; |
| if (val == 0xf4) break; |
| } |
| return; |
| } |
| |
| void |
| dprint(unsigned long start, unsigned long size) |
| { |
| int i,j; |
| char *c = (char *)start; |
| |
| for (j = 0; j < (size >> 4); j++) { |
| printf ("\n0x%lx: ",(unsigned long)c); |
| for (i = 0; i<16; i++) |
| printf("%x ",(unsigned char) (*(c++))); |
| } |
| printf("\n"); |
| } |