Exemple #1
0
void
CALL32_Ap(void)
{
	descriptor_t sd;
	UINT32 new_ip;
	UINT16 new_cs;
	UINT16 sreg;

	CPU_WORKCLOCK(13);
	GET_PCDWORD(new_ip);
	GET_PCWORD(new_cs);
	if (!CPU_STAT_PM || CPU_STAT_VM86) {
		/* Real mode or VM86 mode */
		CPU_SET_PREV_ESP();
		load_segreg(CPU_CS_INDEX, new_cs, &sreg, &sd, GP_EXCEPTION);
		if (new_ip > sd.u.seg.limit) {
			EXCEPTION(GP_EXCEPTION, 0);
		}

		PUSH0_32(CPU_CS);
		PUSH0_32(CPU_EIP);

		LOAD_SEGREG(CPU_CS_INDEX, new_cs);
		CPU_EIP = new_ip;
		CPU_CLEAR_PREV_ESP();
	} else {
		/* Protected mode */
		CALLfar_pm(new_cs, new_ip);
	}
}
Exemple #2
0
void
RETfar32(void)
{
	descriptor_t sd;
	UINT32 new_ip;
	UINT32 new_cs;
	UINT16 sreg;

	CPU_WORKCLOCK(15);
	if (!CPU_STAT_PM || CPU_STAT_VM86) {
		/* Real mode or VM86 mode */
		CPU_SET_PREV_ESP();
		POP0_32(new_ip);
		POP0_32(new_cs);

		/* check new instrunction pointer with new code segment */
		load_segreg(CPU_CS_INDEX, new_cs, &sreg, &sd, GP_EXCEPTION);
		if (new_ip > sd.u.seg.limit) {
			EXCEPTION(GP_EXCEPTION, 0);
		}

		LOAD_SEGREG(CPU_CS_INDEX, (UINT16)new_cs);
		CPU_EIP = new_ip;
		CPU_CLEAR_PREV_ESP();
	} else {
		/* Protected mode */
		RETfar_pm(0);
	}
}
Exemple #3
0
void
RETnear32(void)
{
	UINT32 new_ip;

	CPU_WORKCLOCK(11);
	CPU_SET_PREV_ESP();
	POP0_32(new_ip);
	if (new_ip > CPU_STAT_CS_LIMIT) {
		EXCEPTION(GP_EXCEPTION, 0);
	}
	CPU_EIP = new_ip;
	CPU_CLEAR_PREV_ESP();
}
Exemple #4
0
void
CALL_Ad(void)
{
	UINT32 new_ip;
	UINT32 dest;

	CPU_WORKCLOCK(7);
	CPU_SET_PREV_ESP();
	GET_PCDWORD(dest);
	new_ip = CPU_EIP + dest;
	if (new_ip > CPU_STAT_CS_LIMIT) {
		EXCEPTION(GP_EXCEPTION, 0);
	}
	PUSH0_32(CPU_EIP);
	CPU_EIP = new_ip;
	CPU_CLEAR_PREV_ESP();
}
Exemple #5
0
/*
 * CALL
 */
