From 60e058ca768e1b58f5e5f2dc25dd9de2468fb6b7 Mon Sep 17 00:00:00 2001 From: Sjoerd van der Berg Date: Sun, 20 Apr 2003 10:40:13 +0000 Subject: [PATCH] Some more protected mode opcodes added. Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@946 --- include/cpu.h | 6 +- src/cpu/cpu.cpp | 237 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 181 insertions(+), 62 deletions(-) diff --git a/include/cpu.h b/include/cpu.h index 190032b5..74957aca 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -70,17 +70,19 @@ enum { void CPU_LLDT(Bitu selector); +void CPU_LTR(Bitu selector); void CPU_LIDT(Bitu limit,Bitu base); void CPU_LGDT(Bitu limit,Bitu base); +void CPU_STR(Bitu & selector); void CPU_SLDT(Bitu & selector); void CPU_SIDT(Bitu & limit,Bitu & base); void CPU_SGDT(Bitu & limit,Bitu & base); -void CPU_SLDT(Bitu & limit,Bitu & base); - +void CPU_ARPL(Bitu & dest_sel,Bitu src_sel); void CPU_LAR(Bitu selector,Bitu & ar); +void CPU_LSL(Bitu selector,Bitu & limit); bool CPU_SET_CRX(Bitu cr,Bitu value); Bitu CPU_GET_CRX(Bitu cr); diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp index 19370e42..0dc34471 100644 --- a/src/cpu/cpu.cpp +++ b/src/cpu/cpu.cpp @@ -105,7 +105,7 @@ bool CPU_CheckState(void) { cpu.full.entry=cpu.full.prefix=0; } if (Segs.big[ss]) cpu.state|=STATE_STACK32; - LOG_MSG("CPL Level %x",cpu.cpl); + LOG_MSG("CPL Level %x at %X:%X",cpu.cpl,SegValue(cs),reg_eip); } return true; } @@ -175,7 +175,9 @@ bool Interrupt(Bitu num) { return true; } else { /* Protected Mode Interrupt */ Descriptor gate; +//TODO Check for software interrupt and check gate's dpl=cpu.cpl)) E_Exit("IRET to C segment of higher privilege"); + if (!(desc.DPL()>=cpu.cpl)) E_Exit("IRET:Same level:C:DPLcpu.cpl)) E_Exit("IRET:Outer level:C:DPL <= CPL"); + break; + default: + E_Exit("IRET from illegal descriptor type %X",desc.Type()); + } + Segs.phys[cs]=desc.GetBase(); + Segs.big[cs]=desc.Big(); + Segs.val[cs]=selector; + cpu.cpl=rpl; + reg_eip=offset; + Bitu new_ss,new_esp; + if (use32) { + new_esp=CPU_Pop32(); + new_ss=CPU_Pop32() & 0xffff; + } else { + new_esp=CPU_Pop16(); + new_ss=CPU_Pop16(); + } + reg_esp=new_esp; + CPU_SetSegGeneral(ss,new_ss); + //TODO Maybe validate other segments, but why would anyone use them? + LOG_MSG("IRET:Outer level return to %X:%X",selector,offset); } return CPU_CheckState(); - - - - - - - return true; } return false; } @@ -306,26 +327,25 @@ bool CPU_JMP(bool use32,Bitu selector,Bitu offset) { SegSet16(cs,selector); return true; } 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 (cpu.cplcpu.cpl) E_Exit("JMP:NC:RPL>CPL"); + if (rpl!=desc.DPL()) E_Exit("JMP:NC:RPL != DPL"); cpu.cpl=desc.DPL(); + LOG_MSG("JMP:Code:NC to %X:%X",selector,offset); 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: + 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_MSG("JMP:Code:C to %X:%X",selector,offset); CODE_jmp: /* Normal jump to another selector:offset */ - LOG_MSG("CODE JMP to %X:%X DPL %X",selector,offset,desc.DPL()); Segs.phys[cs]=desc.GetBase(); Segs.big[cs]=desc.Big(); - Segs.val[cs]=selector; + Segs.val[cs]=(selector & 0xfffc) | cpu.cpl; reg_eip=offset; return CPU_CheckState(); default: @@ -352,7 +372,40 @@ bool CPU_CALL(bool use32,Bitu selector,Bitu offset) { SegSet16(cs,selector); return true; } else { - E_Exit("Prot call"); + Descriptor call; + Bitu rpl=selector & 3; + cpu.gdt.GetDescriptor(selector,call); + /* Check for type of far call */ + switch (call.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("CALL:CODE:NC:RPL>CPL"); + if (call.DPL()!=cpu.cpl) E_Exit("CALL:CODE:NC:DPL!=CPL"); + LOG_MSG("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_MSG("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(); + Segs.big[cs]=call.Big(); + Segs.val[cs]=(selector & 0xfffc) | cpu.cpl; + reg_eip=offset; + return CPU_CheckState(); + default: + E_Exit("CALL:Descriptor type %x unsupported",call.Type()); + + }; return CPU_CheckState(); } return false; @@ -382,6 +435,11 @@ bool CPU_RET(bool use32,Bitu bytes) { offset=CPU_Pop32(); selector=CPU_Pop32() & 0xffff; } + if (cpu.state & STATE_STACK32) { + reg_esp+=bytes; + } else { + reg_sp+=bytes; + } Descriptor desc; Bitu rpl=selector & 3; if (rpl