- return FALSE; /* handle as single-step */
- }
- /*
- * Fall through to check for interrupts.
- */
- }
- else if (regs->trapno == T_GENERAL_PROTECTION) {
- /*
- * General protection error - must be an 8086 instruction
- * to emulate.
- */
- register int eip;
- boolean_t addr_32 = FALSE;
- boolean_t data_32 = FALSE;
- int io_port;
-
- /*
- * Set up error handler for bad instruction/data
- * fetches.
- */
- __asm__("movl $(addr_error), %0" : : "m" (thread->recover));
-
- eip = regs->eip;
- while (TRUE) {
- unsigned char opcode;
-
- if (eip > 0xFFFF) {
- thread->recover = 0;
- return FALSE; /* GP fault: IP out of range */
- }
-
- opcode = *(unsigned char *)Addr8086(regs->cs,eip);
- eip++;
- switch (opcode) {
- case 0xf0: /* lock */
- case 0xf2: /* repne */
- case 0xf3: /* repe */
- case 0x2e: /* cs */
- case 0x36: /* ss */
- case 0x3e: /* ds */
- case 0x26: /* es */
- case 0x64: /* fs */
- case 0x65: /* gs */
- /* ignore prefix */
- continue;
-
- case 0x66: /* data size */
- data_32 = TRUE;
- continue;
-
- case 0x67: /* address size */
- addr_32 = TRUE;
- continue;
-
- case 0xe4: /* inb imm */
- case 0xe5: /* inw imm */
- case 0xe6: /* outb imm */
- case 0xe7: /* outw imm */
- io_port = *(unsigned char *)Addr8086(regs->cs, eip);
- eip++;
- goto do_in_out;
-
- case 0xec: /* inb dx */
- case 0xed: /* inw dx */
- case 0xee: /* outb dx */
- case 0xef: /* outw dx */
- case 0x6c: /* insb */
- case 0x6d: /* insw */
- case 0x6e: /* outsb */
- case 0x6f: /* outsw */
- io_port = regs->edx & 0xffff;
-
- do_in_out:
- if (!data_32)
- opcode |= 0x6600; /* word IO */
-
- switch (emulate_io(regs, opcode, io_port)) {
- case EM_IO_DONE:
- /* instruction executed */
- break;
- case EM_IO_RETRY:
- /* port mapped, retry instruction */
- thread->recover = 0;
- return TRUE;
- case EM_IO_ERROR:
- /* port not mapped */
- thread->recover = 0;
- return FALSE;
- }
- break;
-
- case 0xfa: /* cli */
- if (!v86_do_sti_cli) {
- thread->recover = 0;
- return (FALSE);
- }
-
- v86->flags &= ~EFL_IF;
- /* disable simulated interrupts */
- cli_count++;
- break;
-
- case 0xfb: /* sti */
- if (!v86_do_sti_cli) {
- thread->recover = 0;
- return (FALSE);
- }
-
- if ((v86->flags & EFL_IF) == 0) {
- if (v86_do_sti_immediate) {
- v86->flags |= EFL_IF;
- } else {
- v86->flags |= V86_IF_PENDING;
- regs->efl |= EFL_TF;
- }
- /* single step to set IF next inst. */
- }
- sti_count++;
- break;
-
- case 0x9c: /* pushf */
- {
- int flags;
- vm_offset_t sp;
- int size;
-
- flags = regs->efl;
- if ((v86->flags & EFL_IF) == 0)
- flags &= ~EFL_IF;
-
- if ((v86->flags & EFL_TF) == 0)
- flags &= ~EFL_TF;
- else flags |= EFL_TF;
-
- sp = regs->uesp;
- if (!addr_32)
- sp &= 0xffff;
- else if (sp > 0xffff)
- goto stack_error;
- size = (data_32) ? 4 : 2;
- if (sp < size)
- goto stack_error;
- sp -= size;
- if (copyout((char *)&flags,
- (char *)Addr8086(regs->ss,sp),
- size))
- goto addr_error;
- if (addr_32)
- regs->uesp = sp;
- else
- regs->uesp = (regs->uesp & 0xffff0000) | sp;
- break;
- }
-
- case 0x9d: /* popf */
- {
- vm_offset_t sp;
- int nflags;
-
- sp = regs->uesp;
- if (!addr_32)
- sp &= 0xffff;
- else if (sp > 0xffff)
- goto stack_error;
-
- if (data_32) {
- if (sp > 0xffff - sizeof(int))
- goto stack_error;
- nflags = *(int *)Addr8086(regs->ss,sp);
- sp += sizeof(int);
- }
- else {
- if (sp > 0xffff - sizeof(short))
- goto stack_error;
- nflags = *(unsigned short *)
- Addr8086(regs->ss,sp);
- sp += sizeof(short);
- }
- if (addr_32)
- regs->uesp = sp;
- else
- regs->uesp = (regs->uesp & 0xffff0000) | sp;
-
- if (v86->flags & V86_IRET_PENDING) {
- v86->flags = nflags & (EFL_TF | EFL_IF);
- v86->flags |= V86_IRET_PENDING;
- } else {
- v86->flags = nflags & (EFL_TF | EFL_IF);
- }
- regs->efl = (regs->efl & ~EFL_V86_SAFE)
- | (nflags & EFL_V86_SAFE);
- break;
- }
- case 0xcf: /* iret */
- {
- vm_offset_t sp;
- int nflags;
- int size;
- union iret_struct iret_struct;
-
- v86->flags &= ~V86_IRET_PENDING;
- sp = regs->uesp;
- if (!addr_32)
- sp &= 0xffff;
- else if (sp > 0xffff)
- goto stack_error;
-
- if (data_32) {
- if (sp > 0xffff - sizeof(struct iret_32))
- goto stack_error;
- iret_struct.iret_32 =
- *(struct iret_32 *) Addr8086(regs->ss,sp);
- sp += sizeof(struct iret_32);
- }
- else {
- if (sp > 0xffff - sizeof(struct iret_16))
- goto stack_error;
- iret_struct.iret_16 =
- *(struct iret_16 *) Addr8086(regs->ss,sp);
- sp += sizeof(struct iret_16);
- }
- if (addr_32)
- regs->uesp = sp;
- else
- regs->uesp = (regs->uesp & 0xffff0000) | sp;
-
- if (data_32) {
- eip = iret_struct.iret_32.eip;
- regs->cs = iret_struct.iret_32.cs & 0xffff;
- nflags = iret_struct.iret_32.eflags;
- }
- else {
- eip = iret_struct.iret_16.ip;
- regs->cs = iret_struct.iret_16.cs;
- nflags = iret_struct.iret_16.flags;
- }
-
- v86->flags = nflags & (EFL_TF | EFL_IF);
- regs->efl = (regs->efl & ~EFL_V86_SAFE)
- | (nflags & EFL_V86_SAFE);
- break;
- }
- default:
- /*
- * Instruction not emulated here.
- */
- thread->recover = 0;
- return FALSE;
- }
- break; /* exit from 'while TRUE' */
- }
- regs->eip = (regs->eip & 0xffff0000 | eip);
- }
- else {
- /*
- * Not a trap we handle.
- */
- thread->recover = 0;
- return FALSE;
- }
-
- if ((v86->flags & EFL_IF) && ((v86->flags & V86_IRET_PENDING)==0)) {
-
- struct v86_interrupt_table *int_table;
- int int_count;
- int vec;
- int i;
-
- int_table = (struct v86_interrupt_table *) v86->int_table;
- int_count = v86->int_count;