void
CALL_Aw(void)
{
	UINT16 new_ip;
	SINT16 dest;

	CPU_WORKCLOCK(7);
	CPU_SET_PREV_ESP();
	GET_PCWORDS(dest);
	new_ip = CPU_EIP + dest;
	if (new_ip > CPU_STAT_CS_LIMIT) {
		EXCEPTION(GP_EXCEPTION, 0);
	}
	PUSH0_16(CPU_IP);
	CPU_EIP = new_ip;
	CPU_CLEAR_PREV_ESP();
}
Exemple #6
0
void
LEAVE(void)
{

	CPU_WORKCLOCK(4);

	CPU_SET_PREV_ESP();
	if (!CPU_STAT_SS32) {
		CPU_SP = CPU_BP;
	} else {
		CPU_ESP = CPU_EBP;
	}
	if (!CPU_INST_OP32) {
		POP0_16(CPU_BP);
	} else {
		POP0_32(CPU_EBP);
	}
	CPU_CLEAR_PREV_ESP();
}
Exemple #7
0
void
IRET(void)
{
	descriptor_t sd;
	UINT32 new_ip;
	UINT32 new_flags;
	UINT32 new_cs;
	UINT32 mask;
	UINT16 sreg;

	CPU_WORKCLOCK(22);
	if (!CPU_STAT_PM) {
		/* Real mode */
		CPU_SET_PREV_ESP();
		mask = I_FLAG|IOPL_FLAG;
		if (!CPU_INST_OP32) {
			POP0_16(new_ip);
			POP0_16(new_cs);
			POP0_16(new_flags);
		} else {
			POP0_32(new_ip);
			POP0_32(new_cs);
			POP0_32(new_flags);
			mask |= RF_FLAG;
		}

		/* check new instrunction pointer with new code segment */
		load_segreg(CPU_CS_INDEX, new_cs, &sreg, &sd, GP_EXCEPTION);
		if (new_ip > sd.u.seg.limit) {
			EXCEPTION(GP_EXCEPTION, 0);
		}

		LOAD_SEGREG(CPU_CS_INDEX, (UINT16)new_cs);
		CPU_EIP = new_ip;

		set_eflags(new_flags, mask);
		CPU_CLEAR_PREV_ESP();
	} else {
		/* Protected mode */
		IRET_pm();
	}
	IRQCHECKTERM();
}
Exemple #8
0
void
RETnear32_Iw(void)
{
	UINT32 new_ip;
	UINT16 size;

	CPU_WORKCLOCK(11);
	CPU_SET_PREV_ESP();
	GET_PCWORD(size);
	POP0_32(new_ip);
	if (new_ip > CPU_STAT_CS_LIMIT) {
		EXCEPTION(GP_EXCEPTION, 0);
	}
	CPU_EIP = new_ip;
	if (!CPU_STAT_SS32) {
		CPU_SP += size;
	} else {
		CPU_ESP += size;
	}
	CPU_CLEAR_PREV_ESP();
}
Exemple #9
0
void CPUCALL
CALL_Ed(UINT32 op)
{
	UINT32 madr;
	UINT32 new_ip;

	CPU_SET_PREV_ESP();
	if (op >= 0xc0) {
		CPU_WORKCLOCK(7);
		new_ip = *(reg32_b20[op]);
	} else {
		CPU_WORKCLOCK(11);
		madr = calc_ea_dst(op);
		new_ip = cpu_vmemoryread_d(CPU_INST_SEGREG_INDEX, madr);
	}
	if (new_ip > CPU_STAT_CS_LIMIT) {
		EXCEPTION(GP_EXCEPTION, 0);
	}
	PUSH0_32(CPU_EIP);
	CPU_EIP = new_ip;
	CPU_CLEAR_PREV_ESP();
}
Exemple #10
0
void CPUCALL
CALL32_Ep(UINT32 op)
{
	descriptor_t sd;
	UINT32 madr;
	UINT32 new_ip;
	UINT16 new_cs;
	UINT16 sreg;

	CPU_WORKCLOCK(16);
	if (op < 0xc0) {
		madr = calc_ea_dst(op);
		new_ip = cpu_vmemoryread_d(CPU_INST_SEGREG_INDEX, madr);
		new_cs = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr + 4);
		if (!CPU_STAT_PM || CPU_STAT_VM86) {
			/* Real mode or VM86 mode */
			CPU_SET_PREV_ESP();
			load_segreg(CPU_CS_INDEX, new_cs, &sreg, &sd, GP_EXCEPTION);
			if (new_ip > sd.u.seg.limit) {
				EXCEPTION(GP_EXCEPTION, 0);
			}

			PUSH0_32(CPU_CS);
			PUSH0_32(CPU_EIP);

			LOAD_SEGREG(CPU_CS_INDEX, new_cs);
			CPU_EIP = new_ip;
			CPU_CLEAR_PREV_ESP();
		} else {
			/* Protected mode */
			CALLfar_pm(new_cs, new_ip);
		}
		return;
	}
	EXCEPTION(UD_EXCEPTION, 0);
}
Exemple #11
0
void
ENTER32_IwIb(void)
{
	UINT32 sp, bp;
	UINT32 new_bp;
	UINT32 val;
	UINT16 dimsize;
	UINT8 level;

	GET_PCWORD(dimsize);
	GET_PCBYTE(level);
	level &= 0x1f;

	CPU_SET_PREV_ESP();
	PUSH0_32(CPU_EBP);
	if (level == 0) {			/* enter level=0 */
		CPU_WORKCLOCK(11);
		CPU_EBP = CPU_ESP;
		if (!CPU_STAT_SS32) {
			CPU_SP -= dimsize;
		} else {
			CPU_ESP -= dimsize;
		}
	} else {
		--level;
		if (level == 0) {		/* enter level=1 */
			CPU_WORKCLOCK(15);
			sp = CPU_ESP;
			PUSH0_32(sp);
			CPU_EBP = sp;
			if (CPU_STAT_SS32) {
				CPU_ESP -= dimsize;
			} else {
				CPU_SP -= dimsize;
			}
		} else {			/* enter level=2-31 */
			CPU_WORKCLOCK(12 + level * 4);
			if (CPU_STAT_SS32) {
				bp = CPU_EBP;
				new_bp = CPU_ESP;
				while (level--) {
					bp -= 4;
					CPU_ESP -= 4;
					val = cpu_vmemoryread_d(CPU_SS_INDEX, bp);
					cpu_vmemorywrite_d(CPU_SS_INDEX, CPU_ESP, val);
				}
				REGPUSH0_32(new_bp);
				CPU_EBP = new_bp;
				CPU_ESP -= dimsize;
			} else {
				bp = CPU_BP;
				new_bp = CPU_ESP;
				while (level--) {
					bp -= 4;
					CPU_SP -= 4;
					val = cpu_vmemoryread_d(CPU_SS_INDEX, bp);
					cpu_vmemorywrite_d(CPU_SS_INDEX, CPU_SP, val);
				}
				REGPUSH0_32_16(new_bp);
				CPU_EBP = new_bp;
				CPU_SP -= dimsize;
			}
		}
	}
	CPU_CLEAR_PREV_ESP();
}
Exemple #12
0
void CPUCALL
interrupt(int num, int intrtype, int errorp, int error_code)
{
    descriptor_t gsd;
    UINT idt_idx;
    UINT32 new_ip;
    UINT16 new_cs;
    int exc_errcode;

    VERBOSE(("interrupt: num = 0x%02x, intrtype = %s, errorp = %s, error_code = %08x", num, (intrtype == INTR_TYPE_EXTINTR) ? "external" : (intrtype == INTR_TYPE_EXCEPTION ? "exception" : "softint"), errorp ? "on" : "off", error_code));

    if(num == 0x21 && md_int21())	{
        return;
    }

    CPU_SET_PREV_ESP();

    if (!CPU_STAT_PM) {
        /* real mode */
        CPU_WORKCLOCK(20);

        idt_idx = num * 4;
        if (idt_idx + 3 > CPU_IDTR_LIMIT) {
            VERBOSE(("interrupt: real-mode IDTR limit check failure (idx = 0x%04x, limit = 0x%08x", idt_idx, CPU_IDTR_LIMIT));
            EXCEPTION(GP_EXCEPTION, idt_idx + 2);
        }

        if ((intrtype == INTR_TYPE_EXTINTR) && CPU_STAT_HLT) {
            VERBOSE(("interrupt: reset HTL in real mode"));
            CPU_EIP++;
            CPU_STAT_HLT = 0;
        }

        REGPUSH0(REAL_FLAGREG);
        REGPUSH0(CPU_CS);
        REGPUSH0(CPU_IP);

        CPU_EFLAG &= ~(T_FLAG | I_FLAG | AC_FLAG | RF_FLAG);
        CPU_TRAP = 0;

        new_ip = cpu_memoryread_w(CPU_IDTR_BASE + idt_idx);
        new_cs = cpu_memoryread_w(CPU_IDTR_BASE + idt_idx + 2);
        LOAD_SEGREG(CPU_CS_INDEX, new_cs);
        CPU_EIP = new_ip;
    } else {
        /* protected mode */
        CPU_WORKCLOCK(200);

        VERBOSE(("interrupt: -------------------------------------------------------------- start"));
        VERBOSE(("interrupt: old EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP));

#if defined(DEBUG)
        if (num == 0x80) {
            /* Linux, FreeBSD, NetBSD, OpenBSD system call */
            VERBOSE(("interrupt: syscall# = %d\n%s", CPU_EAX, cpu_reg2str()));
        }
#endif

        idt_idx = num * 8;
        exc_errcode = idt_idx + 2;
        if (intrtype == INTR_TYPE_EXTINTR)
            exc_errcode++;

        if (idt_idx + 7 > CPU_IDTR_LIMIT) {
            VERBOSE(("interrupt: IDTR limit check failure (idx = 0x%04x, limit = 0x%08x", idt_idx, CPU_IDTR_LIMIT));
            EXCEPTION(GP_EXCEPTION, exc_errcode);
        }

        /* load a gate descriptor from interrupt descriptor table */
        memset(&gsd, 0, sizeof(gsd));
        load_descriptor(&gsd, CPU_IDTR_BASE + idt_idx);
        if (!SEG_IS_VALID(&gsd)) {
            VERBOSE(("interrupt: gate descripter is invalid."));
            EXCEPTION(GP_EXCEPTION, exc_errcode);
        }
        if (!SEG_IS_SYSTEM(&gsd)) {
            VERBOSE(("interrupt: gate descriptor is not system segment."));
            EXCEPTION(GP_EXCEPTION, exc_errcode);
        }

        switch (gsd.type) {
        case CPU_SYSDESC_TYPE_TASK:
        case CPU_SYSDESC_TYPE_INTR_16:
        case CPU_SYSDESC_TYPE_INTR_32:
        case CPU_SYSDESC_TYPE_TRAP_16:
        case CPU_SYSDESC_TYPE_TRAP_32:
            break;

        default:
            VERBOSE(("interrupt: invalid gate type (%d)", gsd.type));
            EXCEPTION(GP_EXCEPTION, exc_errcode);
            break;
        }

        /* 5.10.1.1. 例外/割り込みハンドラ・プロシージャの保護 */
        if ((intrtype == INTR_TYPE_SOFTINTR) && (gsd.dpl < CPU_STAT_CPL)) {
            VERBOSE(("interrupt: intrtype(softint) && DPL(%d) < CPL(%d)", gsd.dpl, CPU_STAT_CPL));
            EXCEPTION(GP_EXCEPTION, exc_errcode);
        }

        if (!SEG_IS_PRESENT(&gsd)) {
            VERBOSE(("interrupt: gate descriptor is not present."));
            EXCEPTION(NP_EXCEPTION, exc_errcode);
        }

        if ((intrtype == INTR_TYPE_EXTINTR) && CPU_STAT_HLT) {
            VERBOSE(("interrupt: reset HTL in protected mode"));
            CPU_EIP++;
            CPU_STAT_HLT = 0;
        }

        switch (gsd.type) {
        case CPU_SYSDESC_TYPE_TASK:
            interrupt_task_gate(&gsd, intrtype, errorp, error_code);
            break;

        case CPU_SYSDESC_TYPE_INTR_16:
        case CPU_SYSDESC_TYPE_INTR_32:
        case CPU_SYSDESC_TYPE_TRAP_16:
        case CPU_SYSDESC_TYPE_TRAP_32:
            interrupt_intr_or_trap(&gsd, intrtype, errorp, error_code);
            break;

        default:
            EXCEPTION(GP_EXCEPTION, exc_errcode);
            break;
        }

        VERBOSE(("interrupt: ---------------------------------------------------------------- end"));
    }

    CPU_CLEAR_PREV_ESP();
}