From 72b321a4cfccbd20949eeda6ef511cfd601e8dda Mon Sep 17 00:00:00 2001 From: Sjoerd van der Berg Date: Sun, 13 Apr 2003 18:32:41 +0000 Subject: [PATCH] Changes for new flags Added a load of support functions for protected mode operations. Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@915 --- src/cpu/cpu.cpp | 561 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 505 insertions(+), 56 deletions(-) diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp index 08f55805..69595542 100644 --- a/src/cpu/cpu.cpp +++ b/src/cpu/cpu.cpp @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + #include "dosbox.h" #include "cpu.h" #include "memory.h" @@ -23,10 +24,10 @@ #include "keyboard.h" #include "setup.h" + Flag_Info flags; - CPU_Regs cpu_regs; - +CPUBlock cpu; Segments Segs; Bits CPU_Cycles=0; @@ -35,26 +36,85 @@ Bits CPU_CycleMax=1500; CPU_Decoder * cpudecoder; -static void CPU_CycleIncrease(void) { - Bitu old_cycles=CPU_CycleMax; - CPU_CycleMax=(Bitu)(CPU_CycleMax*1.2); - CPU_CycleLeft=0;CPU_Cycles=0; - if (CPU_CycleMax==old_cycles) CPU_CycleMax++; - LOG_MSG("CPU:%d cycles",CPU_CycleMax); +INLINE void CPU_Push16(Bitu value) { + if (cpu.state & STATE_STACK32) { + reg_esp-=2; + mem_writew(SegPhys(ss)+reg_esp,value); + } else { + reg_sp-=2; + mem_writew(SegPhys(ss)+reg_sp,value); + } } -static void CPU_CycleDecrease(void) { - CPU_CycleMax=(Bitu)(CPU_CycleMax/1.2); - CPU_CycleLeft=0;CPU_Cycles=0; - if (!CPU_CycleMax) CPU_CycleMax=1; - LOG_MSG("CPU:%d cycles",CPU_CycleMax); +INLINE void CPU_Push32(Bitu value) { + if (cpu.state & STATE_STACK32) { + reg_esp-=4; + mem_writed(SegPhys(ss)+reg_esp,value); + } else { + reg_sp-=4; + mem_writed(SegPhys(ss)+reg_sp,value); + } } +INLINE Bitu CPU_Pop16(void) { + if (cpu.state & STATE_STACK32) { + Bitu val=mem_readw(SegPhys(ss)+reg_esp); + reg_esp+=2; + return val; + } else { + Bitu val=mem_readw(SegPhys(ss)+reg_sp); + reg_sp+=2; + return val; + } +} + +INLINE Bitu CPU_Pop32(void) { + if (cpu.state & STATE_STACK32) { + Bitu val=mem_readd(SegPhys(ss)+reg_esp); + reg_esp+=4; + return val; + } else { + Bitu val=mem_readd(SegPhys(ss)+reg_sp); + reg_sp+=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; + } +} + +bool CPU_CheckState(void) { + cpu.state=0; + if (!cpu.cr0 & CR0_PROTECTION) { + cpu.full.entry=cpu.full.prefix=0; + return true; + } else { + cpu.state|=STATE_PROTECTED; + if (Segs.big[cs]) { + cpu.state|=STATE_USE32; + cpu.full.entry=0x200; + cpu.full.prefix=0x02; /* PREFIX_ADDR */ + } else { + cpu.full.entry=cpu.full.prefix=0; + } + if (Segs.big[ss]) cpu.state|=STATE_STACK32; + LOG_MSG("CPL Level %x",cpu.cpl); + } + return true; +} Bit8u lastint; -void Interrupt(Bit8u num) { +bool Interrupt(Bitu num) { lastint=num; //DEBUG THINGIE to check fucked ints +#if C_DEBUG switch (num) { case 0x00: LOG(LOG_CPU,"Divide Error"); @@ -89,47 +149,424 @@ void Interrupt(Bit8u num) { #endif E_Exit("Call to interrupt 0xCD this is BAD"); case 0x03: -#if C_DEBUG - if (DEBUG_Breakpoint()) return; -#endif + if (DEBUG_Breakpoint()) return true; break; case 0x05: LOG(LOG_CPU,"CPU:Out Of Bounds interrupt"); break; default: // LOG_WARN("Call to unsupported INT %02X call %02X",num,reg_ah); - break; }; -/* Check for 16-bit or 32-bit and then setup everything for the interrupt to start */ - Bit16u pflags; - pflags= - (get_CF() << 0) | - (get_PF() << 2) | - (get_AF() << 4) | - (get_ZF() << 6) | - (get_SF() << 7) | - (flags.tf << 8) | - (flags.intf << 9) | - (flags.df << 10) | - (get_OF() << 11) | - (flags.io << 12) | - (flags.nt <<14); - - flags.intf=false; - flags.tf=false; -/* Save everything on a 16-bit stack */ - reg_sp-=2; - mem_writew(SegPhys(ss)+reg_sp,pflags); - reg_sp-=2; - mem_writew(SegPhys(ss)+reg_sp,SegValue(cs)); - reg_sp-=2; - mem_writew(SegPhys(ss)+reg_sp,reg_ip); -/* Get the new CS:IP from vector table */ - Bit16u newip=mem_readw(num << 2); - Bit16u newcs=mem_readw((num <<2)+2); - SegSet16(cs,newcs); - reg_ip=newip; +#endif + FILLFLAGS; + + if (!(cpu.state & STATE_PROTECTED)) { /* RealMode Interrupt */ + /* Save everything on a 16-bit stack */ + CPU_Push16(flags.word & 0xffff); + CPU_Push16(SegValue(cs)); + CPU_Push16(reg_ip); + 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); + Segs.phys[cs]=Segs.val[cs]<<4; + return true; + } else { /* Protected Mode Interrupt */ + Descriptor gate; + cpu.idt.GetDescriptor(num<<3,gate); + switch (gate.Type()) { + case DESC_286_INT_GATE: + case DESC_386_INT_GATE: + SETFLAGBIT(IF,false); + case DESC_286_TRAP_GATE: + case DESC_386_TRAP_GATE: + { + Descriptor desc; + Bitu selector=gate.GetSelector(); + Bitu offset=gate.GetOffset(); + cpu.gdt.GetDescriptor(selector,desc); + Bitu dpl=desc.DPL(); + if (dpl>cpu.cpl) E_Exit("Interrupt to higher privilege"); + 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 (dpl=cpu.cpl)) E_Exit("IRET to C segment of higher privilege"); + break; + default: + E_Exit("IRET from illegal descriptor type %X",desc.Type()); + } +IRET_same_level: + Segs.phys[cs]=desc.GetBase(); + Segs.big[cs]=desc.Big(); + Segs.val[cs]=selector; + reg_eip=offset; + SETFLAGSw(old_flags); + LOG_MSG("IRET:Same level return to %X:%X",selector,offset); + } else { + E_Exit("IRET to other privilege"); + /* Return to higher level */ + } + return CPU_CheckState(); + + + + + + + return true; + } + return false; +} + +bool CPU_JMP(bool use32,Bitu selector,Bitu offset) { + if (!(cpu.state & STATE_PROTECTED)) { + if (!use32) { + reg_eip=offset&0xffff; + } else { + reg_eip=offset; + } + SegSet16(cs,selector); + return true; + } else { + 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 (cpu.cpl=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(); + Segs.big[cs]=desc.Big(); + Segs.val[cs]=selector; + reg_eip=offset; + LOG(LOG_CPU,"RET - Same level to %X:%X RPL %X DPL %X",selector,offset,rpl,desc.DPL()); + return CPU_CheckState(); + } else { + /* Return to higher level */ + E_Exit("REturn to higher priviledge"); + } + LOG_MSG("Prot ret %X:%X",selector,offset); + return CPU_CheckState(); + } + return false; +} + + +void CPU_SLDT(Bitu selector) { + selector=cpu.gdt.SLDT(); +} + +void CPU_LLDT(Bitu selector) { + cpu.gdt.LLDT(selector); + LOG_MSG("LDT Set to %X",selector); +} + +void CPU_LGDT(Bitu limit,Bitu base) { + LOG_MSG("GDT Set to base:%X limit:%X",base,limit); + cpu.gdt.SetLimit(limit); + cpu.gdt.SetBase(base); +} + +void CPU_LIDT(Bitu limit,Bitu base) { + LOG_MSG("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; + if (value & CR0_PAGING) LOG_MSG("Paging enabled"); + if (value & CR0_PROTECTION) { + LOG_MSG("Protected mode"); + } else { + LOG_MSG("Real mode"); + } + return CPU_CheckState(); + } + 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; + default: + LOG(LOG_CPU|LOG_ERROR,"Unhandled MOV XXX, CR%d",cr); + break; + } + return 0; +} + + +void CPU_SMSW(Bitu & word) { + word=cpu.cr0 & 0xffff; +} + +bool CPU_LMSW(Bitu word) { + word&=0xffff; + word|=cpu.cr0&0xffff0000; + return CPU_SET_CRX(0,word); +} + +void CPU_LAR(Bitu selector,Bitu & ar) { + Descriptor desc;Bitu rpl=selector & 3; + flags.type=t_UNKNOWN; + 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_INVALID: + case DESC_286_TSS_A: + case DESC_LDT: + case DESC_286_TSS_B: + case DESC_286_CALL_GATE: + case DESC_TASK_GATE: + case DESC_286_INT_GATE: + case DESC_286_TRAP_GATE: + case DESC_386_TSS_A: + case DESC_386_TSS_B: + case DESC_386_CALL_GATE: + case DESC_386_INT_GATE: + case DESC_386_TRAP_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); @@ -163,16 +617,10 @@ void CPU_Init(Section* sec) { SegSet16(ss,0); reg_eip=0; + flags.word=FLAG_IF; flags.type=t_UNKNOWN; - flags.af=0; - flags.cf=0; - flags.cf=0; - flags.sf=0; - flags.zf=0; - flags.intf=true; - flags.nt=0; - flags.io=0; + cpu.full.entry=cpu.full.prefix=0; SetCPU16bit(); KEYBOARD_AddEvent(KBD_f11,KBD_MOD_CTRL,CPU_CycleDecrease); @@ -184,5 +632,6 @@ void CPU_Init(Section* sec) { CPU_CycleLeft=0; MSG_Add("CPU_CONFIGFILE_HELP","The amount of cycles to execute each loop. Lowering this setting will slowdown dosbox\n"); + }