--- np2/i386c/ia32/instructions/system_inst.c 2004/01/07 14:50:21 1.4 +++ np2/i386c/ia32/instructions/system_inst.c 2011/01/15 17:17:23 1.34 @@ -1,5 +1,3 @@ -/* $Id: system_inst.c,v 1.4 2004/01/07 14:50:21 monaka Exp $ */ - /* * Copyright (c) 2003 NONAKA Kimihiro * All rights reserved. @@ -12,8 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -35,87 +31,51 @@ void -LGDT16_Ms(DWORD op) +LGDT_Ms(UINT32 op) { - DWORD madr; - DWORD base; - WORD limit; + UINT32 madr; + UINT32 base; + UINT16 limit; if (op < 0xc0) { - if (!CPU_STAT_PM || !CPU_STAT_VM86 || CPU_STAT_CPL == 0) { + if (!CPU_STAT_PM || (CPU_STAT_CPL == 0 && !CPU_STAT_VM86)) { CPU_WORKCLOCK(11); - madr = get_ea(op); - limit = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); - base = cpu_vmemoryread_d(CPU_INST_SEGREG_INDEX, madr + 2); - base &= 0x00ffffff; - - VERBOSE(("LGDT16_Ms: GDTR_BASE = 0x%08x, GDTR_LIMIT = 0x%04x", base, limit)); - - CPU_GDTR_BASE = base; - CPU_GDTR_LIMIT = limit; - return; - } - EXCEPTION(GP_EXCEPTION, 0); - } - EXCEPTION(UD_EXCEPTION, 0); -} - -void -LGDT32_Ms(DWORD op) -{ - DWORD madr; - DWORD base; - WORD limit; - - if (op < 0xc0) { - if (!CPU_STAT_PM || !CPU_STAT_VM86 || CPU_STAT_CPL == 0) { - CPU_WORKCLOCK(11); - madr = get_ea(op); + madr = calc_ea_dst(op); limit = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); base = cpu_vmemoryread_d(CPU_INST_SEGREG_INDEX, madr + 2); + if (!CPU_INST_OP32) { + base &= 0x00ffffff; + } - VERBOSE(("LGDT32_Ms: GDTR_BASE = 0x%08x, GDTR_LIMIT = 0x%04x", base, limit)); +#if defined(MORE_DEBUG) + gdtr_dump(base, limit); +#endif CPU_GDTR_BASE = base; CPU_GDTR_LIMIT = limit; return; } + VERBOSE(("LGDT: VM86(%s) or CPL(%d) != 0", CPU_STAT_VM86 ? "true" : "false", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } EXCEPTION(UD_EXCEPTION, 0); } void -SGDT16_Ms(DWORD op) +SGDT_Ms(UINT32 op) { - DWORD madr; - DWORD base; - WORD limit; + UINT32 madr; + UINT32 base; + UINT16 limit; if (op < 0xc0) { CPU_WORKCLOCK(11); - base = CPU_GDTR_BASE & 0x00ffffff; limit = CPU_GDTR_LIMIT; - madr = get_ea(op); - cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, limit); - cpu_vmemorywrite_d(CPU_INST_SEGREG_INDEX, madr + 2, base); - return; - } - EXCEPTION(UD_EXCEPTION, 0); -} - -void -SGDT32_Ms(DWORD op) -{ - DWORD madr; - DWORD base; - WORD limit; - - if (op < 0xc0) { - CPU_WORKCLOCK(11); base = CPU_GDTR_BASE; - limit = CPU_GDTR_LIMIT; - madr = get_ea(op); + if (!CPU_INST_OP32) { + base &= 0x00ffffff; + } + madr = calc_ea_dst(op); cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, limit); cpu_vmemorywrite_d(CPU_INST_SEGREG_INDEX, madr + 2, base); return; @@ -124,9 +84,10 @@ SGDT32_Ms(DWORD op) } void -LLDT_Ew(DWORD op) +LLDT_Ew(UINT32 op) { - DWORD src, madr; + UINT32 madr; + UINT16 src; if (CPU_STAT_PM && !CPU_STAT_VM86) { if (CPU_STAT_CPL == 0) { @@ -141,53 +102,44 @@ LLDT_Ew(DWORD op) load_ldtr(src, GP_EXCEPTION); return; } + VERBOSE(("LLDT: CPL(%d) != 0", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } + VERBOSE(("LLDT: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } void -SLDT_Ew(DWORD op) +SLDT_Ew(UINT32 op) { - DWORD madr; + UINT32 madr; + UINT16 ldtr; if (CPU_STAT_PM && !CPU_STAT_VM86) { + ldtr = CPU_LDTR; if (op >= 0xc0) { CPU_WORKCLOCK(5); - *(reg16_b20[op]) = CPU_LDTR; - } else { - CPU_WORKCLOCK(11); - madr = calc_ea_dst(op); - cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, CPU_LDTR); - } - return; - } - EXCEPTION(UD_EXCEPTION, 0); -} - -void -SLDT_Ed(DWORD op) -{ - DWORD madr; - - if (CPU_STAT_PM && !CPU_STAT_VM86) { - if (op >= 0xc0) { - CPU_WORKCLOCK(5); - *(reg32_b20[op]) = CPU_LDTR; + if (CPU_INST_OP32) { + *(reg32_b20[op]) = ldtr; + } else { + *(reg16_b20[op]) = ldtr; + } } else { CPU_WORKCLOCK(11); madr = calc_ea_dst(op); - cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, CPU_LDTR); + cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, ldtr); } return; } + VERBOSE(("SLDT: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } void -LTR_Ew(DWORD op) +LTR_Ew(UINT32 op) { - DWORD src, madr; + UINT32 madr; + UINT16 src; if (CPU_STAT_PM && !CPU_STAT_VM86) { if (CPU_STAT_CPL == 0) { @@ -202,111 +154,85 @@ LTR_Ew(DWORD op) load_tr(src); return; } + VERBOSE(("LTR: CPL(%d) != 0", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } + VERBOSE(("LTR: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } void -STR_Ew(DWORD op) -{ - DWORD madr; - - if (op >= 0xc0) { - CPU_WORKCLOCK(5); - *(reg16_b20[op]) = CPU_TR; - } else { - CPU_WORKCLOCK(11); - madr = calc_ea_dst(op); - cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, CPU_TR); - } -} - -void -STR_Ed(DWORD op) -{ - DWORD madr; - - if (op >= 0xc0) { - CPU_WORKCLOCK(5); - *(reg32_b20[op]) = CPU_TR; - } else { - CPU_WORKCLOCK(11); - madr = calc_ea_dst(op); - cpu_vmemorywrite_d(CPU_INST_SEGREG_INDEX, madr, CPU_TR); - } -} - -void -LIDT16_Ms(DWORD op) +STR_Ew(UINT32 op) { - DWORD madr; - DWORD base; - WORD limit; + UINT32 madr; + UINT16 tr; - if (op < 0xc0) { - CPU_WORKCLOCK(11); - madr = get_ea(op); - limit = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); - base = cpu_vmemoryread_d(CPU_INST_SEGREG_INDEX, madr + 2); - base &= 0x00ffffff; - CPU_IDTR_BASE = base; - CPU_IDTR_LIMIT = limit; + if (CPU_STAT_PM && !CPU_STAT_VM86) { + tr = CPU_TR; + if (op >= 0xc0) { + CPU_WORKCLOCK(5); + if (CPU_INST_OP32) { + *(reg32_b20[op]) = tr; + } else { + *(reg16_b20[op]) = tr; + } + } else { + CPU_WORKCLOCK(11); + madr = calc_ea_dst(op); + cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, tr); + } return; } + VERBOSE(("STR: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } void -LIDT32_Ms(DWORD op) +LIDT_Ms(UINT32 op) { - DWORD madr; - DWORD base; - WORD limit; + UINT32 madr; + UINT32 base; + UINT16 limit; if (op < 0xc0) { - CPU_WORKCLOCK(11); - madr = get_ea(op); - limit = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); - base = cpu_vmemoryread_d(CPU_INST_SEGREG_INDEX, madr + 2); - CPU_IDTR_BASE = base; - CPU_IDTR_LIMIT = limit; - return; - } - EXCEPTION(UD_EXCEPTION, 0); -} + if (!CPU_STAT_PM || (CPU_STAT_CPL == 0 && !CPU_STAT_VM86)) { + CPU_WORKCLOCK(11); + madr = calc_ea_dst(op); + limit = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); + base = cpu_vmemoryread_d(CPU_INST_SEGREG_INDEX, madr + 2); + if (!CPU_INST_OP32) { + base &= 0x00ffffff; + } -void -SIDT16_Ms(DWORD op) -{ - DWORD madr; - DWORD base; - WORD limit; +#if defined(MORE_DEBUG) + idtr_dump(base, limit); +#endif - if (op < 0xc0) { - CPU_WORKCLOCK(11); - base = CPU_IDTR_BASE & 0x00ffffff; - limit = CPU_IDTR_LIMIT; - madr = get_ea(op); - cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, limit); - cpu_vmemorywrite_d(CPU_INST_SEGREG_INDEX, madr + 2, base); - return; + CPU_IDTR_BASE = base; + CPU_IDTR_LIMIT = limit; + return; + } + VERBOSE(("LIDT: VM86(%s) or CPL(%d) != 0", CPU_STAT_VM86 ? "true" : "false", CPU_STAT_CPL)); + EXCEPTION(GP_EXCEPTION, 0); } EXCEPTION(UD_EXCEPTION, 0); } void -SIDT32_Ms(DWORD op) +SIDT_Ms(UINT32 op) { - DWORD madr; - DWORD base; - WORD limit; + UINT32 madr; + UINT32 base; + UINT16 limit; if (op < 0xc0) { CPU_WORKCLOCK(11); - base = CPU_IDTR_BASE; limit = CPU_IDTR_LIMIT; - madr = get_ea(op); + base = CPU_IDTR_BASE; + if (!CPU_INST_OP32) { + base &= 0x00ffffff; + } + madr = calc_ea_dst(op); cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, limit); cpu_vmemorywrite_d(CPU_INST_SEGREG_INDEX, madr + 2, base); return; @@ -317,19 +243,21 @@ SIDT32_Ms(DWORD op) void MOV_CdRd(void) { - DWORD op, src; - DWORD reg; + UINT32 op, src; + UINT32 reg; int idx; CPU_WORKCLOCK(11); GET_PCBYTE(op); if (op >= 0xc0) { if (CPU_STAT_PM && (CPU_STAT_VM86 || CPU_STAT_CPL != 0)) { + VERBOSE(("MOV_CdRd: VM86(%s) or CPL(%d) != 0", CPU_STAT_VM86 ? "true" : "false", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } src = *(reg32_b20[op]); idx = (op >> 3) & 7; + switch (idx) { case 0: /* CR0 */ /* @@ -347,7 +275,7 @@ MOV_CdRd(void) */ /* 下巻 p.182 割り込み 13 - 一般保護例外 */ - if ((src & (CPU_CR0_PE|CPU_CR0_PG)) == (DWORD)CPU_CR0_PG) { + if ((src & (CPU_CR0_PE|CPU_CR0_PG)) == (UINT32)CPU_CR0_PG) { EXCEPTION(GP_EXCEPTION, 0); } if ((src & (CPU_CR0_NW|CPU_CR0_CD)) == CPU_CR0_NW) { @@ -355,17 +283,18 @@ MOV_CdRd(void) } reg = CPU_CR0; - src &= 0xe005003f; -#ifndef USE_FPU - src &= ~CPU_CR0_ET; /* FPU not present */ -#else + src &= CPU_CR0_ALL; +#if defined(USE_FPU) src |= CPU_CR0_ET; /* FPU present */ +#else + src |= CPU_CR0_EM | CPU_CR0_NE; + src &= ~(CPU_CR0_MP | CPU_CR0_ET); #endif CPU_CR0 = src; - VERBOSE(("cr0: 0x%08x -> 0x%08x", reg, CPU_CR0)); + VERBOSE(("MOV_CdRd: %04x:%08x: cr0: 0x%08x <- 0x%08x(%s)", CPU_CS, CPU_PREV_EIP, reg, CPU_CR0, reg32_str[op & 7])); if ((reg ^ CPU_CR0) & (CPU_CR0_PE|CPU_CR0_PG)) { - tlb_flush(FALSE); + tlb_flush(1); } if ((reg ^ CPU_CR0) & CPU_CR0_PE) { if (CPU_CR0 & CPU_CR0_PE) { @@ -384,12 +313,14 @@ MOV_CdRd(void) change_pm(0); } } + + CPU_STAT_WP = (CPU_CR0 & CPU_CR0_WP) ? 0x10 : 0; break; case 2: /* CR2 */ reg = CPU_CR2; CPU_CR2 = src; /* page fault linear address */ - VERBOSE(("cr2: 0x%08x -> 0x%08x", reg, CPU_CR2)); + VERBOSE(("MOV_CdRd: %04x:%08x: cr2: 0x%08x <- 0x%08x(%s)", CPU_CS, CPU_PREV_EIP, reg, CPU_CR2, reg32_str[op & 7])); break; case 3: /* CR3 */ @@ -399,9 +330,8 @@ MOV_CdRd(void) * 3 = PWT (page level write throgh) */ reg = CPU_CR3; - CPU_CR3 = src & 0xfffff018; - VERBOSE(("cr3: 0x%08x -> 0x%08x", reg, CPU_CR3)); - tlb_flush(FALSE); + set_cr3(src); + VERBOSE(("MOV_CdRd: %04x:%08x: cr3: 0x%08x <- 0x%08x(%s)", CPU_CS, CPU_PREV_EIP, reg, CPU_CR3, reg32_str[op & 7])); break; case 4: /* CR4 */ @@ -418,7 +348,11 @@ MOV_CdRd(void) * 1 = PVI (protected mode virtual interrupt) * 0 = VME (VM8086 mode extention) */ - reg = 0; /* allow */ + reg = 0 /* allow bit */ +#if (CPU_FEATURES & CPU_FEATURE_PGE) == CPU_FEATURE_PGE + | CPU_CR4_PGE +#endif + ; if (src & ~reg) { if (src & 0xfffffc00) { EXCEPTION(GP_EXCEPTION, 0); @@ -428,10 +362,10 @@ MOV_CdRd(void) reg = CPU_CR4; CPU_CR4 = src; - VERBOSE(("cr4: 0x%08x -> 0x%08x", reg, CPU_CR4)); + VERBOSE(("MOV_CdRd: %04x:%08x: cr4: 0x%08x <- 0x%08x(%s)", CPU_CS, CPU_PREV_EIP, reg, CPU_CR4, reg32_str[op & 7])); if ((reg ^ CPU_CR4) & (CPU_CR4_PSE|CPU_CR4_PGE|CPU_CR4_PAE)) { - tlb_flush(FALSE); + tlb_flush(1); } break; @@ -448,17 +382,22 @@ MOV_CdRd(void) void MOV_RdCd(void) { - DWORD *out; - DWORD op; + UINT32 *out; + UINT32 op; + int idx; CPU_WORKCLOCK(11); - PREPART_EA_REG32P(op, out); + GET_PCBYTE(op); if (op >= 0xc0) { if (CPU_STAT_PM && (CPU_STAT_VM86 || CPU_STAT_CPL != 0)) { + VERBOSE(("MOV_RdCd: VM86(%s) or CPL(%d) != 0", CPU_STAT_VM86 ? "true" : "false", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } - switch (op & 7) { + out = reg32_b20[op]; + idx = (op >> 3) & 7; + + switch (idx) { case 0: *out = CPU_CR0; break; @@ -476,69 +415,60 @@ MOV_RdCd(void) break; default: - ia32_panic("MOV_RdCd: CR reg index (%d)", op & 7); + ia32_panic("MOV_RdCd: CR reg index (%d)", idx); /*NOTREACHED*/ break; } + VERBOSE(("MOV_RdCd: %04x:%08x: cr%d: 0x%08x -> %s", CPU_CS, CPU_PREV_EIP, idx, *out, reg32_str[op & 7])); return; } EXCEPTION(UD_EXCEPTION, 0); } void -LMSW_Ew(DWORD op) +LMSW_Ew(UINT32 op) { - DWORD src, madr; - DWORD cr0; - - if (CPU_STAT_PM && CPU_STAT_CPL != 0) { - EXCEPTION(GP_EXCEPTION, 0); - } + UINT32 src, madr; + UINT32 cr0; - if (op >= 0xc0) { - CPU_WORKCLOCK(2); - src = *(reg16_b20[op]); - } else { - CPU_WORKCLOCK(3); - madr = calc_ea_dst(op); - src = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); - } - - cr0 = CPU_CR0; - CPU_CR0 &= ~0xe; /* can't switch back from protected mode */ - CPU_CR0 |= (src & 0xf); /* TS, EM, MP, PE */ - if (!(cr0 & CPU_CR0_PE) && (src & CPU_CR0_PE)) { - change_pm(1); /* switch to protected mode */ - } -} - -void -SMSW_Ew(DWORD op) -{ - DWORD madr; + if (!CPU_STAT_PM || CPU_STAT_CPL == 0) { + if (op >= 0xc0) { + CPU_WORKCLOCK(2); + src = *(reg16_b20[op]); + } else { + CPU_WORKCLOCK(3); + madr = calc_ea_dst(op); + src = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); + } - if (op >= 0xc0) { - CPU_WORKCLOCK(2); - *(reg16_b20[op]) = (WORD)CPU_CR0; - } else { - CPU_WORKCLOCK(3); - madr = calc_ea_dst(op); - cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, (WORD)CPU_CR0); + cr0 = CPU_CR0; + CPU_CR0 &= ~0xe; /* can't switch back from protected mode */ + CPU_CR0 |= (src & 0xf); /* TS, EM, MP, PE */ + if (!(cr0 & CPU_CR0_PE) && (src & CPU_CR0_PE)) { + change_pm(1); /* switch to protected mode */ + } + return; } + VERBOSE(("LMSW: CPL(%d) != 0", CPU_STAT_CPL)); + EXCEPTION(GP_EXCEPTION, 0); } void -SMSW_Ed(DWORD op) +SMSW_Ew(UINT32 op) { - DWORD madr; + UINT32 madr; if (op >= 0xc0) { CPU_WORKCLOCK(2); - *(reg32_b20[op]) = (WORD)CPU_CR0; + if (CPU_INST_OP32) { + *(reg32_b20[op]) = (UINT16)CPU_CR0; + } else { + *(reg16_b20[op]) = (UINT16)CPU_CR0; + } } else { CPU_WORKCLOCK(3); madr = calc_ea_dst(op); - cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, (WORD)CPU_CR0); + cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, (UINT16)CPU_CR0); } } @@ -546,8 +476,9 @@ void CLTS(void) { - CPU_WORKCLOCK(2); - if (CPU_STAT_PM && CPU_STAT_CPL != 0) { + CPU_WORKCLOCK(5); + if (CPU_STAT_PM && (CPU_STAT_VM86 || (CPU_STAT_CPL != 0))) { + VERBOSE(("CLTS: VM86(%s) or CPL(%d) != 0", CPU_STAT_VM86 ? "true" : "false", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } CPU_CR0 &= ~CPU_CR0_TS; @@ -556,28 +487,38 @@ CLTS(void) void ARPL_EwGw(void) { - DWORD op, src, dst, madr; + UINT32 op, madr; + UINT src, dst; if (CPU_STAT_PM && !CPU_STAT_VM86) { PREPART_EA_REG16(op, src); if (op >= 0xc0) { CPU_WORKCLOCK(2); dst = *(reg16_b20[op]); + if ((dst & 3) < (src & 3)) { + CPU_FLAGL |= Z_FLAG; + dst &= ~3; + dst |= (src & 3); + *(reg16_b20[op]) = (UINT16)dst; + } else { + CPU_FLAGL &= ~Z_FLAG; + } } else { CPU_WORKCLOCK(3); madr = calc_ea_dst(op); dst = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); - } - - if ((dst & 3) < (src & 3)) { - dst &= ~3; - dst |= (src & 3); - CPU_FLAGL |= Z_FLAG; - } else { - CPU_FLAGL &= ~Z_FLAG; + if ((dst & 3) < (src & 3)) { + CPU_FLAGL |= Z_FLAG; + dst &= ~3; + dst |= (src & 3); + cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, (UINT16)dst); + } else { + CPU_FLAGL &= ~Z_FLAG; + } } return; } + VERBOSE(("ARPL: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } @@ -588,10 +529,11 @@ void LAR_GwEw(void) { selector_t sel; - WORD *out; - DWORD op; + UINT16 *out; + UINT32 op; + UINT32 h; int rv; - WORD selector; + UINT16 selector; if (CPU_STAT_PM && !CPU_STAT_VM86) { PREPART_REG16_EA(op, selector, out, 5, 11); @@ -602,13 +544,19 @@ LAR_GwEw(void) return; } - if (sel.desc.s) { - if (!(sel.desc.u.seg.c && !sel.desc.u.seg.ec) && - ((sel.desc.dpl < CPU_STAT_CPL) || (sel.desc.dpl < sel.rpl))) { - CPU_FLAGL &= ~Z_FLAG; - return; + if (!SEG_IS_SYSTEM(&sel.desc)) { + /* code or data segment */ + if ((SEG_IS_DATA(&sel.desc) + || !SEG_IS_CONFORMING_CODE(&sel.desc))) { + /* data or non-conforming code segment */ + if ((sel.desc.dpl < CPU_STAT_CPL) + || (sel.desc.dpl < sel.rpl)) { + CPU_FLAGL &= ~Z_FLAG; + return; + } } } else { + /* system segment */ switch (sel.desc.type) { case CPU_SYSDESC_TYPE_TSS_16: case CPU_SYSDESC_TYPE_LDT: @@ -626,10 +574,12 @@ LAR_GwEw(void) } } - *out = sel.desc.h & 0xff00; + h = cpu_kmemoryread_d(sel.addr + 4); + *out = (UINT16)(h & 0xff00); CPU_FLAGL |= Z_FLAG; return; } + VERBOSE(("LAR: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } @@ -637,27 +587,34 @@ void LAR_GdEw(void) { selector_t sel; - DWORD *out; - DWORD op; + UINT32 *out; + UINT32 op; + UINT32 h; int rv; - WORD selector; + UINT32 selector; if (CPU_STAT_PM && !CPU_STAT_VM86) { PREPART_REG32_EA(op, selector, out, 5, 11); - rv = parse_selector(&sel, selector); + rv = parse_selector(&sel, (UINT16)selector); if (rv < 0) { CPU_FLAGL &= ~Z_FLAG; return; } - if (sel.desc.s) { - if (!(sel.desc.u.seg.c && !sel.desc.u.seg.ec) - && ((sel.desc.dpl < CPU_STAT_CPL) || (sel.desc.dpl < sel.rpl))) { - CPU_FLAGL &= ~Z_FLAG; - return; + if (!SEG_IS_SYSTEM(&sel.desc)) { + /* code or data segment */ + if ((SEG_IS_DATA(&sel.desc) + || !SEG_IS_CONFORMING_CODE(&sel.desc))) { + /* data or non-conforming code segment */ + if ((sel.desc.dpl < CPU_STAT_CPL) + || (sel.desc.dpl < sel.rpl)) { + CPU_FLAGL &= ~Z_FLAG; + return; + } } } else { + /* system segment */ switch (sel.desc.type) { case CPU_SYSDESC_TYPE_TSS_16: case CPU_SYSDESC_TYPE_LDT: @@ -675,10 +632,12 @@ LAR_GdEw(void) } } - *out = sel.desc.h & 0x00ffff00; /* 0x00fxff00, x? */ + h = cpu_kmemoryread_d(sel.addr + 4); + *out = h & 0x00ffff00; /* 0x00fxff00, x? */ CPU_FLAGL |= Z_FLAG; return; } + VERBOSE(("LAR: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } @@ -686,10 +645,10 @@ void LSL_GwEw(void) { selector_t sel; - WORD *out; - DWORD op; + UINT16 *out; + UINT32 op; int rv; - WORD selector; + UINT16 selector; if (CPU_STAT_PM && !CPU_STAT_VM86) { PREPART_REG16_EA(op, selector, out, 5, 11); @@ -700,13 +659,19 @@ LSL_GwEw(void) return; } - if (sel.desc.s) { - if (!(sel.desc.u.seg.c && !sel.desc.u.seg.ec) - && ((sel.desc.dpl < CPU_STAT_CPL) || (sel.desc.dpl < sel.rpl))) { - CPU_FLAGL &= ~Z_FLAG; - return; + if (!SEG_IS_SYSTEM(&sel.desc)) { + /* code or data segment */ + if ((SEG_IS_DATA(&sel.desc) + || !SEG_IS_CONFORMING_CODE(&sel.desc))) { + /* data or non-conforming code segment */ + if ((sel.desc.dpl < CPU_STAT_CPL) + || (sel.desc.dpl < sel.rpl)) { + CPU_FLAGL &= ~Z_FLAG; + return; + } } } else { + /* system segment */ switch (sel.desc.type) { case CPU_SYSDESC_TYPE_TSS_16: case CPU_SYSDESC_TYPE_LDT: @@ -721,10 +686,11 @@ LSL_GwEw(void) } } - *out = (WORD)sel.desc.u.seg.limit; + *out = (UINT16)sel.desc.u.seg.limit; CPU_FLAGL |= Z_FLAG; return; } + VERBOSE(("LSL: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } @@ -732,27 +698,33 @@ void LSL_GdEw(void) { selector_t sel; - DWORD *out; - DWORD op; + UINT32 *out; + UINT32 op; int rv; - WORD selector; + UINT32 selector; if (CPU_STAT_PM && !CPU_STAT_VM86) { PREPART_REG32_EA(op, selector, out, 5, 11); - rv = parse_selector(&sel, selector); + rv = parse_selector(&sel, (UINT16)selector); if (rv < 0) { CPU_FLAGL &= ~Z_FLAG; return; } - if (sel.desc.s) { - if (!(sel.desc.u.seg.c && !sel.desc.u.seg.ec) - && ((CPU_STAT_CPL > sel.desc.dpl) || (sel.rpl > sel.desc.dpl))) { - CPU_FLAGL &= ~Z_FLAG; - return; + if (!SEG_IS_SYSTEM(&sel.desc)) { + /* code or data segment */ + if ((SEG_IS_DATA(&sel.desc) + || !SEG_IS_CONFORMING_CODE(&sel.desc))) { + /* data or non-conforming code segment */ + if ((sel.desc.dpl < CPU_STAT_CPL) + || (sel.desc.dpl < sel.rpl)) { + CPU_FLAGL &= ~Z_FLAG; + return; + } } } else { + /* system segment */ switch (sel.desc.type) { case CPU_SYSDESC_TYPE_TSS_16: case CPU_SYSDESC_TYPE_LDT: @@ -771,16 +743,17 @@ LSL_GdEw(void) CPU_FLAGL |= Z_FLAG; return; } + VERBOSE(("LSL: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } void -VERR_Ew(DWORD op) +VERR_Ew(UINT32 op) { selector_t sel; - DWORD madr; + UINT32 madr; int rv; - WORD selector; + UINT16 selector; if (CPU_STAT_PM && !CPU_STAT_VM86) { if (op >= 0xc0) { @@ -799,34 +772,41 @@ VERR_Ew(DWORD op) } /* system segment */ - if (!sel.desc.s) { + if (SEG_IS_SYSTEM(&sel.desc)) { CPU_FLAGL &= ~Z_FLAG; return; } - /* non-conforming code segment && (CPL > DPL || RPL > DPL) */ - if ((sel.desc.u.seg.c && !sel.desc.u.seg.ec) - && ((CPU_STAT_CPL > sel.desc.dpl) || (sel.rpl > sel.desc.dpl))) { - CPU_FLAGL &= ~Z_FLAG; - return; + + /* data or non-conforming code segment */ + if ((SEG_IS_DATA(&sel.desc) + || !SEG_IS_CONFORMING_CODE(&sel.desc))) { + if ((sel.desc.dpl < CPU_STAT_CPL) + || (sel.desc.dpl < sel.rpl)) { + CPU_FLAGL &= ~Z_FLAG; + return; + } } /* code segment is not readable */ - if (sel.desc.u.seg.c && !sel.desc.u.seg.wr) { + if (SEG_IS_CODE(&sel.desc) + && !SEG_IS_READABLE_CODE(&sel.desc)) { CPU_FLAGL &= ~Z_FLAG; return; } + CPU_FLAGL |= Z_FLAG; return; } + VERBOSE(("VERR: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } void -VERW_Ew(DWORD op) +VERW_Ew(UINT32 op) { selector_t sel; - DWORD madr; + UINT32 madr; int rv; - WORD selector; + UINT16 selector; if (CPU_STAT_PM && !CPU_STAT_VM86) { if (op >= 0xc0) { @@ -845,12 +825,12 @@ VERW_Ew(DWORD op) } /* system segment || code segment */ - if (!sel.desc.s || sel.desc.u.seg.c) { + if (SEG_IS_SYSTEM(&sel.desc) || SEG_IS_CODE(&sel.desc)) { CPU_FLAGL &= ~Z_FLAG; return; } /* data segment is not writable */ - if (sel.desc.u.seg.c && !sel.desc.u.seg.wr) { + if (!SEG_IS_WRITABLE_DATA(&sel.desc)) { CPU_FLAGL &= ~Z_FLAG; return; } @@ -859,24 +839,126 @@ VERW_Ew(DWORD op) CPU_FLAGL &= ~Z_FLAG; return; } + CPU_FLAGL |= Z_FLAG; return; } + VERBOSE(("VERW: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } void MOV_DdRd(void) { + UINT32 src; + UINT op; + int idx; +#if defined(IA32_SUPPORT_DEBUG_REGISTER) + int i; +#endif + + CPU_WORKCLOCK(11); + GET_PCBYTE(op); + if (op >= 0xc0) { + if (CPU_STAT_PM && (CPU_STAT_VM86 || CPU_STAT_CPL != 0)) { + VERBOSE(("MOV_DdRd: VM86(%s) or CPL(%d) != 0", CPU_STAT_VM86 ? "true" : "false", CPU_STAT_CPL)); + EXCEPTION(GP_EXCEPTION, 0); + } + + if (CPU_DR7 & CPU_DR7_GD) { + CPU_DR6 |= CPU_DR6_BD; + CPU_DR7 &= ~CPU_DR7_GD; + EXCEPTION(DB_EXCEPTION, 0); + } + + src = *(reg32_b20[op]); + idx = (op >> 3) & 7; + + CPU_DR(idx) = src; + switch (idx) { + case 0: + case 1: + case 2: + case 3: + CPU_DR(idx) = src; + break; + + case 6: + CPU_DR6 = src; + break; - ia32_panic("MOV_DdRd: not implemented yet!"); + case 7: + CPU_DR7 = src; + CPU_STAT_BP = 0; +#if defined(IA32_SUPPORT_DEBUG_REGISTER) + for (i = 0; i < CPU_DEBUG_REG_INDEX_NUM; i++) { + if (CPU_DR7 & (CPU_DR7_L(i)|CPU_DR7_G(i))) { + CPU_STAT_BP |= (1 << i); + } + } +#endif /* IA32_SUPPORT_DEBUG_REGISTER */ + break; + + default: + ia32_panic("MOV_DdRd: DR reg index (%d)", idx); + /*NOTREACHED*/ + break; + } + + return; + } + EXCEPTION(UD_EXCEPTION, 0); } void MOV_RdDd(void) { + UINT32 *out; + UINT op; + int idx; + + CPU_WORKCLOCK(11); + GET_PCBYTE(op); + if (op >= 0xc0) { + if (CPU_STAT_PM && (CPU_STAT_VM86 || CPU_STAT_CPL != 0)) { + VERBOSE(("MOV_RdDd: VM86(%s) or CPL(%d) != 0", CPU_STAT_VM86 ? "true" : "false", CPU_STAT_CPL)); + EXCEPTION(GP_EXCEPTION, 0); + } + + if (CPU_DR7 & CPU_DR7_GD) { + CPU_DR6 |= CPU_DR6_BD; + CPU_DR7 &= ~CPU_DR7_GD; + EXCEPTION(DB_EXCEPTION, 0); + } + + out = reg32_b20[op]; + idx = (op >> 3) & 7; + + switch (idx) { + case 0: + case 1: + case 2: + case 3: + *out = CPU_DR(idx); + break; + + case 4: + case 6: + *out = (CPU_DR6 & 0x0000f00f) | 0xffff0ff0; + break; + + case 7: + *out = CPU_DR7; + break; - ia32_panic("MOV_DdRd: not implemented yet!"); + default: + ia32_panic("MOV_RdDd: DR reg index (%d)", idx); + /*NOTREACHED*/ + break; + } + return; + } + EXCEPTION(UD_EXCEPTION, 0); } void @@ -885,9 +967,9 @@ INVD(void) CPU_WORKCLOCK(11); if (CPU_STAT_PM && (CPU_STAT_VM86 || CPU_STAT_CPL != 0)) { + VERBOSE(("INVD: VM86(%s) or CPL(%d) != 0", CPU_STAT_VM86 ? "true" : "false", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } - /* nothing to do */ } void @@ -896,24 +978,48 @@ WBINVD(void) CPU_WORKCLOCK(11); if (CPU_STAT_PM && (CPU_STAT_VM86 || CPU_STAT_CPL != 0)) { + VERBOSE(("WBINVD: VM86(%s) or CPL(%d) != 0", CPU_STAT_VM86 ? "true" : "false", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } - /* nothing to do */ } void -INVLPG(DWORD op) +INVLPG(UINT32 op) { - DWORD madr; + descriptor_t *sdp; + UINT32 madr; + int idx; if (CPU_STAT_PM && (CPU_STAT_VM86 || CPU_STAT_CPL != 0)) { + VERBOSE(("INVLPG: VM86(%s) or CPL(%d) != 0", CPU_STAT_VM86 ? "true" : "false", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } if (op < 0xc0) { CPU_WORKCLOCK(11); - madr = get_ea(op); - tlb_flush_page(madr); + madr = calc_ea_dst(op); + + idx = CPU_INST_SEGREG_INDEX; + sdp = &CPU_STAT_SREG(idx); + if (!SEG_IS_VALID(sdp)) { + EXCEPTION(GP_EXCEPTION, 0); + } + switch (sdp->type) { + case 4: case 5: case 6: case 7: + if (madr <= sdp->u.seg.limit) { + EXCEPTION((idx == CPU_SS_INDEX) ? + SS_EXCEPTION: GP_EXCEPTION, 0); + } + break; + + default: + if (madr > sdp->u.seg.limit) { + EXCEPTION((idx == CPU_SS_INDEX) ? + SS_EXCEPTION: GP_EXCEPTION, 0); + } + break; + } + tlb_flush_page(sdp->u.seg.segbase + madr); return; } EXCEPTION(UD_EXCEPTION, 0); @@ -931,11 +1037,13 @@ HLT(void) { if (CPU_STAT_PM && CPU_STAT_CPL != 0) { + VERBOSE(("HLT: CPL(%d) != 0", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } CPU_HALT(); - CPU_EIP--; + CPU_EIP = CPU_PREV_EIP; + CPU_STAT_HLT = 1; } void @@ -948,28 +1056,39 @@ RSM(void) void RDMSR(void) { + int idx; -#if 1 - EXCEPTION(UD_EXCEPTION, 0); -#else if (CPU_STAT_PM && (CPU_STAT_VM86 || CPU_STAT_CPL != 0)) { + VERBOSE(("RDMSR: VM86(%s) or CPL(%d) != 0", CPU_STAT_VM86 ? "true" : "false", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } -#endif + + idx = CPU_ECX; + switch (idx) { + default: + EXCEPTION(GP_EXCEPTION, 0); + break; + } } void WRMSR(void) { + int idx; -#if 1 - EXCEPTION(UD_EXCEPTION, 0); -#else if (CPU_STAT_PM && (CPU_STAT_VM86 || CPU_STAT_CPL != 0)) { + VERBOSE(("WRMSR: VM86(%s) or CPL(%d) != 0", CPU_STAT_VM86 ? "true" : "false", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); - /* MTRR への書き込み時 tlb_flush(FALSE) */ } -#endif + + idx = CPU_ECX; + switch (idx) { + /* MTRR への書き込み時 tlb_flush(1); */ + + default: + EXCEPTION(GP_EXCEPTION, 0); + break; + } } void