/* * Copyright (C) 2002-2003 The DOSBox Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* $Id: cpu.cpp,v 1.39 2003-11-18 22:35:56 harekiet Exp $ */ #include #include "dosbox.h" #include "cpu.h" #include "memory.h" #include "debug.h" #include "keyboard.h" #include "setup.h" #include "paging.h" Bitu DEBUG_EnableDebugger(void); #if 1 #undef LOG #define LOG(X,Y) #endif CPU_Regs cpu_regs; CPUBlock cpu; Segments Segs; Bits CPU_Cycles=0; Bits CPU_CycleLeft=0; Bits CPU_CycleMax=1500; CPU_Decoder * cpudecoder; void CPU_Real_16_Slow_Start(bool big); void CPU_Core_Full_Start(bool big); void CPU_Core_Normal_Start(bool big); static Bits CPU_Core_Normal_Decode(void); static Bits CPU_Core_Full_Decode(void); #if 1 #define realcore_start CPU_Core_Normal_Start #else #define realcore_start CPU_Core_Full_Start #endif void CPU_Push16(Bitu value) { reg_esp-=2; mem_writew(SegPhys(ss) + (reg_esp & cpu.stack.mask) ,value); } void CPU_Push32(Bitu value) { reg_esp-=4; mem_writed(SegPhys(ss) + (reg_esp & cpu.stack.mask) ,value); } Bitu CPU_Pop16(void) { Bitu val=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask)); reg_esp+=2; return val; } Bitu CPU_Pop32(void) { Bitu val=mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask)); reg_esp+=4; return val; } PhysPt SelBase(Bitu sel) { if (cpu.cr0 & CR0_PROTECTION) { Descriptor desc; cpu.gdt.GetDescriptor(sel,desc); return desc.GetBase(); } else { return sel<<4; } } void CPU_SetFlags(Bitu word,Bitu mask) { reg_flags=(reg_flags & ~mask)|(word & mask)|2; } class TaskStateSegment { public: TaskStateSegment() { valid=false; } bool IsValid(void) { return valid; } Bitu Get_back(void) { return mem_readw(base); } void SaveSelector(void) { cpu.gdt.SetDescriptor(selector,desc); } void Get_SSx_ESPx(Bitu level,Bitu & _ss,Bitu & _esp) { if (is386) { PhysPt where=base+offsetof(TSS_32,esp0)+level*8; _esp=mem_readd(where); _ss=mem_readw(where+4); } else { PhysPt where=base+offsetof(TSS_16,sp0)+level*4; _esp=mem_readw(where); _ss=mem_readw(where+2); } } bool SetSelector(Bitu new_sel) { valid=false; selector=new_sel; if (!cpu.gdt.GetDescriptor(selector,desc)) return false; switch (desc.Type()) { case DESC_286_TSS_A: case DESC_286_TSS_B: case DESC_386_TSS_A: case DESC_386_TSS_B: break; default: valid=false; return false; } valid=true; base=desc.GetBase(); limit=desc.GetLimit(); is386=desc.Is386(); return true; } TSS_Descriptor desc; Bitu selector; PhysPt base; Bitu limit; Bitu is386; bool valid; }; TaskStateSegment cpu_tss; enum TSwitchType { TSwitch_JMP,TSwitch_CALL_INT,TSwitch_IRET }; bool CPU_SwitchTask(Bitu new_tss_selector,TSwitchType tstype) { TaskStateSegment new_tss; if (!new_tss.SetSelector(new_tss_selector)) E_Exit("Illegal TSS for switch"); /* Save current context in current TSS */ /* Check if we need to clear busy bit of old TASK */ if (tstype==TSwitch_JMP || tstype==TSwitch_IRET) { cpu_tss.desc.SetBusy(false); cpu_tss.SaveSelector(); } Bitu new_cr3=0; Bitu new_es,new_cs,new_ss,new_ds,new_fs,new_gs; Bitu new_ldt; if (cpu_tss.is386) { mem_writed(cpu_tss.base+offsetof(TSS_32,eflags),reg_flags); mem_writed(cpu_tss.base+offsetof(TSS_32,eip),reg_eip); mem_writed(cpu_tss.base+offsetof(TSS_32,eax),reg_eax); mem_writed(cpu_tss.base+offsetof(TSS_32,ecx),reg_ecx); mem_writed(cpu_tss.base+offsetof(TSS_32,edx),reg_edx); mem_writed(cpu_tss.base+offsetof(TSS_32,ebx),reg_ebx); mem_writed(cpu_tss.base+offsetof(TSS_32,esp),reg_esp); mem_writed(cpu_tss.base+offsetof(TSS_32,ebp),reg_ebp); mem_writed(cpu_tss.base+offsetof(TSS_32,esi),reg_esi); mem_writed(cpu_tss.base+offsetof(TSS_32,edi),reg_edi); mem_writed(cpu_tss.base+offsetof(TSS_32,es),SegValue(es)); mem_writed(cpu_tss.base+offsetof(TSS_32,cs),SegValue(cs)); mem_writed(cpu_tss.base+offsetof(TSS_32,ss),SegValue(ss)); mem_writed(cpu_tss.base+offsetof(TSS_32,ds),SegValue(ds)); mem_writed(cpu_tss.base+offsetof(TSS_32,fs),SegValue(fs)); mem_writed(cpu_tss.base+offsetof(TSS_32,gs),SegValue(gs)); } else { E_Exit("286 task switch"); } /* Load new context from new TSS */ if (new_tss.is386) { new_cr3=mem_readd(new_tss.base+offsetof(TSS_32,cr3)); reg_eip=mem_readd(new_tss.base+offsetof(TSS_32,eip)); CPU_SetFlags(mem_readd(new_tss.base+offsetof(TSS_32,eflags)),FMASK_ALL | FLAG_VM); reg_eax=mem_readd(new_tss.base+offsetof(TSS_32,eax)); reg_ecx=mem_readd(new_tss.base+offsetof(TSS_32,ecx)); reg_edx=mem_readd(new_tss.base+offsetof(TSS_32,edx)); reg_ebx=mem_readd(new_tss.base+offsetof(TSS_32,ebx)); reg_esp=mem_readd(new_tss.base+offsetof(TSS_32,esp)); reg_ebp=mem_readd(new_tss.base+offsetof(TSS_32,ebp)); reg_edi=mem_readd(new_tss.base+offsetof(TSS_32,edi)); reg_esi=mem_readd(new_tss.base+offsetof(TSS_32,esi)); new_es=mem_readw(new_tss.base+offsetof(TSS_32,es)); new_cs=mem_readw(new_tss.base+offsetof(TSS_32,cs)); new_ss=mem_readw(new_tss.base+offsetof(TSS_32,ss)); new_ds=mem_readw(new_tss.base+offsetof(TSS_32,ds)); new_fs=mem_readw(new_tss.base+offsetof(TSS_32,fs)); new_gs=mem_readw(new_tss.base+offsetof(TSS_32,gs)); new_ldt=mem_readw(new_tss.base+offsetof(TSS_32,ldt)); } else { E_Exit("286 task switch"); } /* Setup a back link to the old TSS in new TSS */ if (tstype==TSwitch_CALL_INT) { if (new_tss.is386) { mem_writed(new_tss.base+offsetof(TSS_32,back),cpu_tss.selector); } else { mem_writew(new_tss.base+offsetof(TSS_16,back),cpu_tss.selector); } /* And make the new task's eflag have the nested task bit */ reg_flags|=FLAG_NT; } /* Set the busy bit in the new task */ if (tstype==TSwitch_JMP || tstype==TSwitch_IRET) { new_tss.desc.SetBusy(true); new_tss.SaveSelector(); } /* Setup the new cr3 */ PAGING_SetDirBase(new_cr3); /* Load the new selectors */ if (reg_flags & FLAG_VM) { // LOG_MSG("Entering v86 task"); SegSet16(cs,new_cs); cpu.code.big=false; cpu.cpl=3; //We don't have segment caches so this will do } else { //DEBUG_EnableDebugger(); /* Protected mode task */ CPU_LLDT(new_ldt); /* Load the new CS*/ Descriptor cs_desc; cpu.cpl=new_cs & 3; cpu.gdt.GetDescriptor(new_cs,cs_desc); switch (cs_desc.Type()) { case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: if (cpu.cpl != cs_desc.DPL()) E_Exit("Task CS RPL != DPL"); goto doconforming; case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA: case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA: doconforming: Segs.phys[cs]=cs_desc.GetBase(); cpu.code.big=cs_desc.Big()>0; Segs.val[cs]=new_cs; break; default: E_Exit("Task switch CS Type %d",cs_desc.Type()); } } CPU_SetSegGeneral(es,new_es); CPU_SetSegGeneral(ss,new_ss); CPU_SetSegGeneral(ds,new_ds); CPU_SetSegGeneral(fs,new_fs); CPU_SetSegGeneral(gs,new_gs); CPU_LTR(new_tss_selector); // LOG_MSG("Task CPL %X CS:%X IP:%X SS:%X SP:%X eflags %x",cpu.cpl,SegValue(cs),reg_eip,SegValue(ss),reg_esp,reg_flags); return true; } Bit8u lastint; void CPU_Exception(Bitu num,Bitu error_code) { // LOG_MSG("Exception %d CS:%X IP:%X FLAGS:%X",num,SegValue(cs),reg_eip,reg_flags); CPU_Interrupt(num,error_code,((num>=8) ? CPU_INT_HAS_ERROR : 0)); } void CPU_Interrupt(Bitu num,Bitu error_code,Bitu type) { lastint=num; #if C_DEBUG switch (num) { case 0xcd: #if C_HEAVY_DEBUG LOG(LOG_CPU,LOG_ERROR)("Call to interrupt 0xCD this is BAD"); DEBUG_HeavyWriteLogInstruction(); #endif E_Exit("Call to interrupt 0xCD this is BAD"); case 0x03: if (DEBUG_Breakpoint()) { CPU_Cycles=0; return; } }; #endif if (!cpu.pmode) { /* Save everything on a 16-bit stack */ CPU_Push16(reg_flags & 0xffff); CPU_Push16(SegValue(cs)); CPU_Push16(reg_ip); SETFLAGBIT(IF,false); SETFLAGBIT(TF,false); /* Get the new CS:IP from vector table */ PhysPt base=cpu.idt.GetBase(); reg_eip=mem_readw(base+(num << 2)); Segs.val[cs]=mem_readw(base+(num << 2)+2); Segs.phys[cs]=Segs.val[cs]<<4; cpu.code.big=false; return; } else { /* Protected Mode Interrupt */ // if (type&CPU_INT_SOFTWARE && cpu.v86) goto realmode_interrupt; // DEBUG_EnableDebugger(); // LOG_MSG("interrupt start CPL %d v86 %d",cpu.cpl,cpu.v86); if ((reg_flags & FLAG_VM) && (type&CPU_INT_SOFTWARE)) { LOG_MSG("Software int in v86, AH %X IOPL %x",reg_ah,(reg_flags & FLAG_IOPL) >>12); if ((reg_flags & FLAG_IOPL)!=FLAG_IOPL) { reg_eip-=error_code; CPU_Exception(13,0); return; } } Descriptor gate; //TODO Check for software interrupt and check gate's dplcpu.cpl) E_Exit("Interrupt to higher privilege"); switch (cs_desc.Type()) { case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: if (cs_dpl0; LOG(LOG_CPU,LOG_NORMAL)("INT:Gate to %X:%X big %d %s",gate_sel,gate_off,cs_desc.Big(),gate.Type() & 0x8 ? "386" : "286"); reg_eip=gate_off; return; } case DESC_TASK_GATE: CPU_SwitchTask(gate.GetSelector(),TSwitch_CALL_INT); if (type & CPU_INT_HAS_ERROR) { //TODO Be sure about this, seems somewhat unclear if (cpu_tss.is386) CPU_Push32(error_code); else CPU_Push16(error_code); } return; default: E_Exit("Illegal descriptor type %X for int %X",gate.Type(),num); } } assert(1); } void CPU_IRET(bool use32) { if (!cpu.pmode) { /* RealMode IRET */ realmode_iret: if (use32) { reg_eip=CPU_Pop32(); SegSet16(cs,CPU_Pop32()); CPU_SetFlagsd(CPU_Pop32()); } else { reg_eip=CPU_Pop16(); SegSet16(cs,CPU_Pop16()); CPU_SetFlagsw(CPU_Pop16()); } cpu.code.big=false; return; } else { /* Protected mode IRET */ if (reg_flags & FLAG_VM) { if ((reg_flags & FLAG_IOPL)!=FLAG_IOPL) { reg_eip--; CPU_Exception(13,0); return; } else goto realmode_iret; } // DEBUG_EnableDebugger(); // LOG_MSG("IRET start CPL %d v86 %d",cpu.cpl,cpu.v86); /* Check if this is task IRET */ if (GETFLAG(NT)) { if (GETFLAG(VM)) E_Exit("Pmode IRET with VM bit set"); if (!cpu_tss.IsValid()) E_Exit("TASK Iret without valid TSS"); Bitu back_link=cpu_tss.Get_back(); CPU_SwitchTask(back_link,TSwitch_IRET); return; } Bitu n_cs_sel,n_eip,n_flags; if (use32) { n_eip=CPU_Pop32(); n_cs_sel=CPU_Pop32() & 0xffff; n_flags=CPU_Pop32(); if (n_flags & FLAG_VM) { cpu.cpl=3; CPU_SetFlags(n_flags,FMASK_ALL | FLAG_VM); Bitu n_ss,n_esp,n_es,n_ds,n_fs,n_gs; n_esp=CPU_Pop32(); n_ss=CPU_Pop32() & 0xffff; n_es=CPU_Pop32() & 0xffff; n_ds=CPU_Pop32() & 0xffff; n_fs=CPU_Pop32() & 0xffff; n_gs=CPU_Pop32() & 0xffff; CPU_SetSegGeneral(ss,n_ss); CPU_SetSegGeneral(es,n_es); CPU_SetSegGeneral(ds,n_ds); CPU_SetSegGeneral(fs,n_fs); CPU_SetSegGeneral(gs,n_gs); reg_eip=n_eip & 0xffff; reg_esp=n_esp; cpu.code.big=false; SegSet16(cs,n_cs_sel); LOG(LOG_CPU,LOG_NORMAL)("IRET:Back to V86: CS:%X IP %X SS:%X SP %X FLAGS:%X",SegValue(cs),reg_eip,SegValue(ss),reg_esp,reg_flags); return; } } else { n_eip=CPU_Pop16(); n_cs_sel=CPU_Pop16(); n_flags=(reg_flags & 0xffff0000) | CPU_Pop16(); if (n_flags & FLAG_VM) E_Exit("VM Flag in 16-bit iret"); } Bitu n_cs_rpl=n_cs_sel & 3; Descriptor n_cs_desc; cpu.gdt.GetDescriptor(n_cs_sel,n_cs_desc); if (n_cs_rpl=cpu.cpl)) E_Exit("IRET:Same level:C:DPL0; Segs.val[cs]=n_cs_sel; reg_eip=n_eip; CPU_SetFlagsd(n_flags); LOG(LOG_CPU,LOG_NORMAL)("IRET:Same level:%X:%X big %d",n_cs_sel,n_eip,cpu.code.big); } else { /* Return to outer level */ switch (n_cs_desc.Type()) { case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: if (n_cs_desc.DPL()!=n_cs_rpl) E_Exit("IRET:Outer level:NC:CS RPL != CS DPL"); break; case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA: case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA: if (n_cs_desc.DPL()<=cpu.cpl) E_Exit("IRET:Outer level:C:DPL <= CPL"); break; default: E_Exit("IRET:Outer level:Illegal descriptor type %X",n_cs_desc.Type()); } Segs.phys[cs]=n_cs_desc.GetBase(); cpu.code.big=n_cs_desc.Big()>0; Segs.val[cs]=n_cs_sel; cpu.cpl=n_cs_rpl; reg_eip=n_eip; CPU_SetFlagsd(n_flags); Bitu n_ss,n_esp; if (use32) { n_esp=CPU_Pop32(); n_ss=CPU_Pop32() & 0xffff; } else { n_esp=CPU_Pop16(); n_ss=CPU_Pop16(); } CPU_SetSegGeneral(ss,n_ss); if (cpu.stack.big) { reg_esp=n_esp; } else { reg_sp=n_esp; } //TODO Maybe validate other segments, but why would anyone use them? LOG(LOG_CPU,LOG_NORMAL)("IRET:Outer level:%X:X big %d",n_cs_sel,n_eip,cpu.code.big); } return; } } void CPU_JMP(bool use32,Bitu selector,Bitu offset) { if (!cpu.pmode || (reg_flags & FLAG_VM)) { if (!use32) { reg_eip=offset&0xffff; } else { reg_eip=offset; } SegSet16(cs,selector); cpu.code.big=false; return; } else { Bitu rpl=selector & 3; Descriptor desc; cpu.gdt.GetDescriptor(selector,desc); switch (desc.Type()) { case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: if (rpl>cpu.cpl) E_Exit("JMP:NC:RPL>CPL"); if (rpl!=desc.DPL()) E_Exit("JMP:NC:RPL != DPL"); cpu.cpl=desc.DPL(); LOG(LOG_CPU,LOG_NORMAL)("JMP:Code:NC to %X:%X big %d",selector,offset,desc.Big()); goto CODE_jmp; case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA: case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA: LOG(LOG_CPU,LOG_NORMAL)("JMP:Code:C to %X:%X big %d",selector,offset,desc.Big()); CODE_jmp: /* Normal jump to another selector:offset */ Segs.phys[cs]=desc.GetBase(); cpu.code.big=desc.Big()>0; Segs.val[cs]=(selector & 0xfffc) | cpu.cpl; reg_eip=offset; return; case DESC_386_TSS_A: if (desc.DPL()cpu.cpl) E_Exit("CALL:CODE:NC:RPL>CPL"); if (call.DPL()!=cpu.cpl) E_Exit("CALL:CODE:NC:DPL!=CPL"); LOG(LOG_CPU,LOG_NORMAL)("CALL:CODE:NC to %X:%X",selector,offset); goto call_code; case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA: case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA: if (call.DPL()>cpu.cpl) E_Exit("CALL:CODE:C:DPL>CPL"); LOG(LOG_CPU,LOG_NORMAL)("CALL:CODE:C to %X:%X",selector,offset); call_code: if (!use32) { CPU_Push16(SegValue(cs)); CPU_Push16(reg_ip); reg_eip=offset & 0xffff; } else { CPU_Push32(SegValue(cs)); CPU_Push32(reg_eip); reg_eip=offset; } Segs.phys[cs]=call.GetBase(); cpu.code.big=call.Big()>0; Segs.val[cs]=(selector & 0xfffc) | cpu.cpl; return; case DESC_386_CALL_GATE: case DESC_286_CALL_GATE: { if (call.DPL()0; reg_eip = n_eip; if (!use32) reg_eip&=0xffff; break; } case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA: case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA: call_gate_same_privilege: E_Exit("Call gate to same priviledge"); break; } } /* Call Gates */ break; case DESC_386_TSS_A: if (call.DPL()=cpu.cpl)) E_Exit("RET to C segment of higher privilege"); break; default: E_Exit("RET from illegal descriptor type %X",desc.Type()); } RET_same_level: Segs.phys[cs]=desc.GetBase(); cpu.code.big=desc.Big()>0; Segs.val[cs]=selector; reg_eip=offset; LOG(LOG_CPU,LOG_NORMAL)("RET - Same level to %X:%X RPL %X DPL %X",selector,offset,rpl,desc.DPL()); return; } else { /* Return to higher level */ if (bytes) E_Exit("RETF with immediate value"); Bitu n_esp = CPU_Pop16(); Bitu n_ss = CPU_Pop16(); cpu.cpl = rpl; CPU_SetSegGeneral(ss,n_ss); if (cpu.stack.big) { reg_esp = n_esp; } else { reg_sp = n_esp; } Segs.phys[cs]=desc.GetBase(); cpu.code.big=desc.Big()>0; Segs.val[cs]=selector; reg_eip=offset; // LOG(LOG_MISC,LOG_ERROR)("RET - Higher level to %X:%X RPL %X DPL %X",selector,offset,rpl,desc.DPL()); return; } LOG(LOG_CPU,LOG_NORMAL)("Prot ret %X:%X",selector,offset); return; } assert(1); } void CPU_SLDT(Bitu & selector) { selector=cpu.gdt.SLDT(); } void CPU_LLDT(Bitu selector) { cpu.gdt.LLDT(selector); LOG(LOG_CPU,LOG_NORMAL)("LDT Set to %X",selector); } void CPU_STR(Bitu & selector) { selector=cpu_tss.selector; } void CPU_LTR(Bitu selector) { cpu_tss.SetSelector(selector); } Bitu gdt_count=0; void CPU_LGDT(Bitu limit,Bitu base) { LOG(LOG_CPU,LOG_NORMAL)("GDT Set to base:%X limit:%X count %d",base,limit,gdt_count++); cpu.gdt.SetLimit(limit); cpu.gdt.SetBase(base); // if (gdt_count>20) DEBUG_EnableDebugger(); // DEBUG_EnableDebugger(); } void CPU_LIDT(Bitu limit,Bitu base) { LOG(LOG_CPU,LOG_NORMAL)("IDT Set to base:%X limit:%X",base,limit); cpu.idt.SetLimit(limit); cpu.idt.SetBase(base); } void CPU_SGDT(Bitu & limit,Bitu & base) { limit=cpu.gdt.GetLimit(); base=cpu.gdt.GetBase(); } void CPU_SIDT(Bitu & limit,Bitu & base) { limit=cpu.idt.GetLimit(); base=cpu.idt.GetBase(); } bool CPU_SET_CRX(Bitu cr,Bitu value) { switch (cr) { case 0: { Bitu changed=cpu.cr0 ^ value; if (!changed) return true; cpu.cr0=value; //TODO Maybe always first change to core_full for a change to cr0 if (value & CR0_PROTECTION) { cpu.pmode=true; LOG(LOG_CPU,LOG_NORMAL)("Protected mode"); PAGING_Enable((value & CR0_PAGING)>0); } else { cpu.pmode=false; PAGING_Enable(false); LOG(LOG_CPU,LOG_NORMAL)("Real mode"); } return false; //Only changes with next CS change } case 2: paging.cr2=value; break; case 3: PAGING_SetDirBase(value); break; default: LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV CR%d,%X",cr,value); break; } return false; } Bitu CPU_GET_CRX(Bitu cr) { switch (cr) { case 0: return cpu.cr0; case 2: return paging.cr2; case 3: return PAGING_GetDirBase(); default: LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV XXX, CR%d",cr); break; } return 0; } void CPU_SMSW(Bitu & word) { word=cpu.cr0; } bool CPU_LMSW(Bitu word) { word&=0xf; if (cpu.cr0 & 1) word|=1; word|=(cpu.cr0&0xfffffff0); return CPU_SET_CRX(0,word); } void CPU_ARPL(Bitu & dest_sel,Bitu src_sel) { if ((dest_sel & 3) < (src_sel & 3)) { dest_sel=(dest_sel & 0xfffc) + (src_sel & 3); // dest_sel|=0xff3f0000; SETFLAGBIT(ZF,true); } else { SETFLAGBIT(ZF,false); } } void CPU_LAR(Bitu selector,Bitu & ar) { Descriptor desc;Bitu rpl=selector & 3; ar=0; if (!cpu.gdt.GetDescriptor(selector,desc)){ SETFLAGBIT(ZF,false); return; } if (!desc.saved.seg.p) { SETFLAGBIT(ZF,false); return; } switch (desc.Type()){ case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA: case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA: break; case DESC_LDT: case DESC_TASK_GATE: case DESC_286_TSS_A: case DESC_286_TSS_B: case DESC_286_INT_GATE: case DESC_286_TRAP_GATE: case DESC_286_CALL_GATE: case DESC_386_TSS_A: case DESC_386_TSS_B: case DESC_386_INT_GATE: case DESC_386_TRAP_GATE: case DESC_386_CALL_GATE: case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: if (desc.DPL()(sec); reg_eax=0; reg_ebx=0; reg_ecx=0; reg_edx=0; reg_edi=0; reg_esi=0; reg_ebp=0; reg_esp=0; SegSet16(cs,0); SegSet16(ds,0); SegSet16(es,0); SegSet16(fs,0); SegSet16(gs,0); SegSet16(ss,0); reg_flags=0x2; CPU_SetFlags(FLAG_IF,FMASK_ALL); //Enable interrupts cpu.cr0=0xffffffff; CPU_SET_CRX(0,0); //Initialize cpu.code.big=false; cpu.stack.mask=0xffff; cpu.stack.big=false; cpu.idt.SetBase(0); cpu.idt.SetLimit(1023); realcore_start(false); CPU_JMP(false,0,0); //Setup the first cpu core KEYBOARD_AddEvent(KBD_f11,KBD_MOD_CTRL,CPU_CycleDecrease); KEYBOARD_AddEvent(KBD_f12,KBD_MOD_CTRL,CPU_CycleIncrease); CPU_Cycles=0; CPU_CycleMax=section->Get_int("cycles");; if (!CPU_CycleMax) CPU_CycleMax=1500; CPU_CycleLeft=0; GFX_SetTitle(CPU_CycleMax,-1); }