diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp index 9c6ae0d7..1168c0cd 100644 --- a/src/cpu/cpu.cpp +++ b/src/cpu/cpu.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: cpu.cpp,v 1.37 2003-11-05 19:41:10 harekiet Exp $ */ +/* $Id: cpu.cpp,v 1.38 2003-11-18 22:29:31 harekiet Exp $ */ #include #include "dosbox.h" @@ -27,6 +27,8 @@ #include "setup.h" #include "paging.h" +Bitu DEBUG_EnableDebugger(void); + #if 1 #undef LOG #define LOG(X,Y) @@ -39,7 +41,6 @@ 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); @@ -49,15 +50,14 @@ 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 -#define pmodecore_start CPU_Core_Normal_Start #else #define realcore_start CPU_Core_Full_Start -#define pmodecore_start CPU_Core_Full_Start #endif @@ -93,15 +93,188 @@ PhysPt SelBase(Bitu sel) { } } -void CPU_SetFlags(Bitu word) { - reg_flags=(word|2)&~0x28; +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) { - CPU_Interrupt(num,0,0); +// 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 @@ -127,64 +300,128 @@ void CPU_Interrupt(Bitu num,Bitu error_code,Bitu type) { SETFLAGBIT(IF,false); SETFLAGBIT(TF,false); /* Get the new CS:IP from vector table */ - reg_eip=mem_readw(num << 2); - Segs.val[cs]=mem_readw((num << 2)+2); + 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 (desc.Type()) { + Descriptor cs_desc; + Bitu gate_sel=gate.GetSelector(); + Bitu gate_off=gate.GetOffset(); + cpu.gdt.GetDescriptor(gate_sel,cs_desc); + Bitu cs_dpl=cs_desc.DPL(); + if (cs_dpl>cpu.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 (dpl0; - LOG(LOG_CPU,LOG_NORMAL)("INT:Gate to %X:%X big %d %s",selector,reg_eip,desc.Big(),gate.Type() & 0x8 ? "386" : "286"); - reg_eip=offset; + SETFLAGBIT(VM,false); + Segs.val[cs]=(gate_sel&0xfffc) | cpu.cpl; + Segs.phys[cs]=cs_desc.GetBase(); + cpu.code.big=cs_desc.Big()>0; + 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); } @@ -193,11 +430,12 @@ void CPU_Interrupt(Bitu num,Bitu error_code,Bitu type) { } void CPU_IRET(bool use32) { - if (!cpu.pmode || cpu.v86) { /* RealMode IRET */ + if (!cpu.pmode) { /* RealMode IRET */ +realmode_iret: if (use32) { reg_eip=CPU_Pop32(); SegSet16(cs,CPU_Pop32()); - CPU_SetFlags(CPU_Pop32()); + CPU_SetFlagsd(CPU_Pop32()); } else { reg_eip=CPU_Pop16(); SegSet16(cs,CPU_Pop16()); @@ -206,87 +444,125 @@ void CPU_IRET(bool use32) { cpu.code.big=false; return; } else { /* Protected mode IRET */ - /* Check if this is task 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"); - E_Exit("Task IRET"); - - + 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 selector,offset,old_flags; + Bitu n_cs_sel,n_eip,n_flags; if (use32) { - offset=CPU_Pop32(); - selector=CPU_Pop32() & 0xffff; - old_flags=CPU_Pop32(); - if (old_flags & FLAG_VM) E_Exit("No vm86 support"); + 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 { - offset=CPU_Pop16(); - selector=CPU_Pop16(); - old_flags=(reg_flags & 0xffff0000) | CPU_Pop16(); + 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 rpl=selector & 3; - Descriptor desc; - cpu.gdt.GetDescriptor(selector,desc); - if (rpl=cpu.cpl)) E_Exit("IRET:Same level:C:DPL=cpu.cpl)) E_Exit("IRET:Same level:C:DPL0; - Segs.val[cs]=(selector & 0xfffc) | cpu.cpl;; - reg_eip=offset; - CPU_SetFlags(old_flags); - LOG(LOG_CPU,LOG_NORMAL)("IRET:Same level return to %X:%X big %d",selector,offset,cpu.code.big); + Segs.phys[cs]=n_cs_desc.GetBase(); + cpu.code.big=n_cs_desc.Big()>0; + 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 higher privilege */ - switch (desc.Type()) { + /* 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 (!(cpu.cpl==rpl)) E_Exit("IRET:Outer level:NC:RPL != DPL"); + 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 (!(desc.DPL()>cpu.cpl)) E_Exit("IRET:Outer level:C:DPL <= CPL"); + if (n_cs_desc.DPL()<=cpu.cpl) E_Exit("IRET:Outer level:C:DPL <= CPL"); break; default: - E_Exit("IRET from illegal descriptor type %X",desc.Type()); + E_Exit("IRET:Outer level:Illegal descriptor type %X",n_cs_desc.Type()); } - Segs.phys[cs]=desc.GetBase(); - cpu.code.big=desc.Big()>0; - Segs.val[cs]=selector; - cpu.cpl=rpl; - reg_eip=offset; - Bitu new_ss,new_esp; + 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) { - new_esp=CPU_Pop32(); - new_ss=CPU_Pop32() & 0xffff; + n_esp=CPU_Pop32(); + n_ss=CPU_Pop32() & 0xffff; } else { - new_esp=CPU_Pop16(); - new_ss=CPU_Pop16(); + 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; } - reg_esp=new_esp; - CPU_SetSegGeneral(ss,new_ss); //TODO Maybe validate other segments, but why would anyone use them? - LOG(LOG_CPU,LOG_NORMAL)("IRET:Outer level return to %X:X big %d",selector,offset,cpu.code.big); + 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 || cpu.v86) { + if (!cpu.pmode || (reg_flags & FLAG_VM)) { if (!use32) { reg_eip=offset&0xffff; } else { @@ -317,6 +593,12 @@ CODE_jmp: Segs.val[cs]=(selector & 0xfffc) | cpu.cpl; reg_eip=offset; return; + case DESC_386_TSS_A: + if (desc.DPL()0; Segs.val[cs]=(selector & 0xfffc) | cpu.cpl; - reg_eip=offset; return; - case DESC_286_CALL_GATE: { - if (call.DPL()0; - reg_eip = neweip; - // Set CPL to stack segment DPL - // Set RPL of CS to CPL - cpu.cpl = newcpl; - Segs.val[cs] = (newcs & 0xfffc) | newcpl; - // 4. Load SS descriptor - // 5. Push long pointer of old stack onto new stack - Bitu oldsp = reg_sp; - CPU_Push16(SegValue(ss)); - CPU_Push16(oldsp); - // 6. Get word count from call gate, mask to 5 bits - Bitu wordCount = call.saved.gate.paramcount; - if (wordCount>0) LOG(LOG_CPU,LOG_NORMAL)("CPU: Callgate 286 wordcount : %d)",wordCount); - // 7. Copy parameters from old stack onto new stack - while (wordCount>0) { - CPU_Push16(mem_readw(SegPhys(ss)+oldsp)); - oldsp += 2; wordCount--; + 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; } - // Push return address onto new stack - CPU_Push16(oldcs); - CPU_Push16(oldip); -// LOG(LOG_MISC,LOG_ERROR)("CPU: Callgate (Higher) %04X:%04X",newcs,neweip); - return; - } else { - // same privilidge level - Bitu oldcs = SegValue(cs); - Bitu oldip = reg_ip; - Bitu newcs = call.GetSelector() | 3; - Bitu neweip = call.GetOffset(); - // 3. Load CS descriptor (Set RPL of CS to CPL) - Descriptor code2; - if (!cpu.gdt.GetDescriptor(newcs,code2)) E_Exit("286 Call Gate: Invalid code segment."); - Segs.phys[cs] = code.GetBase(); - cpu.code.big = code.Big()>0; - // Set RPL of CS to CPL - cpu.cpl = seldpl; - Segs.val[cs] = (newcs & 0xfffc) | seldpl; - reg_eip = neweip; - // Push return address onto new stack - CPU_Push16(oldcs); - CPU_Push16(oldip); -// LOG(LOG_MISC,LOG_ERROR)("CPU: Callgate (Same) %04X:%04X",newcs,neweip); - return; - }; break; - }; + } /* Call Gates */ + break; + case DESC_386_TSS_A: + if (call.DPL()0; Segs.val[cs]=selector; @@ -525,26 +815,26 @@ void CPU_SLDT(Bitu & selector) { selector=cpu.gdt.SLDT(); } -Bitu tr=0; 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=tr; + selector=cpu_tss.selector; } void CPU_LTR(Bitu selector) { - tr=selector; - LOG(LOG_CPU,LOG_NORMAL)("TR Set to %X",selector); + cpu_tss.SetSelector(selector); } - +static gdt_count=0; void CPU_LGDT(Bitu limit,Bitu base) { - LOG(LOG_CPU,LOG_NORMAL)("GDT Set to base:%X limit:%X",base,limit); + 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) { @@ -583,6 +873,9 @@ bool CPU_SET_CRX(Bitu cr,Bitu value) { } return false; //Only changes with next CS change } + case 2: + paging.cr2=value; + break; case 3: PAGING_SetDirBase(value); break; @@ -597,6 +890,8 @@ Bitu CPU_GET_CRX(Bitu cr) { switch (cr) { case 0: return cpu.cr0; + case 2: + return paging.cr2; case 3: return PAGING_GetDirBase(); default: @@ -612,8 +907,9 @@ void CPU_SMSW(Bitu & word) { } bool CPU_LMSW(Bitu word) { - word&=0xffff; - word|=(cpu.cr0&0xffff0000); + word&=0xf; + if (cpu.cr0 & 1) word|=1; + word|=(cpu.cr0&0xfffffff0); return CPU_SET_CRX(0,word); } @@ -778,9 +1074,8 @@ void CPU_VERW(Bitu selector) { void CPU_SetSegGeneral(SegNames seg,Bitu value) { Segs.val[seg]=value; - if (!cpu.pmode || cpu.v86) { + if (!cpu.pmode || (reg_flags & FLAG_VM)) { Segs.phys[seg]=value << 4; -//TODO maybe just always do this when they enable/real/v86 mode if (seg==ss) { cpu.stack.big=false; cpu.stack.mask=0xffff; @@ -821,41 +1116,6 @@ void CPU_CPUID(void) { } } -void CPU_ReadTaskSeg32(PhysPt base,TaskSegment_32 * seg) { - seg->back =mem_readw(base+offsetof(TSS_386,back )); - seg->esp0 =mem_readd(base+offsetof(TSS_386,esp0 )); - seg->ss0 =mem_readw(base+offsetof(TSS_386,ss0 )); - seg->esp1 =mem_readd(base+offsetof(TSS_386,esp1 )); - seg->ss1 =mem_readw(base+offsetof(TSS_386,ss1 )); - seg->esp2 =mem_readd(base+offsetof(TSS_386,esp2 )); - seg->ss2 =mem_readw(base+offsetof(TSS_386,ss2 )); - - seg->cr3 =mem_readd(base+offsetof(TSS_386,cr3 )); - seg->eflags =mem_readd(base+offsetof(TSS_386,eflags )); - seg->eip =mem_readd(base+offsetof(TSS_386,eip )); - - seg->eax =mem_readd(base+offsetof(TSS_386,eax )); - seg->ecx =mem_readd(base+offsetof(TSS_386,ecx )); - seg->edx =mem_readd(base+offsetof(TSS_386,edx )); - seg->ebx =mem_readd(base+offsetof(TSS_386,ebx )); - seg->esp =mem_readd(base+offsetof(TSS_386,esp )); - seg->ebp =mem_readd(base+offsetof(TSS_386,ebp )); - seg->esi =mem_readd(base+offsetof(TSS_386,esi )); - seg->edi =mem_readd(base+offsetof(TSS_386,edi )); - - seg->es =mem_readw(base+offsetof(TSS_386,es )); - seg->cs =mem_readw(base+offsetof(TSS_386,cs )); - seg->ss =mem_readw(base+offsetof(TSS_386,ss )); - seg->ds =mem_readw(base+offsetof(TSS_386,ds )); - seg->fs =mem_readw(base+offsetof(TSS_386,fs )); - seg->gs =mem_readw(base+offsetof(TSS_386,gs )); - - seg->ldt =mem_readw(base+offsetof(TSS_386,ldt )); - seg->trap =mem_readw(base+offsetof(TSS_386,trap )); - seg->io =mem_readw(base+offsetof(TSS_386,io )); - -} - static Bits HLT_Decode(void) { /* Once an interrupt occurs, it should change cpu core */ if (reg_eip!=cpu.hlt.eip || SegValue(cs) != cpu.hlt.cs) { @@ -866,7 +1126,12 @@ static Bits HLT_Decode(void) { return 0; } -void CPU_HLT(void) { +void CPU_HLT(Bitu oplen) { + if (cpu.cpl) { + reg_eip-=oplen; + CPU_Exception(13,0); + return; + } CPU_Cycles=0; cpu.hlt.cs=SegValue(cs); cpu.hlt.eip=reg_eip; @@ -912,14 +1177,15 @@ void CPU_Init(Section* sec) { SegSet16(gs,0); SegSet16(ss,0); - reg_eip=0; - CPU_SetFlags(FLAG_IF); //Enable interrupts + reg_flags=0x2; + CPU_SetFlags(FLAG_IF,FMASK_ALL); //Enable interrupts cpu.cr0=0xffffffff; - CPU_SET_CRX(0,0); //Initialize - cpu.v86=false; + 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