/*
 * DANG_BEGIN_MODULE
 *
 *
 *
 * DANG_END_MODULE
 *
 * DANG_BEGIN_CHANGELOG
 *
 * $Date: $
 * $Source: $
 * $Revision: $
 * $State: $
 *
 * $Log: $
 *
 * DANG_END_CHANGELOG
 */

#include "dosemu.h"
#include "base/cpu.h"
#include "base/int.h"
#include "base/bios.h"
#include "dosext/dpmi.h"

/*
 * DANG_BEGIN_FUNCTION dosemu_fault(int, struct sigcontext_struct);
 *
 * All CPU exceptions (except 13=general_protection from V86 mode,
 * which is directly scaned by the kernel) are handled here.
 *
 * DANG_END_FUNCTION
 */

void dosemu_fault(int signal, struct sigcontext_struct context)
{
  struct sigcontext_struct *scp = &context;
  unsigned char *csp;
  int i;

  if (in_vm86) {
    in_vm86 = 0;
    switch (context.trapno) {
      case 0x01: /* debug */
        if (ignore_trap) {
	  h_printf("FAULT: trap ignored\n");
	  return;
	}
      case 0x00: /* divide_error */
      case 0x03: /* int3 */
      case 0x04: /* overflow */
      case 0x05: /* bounds */
      case 0x07: /* device_not_available */
	h_printf("FAULT: redirecting trap 0x%02lx to vm86()\n",
		 context.trapno);
	show_regs(__FILE__, __LINE__);
        int_run(context.trapno);
        return;

      case 0x0e: /* page fault */
	if ((context.err & 1) == 0) {
	  error("Page fault (0x%08lx): no page present!?!\n", context.cr2);
	  break;
	}
	if ((context.err & 2) == 0) {
	  error("Page fault (0x%08lx): page READ protected!?!\n", context.cr2);
	  break;
	}
	/* page present, write protected page -- is it the BIOS? */
	if ((context.cr2 >= 0xfc000) && (context.cr2 <= 0xfffff)) {
	  bios_write((Bit8u *)context.cr2);
	  h_printf("BIOS: Hey!!!  Someone is overwriting our BIOS!\n");
	  return;
	}
	error("Page fault (0x%08lx): write to protected page!\n", context.cr2);
	break;

      case 0x06: /* invalid_op */
	h_printf("SIGILL while in vm86()\n");
	show_regs(__FILE__, __LINE__);
	csp = SEG_ADR((unsigned char *), cs, ip);
	/* Some db commands start with 2e (use cs segment) */
	if (csp[0] == 0x2e) {
	  csp++;
	  _IP++;
	}
	if (csp[0] == 0xf0) {
	  h_printf("ERROR: LOCK prefix not permitted!\n");
	  _IP++;
	  return;
	}
    }
    error("ERROR: unexpected CPU exception 0x%02lx errorcode: 0x%08lx"
	  " while in vm86()\neip: 0x%08lx  esp: 0x%08lx  eflags: 0x%lx\n"
	  "cs: 0x%04x  ds: 0x%04x  es: 0x%04x  ss: 0x%04x\n", context.trapno,
	  context.err, _EIP, _ESP, _eflags, _CS, _DS, _ES, _SS);
    perror("YUCK");
    show_regs(__FILE__, __LINE__);
    leavedos(4);
  }

  if (in_dpmi)
    return dpmi_fault(&context);

  csp = (char *) _eip;

  /* This has been added temporarily as most illegal sigsegv's are attempt
     to call Linux int routines */

#if 0
  if (!(csp[-2] == 0xcd && csp[-1] == 0x80 && csp[0] == 0x85)) {
#else
  {
#endif
    error("ERROR: cpu exception in dosemu code outside of VM86()!\n"
	  "trapno: 0x%02lx  errorcode: 0x%08lx  cr2: 0x%08lx\n"
	  "eip: 0x%08lx  esp: 0x%08lx  eflags: 0x%08lx\n"
	  "cs: 0x%04x  ds: 0x%04x  es: 0x%04x  ss: 0x%04x\n",
	  _trapno, scp->err, scp->cr2,
	  _eip, _esp, _eflags, _cs, _ds, _es, _ss);

    dbug_printf("  VFLAGS(b): ");
    for (i = (1 << 17); i; i >>= 1)
      dbug_printf((_eflags & i) ? "1" : "0");
    dbug_printf("\n");

    dbug_printf("EAX: %08lx  EBX: %08lx  ECX: %08lx  EDX: %08lx"
		"  VFLAGS(h): %08lx\n",
		_eax, _ebx, _ecx, _edx, _eflags);
    dbug_printf("ESI: %08lx  EDI: %08lx  EBP: %08lx\n",
		_esi, _edi, _ebp);
    dbug_printf("CS: %04x  DS: %04x  ES: %04x  FS: %04x  GS: %04x\n",
		_cs, _ds, _es, _fs, _gs);

    /* display vflags symbolically...the #f "stringizes" the macro name */
#undef PFLAG
#define PFLAG(f)  if ((_eflags)&(f)) dbug_printf(" " #f)

    dbug_printf("FLAGS:");
    PFLAG(CF);
    PFLAG(PF);
    PFLAG(AF);
    PFLAG(ZF);
    PFLAG(SF);
    PFLAG(TF);
    PFLAG(IF);
    PFLAG(DF);
    PFLAG(OF);
    PFLAG(NT);
    PFLAG(RF);
    PFLAG(VM);
    PFLAG(AC);
    dbug_printf("  IOPL: %u\n", (unsigned) ((_eflags & IOPL_MASK) >> 12));

    /* display the 10 bytes before and after CS:EIP.  the -> points
     * to the byte at address CS:EIP
     */
    dbug_printf("OPS  : ");
    csp = (unsigned char *) _eip - 10;
    for (i = 0; i < 10; i++)
      dbug_printf("%02x ", *csp++);
    dbug_printf("-> ");
    for (i = 0; i < 10; i++)
      dbug_printf("%02x ", *csp++);
    dbug_printf("\n");

    show_regs(__FILE__, __LINE__);

    fatalerr = 4;
    leavedos(fatalerr);		/* shouldn't return */
  }
}
