--- np2/i386c/ia32/instructions/system_inst.c 2004/03/12 13:34:08 1.24 +++ np2/i386c/ia32/instructions/system_inst.c 2012/01/08 11:36:06 1.38 @@ -1,5 +1,3 @@ -/* $Id: system_inst.c,v 1.24 2004/03/12 13:34:08 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 @@ -34,7 +30,7 @@ #include "system_inst.h" -void +void CPUCALL LGDT_Ms(UINT32 op) { UINT32 madr; @@ -42,7 +38,7 @@ LGDT_Ms(UINT32 op) 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 = calc_ea_dst(op); limit = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); @@ -65,7 +61,7 @@ LGDT_Ms(UINT32 op) EXCEPTION(UD_EXCEPTION, 0); } -void +void CPUCALL SGDT_Ms(UINT32 op) { UINT32 madr; @@ -87,7 +83,7 @@ SGDT_Ms(UINT32 op) EXCEPTION(UD_EXCEPTION, 0); } -void +void CPUCALL LLDT_Ew(UINT32 op) { UINT32 madr; @@ -109,11 +105,11 @@ LLDT_Ew(UINT32 op) VERBOSE(("LLDT: CPL(%d) != 0", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } - VERBOSE(("LLDT: VM86")); + VERBOSE(("LLDT: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } -void +void CPUCALL SLDT_Ew(UINT32 op) { UINT32 madr; @@ -135,14 +131,15 @@ SLDT_Ew(UINT32 op) } return; } - VERBOSE(("SLDT: VM86")); + VERBOSE(("SLDT: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } -void +void CPUCALL LTR_Ew(UINT32 op) { - UINT32 src, madr; + UINT32 madr; + UINT16 src; if (CPU_STAT_PM && !CPU_STAT_VM86) { if (CPU_STAT_CPL == 0) { @@ -154,17 +151,17 @@ LTR_Ew(UINT32 op) madr = calc_ea_dst(op); src = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); } - load_tr((UINT16)src); + load_tr(src); return; } VERBOSE(("LTR: CPL(%d) != 0", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } - VERBOSE(("LTR: VM86")); + VERBOSE(("LTR: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } -void +void CPUCALL STR_Ew(UINT32 op) { UINT32 madr; @@ -186,11 +183,11 @@ STR_Ew(UINT32 op) } return; } - VERBOSE(("STR: VM86")); + VERBOSE(("STR: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } -void +void CPUCALL LIDT_Ms(UINT32 op) { UINT32 madr; @@ -198,7 +195,7 @@ LIDT_Ms(UINT32 op) 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 = calc_ea_dst(op); limit = cpu_vmemoryread_w(CPU_INST_SEGREG_INDEX, madr); @@ -221,7 +218,7 @@ LIDT_Ms(UINT32 op) EXCEPTION(UD_EXCEPTION, 0); } -void +void CPUCALL SIDT_Ms(UINT32 op) { UINT32 madr; @@ -277,7 +274,7 @@ MOV_CdRd(void) * 31 = PG (pageing) */ - /* 下巻 p.182 割り込み 13 - 一般保護例外 */ + /* 筝 p.182 割り込み 13 - 一般保護例外 */ if ((src & (CPU_CR0_PE|CPU_CR0_PG)) == (UINT32)CPU_CR0_PG) { EXCEPTION(GP_EXCEPTION, 0); } @@ -286,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(("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) { @@ -332,11 +330,10 @@ MOV_CdRd(void) * 3 = PWT (page level write throgh) */ reg = CPU_CR3; - set_CR3(src); + 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; -#if CPU_FAMILY >= 5 case 4: /* CR4 */ /* * 10 = OSXMMEXCPT (support non masking exception by OS) @@ -351,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); @@ -364,10 +365,9 @@ MOV_CdRd(void) 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; -#endif /* CPU_FAMILY >= 5 */ default: ia32_panic("MOV_CdRd: CR reg index (%d)", idx); @@ -410,11 +410,9 @@ MOV_RdCd(void) *out = CPU_CR3; break; -#if CPU_FAMILY >= 5 case 4: *out = CPU_CR4; break; -#endif /* CPU_FAMILY >= 5 */ default: ia32_panic("MOV_RdCd: CR reg index (%d)", idx); @@ -427,7 +425,7 @@ MOV_RdCd(void) EXCEPTION(UD_EXCEPTION, 0); } -void +void CPUCALL LMSW_Ew(UINT32 op) { UINT32 src, madr; @@ -455,14 +453,18 @@ LMSW_Ew(UINT32 op) EXCEPTION(GP_EXCEPTION, 0); } -void +void CPUCALL SMSW_Ew(UINT32 op) { UINT32 madr; if (op >= 0xc0) { CPU_WORKCLOCK(2); - *(reg16_b20[op]) = (UINT16)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); @@ -485,8 +487,8 @@ CLTS(void) void ARPL_EwGw(void) { - UINT32 op, src, madr; - UINT16 dst; + UINT32 op, madr; + UINT src, dst; if (CPU_STAT_PM && !CPU_STAT_VM86) { PREPART_EA_REG16(op, src); @@ -497,7 +499,7 @@ ARPL_EwGw(void) CPU_FLAGL |= Z_FLAG; dst &= ~3; dst |= (src & 3); - *(reg16_b20[op]) = dst; + *(reg16_b20[op]) = (UINT16)dst; } else { CPU_FLAGL &= ~Z_FLAG; } @@ -509,14 +511,14 @@ ARPL_EwGw(void) CPU_FLAGL |= Z_FLAG; dst &= ~3; dst |= (src & 3); - cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, dst); + cpu_vmemorywrite_w(CPU_INST_SEGREG_INDEX, madr, (UINT16)dst); } else { CPU_FLAGL &= ~Z_FLAG; } } return; } - VERBOSE(("ARPL: VM86")); + VERBOSE(("ARPL: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } @@ -542,10 +544,11 @@ LAR_GwEw(void) return; } - if (sel.desc.s) { + if (!SEG_IS_SYSTEM(&sel.desc)) { /* code or data segment */ - if (!(sel.desc.u.seg.c && sel.desc.u.seg.ec)) { - /* not conforming code 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; @@ -576,7 +579,7 @@ LAR_GwEw(void) CPU_FLAGL |= Z_FLAG; return; } - VERBOSE(("LAR: VM86")); + VERBOSE(("LAR: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } @@ -599,10 +602,11 @@ LAR_GdEw(void) return; } - if (sel.desc.s) { + if (!SEG_IS_SYSTEM(&sel.desc)) { /* code or data segment */ - if (!(sel.desc.u.seg.c && sel.desc.u.seg.ec)) { - /* not conforming code 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; @@ -633,7 +637,7 @@ LAR_GdEw(void) CPU_FLAGL |= Z_FLAG; return; } - VERBOSE(("LAR: VM86")); + VERBOSE(("LAR: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } @@ -655,10 +659,11 @@ LSL_GwEw(void) return; } - if (sel.desc.s) { + if (!SEG_IS_SYSTEM(&sel.desc)) { /* code or data segment */ - if (!(sel.desc.u.seg.c && sel.desc.u.seg.ec)) { - /* not conforming code 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; @@ -685,7 +690,7 @@ LSL_GwEw(void) CPU_FLAGL |= Z_FLAG; return; } - VERBOSE(("LSL: VM86")); + VERBOSE(("LSL: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } @@ -707,10 +712,11 @@ LSL_GdEw(void) return; } - if (sel.desc.s) { + if (!SEG_IS_SYSTEM(&sel.desc)) { /* code or data segment */ - if (!(sel.desc.u.seg.c && sel.desc.u.seg.ec)) { - /* not conforming code 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; @@ -737,11 +743,11 @@ LSL_GdEw(void) CPU_FLAGL |= Z_FLAG; return; } - VERBOSE(("LSL: VM86")); + VERBOSE(("LSL: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } -void +void CPUCALL VERR_Ew(UINT32 op) { selector_t sel; @@ -766,13 +772,14 @@ VERR_Ew(UINT32 op) } /* system segment */ - if (!sel.desc.s) { + if (SEG_IS_SYSTEM(&sel.desc)) { CPU_FLAGL &= ~Z_FLAG; return; } - /* not conforming code segment && (CPL > DPL || RPL > DPL) */ - if (!(sel.desc.u.seg.c && sel.desc.u.seg.ec)) { - /* not conforming code segment */ + + /* 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; @@ -780,7 +787,8 @@ VERR_Ew(UINT32 op) } } /* 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; } @@ -788,11 +796,11 @@ VERR_Ew(UINT32 op) CPU_FLAGL |= Z_FLAG; return; } - VERBOSE(("VERR: VM86")); + VERBOSE(("VERR: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } -void +void CPUCALL VERW_Ew(UINT32 op) { selector_t sel; @@ -817,12 +825,12 @@ VERW_Ew(UINT32 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.wr) { + if (!SEG_IS_WRITABLE_DATA(&sel.desc)) { CPU_FLAGL &= ~Z_FLAG; return; } @@ -835,7 +843,7 @@ VERW_Ew(UINT32 op) CPU_FLAGL |= Z_FLAG; return; } - VERBOSE(("VERW: VM86")); + VERBOSE(("VERW: real-mode or VM86")); EXCEPTION(UD_EXCEPTION, 0); } @@ -845,7 +853,6 @@ MOV_DdRd(void) UINT32 src; UINT op; int idx; - int i; CPU_WORKCLOCK(11); GET_PCBYTE(op); @@ -873,32 +880,13 @@ MOV_DdRd(void) CPU_DR(idx) = src; break; -#if CPU_FAMILY >= 5 - case 4: - if (CPU_CR4 & CPU_CR4_DE) { - EXCEPTION(UD_EXCEPTION, 0); - } -#endif case 6: CPU_DR6 = src; break; -#if CPU_FAMILY >= 5 - case 5: - if (CPU_CR4 & CPU_CR4_DE) { - EXCEPTION(UD_EXCEPTION, 0); - } -#endif 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: @@ -945,25 +933,10 @@ MOV_RdDd(void) break; case 4: -#if CPU_FAMILY >= 5 - if (CPU_CR4 & CPU_CR4_DE) { - EXCEPTION(UD_EXCEPTION, 0); - } -#endif case 6: -#if CPU_FAMILY == 4 *out = (CPU_DR6 & 0x0000f00f) | 0xffff0ff0; -#elif CPU_FAMILY >= 5 - *out = (CPU_DR6 & 0x0000e00f) | 0xffff0ff0; -#endif break; -#if CPU_FAMILY >= 5 - case 5: - if (CPU_CR4 & CPU_CR4_DE) { - EXCEPTION(UD_EXCEPTION, 0); - } -#endif case 7: *out = CPU_DR7; break; @@ -987,8 +960,6 @@ INVD(void) VERBOSE(("INVD: VM86(%s) or CPL(%d) != 0", CPU_STAT_VM86 ? "true" : "false", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } - - tlb_flush(TRUE); } void @@ -1000,17 +971,14 @@ WBINVD(void) VERBOSE(("WBINVD: VM86(%s) or CPL(%d) != 0", CPU_STAT_VM86 ? "true" : "false", CPU_STAT_CPL)); EXCEPTION(GP_EXCEPTION, 0); } - - tlb_flush(TRUE); } -void +void CPUCALL INVLPG(UINT32 op) { - descriptor_t *sd; + descriptor_t *sdp; UINT32 madr; int idx; - int exc; 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)); @@ -1022,38 +990,29 @@ INVLPG(UINT32 op) madr = calc_ea_dst(op); idx = CPU_INST_SEGREG_INDEX; - sd = &CPU_STAT_SREG(idx); - if (!sd->valid) { - exc = GP_EXCEPTION; - goto err; + sdp = &CPU_STAT_SREG(idx); + if (!SEG_IS_VALID(sdp)) { + EXCEPTION(GP_EXCEPTION, 0); } - switch (sd->type) { + switch (sdp->type) { case 4: case 5: case 6: case 7: - if (madr <= sd->u.seg.limit) { - if (idx == CPU_SS_INDEX) - exc = SS_EXCEPTION; - else - exc = GP_EXCEPTION; - goto err; + if (madr <= sdp->u.seg.limit) { + EXCEPTION((idx == CPU_SS_INDEX) ? + SS_EXCEPTION: GP_EXCEPTION, 0); } break; default: - if (madr > sd->u.seg.limit) { - if (idx == CPU_SS_INDEX) - exc = SS_EXCEPTION; - else - exc = GP_EXCEPTION; - goto err; + if (madr > sdp->u.seg.limit) { + EXCEPTION((idx == CPU_SS_INDEX) ? + SS_EXCEPTION: GP_EXCEPTION, 0); } break; } - tlb_flush_page(sd->u.seg.segbase + madr); + tlb_flush_page(sdp->u.seg.segbase + madr); return; } - exc = UD_EXCEPTION; -err: - EXCEPTION(exc, 0); + EXCEPTION(UD_EXCEPTION, 0); } void @@ -1072,11 +1031,9 @@ HLT(void) EXCEPTION(GP_EXCEPTION, 0); } + VERBOSE(("HLT: do HLT.")); CPU_HALT(); - CPU_EIP--; -#if defined(IA32_SUPPORT_PREFETCH_QUEUE) - CPU_PREFETCHQ_REMAIN++; -#endif + CPU_EIP = CPU_PREV_EIP; CPU_STAT_HLT = 1; } @@ -1117,7 +1074,7 @@ WRMSR(void) idx = CPU_ECX; switch (idx) { - /* MTRR への書き込み時 tlb_flush(FALSE); */ + /* MTRR への書き込み時 tlb_flush(1); */ default: EXCEPTION(GP_EXCEPTION, 0);