]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blobdiff - src/hwinfo/src/int10/i10_vbios.c
Zwischencommit Installer...
[people/teissler/ipfire-2.x.git] / src / hwinfo / src / int10 / i10_vbios.c
diff --git a/src/hwinfo/src/int10/i10_vbios.c b/src/hwinfo/src/int10/i10_vbios.c
new file mode 100644 (file)
index 0000000..c952199
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * Copyright 1999 Egbert Eich
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the authors not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  The authors makes no representations
+ * about the suitability of this software for any purpose.  It is provided
+ * "as is" without express or implied warranty.
+ *
+ * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <setjmp.h>
+#if defined(__alpha__) || defined (__ia64__)
+#include <sys/io.h>
+//#elif defined(HAVE_SYS_PERM)
+#else
+#include <sys/perm.h>
+#endif
+#include "v86bios.h"
+#include "pci.h"
+#include "AsmMacros.h"
+#include "vbios.h"
+
+void log_err(char *format, ...) __attribute__ ((format (printf, 1, 2)));
+
+#define SIZE 0x100000
+#define VRAM_START 0xA0000
+#define VRAM_SIZE 0x1FFFF
+#define V_BIOS_SIZE 0x1FFFF
+#define BIOS_START 0x7C00            /* default BIOS entry */
+
+static CARD8 code[] = { 0xcd, 0x10, 0xf4 };    /* int 0x10, hlt */
+// static CARD8 code13[] = { 0xcd, 0x13, 0xf4 };       /* int 0x13, hlt */
+
+static int int10_bios_ok(void);
+static int map(void);
+static void unmap(void);
+static int map_vram(void);
+static void unmap_vram(void);
+static int copy_vbios(hd_data_t *hd_data);
+// static int copy_sbios(void);
+#if MAP_SYS_BIOS
+static int copy_sys_bios(hd_data_t *hd_data);
+#endif
+static int copy_bios_ram(hd_data_t *hd_data);
+static int setup_system_bios(hd_data_t *hd_data);
+static void setup_int_vect(void);
+static int chksum(CARD8 *start);
+
+void loadCodeToMem(unsigned char *ptr, CARD8 *code);
+
+static int vram_mapped = 0;
+static int int10inited = 0;
+
+static sigjmp_buf longjmp_buf;
+
+static void sigsegv_handler(int);
+
+int InitInt10(hd_data_t *hd_data, int pci_cfg_method)
+{
+  if(geteuid()) return -1;
+
+  if(!map()) return -1;
+
+  if(!setup_system_bios(hd_data)) {
+    unmap();
+    return -1;
+  }
+
+  setup_io();
+
+  if(iopl(3) < 0) {
+    unmap();
+    return -1;
+  }
+
+  scan_pci(pci_cfg_method);
+
+  for(; CurrentPci; CurrentPci = CurrentPci->next) {
+    if(CurrentPci->active) break;
+  }
+
+  iopl(0);
+
+  setup_int_vect();
+
+  if(!copy_vbios(hd_data)) {
+    unmap();
+    return -1;
+  }
+
+  if(!map_vram() || !copy_bios_ram(hd_data)) {
+    unmap();
+    return -1;
+  }
+
+  if(!int10_bios_ok()) {
+    unmap();
+    return -1;
+  }
+
+  int10inited = 1;
+
+  return 0;
+}
+
+
+void FreeInt10()
+{
+  if(!int10inited) return;
+
+  unmap_vram();
+  unmap();
+
+  int10inited = 0;
+}
+
+
+/*
+ * Check whether int 0x10 points to some useful code.
+ */
+int int10_bios_ok()
+{
+  unsigned cs, ip;
+  unsigned char *p;
+
+  ip = ((uint16_t *) 0)[0x10 * 2];
+  cs = ((uint16_t *) 0)[0x10 * 2 + 1];
+
+  p = (unsigned char *) ((cs << 4) + ip);
+
+  log_err(
+    "  vbe: int 10h points to %04x:%04x: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+    cs, ip,
+    p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]
+  );
+
+  /* It can't possibly start with all zeros. */
+  if(!*(uint32_t *) p) {
+    log_err("  vbe: oops, int 10h points into nirvana!\n");
+
+    return 0;
+  }
+
+  return 1;
+}
+
+
+void sigsegv_handler(int num)
+{
+  siglongjmp(longjmp_buf, num + 1000);
+}
+
+
+int CallInt10(int *ax, int *bx, int *cx, unsigned char *buf, int len, int cpuemu)
+{
+  i86biosRegs bRegs;
+  void (*old_sigsegv_handler)(int) = SIG_DFL;
+  void (*old_sigill_handler)(int) = SIG_DFL;
+  void (*old_sigtrap_handler)(int) = SIG_DFL;
+  int jmp;
+
+  if(!int10inited) return -1;
+  memset(&bRegs, 0, sizeof bRegs);
+  bRegs.ax = *ax;
+  bRegs.bx = *bx;
+  bRegs.cx = *cx;
+  bRegs.dx = 0;
+  bRegs.es = 0x7e0;
+  bRegs.di = 0x0;
+  if(buf) memcpy((unsigned char *) 0x7e00, buf, len);
+
+  iopl(3);
+
+  jmp = sigsetjmp(longjmp_buf, 1);
+
+  if(!jmp) {
+    old_sigsegv_handler = signal(SIGSEGV, sigsegv_handler);
+    old_sigill_handler = signal(SIGILL, sigsegv_handler);
+    old_sigtrap_handler = signal(SIGTRAP, sigsegv_handler);
+
+    loadCodeToMem((unsigned char *) BIOS_START, code);
+    do_x86(BIOS_START, &bRegs, cpuemu);
+  }
+  else {
+    int10inited = 0;
+    log_err("oops: got signal %d in vm86() code\n", jmp - 1000);
+  }
+
+  signal(SIGTRAP, old_sigtrap_handler);
+  signal(SIGILL, old_sigill_handler);
+  signal(SIGSEGV, old_sigsegv_handler);
+
+  iopl(0);
+
+  if(buf) memcpy(buf, (unsigned char *) 0x7e00, len);
+
+  *ax = bRegs.ax;
+  *bx = bRegs.bx;
+  *cx = bRegs.cx;
+
+  return bRegs.ax;
+}
+
+
+#if 0
+int CallInt13(int *ax, int *bx, int *cx, int *dx, unsigned char *buf, int len, int cpuemu)
+{
+  i86biosRegs bRegs;
+
+  if(!int10inited) return -1;
+  memset(&bRegs, 0, sizeof bRegs);
+  bRegs.ax = *ax;
+  bRegs.bx = *bx;
+  bRegs.cx = *cx;
+  bRegs.dx = *dx;
+  bRegs.es = 0x7e0;
+  bRegs.ds = 0x7e0;
+  bRegs.di = 0x0;
+  bRegs.si = 0x0;
+  if(buf) memcpy((unsigned char *) 0x7e00, buf, len);
+
+  iopl(3);
+
+  loadCodeToMem((unsigned char *) BIOS_START, code13);
+  do_x86(BIOS_START, &bRegs, cpuemu);
+
+  iopl(0);
+
+  if(buf) memcpy(buf, (unsigned char *) 0x7e00, len);
+
+  *ax = bRegs.ax;
+  *bx = bRegs.bx;
+  *cx = bRegs.cx;
+  *dx = bRegs.dx;
+
+  return bRegs.ax;
+}
+#endif
+
+
+int map()
+{
+  void* mem;
+
+  mem = mmap(0, (size_t) SIZE, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
+
+  if(mem) {
+    perror("anonymous map");
+    return 0;
+  }
+
+  memset(mem, 0, SIZE);
+
+  loadCodeToMem((unsigned char *) BIOS_START, code);
+
+  return 1;
+}
+
+
+void unmap()
+{
+  munmap(0, SIZE);
+}
+
+
+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);
+}
+
+
+void unmap_vram()
+{
+  if(!vram_mapped) return;
+
+  munmap((void*) VRAM_START, VRAM_SIZE);
+
+  vram_mapped = 0;
+}
+
+
+/*
+ * Read video BIOS from /dev/mem.
+ *
+ * Return:
+ *  0: failed
+ *  1: ok
+ */
+int copy_vbios(hd_data_t *hd_data)
+{
+  unsigned size;
+  unsigned char tmp[3];
+
+  if(!hd_read_mmap(hd_data, MEM_FILE, tmp, V_BIOS, sizeof tmp)) {
+    log_err("vbe: failed to read %u bytes at 0x%x\n", (unsigned) sizeof tmp, V_BIOS);
+    return 0;
+  }
+
+  if(tmp[0] != 0x55 || tmp[1] != 0xAA ) {
+    log_err("vbe: no bios found at: 0x%x\n", V_BIOS);
+    return 0;
+  }
+
+  size = tmp[2] * 0x200;
+
+  if(!hd_read_mmap(hd_data, MEM_FILE, (unsigned char *) V_BIOS, V_BIOS, size)) {
+    log_err("vbe: failed to read %d bytes at 0x%x\n", size, V_BIOS);
+    return 0;
+  }
+
+  return chksum((CARD8 *) V_BIOS) ? 1 : 0;
+}
+
+
+#if MAP_SYS_BIOS
+static int
+copy_sys_bios(hd_data_t *hd_data)
+{
+  return hd_read_mmap(hd_data, MEM_FILE, (unsigned char *) 0xf0000, 0xf0000, 0xffff);
+}
+#endif
+
+
+static int copy_bios_ram(hd_data_t *hd_data)
+{
+  return hd_read_mmap(hd_data, MEM_FILE, (unsigned char *) 0, 0, 0x1000);
+}
+
+void loadCodeToMem(unsigned char *ptr, CARD8 *code)
+{
+  while((*ptr++ = *code++) != 0xf4 /* hlt */);
+
+  return;
+}
+               
+
+/*
+ * here we are really paranoid about faking a "real"
+ * BIOS. Most of this information was pulled from
+ * dosem.
+ */
+static void
+setup_int_vect(void)
+{
+       const CARD16 cs = 0x0000;
+       const CARD16 ip = 0x0;
+       int i;
+       
+       /* let the int vects point to the SYS_BIOS seg */
+       for (i=0; i<0x80; i++) {
+               ((CARD16*)0)[i<<1] = ip;
+               ((CARD16*)0)[(i<<1)+1] = cs;
+       }
+       /* video interrupts default location */
+       ((CARD16*)0)[(0x42<<1)+1] = 0xf000;
+       ((CARD16*)0)[0x42<<1] = 0xf065;
+       ((CARD16*)0)[(0x10<<1)+1] = 0xf000;
+       ((CARD16*)0)[0x10<<1] = 0xf065;
+       /* video param table default location (int 1d) */
+       ((CARD16*)0)[(0x1d<<1)+1] = 0xf000;
+       ((CARD16*)0)[0x1d<<1] = 0xf0A4;
+       /* font tables default location (int 1F) */
+       ((CARD16*)0)[(0x1f<<1)+1] = 0xf000;
+       ((CARD16*)0)[0x1f<<1] = 0xfa6e;
+
+       /* int 11 default location */
+       ((CARD16*)0)[(0x11<1)+1] = 0xf000;
+       ((CARD16*)0)[0x11<<1] = 0xf84d;
+       /* int 12 default location */
+       ((CARD16*)0)[(0x12<<1)+1] = 0xf000;
+       ((CARD16*)0)[0x12<<1] = 0xf841;
+       /* int 15 default location */
+       ((CARD16*)0)[(0x15<<1)+1] = 0xf000;
+       ((CARD16*)0)[0x15<<1] = 0xf859;
+       /* int 1A default location */
+       ((CARD16*)0)[(0x1a<<1)+1] = 0xf000;
+       ((CARD16*)0)[0x1a<<1] = 0xff6e;
+       /* int 05 default location */
+       ((CARD16*)0)[(0x05<<1)+1] = 0xf000;
+       ((CARD16*)0)[0x05<<1] = 0xff54;
+       /* int 08 default location */
+       ((CARD16*)0)[(0x8<<1)+1] = 0xf000;
+       ((CARD16*)0)[0x8<<1] = 0xfea5;
+       /* int 13 default location (fdd) */
+       ((CARD16*)0)[(0x13<<1)+1] = 0xf000;
+       ((CARD16*)0)[0x13<<1] = 0xec59;
+       /* int 0E default location */
+       ((CARD16*)0)[(0xe<<1)+1] = 0xf000;
+       ((CARD16*)0)[0xe<<1] = 0xef57;
+       /* int 17 default location */
+       ((CARD16*)0)[(0x17<<1)+1] = 0xf000;
+       ((CARD16*)0)[0x17<<1] = 0xefd2;
+       /* fdd table default location (int 1e) */
+       ((CARD16*)0)[(0x1e<<1)+1] = 0xf000;
+       ((CARD16*)0)[0x1e<<1] = 0xefc7;
+}
+
+static int
+setup_system_bios(hd_data_t *hd_data)
+{
+       char *date = "06/01/99";
+       char *eisa_ident = "PCI/ISA";
+       
+#if MAP_SYS_BIOS
+       if (!copy_sys_bios(hd_data)) return 0;
+       return 1;
+#endif
+//    memset((void *)0xF0000,0xf4,0xfff7);
+       
+       /*
+        * we trap the "industry standard entry points" to the BIOS
+        * and all other locations by filling them with "hlt"
+        * TODO: implement hlt-handler for these
+        */
+       memset((void *)0xF0000,0xf4,0x10000);
+
+       /*
+        * TODO: we should copy the fdd table (0xfec59-0xfec5b)
+        * the video parameter table (0xf0ac-0xf0fb)
+        * and the font tables (0xfa6e-0xfe6d)
+        * from the original bios here
+        */
+       
+       /* set bios date */
+       strcpy((char *)0xFFFF5,date);
+       /* set up eisa ident string */
+       strcpy((char *)0xFFFD9,eisa_ident);
+       /* write system model id for IBM-AT */
+       ((char *)0)[0xFFFFE] = 0xfc;
+
+       return 1;
+}
+
+
+/*
+ * Check BIOS CRC.
+ *
+ * Return:
+ *  0: failed
+ *  1: ok
+ */
+int chksum(CARD8 *start)
+{
+  CARD16 size;
+  CARD8 val = 0;
+  int i;
+
+  size = start[2] * 0x200;
+  for(i = 0; i < size; i++) val += start[i];
+       
+  if(!val) return 1;
+
+  log_err("vbe: BIOS chksum wrong\n");
+
+  return 0;
+}
+