static void do_call(int cs, int ip, struct RealModeCallStructure *rmreg, int rmask) { unsigned int ssp, sp; ssp = SEGOFF2LINEAR(READ_RMREG(ss, rmask), 0); sp = READ_RMREG(sp, rmask); g_printf("fake_call() CS:IP %04x:%04x\n", cs, ip); pushw(ssp, sp, cs); pushw(ssp, sp, ip); RMREG(sp) -= 4; }
int intE6_handler() { #if 0 pciVideoPtr pvp; if ((pvp = xf86GetPciInfoForEntity(pInt->entityIndex))) X86_AX = (pvp->bus << 8) | (pvp->device << 3) | (pvp->func & 0x7); pushw(X86_CS); pushw(X86_IP); X86_CS = pInt->BIOSseg; X86_EIP = 0x0003; X86_ES = 0; /* standard pc es */ #endif printf("intE6 not supported right now.\n"); return 1; }
static void do_int( Virtual86Regs_s * regs, int i, unsigned char *ssp, unsigned long sp ) { unsigned long *intr_ptr, segoffs; intr_ptr = ( unsigned long * )( i << 2 ); segoffs = *intr_ptr; pushw( ssp, sp, regs->eflags & 0xffff ); pushw( ssp, sp, regs->cs ); pushw( ssp, sp, regs->eip & 0xffff ); regs->eflags &= ~EFLG_IF; regs->cs = segoffs >> 16; regs->esp = ( regs->esp - 6 ) & 0xffff; regs->eip = segoffs & 0xffff; /* clear_IF(regs); */ }
void exception68(emu68_t * const emu68, const int vector, const int level) { if ( vector & 0x100 ) { /* Those are specific to EMU68 */ switch (vector) { case HWBREAK_VECTOR: case HWTRACE_VECTOR: break; default: assert(!"invalid eception vector"); } } else { int savesr = REG68.sr; int savest = emu68->status; emu68->status = EMU68_XCT; /* enter exception stat */ REG68.sr &= ~SR_T; /* no TRACE */ REG68.sr |= SR_S; /* Supervisor */ if ( savest == EMU68_XCT && ( vector == BUSERR_VECTOR || vector == ADRERR_VECTOR ) ) { /* Double fault ! */ emu68->status = EMU68_ERR; /* Halt processor */ } else if ( vector == RESET_VECTOR ) { REG68.sr |= SR_I; REG68.a[7] = read_L(RESET_SP_VECTOR << 2); REG68.pc = read_L(RESET_PC_VECTOR << 2); } else { if ( (unsigned int)level < 8u ) { SET_IPL(REG68.sr,level); } pushl(REG68.pc); pushw(savesr); REG68.pc = read_L(vector << 2); emu68->status = EMU68_NRM; /* Back to normal mode */ } } if (emu68->handler && emu68->handler(emu68, vector, emu68->cookie) ) { emu68->status = EMU68_BRK; /* User forced exit */ } }
void handle_v86_fault( Virtual86Regs_s * regs, uint32 nErrorCode ) { unsigned char *csp, *ssp; unsigned long ip, sp; int nInst; // if ( 0xffff == (regs->eip & 0xffff) && 0xffff == regs->cs ) { // return_to_32bit( regs, 0 ); // return; // } csp = ( unsigned char * )( regs->cs << 4 ); ssp = ( unsigned char * )( regs->ss << 4 ); sp = regs->esp & 0xffff; ip = regs->eip & 0xffff; nInst = popb( csp, ip ); switch ( nInst ) { /* Operand size override */ case 0x66: printk( "WARNING : 32 bit code run in v86 mode! Flags are not handled properly!\n" ); nInst = popb( csp, ip ); switch ( nInst ) { /* pushfd */ case 0x9c: regs->esp = ( regs->esp - 4 ) & 0xffff; regs->eip = ( regs->eip + 2 ) & 0xffff; pushl( ssp, sp, regs->eflags ); return; /* popfd */ case 0x9d: regs->esp = ( regs->esp + 4 ) & 0xffff; regs->eip = ( regs->eip + 2 ) & 0xffff; regs->eflags = popl( ssp, sp ); return; /* iretd */ case 0xcf: regs->esp = ( regs->esp + 12 ) & 0xffff; regs->eip = ( uint16 )( popl( ssp, sp ) & 0xffff ); regs->cs = ( uint16 )popl( ssp, sp ); return; /* need this to avoid a fallthrough */ default: printk( "ERROR : unknown v86 32 bit instruction %x\n", nInst ); return_to_32bit( regs, -EFAULT ); } /* pushf */ case 0x9c: regs->esp = ( regs->esp - 2 ) & 0xffff; regs->eip = ( regs->eip + 1 ) & 0xffff; pushw( ssp, sp, regs->eflags & 0xffff ); return; /* popf */ case 0x9d: regs->esp = ( regs->esp + 2 ) & 0xffff; regs->eip = ( regs->eip + 1 ) & 0xffff; regs->eflags = ( regs->eflags & 0xffff0000 ) | ( popw( ssp, sp ) & 0xffff ); return; /* int xx */ case 0xcd: { int intno = popb( csp, ip ); regs->eip = ( regs->eip + 2 ) & 0xffff; do_int( regs, intno, ssp, sp ); return; } /* iret */ case 0xcf: regs->esp = ( regs->esp + 6 ) & 0xffff; regs->eip = popw( ssp, sp ) & 0xffff; regs->cs = popw( ssp, sp ); regs->eflags = ( regs->eflags & 0xffff0000 ) | ( popw( ssp, sp ) & 0xffff ); if ( 0xffff == ( regs->eip & 0xffff ) && 0xffff == regs->cs ) { return_to_32bit( regs, 0 ); } return; /* cli */ case 0xfa: regs->eip = ( regs->eip + 1 ) & 0xffff; regs->eflags &= ~EFLG_IF; return; /* sti */ case 0xfb: /* The interrupts should actually be restored after the NEXT instruction! * Hope this works. As long as no DOS/BIOS code swaps the stack, * nothing bad should happen. */ regs->eip = ( regs->eip + 1 ) & 0xffff; regs->eflags |= EFLG_IF; return; default: printk( "ERROR : unknown v86 16 bit instruction %x\n", nInst ); return_to_32bit( regs, -EFAULT ); } }
int exception(struct trapdata *framedata) { ptptr proc; unsigned int frame, fsize; uint8_t trap = framedata->trap; unsigned int sig = 0; uint16_t m; uint16_t *sp = (uint16_t *)framedata; uint16_t *usp = get_usp(); uint16_t *unwind, *context; uint8_t err = 0; int i; /* We translate debug to SIGIOT and A and F line to SIGILL We will need to fix up 68000 v 68010 move to/from SR */ static const uint8_t trap_to_sig[] = { 0, 0, SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGABRT/*CHK*/, SIGTRAP/*TRAPV */, SIGILL, SIGIOT, SIGILL, SIGFPE }; proc = udata.u_ptab; if (sysinfo.cpu[0] == 10) { /* Long or short frame: the CPU tells us the frame format */ if (framedata->exception[3] & 0x8000) { fsize = 29; frame = FRAME_C; } else { fsize = 4; frame = FRAME_D; } } else { frame = FRAME_B; fsize = 3; } if (trap == 0) { sig = udata.u_cursig; udata.u_cursig = 0; } else if (trap < 12) { if (trap < 4) { /* On a 68010 this frame is 29 words and the event is restartable (although not always usefully). We need to decide whether to set the restart flag case by case */ if (sysinfo.cpu[0] == 0) { frame = FRAME_A; fsize = 7; } } sig = trap_to_sig[trap]; } else if (trap >= 32 && trap < 48) sig = SIGTRAP; /* This processing only applies to synchronous hardware exceptions */ if (trap) { /* Went boom in kernel space or without a user recovery */ if (kernel_flag || sig == 0) { explode(framedata, frame); panic("trap"); } /* Cheating here .. all our exceptions are low 16 signal */ m = 1 << sig; /* * The caller is ignoring our signal. In some cases this is fine * but in others it's less clear (eg division by zero) and we * may need to take different action. */ if (proc->p_sig[0].s_ignored & m) return 0; /* Weird case - we took a sync signal and the caller wants us to report it later. */ if (proc->p_sig[0].s_held & m) { /* TODO: if it's not meaningfully restartable we should probably treat this as a kill */ ssig(proc, sig); return 0; } recalc_cursig(); /* Put any async signal back */ } if (udata.u_sigvec[sig] == SIG_DFL) { /* Default action for our signal ? */ doexit(dump_core(sig)); /* This will never return. We will go schedule new work */ panic("exret"); } /* build signal frame Our unwinder code does move.l 8(sp),sp movem.l a0-a1/d0-d1,(sp)+ move.w (sp)+,ccr rts */ /* Now update the user stack */ /* - Push the recovery PC */ /* - Patch the kernel exception frame */ if (sysinfo.cpu[0]) { /* FIXME */ err |= pushw(&usp, sp[34]); err |= pushw(&usp, sp[33]); *(uint32_t *)(&sp[33]) = (uint32_t)udata.u_sigvec[sig]; } else { err |= pushw(&usp, sp[31 + fsize]); err |= pushw(&usp, sp[30 + fsize]); *(uint32_t *)(&sp[30 + fsize]) = (uint32_t)udata.u_sigvec[sig]; } /* FIXME: when we do ptrace we will need to support adding the T flag back here as the exception cleared it */ err |= pushw(&usp, framedata->sr); /* Push A1 A0 D1 D0 to match MOVEM.L */ err |= pushl(&usp, framedata->a[1]); err |= pushl(&usp, framedata->a[0]); err |= pushl(&usp, framedata->d[1]); err |= pushl(&usp, framedata->d[0]); /* Remember the target for undoing the frame */ unwind = usp; /* Copy in the signal context itself. 30 words of registers, 2 of trap code and then the hardware exception */ for (i = 0; i < 30 + 2 + fsize; i++) err |= pushw(&usp, *sp++); context = usp; err |= pushl(&usp, (uint32_t)unwind); /* Signal context is a secret extra non portable argument */ err |= pushl(&usp, (uint32_t)context); /* We end it with the call frame as seen from the signal handler, a single argument and a return address */ err |= pushl(&usp, sig); err |= pushl(&usp, udata.u_codebase + 0x04); set_usp(usp); if (err) { doexit(dump_core(SIGSTKFLT)); panic("exret2"); } /* Once built clear the restart state */ udata.u_sigvec[sig] = SIG_DFL; /* Return, RTE and end up on the signal frame */ return 1; }