示例#1
0
/*---
 * CALLfar_pm: call gate (SAME-PRIVILEGE)
 */
static void
CALLfar_pm_call_gate_same_privilege(const selector_t *callgate_sel, selector_t *cs_sel)
{
    UINT32 sp;

    VERBOSE(("CALLfar_pm: SAME-PRIVILEGE"));

    if (CPU_STAT_SS32) {
        sp = CPU_ESP;
    } else {
        sp = CPU_SP;
    }

    if (callgate_sel->desc.type == CPU_SYSDESC_TYPE_CALL_32) {
        STACK_PUSH_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 8);

        PUSH0_32(CPU_CS);
        PUSH0_32(CPU_EIP);

        load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL);
        SET_EIP(callgate_sel->desc.u.gate.offset);
    } else {
        STACK_PUSH_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 4);

        PUSH0_16(CPU_CS);
        PUSH0_16(CPU_IP);

        load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL);
        SET_EIP(callgate_sel->desc.u.gate.offset);
    }
}
示例#2
0
void
IRET_pm(void)
{
    UINT32 sp;
    UINT32 new_ip, new_flags;
    UINT16 new_cs;

    VERBOSE(("IRET_pm: old EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP));

    if (!(CPU_EFLAG & VM_FLAG) && (CPU_EFLAG & NT_FLAG)) {
        /* TASK-RETURN: PE=1, VM=0, NT=1 */
        IRET_pm_nested_task();
    } else {
        if (CPU_STAT_SS32) {
            sp = CPU_ESP;
        } else {
            sp = CPU_SP;
        }
        if (CPU_INST_OP32) {
            STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 12);
            new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp);
            new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4);
            new_flags = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 8);
        } else {
            STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 6);
            new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp);
            new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2);
            new_flags = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4);
        }

        VERBOSE(("IRET_pm: new_ip = %08x, new_cs = %04x, new_eflags = %08x", new_ip, new_cs, new_flags));

        if (CPU_EFLAG & VM_FLAG) {
            /* RETURN-FROM-VIRTUAL-8086-MODE */
            IRET_pm_return_from_vm86(new_cs, new_ip, new_flags);
        } else if (new_flags & VM_FLAG) {
            /* RETURN-TO-VIRTUAL-8086-MODE */
            IRET_pm_return_to_vm86(new_cs, new_ip, new_flags);
        } else {
            /* PROTECTED-MODE-RETURN */
            IRET_pm_protected_mode_return(new_cs, new_ip, new_flags);
        }
    }

    VERBOSE(("IRET_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP));
}
示例#3
0
void debugsub_status(void) {

static int		filenum = 0;
	FILEH		fh;
	OEMCHAR		work[512];
const OEMCHAR	*p;

	OEMSPRINTF(work, file_i386reg, filenum);
	fh = file_create_c(work);
	if (fh != FILEH_INVALID) {
		p = debugsub_regs();
		file_write(fh, p, OEMSTRLEN(p) * sizeof(OEMCHAR));
		OEMSPRINTF(work, str_picstat,
								pic.pi[0].imr, pic.pi[0].irr, pic.pi[0].isr,
								pic.pi[1].imr, pic.pi[1].irr, pic.pi[1].isr,
								mouseif.upd8255.portc, sysport.c);
		file_write(fh, work, OEMSTRLEN(work) * sizeof(OEMCHAR));

		OEMSPRINTF(work, OEMTEXT("CS = %.8x:%.8x") OEMTEXT(CRLITERAL),
						CPU_STAT_SREGBASE(CPU_CS_INDEX),
						CPU_STAT_SREGLIMIT(CPU_CS_INDEX));
		file_write(fh, work, OEMSTRLEN(work) * sizeof(OEMCHAR));

		file_close(fh);
	}

	OEMSPRINTF(work, file_i386cs, filenum);
	debugwriteseg(work, &CPU_STAT_SREG(CPU_CS_INDEX), CPU_EIP & 0xffff0000, 0x10000);
	OEMSPRINTF(work, file_i386ds, filenum);
	debugwriteseg(work, &CPU_STAT_SREG(CPU_DS_INDEX), 0, 0x10000);
	OEMSPRINTF(work, file_i386es, filenum);
	debugwriteseg(work, &CPU_STAT_SREG(CPU_ES_INDEX), 0, 0x10000);
	OEMSPRINTF(work, file_i386ss, filenum);
	debugwriteseg(work, &CPU_STAT_SREG(CPU_SS_INDEX), CPU_ESP & 0xffff0000, 0x10000);
	filenum++;
}
示例#4
0
/*---
 * IRET_pm: new_flags & VM_FLAG
 */
static void
IRET_pm_return_to_vm86(UINT16 new_cs, UINT32 new_ip, UINT32 new_flags)
{
    UINT16 segsel[CPU_SEGREG_NUM];
    UINT32 sp;
    UINT32 new_sp;
    int i;

    VERBOSE(("IRET_pm: Interrupt procedure was in virtual-8086 mode: PE=1, VM=1 in flags image"));

    if (CPU_STAT_CPL != 0) {
        ia32_panic("IRET_pm: CPL != 0");
    }

    if (!CPU_INST_OP32) {
        ia32_panic("IRET_pm: 16bit mode");
    }

    if (CPU_STAT_SS32) {
        sp = CPU_ESP;
    } else {
        sp = CPU_SP;
    }
    STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 36);
    new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12);
    segsel[CPU_SS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16);
    segsel[CPU_ES_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 20);
    segsel[CPU_DS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 24);
    segsel[CPU_FS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 28);
    segsel[CPU_GS_INDEX] = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 32);
    segsel[CPU_CS_INDEX] = (UINT16)new_cs;

    for (i = 0; i < CPU_SEGREG_NUM; i++) {
        CPU_REGS_SREG(i) = segsel[i];
        CPU_STAT_SREG_INIT(i);
    }

    /* to VM86 mode */
    set_eflags(new_flags, IOPL_FLAG|I_FLAG|VM_FLAG|RF_FLAG);

    new_sp &= 0xffff;
    new_ip &= 0xffff;

    CPU_ESP = new_sp;
    SET_EIP(new_ip);
}
示例#5
0
void
ia32_initreg(void)
{
	int i;

	CPU_STATSAVE.cpu_inst_default.seg_base = (UINT32)-1;

	CPU_EDX = (CPU_FAMILY << 8) | (CPU_MODEL << 4) | CPU_STEPPING;
	CPU_EFLAG = 2;
	CPU_CR0 = CPU_CR0_CD | CPU_CR0_NW;
#if defined(USE_FPU)
	CPU_CR0 &= ~CPU_CR0_EM;
	CPU_CR0 |= CPU_CR0_ET;
#else
	CPU_CR0 |= CPU_CR0_EM | CPU_CR0_NE;
	CPU_CR0 &= ~(CPU_CR0_MP | CPU_CR0_ET);
#endif
	CPU_MXCSR = 0x1f80;

	CPU_GDTR_BASE = 0x0;
	CPU_GDTR_LIMIT = 0xffff;
	CPU_IDTR_BASE = 0x0;
	CPU_IDTR_LIMIT = 0xffff;
	CPU_LDTR_BASE = 0x0;
	CPU_LDTR_LIMIT = 0xffff;
	CPU_TR_BASE = 0x0;
	CPU_TR_LIMIT = 0xffff;

	CPU_STATSAVE.cpu_regs.dr[6] = 0xffff1ff0;

	for (i = 0; i < CPU_SEGREG_NUM; ++i) {
		segdesc_init(i, 0, &CPU_STAT_SREG(i));
	}
	LOAD_SEGREG(CPU_CS_INDEX, 0xf000);
	CPU_STAT_CS_BASE = 0xffff0000;
	CPU_EIP = 0xfff0;
	CPU_ADRSMASK = 0x000fffff;

	tlb_init();
#if defined(USE_FPU)
	fpu_init();
#endif
}
示例#6
0
文件: cpu_mem.c 项目: aliaspider/np2
REG80 MEMCALL
cpu_vmemoryread_f(int idx, UINT32 offset)
{
    descriptor_t *sdp;
    UINT32 addr;
    int exc;

    __ASSERT((unsigned int)idx < CPU_SEGREG_NUM);

    sdp = &CPU_STAT_SREG(idx);
    addr = sdp->u.seg.segbase + offset;

    if (!CPU_STAT_PM)
        return cpu_memoryread_f(addr);

    if (!SEG_IS_VALID(sdp)) {
        exc = GP_EXCEPTION;
        goto err;
    }
    if (!(sdp->flag & CPU_DESC_FLAG_READABLE)) {
        cpu_memoryread_check(sdp, offset, 10, CHOOSE_EXCEPTION(idx));
    } else if (!(sdp->flag & CPU_DESC_FLAG_WHOLEADR)) {
        if (!check_limit_upstairs(sdp, offset, 10, SEG_IS_32BIT(sdp)))
            goto range_failure;
    }
    return cpu_lmemoryread_f(addr, CPU_PAGE_READ_DATA | CPU_STAT_USER_MODE);

range_failure:
    VERBOSE(("cpu_vmemoryread_f: type = %d, offset = %08x, limit = %08x", sdp->type, offset, sdp->u.seg.limit));
    exc = CHOOSE_EXCEPTION(idx);
err:
    EXCEPTION(exc, 0);
    {
        REG80 dummy;
        memset(&dummy, 0, sizeof(dummy));
        return dummy;	/* compiler happy */
    }
}
示例#7
0
文件: cpu_mem.c 项目: aliaspider/np2
void MEMCALL
cpu_vmemorywrite_f(int idx, UINT32 offset, const REG80 *value)
{
    descriptor_t *sdp;
    UINT32 addr;
    int exc;

    __ASSERT((unsigned int)idx < CPU_SEGREG_NUM);

    sdp = &CPU_STAT_SREG(idx);
    addr = sdp->u.seg.segbase + offset;

    if (!CPU_STAT_PM) {
        cpu_memorywrite_f(addr, value);
        return;
    }

    if (!SEG_IS_VALID(sdp)) {
        exc = GP_EXCEPTION;
        goto err;
    }
    if (!(sdp->flag & CPU_DESC_FLAG_WRITABLE)) {
        cpu_memorywrite_check(sdp, offset, 10, CHOOSE_EXCEPTION(idx));
    } else if (!(sdp->flag & CPU_DESC_FLAG_WHOLEADR)) {
        if (!check_limit_upstairs(sdp, offset, 10, SEG_IS_32BIT(sdp)))
            goto range_failure;
    }
    cpu_lmemorywrite_f(addr, value, CPU_PAGE_WRITE_DATA | CPU_STAT_USER_MODE);
    return;

range_failure:
    VERBOSE(("cpu_vmemorywrite_f: type = %d, offset = %08x, limit = %08x", sdp->type, offset, sdp->u.seg.limit));
    exc = CHOOSE_EXCEPTION(idx);
err:
    EXCEPTION(exc, 0);
}
示例#8
0
void
RETfar_pm(UINT nbytes)
{
    selector_t cs_sel, ss_sel, temp_sel;
    UINT32 sp;
    UINT32 new_ip, new_sp;
    UINT16 new_cs, new_ss;
    int rv;
    int i;

    VERBOSE(("RETfar_pm: old EIP = %04x:%08x, ESP = %04x:%08x, nbytes = %d", CPU_CS, CPU_PREV_EIP, CPU_SS, CPU_ESP, nbytes));

    if (CPU_STAT_SS32) {
        sp = CPU_ESP;
    } else {
        sp = CPU_SP;
    }
    if (CPU_INST_OP32) {
        STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 8);
        new_ip = cpu_vmemoryread_d(CPU_SS_INDEX, sp);
        new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4);
    } else {
        STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, nbytes + 4);
        new_ip = cpu_vmemoryread_w(CPU_SS_INDEX, sp);
        new_cs = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 2);
    }

    rv = parse_selector(&cs_sel, new_cs);
    if (rv < 0) {
        VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", cs_sel.selector, rv));
        EXCEPTION(GP_EXCEPTION, cs_sel.idx);
    }

    /* check segment type */
    if (!cs_sel.desc.s) {
        VERBOSE(("RETfar_pm: return to system segment"));
        EXCEPTION(GP_EXCEPTION, cs_sel.idx);
    }
    if (!cs_sel.desc.u.seg.c) {
        VERBOSE(("RETfar_pm: return to data segment"));
        EXCEPTION(GP_EXCEPTION, cs_sel.idx);
    }

    /* check privilege level */
    if (cs_sel.rpl < CPU_STAT_CPL) {
        VERBOSE(("RETfar_pm: RPL(%d) < CPL(%d)", cs_sel.rpl, CPU_STAT_CPL));
        EXCEPTION(GP_EXCEPTION, cs_sel.idx);
    }
    if (!cs_sel.desc.u.seg.ec && (cs_sel.desc.dpl > cs_sel.rpl)) {
        VERBOSE(("RETfar_pm: NON-COMFORMING-CODE-SEGMENT and DPL(%d) > RPL(%d)", cs_sel.desc.dpl, cs_sel.rpl));
        EXCEPTION(GP_EXCEPTION, cs_sel.idx);
    }

    /* not present */
    if (selector_is_not_present(&cs_sel)) {
        VERBOSE(("RETfar_pm: returned code segment is not present"));
        EXCEPTION(NP_EXCEPTION, cs_sel.idx);
    }

    if (cs_sel.rpl == CPU_STAT_CPL) {
        VERBOSE(("RETfar_pm: RETURN-TO-SAME-PRIVILEGE-LEVEL"));

        /* check code segment limit */
        if (new_ip > cs_sel.desc.u.seg.limit) {
            VERBOSE(("RETfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit));
            EXCEPTION(GP_EXCEPTION, 0);
        }

        VERBOSE(("RETfar_pm: new_ip = %08x, new_cs = %04x", new_ip, cs_sel.selector));

        if (CPU_INST_OP32) {
            nbytes += 8;
        } else {
            nbytes += 4;
        }
        if (CPU_STAT_SS32) {
            CPU_ESP += nbytes;
        } else {
            CPU_SP += (UINT16)nbytes;
        }

        load_cs(cs_sel.selector, &cs_sel.desc, CPU_STAT_CPL);
        SET_EIP(new_ip);
    } else {
        VERBOSE(("RETfar_pm: RETURN-OUTER-PRIVILEGE-LEVEL"));

        if (CPU_INST_OP32) {
            STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 8 + 8 + nbytes);
            new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 8 + nbytes);
            new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 8 + nbytes + 4);
        } else {
            STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 4 + 4 + nbytes);
            new_sp = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4 + nbytes);
            new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 4 + nbytes + 2);
        }

        rv = parse_selector(&ss_sel, new_ss);
        if (rv < 0) {
            VERBOSE(("RETfar_pm: parse_selector (selector = %04x, rv = %d, %s)", ss_sel.selector, rv));
            EXCEPTION(GP_EXCEPTION, ss_sel.idx);
        }

        /* check stack segment descriptor */
        if (!ss_sel.desc.s) {
            VERBOSE(("RETfar_pm: stack segment is system segment"));
            EXCEPTION(GP_EXCEPTION, cs_sel.idx);
        }
        if (ss_sel.desc.u.seg.c) {
            VERBOSE(("RETfar_pm: stack segment is code segment"));
            EXCEPTION(GP_EXCEPTION, cs_sel.idx);
        }
        if (!ss_sel.desc.u.seg.wr) {
            VERBOSE(("RETfar_pm: stack segment is read-only data segment"));
            EXCEPTION(GP_EXCEPTION, cs_sel.idx);
        }

        /* check privilege level */
        if (ss_sel.rpl != cs_sel.rpl) {
            VERBOSE(("RETfar_pm: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, cs_sel.rpl));
            EXCEPTION(GP_EXCEPTION, cs_sel.idx);
        }
        if (ss_sel.desc.dpl != cs_sel.rpl) {
            VERBOSE(("RETfar_pm: DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, cs_sel.rpl));
            EXCEPTION(GP_EXCEPTION, cs_sel.idx);
        }

        /* not present */
        if (selector_is_not_present(&ss_sel)) {
            VERBOSE(("RETfar_pm: stack segment is not present"));
            EXCEPTION(SS_EXCEPTION, ss_sel.idx);
        }

        /* check code segment limit */
        if (new_ip > cs_sel.desc.u.seg.limit) {
            VERBOSE(("RETfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit));
            EXCEPTION(GP_EXCEPTION, 0);
        }

        VERBOSE(("RETfar_pm: new_ip = %08x, new_cs = %04x", new_ip, cs_sel.selector));
        VERBOSE(("RETfar_pm: new_sp = %08x, new_ss = %04x", new_sp, ss_sel.selector));

        load_cs(cs_sel.selector, &cs_sel.desc, cs_sel.rpl);
        SET_EIP(new_ip);

        load_ss(ss_sel.selector, &ss_sel.desc, cs_sel.rpl);
        if (CPU_STAT_SS32) {
            CPU_ESP = new_sp + nbytes;
        } else {
            CPU_SP = (UINT16)(new_sp + nbytes);
        }

        /* check segment register */
        for (i = 0; i < CPU_SEGREG_NUM; i++) {
            descriptor_t *dp;
            BOOL valid;

            dp = &CPU_STAT_SREG(i);
            if ((!dp->u.seg.c || !dp->u.seg.ec)
                    && (CPU_STAT_SREG(i).dpl < CPU_STAT_CPL)) {
                /* segment register is invalid */
                CPU_REGS_SREG(i) = 0;
                CPU_STAT_SREG_CLEAR(i);
                continue;
            }

            rv = parse_selector(&temp_sel, CPU_REGS_SREG(i));
            if (rv < 0) {
                /* segment register is invalid */
                CPU_REGS_SREG(i) = 0;
                CPU_STAT_SREG_CLEAR(i);
                continue;
            }

            valid = TRUE;
            if (!temp_sel.desc.s) {
                /* system segment */
                valid = FALSE;
            }
            if (temp_sel.desc.u.seg.c && !temp_sel.desc.u.seg.wr) {
                /* execute-only code segment */
                valid = FALSE;
            }
            if (!temp_sel.desc.u.seg.c || !temp_sel.desc.u.seg.ec) {
                if (CPU_STAT_CPL > temp_sel.desc.dpl) {
                    valid = FALSE;
                }
            }

            if (!valid) {
                /* segment register is invalid */
                CPU_REGS_SREG(i) = 0;
                CPU_STAT_SREG(i).valid = 0;
            }
        }
    }

    VERBOSE(("RETfar_pm: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP));
}
示例#9
0
/*---
 * CALLfar_pm: code segment
 */
static void
CALLfar_pm_code_segment(const selector_t *cs_sel, UINT32 new_ip)
{
    UINT32 sp;

    VERBOSE(("CALLfar_pm: CODE-SEGMENT"));

    /* check privilege level */
    if (!cs_sel->desc.u.seg.ec) {
        VERBOSE(("CALLfar_pm: NON-CONFORMING-CODE-SEGMENT"));
        /* 下巻 p.119 4.8.1.1. */
        if (cs_sel->rpl > CPU_STAT_CPL) {
            VERBOSE(("CALLfar_pm: RPL(%d) > CPL(%d)", cs_sel->rpl, CPU_STAT_CPL));
            EXCEPTION(GP_EXCEPTION, cs_sel->idx);
        }
        if (cs_sel->desc.dpl != CPU_STAT_CPL) {
            VERBOSE(("CALLfar_pm: DPL(%d) != CPL(%d)", cs_sel->desc.dpl, CPU_STAT_CPL));
            EXCEPTION(GP_EXCEPTION, cs_sel->idx);
        }
    } else {
        VERBOSE(("CALLfar_pm: CONFORMING-CODE-SEGMENT"));
        /* 下巻 p.120 4.8.1.2. */
        if (cs_sel->desc.dpl > CPU_STAT_CPL) {
            VERBOSE(("CALLfar_pm: DPL(%d) > CPL(%d)", cs_sel->desc.dpl, CPU_STAT_CPL));
            EXCEPTION(GP_EXCEPTION, cs_sel->idx);
        }
    }

    /* not present */
    if (selector_is_not_present(cs_sel)) {
        VERBOSE(("CALLfar_pm: selector is not present"));
        EXCEPTION(NP_EXCEPTION, cs_sel->idx);
    }

    if (CPU_STAT_SS32) {
        sp = CPU_ESP;
    } else {
        sp = CPU_SP;
    }
    if (CPU_INST_OP32) {
        STACK_PUSH_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 8);

        /* out of range */
        if (new_ip > cs_sel->desc.u.seg.limit) {
            VERBOSE(("CALLfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel->desc.u.seg.limit));
            EXCEPTION(GP_EXCEPTION, 0);
        }

        PUSH0_32(CPU_CS);
        PUSH0_32(CPU_EIP);
    } else {
        STACK_PUSH_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 4);

        /* out of range */
        if (new_ip > cs_sel->desc.u.seg.limit) {
            VERBOSE(("CALLfar_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel->desc.u.seg.limit));
            EXCEPTION(GP_EXCEPTION, 0);
        }

        PUSH0_16(CPU_CS);
        PUSH0_16(CPU_IP);
    }

    load_cs(cs_sel->selector, &cs_sel->desc, CPU_STAT_CPL);
    SET_EIP(new_ip);
}
示例#10
0
/*---
 * IRET_pm: OUTER-PRIVILEGE
 */
static void
IRET_pm_protected_mode_return_outer_privilege(const selector_t *cs_sel, UINT32 new_ip, UINT32 new_flags)
{
    descriptor_t *dp;
    selector_t ss_sel;
    UINT32 mask;
    UINT32 sp;
    UINT32 new_sp;
    UINT16 new_ss;
    int rv;
    int i;

    VERBOSE(("IRET_pm: RETURN-OUTER-PRIVILEGE-LEVEL"));

    if (CPU_STAT_SS32) {
        sp = CPU_ESP;
    } else {
        sp = CPU_SP;
    }
    if (CPU_INST_OP32) {
        STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 20);
        new_sp = cpu_vmemoryread_d(CPU_SS_INDEX, sp + 12);
        new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 16);
    } else {
        STACK_POP_CHECK(CPU_REGS_SREG(CPU_SS_INDEX), &CPU_STAT_SREG(CPU_SS_INDEX), sp, 10);
        new_sp = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 6);
        new_ss = cpu_vmemoryread_w(CPU_SS_INDEX, sp + 8);
    }
    VERBOSE(("IRET_pm: new_sp = 0x%08x, new_ss = 0x%04x", new_sp, new_ss));

    rv = parse_selector(&ss_sel, new_ss);
    if (rv < 0) {
        VERBOSE(("IRET_pm: parse_selector (selector = %04x, rv = %d)", ss_sel.selector, rv));
        EXCEPTION(GP_EXCEPTION, ss_sel.idx);
    }

    /* check privilege level */
    if (ss_sel.rpl != cs_sel->rpl) {
        VERBOSE(("IRET_pm: RPL[SS](%d) != RPL[CS](%d)", ss_sel.rpl, cs_sel->rpl));
        EXCEPTION(GP_EXCEPTION, ss_sel.idx);
    }
    if (ss_sel.desc.dpl != cs_sel->rpl) {
        VERBOSE(("IRET_pm: DPL[SS](%d) != RPL[CS](%d)", ss_sel.desc.dpl, cs_sel->rpl));
        EXCEPTION(GP_EXCEPTION, ss_sel.idx);
    }

    /* check stack segment descriptor */
    if (!ss_sel.desc.s) {
        VERBOSE(("IRET_pm: stack segment is system segment"));
        EXCEPTION(GP_EXCEPTION, ss_sel.idx);
    }
    if (ss_sel.desc.u.seg.c) {
        VERBOSE(("IRET_pm: stack segment is code segment"));
        EXCEPTION(GP_EXCEPTION, ss_sel.idx);
    }
    if (!ss_sel.desc.u.seg.wr) {
        VERBOSE(("IRET_pm: stack segment is read-only data segment"));
        EXCEPTION(GP_EXCEPTION, ss_sel.idx);
    }

    /* not present */
    if (selector_is_not_present(&ss_sel)) {
        VERBOSE(("IRET_pm: stack segment is not present"));
        EXCEPTION(SS_EXCEPTION, ss_sel.idx);
    }

    /* check code segment limit */
    if (new_ip > cs_sel->desc.u.seg.limit) {
        VERBOSE(("IRET_pm: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel->desc.u.seg.limit));
        EXCEPTION(GP_EXCEPTION, 0);
    }

    mask = 0;
    if (CPU_INST_OP32)
        mask |= RF_FLAG;
    if (CPU_STAT_CPL <= CPU_STAT_IOPL)
        mask |= I_FLAG;
    if (CPU_STAT_CPL == 0) {
        mask |= IOPL_FLAG;
        if (CPU_INST_OP32) {
            mask |= VM_FLAG|VIF_FLAG|VIP_FLAG;
        }
    }

    /* set new register */
    load_cs(cs_sel->selector, &cs_sel->desc, cs_sel->rpl);
    SET_EIP(new_ip);

    set_eflags(new_flags, mask);

    load_ss(ss_sel.selector, &ss_sel.desc, cs_sel->rpl);
    if (CPU_STAT_SS32) {
        CPU_ESP = new_sp;
    } else {
        CPU_SP = (UINT16)new_sp;
    }

    /* check segment register */
    for (i = 0; i < CPU_SEGREG_NUM; i++) {
        if ((i != CPU_CS_INDEX) && (i != CPU_SS_INDEX)) {
            dp = &CPU_STAT_SREG(i);
            if ((!dp->u.seg.c || !dp->u.seg.ec)
                    && (CPU_STAT_SREG(i).dpl < CPU_STAT_CPL)) {
                /* segment register is invalid */
                CPU_REGS_SREG(i) = 0;
                CPU_STAT_SREG_CLEAR(i);
            }
        }
    }
}
示例#11
0
static void CPUCALL
interrupt_intr_or_trap(const descriptor_t *gsdp, int intrtype, int errorp, int error_code)
{
    selector_t cs_sel, ss_sel;
    UINT stacksize;
    UINT32 old_flags;
    UINT32 new_flags;
    UINT32 mask;
    UINT32 sp;
    UINT32 new_ip, new_sp;
    UINT32 old_ip, old_sp;
    UINT16 old_cs, old_ss, new_ss;
    BOOL is32bit;
    int exc_errcode;
    int rv;

    new_ip = gsdp->u.gate.offset;
    old_ss = CPU_SS;
    old_cs = CPU_CS;
    old_ip = CPU_EIP;
    old_sp = CPU_ESP;
    old_flags = REAL_EFLAGREG;
    new_flags = REAL_EFLAGREG & ~(T_FLAG|RF_FLAG|NT_FLAG|VM_FLAG);
    mask = T_FLAG|RF_FLAG|NT_FLAG|VM_FLAG;

    switch (gsdp->type) {
    case CPU_SYSDESC_TYPE_INTR_16:
    case CPU_SYSDESC_TYPE_INTR_32:
        VERBOSE(("interrupt: INTERRUPT-GATE"));
        new_flags &= ~I_FLAG;
        mask |= I_FLAG;
        break;

    case CPU_SYSDESC_TYPE_TRAP_16:
    case CPU_SYSDESC_TYPE_TRAP_32:
        VERBOSE(("interrupt: TRAP-GATE"));
        break;

    default:
        ia32_panic("interrupt: gate descriptor type is invalid (type = %d)", gsdp->type);
        break;
    }

    exc_errcode = gsdp->u.gate.selector & ~3;
    if (intrtype == INTR_TYPE_EXTINTR)
        exc_errcode++;

    rv = parse_selector(&cs_sel, gsdp->u.gate.selector);
    if (rv < 0) {
        VERBOSE(("interrupt: parse_selector (selector = %04x, rv = %d)", gsdp->u.gate.selector, rv));
        EXCEPTION(GP_EXCEPTION, exc_errcode);
    }

    /* check segment type */
    if (SEG_IS_SYSTEM(&cs_sel.desc)) {
        VERBOSE(("interrupt: code segment is system segment"));
        EXCEPTION(GP_EXCEPTION, exc_errcode);
    }
    if (SEG_IS_DATA(&cs_sel.desc)) {
        VERBOSE(("interrupt: code segment is data segment"));
        EXCEPTION(GP_EXCEPTION, exc_errcode);
    }

    /* check privilege level */
    if (cs_sel.desc.dpl > CPU_STAT_CPL) {
        VERBOSE(("interrupt: DPL(%d) > CPL(%d)", cs_sel.desc.dpl, CPU_STAT_CPL));
        EXCEPTION(GP_EXCEPTION, exc_errcode);
    }

    /* not present */
    if (selector_is_not_present(&cs_sel)) {
        VERBOSE(("interrupt: selector is not present"));
        EXCEPTION(NP_EXCEPTION, exc_errcode);
    }

    is32bit = gsdp->type & CPU_SYSDESC_TYPE_32BIT;
    if (!SEG_IS_CONFORMING_CODE(&cs_sel.desc) && (cs_sel.desc.dpl < CPU_STAT_CPL)) {
        stacksize = errorp ? 12 : 10;
        if (!CPU_STAT_VM86) {
            VERBOSE(("interrupt: INTER-PRIVILEGE-LEVEL-INTERRUPT"));
        } else {
            /* VM86 */
            VERBOSE(("interrupt: INTERRUPT-FROM-VIRTUAL-8086-MODE"));
            if (cs_sel.desc.dpl != 0) {
                /* 16.3.1.1 */
                VERBOSE(("interrupt: DPL[CS](%d) != 0", cs_sel.desc.dpl));
                EXCEPTION(GP_EXCEPTION, exc_errcode);
            }
            stacksize += 8;
        }
        if (is32bit) {
            stacksize *= 2;
        }

        /* get stack pointer from TSS */
        get_stack_pointer_from_tss(cs_sel.desc.dpl, &new_ss, &new_sp);

        /* parse stack segment descriptor */
        rv = parse_selector(&ss_sel, new_ss);

        /* update exception error code */
        exc_errcode = ss_sel.idx;
        if (intrtype == INTR_TYPE_EXTINTR)
            exc_errcode++;

        if (rv < 0) {
            VERBOSE(("interrupt: parse_selector (selector = %04x, rv = %d)", new_ss, rv));
            EXCEPTION(TS_EXCEPTION, exc_errcode);
        }

        /* check privilege level */
        if (ss_sel.rpl != cs_sel.desc.dpl) {
            VERBOSE(("interrupt: selector RPL[SS](%d) != DPL[CS](%d)", ss_sel.rpl, cs_sel.desc.dpl));
            EXCEPTION(TS_EXCEPTION, exc_errcode);
        }
        if (ss_sel.desc.dpl != cs_sel.desc.dpl) {
            VERBOSE(("interrupt: descriptor DPL[SS](%d) != DPL[CS](%d)", ss_sel.desc.dpl, cs_sel.desc.dpl));
            EXCEPTION(TS_EXCEPTION, exc_errcode);
        }

        /* stack segment must be writable data segment. */
        if (SEG_IS_SYSTEM(&ss_sel.desc)) {
            VERBOSE(("interrupt: stack segment is system segment"));
            EXCEPTION(TS_EXCEPTION, exc_errcode);
        }
        if (SEG_IS_CODE(&ss_sel.desc)) {
            VERBOSE(("interrupt: stack segment is code segment"));
            EXCEPTION(TS_EXCEPTION, exc_errcode);
        }
        if (!SEG_IS_WRITABLE_DATA(&ss_sel.desc)) {
            VERBOSE(("interrupt: stack segment is read-only data segment"));
            EXCEPTION(TS_EXCEPTION, exc_errcode);
        }

        /* not present */
        if (selector_is_not_present(&ss_sel)) {
            VERBOSE(("interrupt: selector is not present"));
            EXCEPTION(SS_EXCEPTION, exc_errcode);
        }

        /* check stack room size */
        cpu_stack_push_check(ss_sel.idx, &ss_sel.desc, new_sp, stacksize, ss_sel.desc.d);

        /* out of range */
        if (new_ip > cs_sel.desc.u.seg.limit) {
            VERBOSE(("interrupt: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit));
            EXCEPTION(GP_EXCEPTION, 0);
        }

        load_ss(ss_sel.selector, &ss_sel.desc, cs_sel.desc.dpl);
        CPU_ESP = new_sp;

        load_cs(cs_sel.selector, &cs_sel.desc, cs_sel.desc.dpl);
        CPU_EIP = new_ip;

        if (is32bit) {
            if (CPU_STAT_VM86) {
                PUSH0_32(CPU_GS);
                PUSH0_32(CPU_FS);
                PUSH0_32(CPU_DS);
                PUSH0_32(CPU_ES);

                LOAD_SEGREG(CPU_GS_INDEX, 0);
                CPU_STAT_SREG(CPU_GS_INDEX).valid = 0;
                LOAD_SEGREG(CPU_FS_INDEX, 0);
                CPU_STAT_SREG(CPU_FS_INDEX).valid = 0;
                LOAD_SEGREG(CPU_DS_INDEX, 0);
                CPU_STAT_SREG(CPU_DS_INDEX).valid = 0;
                LOAD_SEGREG(CPU_ES_INDEX, 0);
                CPU_STAT_SREG(CPU_ES_INDEX).valid = 0;
            }
            PUSH0_32(old_ss);
            PUSH0_32(old_sp);
            PUSH0_32(old_flags);
            PUSH0_32(old_cs);
            PUSH0_32(old_ip);
            if (errorp) {
                PUSH0_32(error_code);
            }
        } else {
            if (CPU_STAT_VM86) {
                ia32_panic("interrupt: 16bit gate && VM86");
            }
            PUSH0_16(old_ss);
            PUSH0_16(old_sp);
            PUSH0_16(old_flags);
            PUSH0_16(old_cs);
            PUSH0_16(old_ip);
            if (errorp) {
                PUSH0_16(error_code);
            }
        }
    } else {
        if (CPU_STAT_VM86) {
            VERBOSE(("interrupt: VM86"));
            EXCEPTION(GP_EXCEPTION, exc_errcode);
        }
        if (!SEG_IS_CONFORMING_CODE(&cs_sel.desc) && (cs_sel.desc.dpl != CPU_STAT_CPL)) {
            VERBOSE(("interrupt: %sCONFORMING-CODE-SEGMENT(%d) && DPL[CS](%d) != CPL", SEG_IS_CONFORMING_CODE(&cs_sel.desc) ? "" : "NON-", cs_sel.desc.dpl, CPU_STAT_CPL));
            EXCEPTION(GP_EXCEPTION, exc_errcode);
        }

        VERBOSE(("interrupt: INTRA-PRIVILEGE-LEVEL-INTERRUPT"));

        stacksize = errorp ? 8 : 6;
        if (is32bit) {
            stacksize *= 2;
        }

        /* check stack room size */
        if (CPU_STAT_SS32) {
            sp = CPU_ESP;
        } else {
            sp = CPU_SP;
        }
        /*
         * 17.1
         * コールゲート、割り込みゲート、またはトラップゲートを通じて
         * プログラムの制御を他のコード・セグメントに移行するときは、
         * 移行中に使用されるオペランド・サイズは使用されるゲートの
         * タイプ(16 ビットまたは32 ビット)によって決まる(移行命
         * 令のD フラグ、プリフィックスのいずれにもよらない)。
         */
        SS_PUSH_CHECK1(sp, stacksize, is32bit);

        /* out of range */
        if (new_ip > cs_sel.desc.u.seg.limit) {
            VERBOSE(("interrupt: new_ip is out of range. new_ip = %08x, limit = %08x", new_ip, cs_sel.desc.u.seg.limit));
            EXCEPTION(GP_EXCEPTION, 0);
        }

        load_cs(cs_sel.selector, &cs_sel.desc, CPU_STAT_CPL);
        CPU_EIP = new_ip;

        if (is32bit) {
            PUSH0_32(old_flags);
            PUSH0_32(old_cs);
            PUSH0_32(old_ip);
            if (errorp) {
                PUSH0_32(error_code);
            }
        } else {
            PUSH0_16(old_flags);
            PUSH0_16(old_cs);
            PUSH0_16(old_ip);
            if (errorp) {
                PUSH0_16(error_code);
            }
        }
    }
    set_eflags(new_flags, mask);

    VERBOSE(("interrupt: new EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP));
}