/* JPC: An x86 PC Hardware Emulator for a pure Java Virtual Machine Copyright (C) 2012-2013 Ian Preston This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Details (including contact information) can be found at: jpc.sourceforge.net or the developer website sourceforge.net/projects/jpc/ End of licence header */ package org.jpc.emulator.processor; import org.jpc.emulator.HardwareComponent; import org.jpc.emulator.motherboard.*; import org.jpc.emulator.memory.*; import org.jpc.emulator.processor.fpu64.*; import org.jpc.j2se.Option; import org.jpc.j2se.VirtualClock; import org.jpc.support.*; import java.io.*; import java.util.*; import java.util.logging.*; import static org.jpc.emulator.execution.Executable.*; import static org.jpc.emulator.execution.UCodes.*; public class Processor implements HardwareComponent { private static final Logger LOGGING = Logger.getLogger(Processor.class.getName()); private static final boolean USEBOCHS = Option.useBochs.isSet(); public static final int STATE_VERSION = 1; public static final int STATE_MINOR_VERSION = 0; public static final int IFLAGS_HARDWARE_INTERRUPT = 0x1; public static final int IFLAGS_PROCESSOR_EXCEPTION = 0x2; public static final int IFLAGS_RESET_REQUEST = 0x4; public static final int IFLAGS_IOPL_MASK = 3 << 12; public static final int CR0_PROTECTION_ENABLE = 0x1; public static final int CR0_MONITOR_COPROCESSOR = 0x2; public static final int CR0_FPU_EMULATION = 0x4; public static final int CR0_TASK_SWITCHED = 0x8; public static final int CR0_NUMERIC_ERROR = 0x20; public static final int CR0_WRITE_PROTECT = 0x10000; public static final int CR0_ALIGNMENT_MASK = 0x40000; public static final int CR0_NOT_WRITETHROUGH = 0x20000000; public static final int CR0_CACHE_DISABLE = 0x40000000; public static final int CR0_PAGING = 0x80000000; public static final int CR3_PAGE_CACHE_DISABLE = 0x10; public static final int CR3_PAGE_WRITES_TRANSPARENT = 0x8; public static final int CR4_VIRTUAL8086_MODE_EXTENSIONS = 0x1; public static final int CR4_PROTECTED_MODE_VIRTUAL_INTERRUPTS = 0x2; public static final int CR4_TIME_STAMP_DISABLE = 0x4; public static final int CR4_DEBUGGING_EXTENSIONS = 0x8; public static final int CR4_PAGE_SIZE_EXTENSIONS = 0x10; public static final int CR4_PHYSICAL_ADDRESS_EXTENSION = 0x20; public static final int CR4_MACHINE_CHECK_ENABLE = 0x40; public static final int CR4_PAGE_GLOBAL_ENABLE = 0x80; public static final int CR4_PERFORMANCE_MONITORING_COUNTER_ENABLE = 0x100; public static final int CR4_OS_SUPPORT_FXSAVE_FXSTORE = 0x200; public static final int CR4_OS_SUPPORT_UNMASKED_SIMD_EXCEPTIONS = 0x400; public static final int SYSENTER_CS_MSR = 0x174; public static final int SYSENTER_ESP_MSR = 0x175; public static final int SYSENTER_EIP_MSR = 0x176; public static final int RPL_MASK = 0xfffc; public static final int EAX_INDEX = 0; public static final int AX_INDEX = 1; public static final int AH_INDEX = 2; public static final int AL_INDEX = 3; public static final int EBX_INDEX = 4; public static final int BX_INDEX = 5; public static final int BH_INDEX = 6; public static final int BL_INDEX = 7; public static final int ECX_INDEX = 8; public static final int CX_INDEX = 9; public static final int CH_INDEX = 10; public static final int CL_INDEX = 11; public static final int EDX_INDEX = 12; public static final int DX_INDEX = 13; public static final int DH_INDEX = 14; public static final int DL_INDEX = 15; public static final int ESI_INDEX = 16; public static final int SI_INDEX = 17; public static final int EDI_INDEX = 18; public static final int DI_INDEX = 19; public static final int ESP_INDEX = 20; public static final int SP_INDEX = 21; public static final int EBP_INDEX = 22; public static final int BP_INDEX = 23; // these coincide with reg encoding of segment public static final int ES_INDEX = 0; public static final int CS_INDEX = 1; public static final int SS_INDEX = 2; public static final int DS_INDEX = 3; public static final int FS_INDEX = 4; public static final int GS_INDEX = 5; public static final int EFLAGS_VALID_MASK = 0x3f7fd5; // supported bits public static final int EFLAGS_CF_BIT = 0; public static final int EFLAGS_PF_BIT = 2; public static final int EFLAGS_AF_BIT = 4; public static final int EFLAGS_ZF_BIT = 6; public static final int EFLAGS_SF_BIT = 7; public static final int EFLAGS_TF_BIT = 8; public static final int EFLAGS_IF_BIT = 9; public static final int EFLAGS_DF_BIT = 10; public static final int EFLAGS_OF_BIT = 11; public static final int EFLAGS_NT_BIT = 14; public static final int EFLAGS_RF_BIT = 16; public static final int EFLAGS_VM_BIT = 17; public static final int EFLAGS_AC_BIT = 18; public static final int EFLAGS_VIF_BIT = 19; public static final int EFLAGS_VIP_BIT = 20; public static final int EFLAGS_ID_BIT = 21; public static final int EFLAGS_CF_MASK = 1 << EFLAGS_CF_BIT; public static final int EFLAGS_PF_MASK = 1 << EFLAGS_PF_BIT; public static final int EFLAGS_AF_MASK = 1 << EFLAGS_AF_BIT; public static final int EFLAGS_ZF_MASK = 1 << EFLAGS_ZF_BIT; public static final int EFLAGS_SF_MASK = 1 << EFLAGS_SF_BIT; public static final int EFLAGS_OF_MASK = 1 << EFLAGS_OF_BIT; public static final int EFLAGS_OSZAPC_MASK = EFLAGS_OF_MASK | EFLAGS_SF_MASK | EFLAGS_ZF_MASK | EFLAGS_AF_MASK | EFLAGS_PF_MASK | EFLAGS_CF_MASK; public static final int EFLAGS_IOPL_MASK = 3 << 12; public static final int EFLAGS_TF_MASK = 1 << EFLAGS_TF_BIT; public static final int EFLAGS_IF_MASK = 1 << EFLAGS_IF_BIT; public static final int EFLAGS_DF_MASK = 1 << EFLAGS_DF_BIT; public static final int EFLAGS_NT_MASK = 1 << EFLAGS_NT_BIT; public static final int EFLAGS_RF_MASK = 1 << EFLAGS_RF_BIT; public static final int EFLAGS_VM_MASK = 1 << EFLAGS_VM_BIT; public static final int EFLAGS_AC_MASK = 1 << EFLAGS_AC_BIT; public static final int EFLAGS_VIF_MASK = 1 << EFLAGS_VIF_BIT; public static final int EFLAGS_VIP_MASK = 1 << EFLAGS_VIP_BIT; public static final int EFLAGS_ID_MASK = 1 << EFLAGS_ID_BIT; private static final boolean[] parityMap; static { parityMap = new boolean[256]; for (int i = 0; i < parityMap.length; i++) parityMap[i] = ((Integer.bitCount(i) & 0x1) == 0); } private static boolean SKIP_SLEEPS = Option.max_instructions_per_block.intValue(1000) == 1; public static final int cpuLevel = Option.cpulevel.intValue(5); public int eip; public Segment cs, ds, ss, es, fs, gs; public Segment idtr, gdtr, ldtr, tss; public final Reg r_eax = new Reg("eax", null); public final Reg r_ax = r_eax; public final Reg r_ah = new Reg("ah", r_eax); public final Reg r_al = r_eax; public final Reg r_ebx = new Reg("ebx", null); public final Reg r_bx = r_ebx; public final Reg r_bh = new Reg("bh", r_ebx); public final Reg r_bl = r_ebx; public final Reg r_ecx = new Reg("ecx", null); public final Reg r_cx = r_ecx; public final Reg r_ch = new Reg("ch", r_ecx); public final Reg r_cl = r_ecx; public final Reg r_edx = new Reg("edx", null); public final Reg r_dx = r_edx; public final Reg r_dh = new Reg("dh", r_edx); public final Reg r_dl = r_edx; public final Reg r_esi = new Reg("esi", null); public final Reg r_si = r_esi; public final Reg r_edi = new Reg("edi", null); public final Reg r_di = r_edi; public final Reg r_esp = new Reg("esp", null); public final Reg r_sp = r_esp; public final Reg r_ebp = new Reg("ebp", null); public final Reg r_bp = r_ebp; public final Reg[] regs = new Reg[] {r_eax, r_ax, r_ah, r_al, r_ebx, r_bx, r_bh, r_bl, r_ecx, r_cx, r_ch, r_cl, r_edx, r_dx, r_dh, r_dl, r_esi, r_si, r_edi, r_di, r_esp, r_sp, r_ebp, r_bp}; public final Segment[] segs = new Segment[6]; private void updateSegmentArray() { segs[CS_INDEX]=cs; segs[DS_INDEX]=ds; segs[ES_INDEX]=es; segs[FS_INDEX]=fs; segs[GS_INDEX]=gs; segs[SS_INDEX]=ss; } public static int getRegIndex(String name) { if (name.equals("eax")) return EAX_INDEX; if (name.equals("ax")) return AX_INDEX; if (name.equals("ah")) return AH_INDEX; if (name.equals("al")) return AL_INDEX; if (name.equals("ebx")) return EBX_INDEX; if (name.equals("bx")) return BX_INDEX; if (name.equals("bh")) return BH_INDEX; if (name.equals("bl")) return BL_INDEX; if (name.equals("ecx")) return ECX_INDEX; if (name.equals("cx")) return CX_INDEX; if (name.equals("ch")) return CH_INDEX; if (name.equals("cl")) return CL_INDEX; if (name.equals("edx")) return EDX_INDEX; if (name.equals("dx")) return DX_INDEX; if (name.equals("dh")) return DH_INDEX; if (name.equals("dl")) return DL_INDEX; if (name.equals("esi")) return ESI_INDEX; if (name.equals("si")) return SI_INDEX; if (name.equals("edi")) return EDI_INDEX; if (name.equals("di")) return DI_INDEX; if (name.equals("esp")) return ESP_INDEX; if (name.equals("sp")) return SP_INDEX; if (name.equals("ebp")) return EBP_INDEX; if (name.equals("bp")) return BP_INDEX; throw new IllegalStateException("Unknown Register: "+name); } public static int getSegmentIndex(String seg) { if (seg.equals("cs")) return CS_INDEX; if (seg.equals("ds")) return DS_INDEX; if (seg.equals("es")) return ES_INDEX; if (seg.equals("fs")) return FS_INDEX; if (seg.equals("gs")) return GS_INDEX; if (seg.equals("ss")) return SS_INDEX; throw new IllegalStateException("Unknown Segment: "+seg); } public static String getSegmentString(int index) { switch (index) { case CS_INDEX: return "cs"; case DS_INDEX: return "ds"; case ES_INDEX: return "es"; case FS_INDEX: return "fs"; case GS_INDEX: return "gs"; case SS_INDEX: return "ss"; default: throw new IllegalStateException("Unknown segment index: "+index); } } public static int getCRIndex(String name) { if (name.equals("cr0")) return 0; if (name.equals("cr1")) return 1; if (name.equals("cr2")) return 2; if (name.equals("cr3")) return 3; if (name.equals("cr4")) return 4; throw new IllegalStateException("Unknown Control Register: "+name); } public static int getDRIndex(String name) { if (name.equals("dr0")) return 0; if (name.equals("dr1")) return 1; if (name.equals("dr2")) return 2; if (name.equals("dr3")) return 3; if (name.equals("dr4")) return 4; if (name.equals("dr5")) return 5; if (name.equals("dr6")) return 6; if (name.equals("dr7")) return 7; throw new IllegalStateException("Unknown Control Register: "+name); } public static final class Reg { private final Reg parent; public String name; private int dword; public Reg(String name, Reg parent) { this.name = name; this.parent = parent; } final public void set8(int b) { if (parent == null) setLow(b); else parent.setHigh(b); } final public int get8() { if (parent == null) return getLow(); else return parent.getHigh(); } final public short get16() { return (short)(dword & 0xFFFF); } final public void set16(int value) { dword = (value & 0xFFFF) | (dword & 0xFFFF0000); } final public int get32() { return dword; } final public void set32(int value) { dword = value; } final public byte getLow() { return (byte)(dword & 0xFF); } final public void setLow(int value) { dword = (value & 0xFF) | (dword & 0xFFFFFF00); } final public int getHigh() { return (byte)((dword >> 8) & 0xFF); } final public void setHigh(int value) { dword = ((value & 0xFF) << 8) | (dword & 0xFFFF00FF); } } public int pop16() { if (ss.getDefaultSizeFlag()) { int val = ss.getWord(r_esp.get32()); r_esp.set32(r_esp.get32() + 2); return val; } else { int val = ss.getWord(r_esp.get16() & 0xFFFF); r_esp.set16(r_esp.get16() + 2); return val; } } public void push8(byte val) { push16(val); } public void push16(short val) { if (ss.getDefaultSizeFlag()) { ss.setWord(r_esp.get32()-2, val); r_esp.set32(r_esp.get32() - 2); } else { ss.setWord((r_esp.get16()-2) & 0xFFFF, val); r_esp.set16(r_esp.get16() - 2); } } public int push16(int addr, short val) { if (ss.getDefaultSizeFlag()) { ss.setWord(addr-2, val); return addr - 2; } else { ss.setWord((addr-2) & 0xFFFF, val); return (addr & ~0xffff) | ((addr-2) & 0xffff); } } public int pop32() { if (ss.getDefaultSizeFlag()) { int val = ss.getDoubleWord(r_esp.get32()); r_esp.set32(r_esp.get32()+4); return val; } else { int val = ss.getDoubleWord(0xffff & r_esp.get16()); r_esp.set16(r_esp.get16() + 4); return val; } } public void push16_o32(short val) { if (ss.getDefaultSizeFlag()) { if ((r_esp.get32() < 4) && (r_esp.get32() > 0)) throw ProcessorException.STACK_SEGMENT_0; int offset = r_esp.get32() - 4; ss.setWord(offset, val); r_esp.set32(offset); } else { if (((r_esp.get32() & 0xffff) < 4) && ((r_esp.get32() & 0xffff) > 0)) throw ProcessorException.STACK_SEGMENT_0; int offset = (r_esp.get32() - 4) & 0xffff; ss.setWord(offset, val); r_esp.set16(offset); } } public void push32(int val) { if (ss.getDefaultSizeFlag()) { if ((r_esp.get32() < 4) && (r_esp.get32() > 0)) throw ProcessorException.STACK_SEGMENT_0; int offset = r_esp.get32() - 4; ss.setDoubleWord(offset, val); r_esp.set32(offset); } else { if (((r_esp.get32() & 0xffff) < 4) && ((r_esp.get32() & 0xffff) > 0)) throw ProcessorException.STACK_SEGMENT_0; int offset = (r_esp.get32() - 4) & 0xffff; ss.setDoubleWord(offset, val); r_esp.set16(offset); } } public short stack16(int offset) { if (ss.getDefaultSizeFlag()) { int targetESP = r_esp.get32() + offset; return ss.getWord(targetESP); } else { int targetESP = r_esp.get16() + offset; return ss.getWord(0xffff & targetESP); } } public int stack32(int offset) { if (ss.getDefaultSizeFlag()) { int targetESP = r_esp.get32() + offset; return ss.getDoubleWord(targetESP); } else { int targetESP = r_esp.get16() + offset; return ss.getDoubleWord(0xffff & targetESP); } } public void incrementStack(int amount) { if (ss.getDefaultSizeFlag()) { r_esp.set32(r_esp.get32()+amount); } else { r_esp.set16(r_esp.get16() + amount); } } public void pusha() { int offset, offmask; if (ss.getDefaultSizeFlag()) { offset = r_esp.get32(); offmask = 0xffffffff; } else { offset = r_esp.get16() & 0xffff; offmask = 0xffff; } //it seems that it checks at every push (we will simulate this) if ((offset < 16) && ((offset & 0x1) == 0x1)) { if (offset < 6) System.err.println("Emulated: Should shutdown machine (PUSHA with small ESP)."); throw ProcessorException.GENERAL_PROTECTION_0; } int temp = r_esp.get32(); offset -= 2; ss.setWord(offset, (short) r_eax.get16()); offset -= 2; ss.setWord(offset, (short) r_ecx.get16()); offset -= 2; ss.setWord(offset, (short) r_edx.get16()); offset -= 2; ss.setWord(offset, (short) r_ebx.get16()); offset -= 2; ss.setWord(offset, (short) temp); offset -= 2; ss.setWord(offset, (short) r_ebp.get16()); offset -= 2; ss.setWord(offset, (short) r_esi.get16()); offset -= 2; ss.setWord(offset, (short) r_edi.get16()); r_esp.set32((r_esp.get32() & ~offmask) | (offset & offmask)); } public void pushad() { int offset, offmask; if (ss.getDefaultSizeFlag()) { offset = r_esp.get32(); offmask = 0xffffffff; } else { offset = r_esp.get16() & 0xffff; offmask = 0xffff; } //it seems that it checks at every push (we will simulate this) if (((offset & 0xffffffffL) < 16) && ((offset & 0x1) == 0x1)) { if ((offset & 0xffffffffL) < 6) System.err.println("Emulated: Should shutdown machine (PUSHA with small ESP)."); throw ProcessorException.GENERAL_PROTECTION_0; } int temp = r_esp.get32(); offset -= 4; ss.setDoubleWord(offset, r_eax.get32()); offset -= 4; ss.setDoubleWord(offset, r_ecx.get32()); offset -= 4; ss.setDoubleWord(offset, r_edx.get32()); offset -= 4; ss.setDoubleWord(offset, r_ebx.get32()); offset -= 4; ss.setDoubleWord(offset, temp); offset -= 4; ss.setDoubleWord(offset, r_ebp.get32()); offset -= 4; ss.setDoubleWord(offset, r_esi.get32()); offset -= 4; ss.setDoubleWord(offset, r_edi.get32()); r_esp.set32((r_esp.get32() & ~offmask) | (offset & offmask)); } public void popa() { int offset, offmask; if (ss.getDefaultSizeFlag()) { offset = r_esp.get32(); offmask = 0xffffffff; } else { offset = r_esp.get16(); offmask = 0xffff; } int edi = ss.getWord(offmask & offset); offset += 2; int esi = ss.getWord(offmask & offset); offset += 2; int ebp = ss.getWord(offmask & offset); offset += 4;// yes - skip 2 bytes in order to skip SP int ebx = ss.getWord(offmask & offset); offset += 2; int edx = ss.getWord(offmask & offset); offset += 2; int ecx = ss.getWord(offmask & offset); offset += 2; int eax = ss.getWord(offmask & offset); offset += 2; r_edi.set16(edi); r_esi.set16(esi); r_ebp.set16(ebp); r_ebx.set16(ebx); r_edx.set16(edx); r_ecx.set16(ecx); r_eax.set16(eax); r_esp.set32((r_esp.get32() & ~offmask) | (offset & offmask)); } public void popad() { int offset, offmask; if (ss.getDefaultSizeFlag()) { offset = r_esp.get32(); offmask = 0xffffffff; } else { offset = r_esp.get16(); offmask = 0xffff; } int edi = ss.getDoubleWord(offmask & offset); offset += 4; int esi = ss.getDoubleWord(offmask & offset); offset += 4; int ebp = ss.getDoubleWord(offmask & offset); offset += 8;// yes - skip 4 bytes in order to skip SP int ebx = ss.getDoubleWord(offmask & offset); offset += 4; int edx = ss.getDoubleWord(offmask & offset); offset += 4; int ecx = ss.getDoubleWord(offmask & offset); offset += 4; int eax =ss.getDoubleWord(offmask & offset); offset += 4; r_edi.set32(edi); r_esi.set32(esi); r_ebp.set32(ebp); r_ebx.set32(ebx); r_edx.set32(edx); r_ecx.set32(ecx); r_eax.set32(eax); r_esp.set32((r_esp.get32() & ~offmask) | (offset & offmask)); } public final int iret_pm_o16_a16() { if (eflagsNestedTask) { iretFromTask(); throw new IllegalStateException("Unimplemented"); } else { try { ss.checkAddress((r_esp.get32() + 5) & 0xffff); } catch (ProcessorException e) { throw ProcessorException.STACK_SEGMENT_0; } int tempEIP = 0xffff & stack16(0); int tempCS = 0xffff & stack16(2); int tempEFlags = 0xffff & stack16(4); return iret16ProtectedMode16BitAddressing(tempCS, tempEIP, tempEFlags); } } public final int iret16ProtectedMode16BitAddressing(int newCS, int newEIP, int newEFlags) { Segment returnSegment = getSegment(newCS); if (returnSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; switch (returnSegment.getType()) { default: LOGGING.log(Level.WARNING, "Invalid segment type {0,number,integer}", Integer.valueOf(returnSegment.getType())); throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, newCS, true); case 0x18: //Code, Execute-Only case 0x19: //Code, Execute-Only, Accessed case 0x1a: //Code, Execute/Read case 0x1b: //Code, Execute/Read, Accessed { if (returnSegment.getRPL() < getCPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, newCS, true); if (!(returnSegment.isPresent())) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, newCS, true); if (returnSegment.getRPL() > getCPL()) { //OUTER PRIVILEGE-LEVEL try { ss.checkAddress((r_esp.get32() + 3+6) & 0xFFFF); } catch (ProcessorException e) { throw ProcessorException.STACK_SEGMENT_0; } int returnESP = 0xffff & stack16(6); int newSS = 0xffff & stack16(8); Segment returnStackSegment = getSegment(newSS, true); if ((returnStackSegment.getRPL() != returnSegment.getRPL()) || ((returnStackSegment.getType() & 0x12) != 0x12) || (returnStackSegment.getDPL() != returnSegment.getRPL())) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, newSS, true); if (!returnStackSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, newSS, true); returnSegment.checkAddress(newEIP); //esp += 20; //includes the 12 from earlier eip = newEIP; cs(returnSegment); ss(returnStackSegment); r_esp.set32(returnESP); int eflags = getEFlags(); eflags &= ~0x4dd5; eflags |= (0x4dd5 & newEFlags); //overwrite: all; preserve: if, iopl, vm, vif, vip if (getCPL() <= eflagsIOPrivilegeLevel) { eflags &= ~0x200; eflags |= (0x200 & newEFlags); //overwrite: all; preserve: iopl, vm, vif, vip } if (getCPL() == 0) { eflags &= ~0x3000; eflags |= (0x3000 & newEFlags); //overwrite: all; } // setEFlags(eflags); setCPL(cs.getRPL()); try { if ((((es.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE)) == ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA) || ((es.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE | ProtectedModeSegment.TYPE_CODE_CONFORMING)) == (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE))) && (getCPL() > es.getDPL())) es(SegmentFactory.NULL_SEGMENT); } catch (ProcessorException e) { } catch (Exception e) { } try { if ((((ds.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE)) == ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA) || ((ds.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE | ProtectedModeSegment.TYPE_CODE_CONFORMING)) == (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE))) && (getCPL() > ds.getDPL())) ds(SegmentFactory.NULL_SEGMENT); } catch (ProcessorException e) { } catch (Exception e) { } try { if ((((fs.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE)) == ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA) || ((fs.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE | ProtectedModeSegment.TYPE_CODE_CONFORMING)) == (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE))) && (getCPL() > fs.getDPL())) fs(SegmentFactory.NULL_SEGMENT); } catch (ProcessorException e) { } catch (Exception e) { } try { if ((((gs.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE)) == ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA) || ((gs.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE | ProtectedModeSegment.TYPE_CODE_CONFORMING)) == (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE))) && (getCPL() > gs.getDPL())) gs(SegmentFactory.NULL_SEGMENT); } catch (ProcessorException e) { } catch (Exception e) { } return eflags; } else { //SAME PRIVILEGE-LEVEL returnSegment.checkAddress(newEIP); cs(returnSegment); eip = newEIP; incrementStack(6); //Set EFlags int eflags = getEFlags(); eflags &= ~0x4dd5; eflags |= (0x4dd5 & newEFlags); if (getCPL() <= eflagsIOPrivilegeLevel) { eflags &= ~0x200; eflags |= (0x200 & newEFlags); } if (getCPL() == 0) { eflags &= ~0x3000; eflags |= (0x3000 & newEFlags); } // setEFlags(eflags); return eflags; } } case 0x1c: //Code: Execute-Only, Conforming case 0x1d: //Code: Execute-Only, Conforming, Accessed case 0x1e: //Code: Execute/Read, Conforming case 0x1f: //Code: Execute/Read, Conforming, Accessed { if (returnSegment.getRPL() < getCPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, newCS, true); if (returnSegment.getDPL() > returnSegment.getRPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, newCS, true); if (!(returnSegment.isPresent())) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, newCS, true); if (returnSegment.getRPL() > getCPL()) { //OUTER PRIVILEGE-LEVEL LOGGING.log(Level.WARNING, "Conforming outer privilege level not implemented"); throw new IllegalStateException("Execute Failed"); } else { //SAME PRIVILEGE-LEVEL LOGGING.log(Level.WARNING, "Conforming same privilege level not implemented"); throw new IllegalStateException("Execute Failed"); } } } } public void iret_o16_a16() { int tmpeip = pop16() & 0xffff; int tmpcs = pop16() & 0xffff; int tmpflags = pop16() & 0xffff; //cs.checkAddress(tmpeip); cs.setSelector(tmpcs); eip = tmpeip; setFlags((short)tmpflags); } public void iret_o32_a16() { int tmpEip = stack32(0); int tmpcs = stack32(4); int tmpflags = stack32(8); cs.checkAddress(tmpEip); cs.setSelector(0xffff & tmpcs); eip = tmpEip; incrementStack(12); setEFlags(tmpflags, 0x257fd5); // VIF, VIP, VM unchanged } public void iret_vm_o16() { if ((eflagsIOPrivilegeLevel < 3) && ((getCR4() & CR4_VIRTUAL8086_MODE_EXTENSIONS) == 0)) throw ProcessorException.GENERAL_PROTECTION_0; try { ss.checkAddress((r_esp.get32() + 5) & 0xffff); } catch (ProcessorException e) { throw ProcessorException.STACK_SEGMENT_0; } int tmpIP = 0xffff & stack16(0); int tmpCS = 0xffff & stack16(2); int tmpFlags = 0xffff & stack16(4); if (cpuLevel >= 5) { if (((getCR4() & CR4_VIRTUAL8086_MODE_EXTENSIONS) != 0) && eflagsIOPrivilegeLevel < 3) { if ((((tmpFlags & EFLAGS_IF_MASK) != 0) && (eflagsVirtualInterruptPending)) || (eflagsTrap)) throw ProcessorException.GENERAL_PROTECTION_0; cs(SegmentFactory.createVirtual8086ModeSegment(linearMemory, tmpCS, true)); eip = tmpIP; // IF, IOPL unchanged, EFLAGS.VIF = tmpFlags.IF int changeMask = EFLAGS_OSZAPC_MASK | EFLAGS_TF_MASK | EFLAGS_DF_MASK | EFLAGS_NT_MASK | EFLAGS_VIF_MASK; if ((tmpFlags & EFLAGS_IF_MASK) != 0) tmpFlags |= EFLAGS_VIF_MASK; setEFlags(tmpFlags, changeMask); incrementStack(6); return; } } cs(SegmentFactory.createVirtual8086ModeSegment(linearMemory, tmpCS, true)); eip = tmpIP; int changeMask = EFLAGS_OSZAPC_MASK | EFLAGS_TF_MASK | EFLAGS_DF_MASK | EFLAGS_NT_MASK | EFLAGS_IF_MASK; setEFlags(tmpFlags, changeMask); incrementStack(6); } public void setSeg(int index, int value) { if (index == CS_INDEX) cs(value); else if (index == DS_INDEX) ds(value); else if (index == ES_INDEX) es(value); else if (index == FS_INDEX) fs(value); else if (index == GS_INDEX) gs(value); else if (index == SS_INDEX) ss(value); else throw new IllegalStateException("Unknown Segment index: "+index); } public void setCR(int index, int value) { if (index == 0) setCR0(value); else if (index == 2) setCR2(value); else if (index == 3) setCR3(value); else if (index == 4) setCR4(value); else throw new IllegalStateException("Unknown Segment index: "+index); } public int getCR(int index) { if (index == 0) return getCR0(); else if (index == 2) return getCR2(); else if (index == 3) return getCR3(); else if (index == 4) return getCR4(); else throw new IllegalStateException("Unknown Segment index: "+index); } public void setDR(int index, int value) { if (index == 0) setDR0(value); else if (index == 1) setDR1(value); else if (index == 2) setDR2(value); else if (index == 3) setDR3(value); else if (index == 4) setDR4(value); else if (index == 5) setDR5(value); else if (index == 6) setDR6(value); else if (index == 7) setDR7(value); else throw new IllegalStateException("Unknown Segment index: "+index); } public int getDR(int index) { if (index == 0) return getDR0(); else if (index == 1) return getDR1(); else if (index == 2) return getDR2(); else if (index == 3) return getDR3(); else if (index == 4) return getDR4(); else if (index == 5) return getDR5(); else if (index == 6) return getDR6(); else if (index == 7) return getDR7(); else throw new IllegalStateException("Unknown Segment index: "+index); } protected final Segment loadSegment(int selector) { return loadSegment(selector, false); } protected final Segment loadSegment(int selector, boolean isStack) { selector &= 0xffff; if (selector < 0x4) return SegmentFactory.NULL_SEGMENT; Segment s = getSegment(selector, isStack); if (!s.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, selector, true); return s; } public int cs() { return cs.getSelector(); } public void cs(int selector) { if (!isProtectedMode() || isVirtual8086Mode()) cs.setSelector(selector & 0xffff); else cs(loadSegment(selector)); } public void cs(Segment seg) { if (seg == SegmentFactory.NULL_SEGMENT) throw ProcessorException.GENERAL_PROTECTION_0; cs = seg; segs[CS_INDEX] = seg; setCPL(seg.getRPL()); } public int ds() { return ds.getSelector(); } public void ds(int selector) { if (!isProtectedMode() || isVirtual8086Mode()) ds.setSelector(selector & 0xffff); else ds(loadSegment(selector)); } public void ds(Segment seg) { ds = seg; segs[DS_INDEX] = seg; } public int es() { return es.getSelector(); } public void es(int selector) { if (!isProtectedMode() || isVirtual8086Mode()) es.setSelector(selector & 0xffff); else es(loadSegment(selector)); } public void es(Segment seg) { es = seg; segs[ES_INDEX] = seg; } public int fs() { return fs.getSelector(); } public void fs(int selector) { if (!isProtectedMode() || isVirtual8086Mode()) fs.setSelector(selector & 0xffff); else fs(loadSegment(selector)); } public void fs(Segment seg) { fs = seg; segs[FS_INDEX] = seg; } public int gs() { return gs.getSelector(); } public void gs(int selector) { if (!isProtectedMode() || isVirtual8086Mode()) gs.setSelector(selector & 0xffff); else gs(loadSegment(selector)); } public void gs(Segment seg) { gs = seg; segs[GS_INDEX] = seg; } public int ss() { return ss.getSelector(); } public void ss(int selector) { if (!isProtectedMode() || isVirtual8086Mode()) ss.setSelector(selector & 0xffff); else ss(loadSegment(selector, true)); } public void ss(Segment seg) { if (seg == SegmentFactory.NULL_SEGMENT) throw ProcessorException.GENERAL_PROTECTION_0; ss = seg; segs[SS_INDEX] = seg; } public void setOSZAPC_Logic8(int res) { setOSZAPC_Logic32((byte) res); } public void setOSZAPC_Logic16(int res) { setOSZAPC_Logic32((short) res); } public void setOSZAPC_Logic32(int res) { flagResult = res; flagStatus = SZP; of = false; af = false; cf = false; } public boolean of() { return getOverflowFlag(flagStatus, of, flagOp1, flagOp2, flagResult, flagIns); } public void of(boolean val) { of = val; flagStatus &= ~OF; } public boolean sf() { return getSignFlag(flagStatus, sf, flagResult); } public void sf(boolean val) { sf = val; flagStatus &= ~SF; } public boolean zf() { return getZeroFlag(flagStatus, zf, flagResult); } public void zf(boolean val) { zf = val; flagStatus &= NZ; } public boolean af() { return getAuxCarryFlag(flagStatus, af, flagOp1, flagOp2, flagResult, flagIns); } public void af(boolean val) { af = val; flagStatus &= ~AF; } public boolean pf() { return getParityFlag(flagStatus, pf, flagResult); } public void pf(boolean val) { pf = val; flagStatus &= ~PF; } public boolean cf() { return getCarryFlag(flagStatus, cf, flagOp1, flagOp2, flagResult, flagIns); } public void cf(boolean val) { cf = val; flagStatus &= ~CF; } public void rf(boolean val) { eflagsResume = val; } public void setIF(boolean val) { eflagsInterruptEnable = val; } public final void cpuid() { if (cpuLevel == 4) // Intel 486 DX/2 stepping 03 { switch (r_eax.get32()) { case 0x00: r_eax.set32(0x02); r_ebx.set32(0x756e6547); /* "Genu", with G in the low nibble of BL */ r_edx.set32(0x49656e69); /* "ineI", with i in the low nibble of DL */ r_ecx.set32(0x6c65746e); /* "ntel", with n in the low nibble of CL */ return; case 0x01: r_eax.set32(0x433); r_ebx.set32(1 << 16); r_ecx.set32(0); int features = 0; features |= 1; //Have an FPU; features |= (1<<31); // Pending break enable r_edx.set32(features); return; default: case 0x02: r_eax.set32(0x410601); r_ebx.set32(0); r_ecx.set32(0); r_edx.set32(0); return; } } else if (cpuLevel == 5) // Intel Pentium { switch (r_eax.get32()) { case 0x00: r_eax.set32(0x01); r_ebx.set32(0x756e6547); /* "Genu", with G in the low nibble of BL */ r_edx.set32(0x49656e69); /* "ineI", with i in the low nibble of DL */ r_ecx.set32(0x6c65746e); /* "ntel", with n in the low nibble of CL */ return; case 0x80000000: case 0x80000001: case 0x01: r_eax.set32(0x00000513); r_ebx.set32(0); r_ecx.set32(0); int features = 0; features |= 1; //Have an FPU; //features |= (1<< 1); // VME - Virtual 8086 mode enhancements, CR4.VME and eflags.VIP and VIF //features |= (1<< 2); // Debugging extensions CR4.DE and DR4 and DR5 features |= (1<< 3); // Support Page-Size Extension (4M pages) features |= (1<< 4); // implement TSC features |= (1<< 5); // support RDMSR/WRMSR features |= (1<< 7); // Machine Check exception features |= (1<< 8); // Support CMPXCHG8B instruction //features |= (1<< 9); // APIC on chip //features |= (1<<11); // SYSENTER/SYSEXIT features |= (1<<13); // Support Global pages. features |= (1<<14); // Machine check architecture features |= (1<<15); // Implement CMOV instructions. features |= (1<<23); // support MMX //features |= (1<<28); // max APIC ID (cpuid.1.ebx[23-16]) is valid r_edx.set32(features); return; case 0x02: r_eax.set32(0x410601); r_ebx.set32(0); r_ecx.set32(0); r_edx.set32(0); return; // case 0x80000000: // case 0x80000001: // r_eax.set32(0); // r_ebx.set32(0); // r_ecx.set32(0); // r_edx.set32(0); // return; default: System.err.printf("Unknown CPUID argument eax=%08x\n", r_eax.get32()); r_eax.set32(0); r_ebx.set32(0); r_ecx.set32(0); r_edx.set32(0); } } else if (cpuLevel == 6) // Intel Pentium II stepping 4 { switch (r_eax.get32()) { case 0x00: r_eax.set32(0x02); r_ebx.set32(0x756e6547); /* "Genu", with G in the low nibble of BL */ r_edx.set32(0x49656e69); /* "ineI", with i in the low nibble of DL */ r_ecx.set32(0x6c65746e); /* "ntel", with n in the low nibble of CL */ return; case 0x01: r_eax.set32(0x634); r_ebx.set32(1 << 16); r_ecx.set32(0); int features = 0; features |= 1; //Have an FPU; features |= (1<< 1); // VME - Virtual 8086 mode enhancements, CR4.VME and eflags.VIP and VIF features |= (1<< 2); // Debugging extensions CR4.DE and DR4 and DR5 features |= (1<< 3); // Support Page-Size Extension (4M pages) features |= (1<< 4); // implement TSC //features |= (1<< 5); // support RDMSR/WRMSR features |= (1<< 6); // Support PAE. features |= (1<< 7); // Machine Check exception features |= (1<< 8); // Support CMPXCHG8B instruction - Bochs doesn't have this! //features |= (1<< 9); // APIC on chip // (1<<10) is reserved features |= (1<<11); // SYSENTER/SYSEXIT //features |= (1<<12); // Memory type range registers (MSR) features |= (1<<13); // Support Global pages. features |= (1<<14); // Machine check architecture features |= (1<<15); // Implement CMOV instructions. features |= (1<<23); // support MMX features |= (1<<28); // max APIC ID (cpuid.1.ebx[23-16]) is valid r_edx.set32(features); return; default: case 0x02: r_eax.set32(0x3020101); r_ebx.set32(0); r_ecx.set32(0); r_edx.set32(0xc040843); return; } } } public void lock(int addr){} public void unlock(int addr){} private int cr0, cr1, cr2, cr3, cr4; public int dr0, dr1, dr2, dr3, dr4, dr5, dr6, dr7; public int flagOp1, flagOp2, flagResult, flagIns, flagStatus; public boolean of, sf, zf, af, pf, cf, df; //program status and control register public boolean eflagsTrap; public boolean eflagsInterruptEnable; public int eflagsIOPrivilegeLevel; public boolean eflagsNestedTask; public boolean eflagsResume; public boolean eflagsVirtual8086Mode; public boolean eflagsAlignmentCheck; public boolean eflagsVirtualInterrupt; public boolean eflagsVirtualInterruptPending; public boolean eflagsID; public LinearAddressSpace linearMemory; public PhysicalAddressSpace physicalMemory; public AlignmentCheckedAddressSpace alignmentCheckedMemory; public IOPortHandler ioports; private volatile int interruptFlags; private InterruptController interruptController; private boolean alignmentChecking; private Map<Integer, Long> modelSpecificRegisters; private long resetTime; private int currentPrivilegeLevel; private boolean started = false; public Clock vmClock; public FpuState fpu; public Processor(Clock clock) { vmClock = clock; fpu = new FpuState64(this); linearMemory = null; physicalMemory = null; alignmentCheckedMemory = null; ioports = null; alignmentChecking = false; modelSpecificRegisters = new HashMap<Integer, Long>(); updateSegmentArray(); } public final boolean checkIOPermissions8(int port) { if ((getCPL() <= eflagsIOPrivilegeLevel) && !isVirtual8086Mode()) return true; if ((tss.getType() != ProtectedModeSegment.TYPE_AVAILABLE_32_TSS) && (tss.getType() != ProtectedModeSegment.TYPE_BUSY_32_TSS)) return false; if (tss.getLimit() < 103) return false; int ioPermMapBaseAddress = 0xffff & tss.getWord(102); if (ioPermMapBaseAddress + port/8 >= tss.getLimit()) return false; try { short ioPermMap = tss.getWord(ioPermMapBaseAddress + (port >>> 3)); int bitIndex = port & 7; return (ioPermMap & (1 << bitIndex)) == 0; } catch (ProcessorException p) { if (p.getType() == ProcessorException.Type.GENERAL_PROTECTION) return false; else throw p; } } public final boolean checkIOPermissions16(int ioportAddress) { if ((getCPL() <= eflagsIOPrivilegeLevel) && !isVirtual8086Mode()) return true; int ioPermMapBaseAddress = 0xffff & tss.getWord(102); try { short ioPermMapShort = tss.getWord(ioPermMapBaseAddress + (ioportAddress >>> 3)); return (ioPermMapShort & (0x3 << (ioportAddress & 0x7))) == 0; } catch (ProcessorException p) { if (p.getType() == ProcessorException.Type.GENERAL_PROTECTION) return false; else throw p; } } public final boolean checkIOPermissions32(int ioportAddress) { if ((getCPL() <= eflagsIOPrivilegeLevel) && !isVirtual8086Mode()) return true; int ioPermMapBaseAddress = 0xffff & tss.getWord(102); try { short ioPermMapShort = tss.getWord(ioPermMapBaseAddress + (ioportAddress >>> 3)); return (ioPermMapShort & (0xf << (ioportAddress & 0x7))) == 0; } catch (ProcessorException p) { if (p.getType() == ProcessorException.Type.GENERAL_PROTECTION) return false; else throw p; } } public final void ret_far_o16_a16(int stackdelta) { int tempEIP = 0xFFFF & stack16(0); int tempCS = 0xFFFF & stack16(2); if ((tempCS & 0xfffc) == 0) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true); Segment returnSegment = getSegment(tempCS); if (returnSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; if (returnSegment.getRPL() < getCPL()) { System.out.println("RPL too small in far ret: RPL=" + returnSegment.getRPL() + ", CPL=" + getCPL() + ", new CS=" + Integer.toHexString(tempCS)); throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS & 0xfffc, true); } switch (returnSegment.getType()) { default: throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS, true); case 0x18: //Code, Execute-Only case 0x19: //Code, Execute-Only, Accessed case 0x1a: //Code, Execute/Read case 0x1b: //Code, Execute/Read, Accessed { if (!(returnSegment.isPresent())) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, tempCS, true); if (returnSegment.getRPL() > getCPL()) { //OUTER PRIVILEGE-LEVEL try { ss.checkAddress((r_esp.get32() + 7 + stackdelta) & 0xFFFF); } catch (ProcessorException e) { throw ProcessorException.STACK_SEGMENT_0; } int returnESP = 0xffff & stack16(4 + stackdelta); int newSS = 0xffff & stack16(6 + stackdelta); if ((newSS & 0xfffc) == 0) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true); Segment returnStackSegment = getSegment(newSS, true); if ((returnStackSegment.getRPL() != returnSegment.getRPL()) || ((returnStackSegment.getType() & 0x12) != 0x12) || (returnStackSegment.getDPL() != returnSegment.getRPL())) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, newSS & 0xfffc, true); if (!returnStackSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.STACK_SEGMENT, newSS & 0xfffc, true); returnSegment.checkAddress(tempEIP); eip = tempEIP; cs(returnSegment); ss(returnStackSegment); r_esp.set16(returnESP + stackdelta); setCPL(cs.getRPL()); try { if ((((es.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE)) == ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA) || ((es.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE | ProtectedModeSegment.TYPE_CODE_CONFORMING)) == (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE))) && (getCPL() > es.getDPL())) { // can't use lower dpl data segment at higher cpl System.out.println("Setting ES to NULL in ret far"); es(SegmentFactory.NULL_SEGMENT); } } catch (ProcessorException e) { } catch (Exception e) { } try { if ((((ds.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE)) == ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA) || ((ds.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE | ProtectedModeSegment.TYPE_CODE_CONFORMING)) == (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE))) && (getCPL() > ds.getDPL())) { // can't use lower dpl data segment at higher cpl System.out.println("Setting DS to NULL in ret far"); ds(SegmentFactory.NULL_SEGMENT); } } catch (ProcessorException e) { } catch (Exception e) { } try { if ((((fs.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE)) == ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA) || ((fs.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE | ProtectedModeSegment.TYPE_CODE_CONFORMING)) == (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE))) && (getCPL() > fs.getDPL())) { // can't use lower dpl data segment at higher cpl System.out.println("Setting FS to NULL in ret far"); fs(SegmentFactory.NULL_SEGMENT); } } catch (ProcessorException e) { } catch (Exception e) { } try { if ((((gs.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE)) == ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA) || ((gs.getType() & (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE | ProtectedModeSegment.TYPE_CODE_CONFORMING)) == (ProtectedModeSegment.DESCRIPTOR_TYPE_CODE_DATA | ProtectedModeSegment.TYPE_CODE))) && (getCPL() > gs.getDPL())) { // can't use lower dpl data segment at higher cpl System.out.println("Setting GS to NULL in ret far"); gs(SegmentFactory.NULL_SEGMENT); } } catch (ProcessorException e) { } catch (Exception e) { } } else { //SAME PRIVILEGE-LEVEL returnSegment.checkAddress(tempEIP); incrementStack(4 + stackdelta); eip = tempEIP; cs(returnSegment); } } break; case 0x1c: //Code: Execute-Only, Conforming case 0x1d: //Code: Execute-Only, Conforming, Accessed case 0x1e: //Code: Execute/Read, Conforming case 0x1f: //Code: Execute/Read, Conforming, Accessed { if (returnSegment.getDPL() > returnSegment.getRPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS, true); if (!(returnSegment.isPresent())) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, tempCS, true); if (returnSegment.getRPL() > getCPL()) { //OUTER PRIVILEGE-LEVEL //esp += 8; LOGGING.log(Level.WARNING, "Conforming outer privilege level not implemented"); throw new IllegalStateException("Execute Failed"); } else { //SAME PRIVILEGE-LEVEL returnSegment.checkAddress(tempEIP); incrementStack(4 + stackdelta); eip = tempEIP; cs(returnSegment); } } } } public final void ret_far_o16_a32(int stackdelta) { int tempEIP = 0xFFFF & stack16(0); int tempCS = 0xFFFF & stack16(2); Segment returnSegment = getSegment(tempCS); if (returnSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; switch (returnSegment.getType()) { default: throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS, true); case 0x18: //Code, Execute-Only case 0x19: //Code, Execute-Only, Accessed case 0x1a: //Code, Execute/Read case 0x1b: //Code, Execute/Read, Accessed { if (returnSegment.getRPL() < getCPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS, true); if (!(returnSegment.isPresent())) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, tempCS, true); if (returnSegment.getRPL() > getCPL()) { //OUTER PRIVILEGE-LEVEL int tmpSS = 0xffff & stack16(6 + stackdelta); int tmpSP = 0xffff & stack16(4 + stackdelta); if ((tmpSS & 0xfffc) == 0) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true); Segment newStack = getSegment(tmpSS, true); if (newStack.getRPL() != returnSegment.getRPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tmpSS & 0xfffc, true); if (!((ProtectedModeSegment)newStack).isDataWritable() || ((ProtectedModeSegment)newStack).isCode()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tmpSS & 0xfffc, true); if (newStack.getDPL() != returnSegment.getRPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tmpSS & 0xfffc, true); if (!newStack.isPresent()) throw new ProcessorException(ProcessorException.Type.STACK_SEGMENT, tmpSS & 0xfffc, true); // commit cs and eip returnSegment.checkAddress(tempEIP); cs(returnSegment); eip = tempEIP; ss(newStack); if (ss.getDefaultSizeFlag()) r_esp.set32(tmpSP + stackdelta); else r_sp.set16(tmpSP + stackdelta); LOGGING.log(Level.WARNING, "Non-conforming outer privilege level ret_far used"); } else { //SAME PRIVILEGE-LEVEL returnSegment.checkAddress(tempEIP); r_esp.set32(r_esp.get32() + 4 + stackdelta); eip = tempEIP; cs(returnSegment); } } break; case 0x1c: //Code: Execute-Only, Conforming case 0x1d: //Code: Execute-Only, Conforming, Accessed case 0x1e: //Code: Execute/Read, Conforming case 0x1f: //Code: Execute/Read, Conforming, Accessed { if (returnSegment.getRPL() < getCPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS, true); if (returnSegment.getDPL() > returnSegment.getRPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS, true); if (!(returnSegment.isPresent())) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, tempCS, true); if (returnSegment.getRPL() > getCPL()) { //OUTER PRIVILEGE-LEVEL //esp += 8; LOGGING.log(Level.WARNING, "Conforming outer privilege level not implemented"); throw new IllegalStateException("Execute Failed"); } else { //SAME PRIVILEGE-LEVEL returnSegment.checkAddress(tempEIP & 0xFFFF); r_esp.set32(r_esp.get32() + 4 + stackdelta); eip = (0xFFFF & tempEIP); cs(returnSegment); } } } } public final void ret_far_o32_a16(int stackdelta) { try { ss.checkAddress((r_esp.get32() + 7) & 0xFFFF); } catch (ProcessorException e) { throw ProcessorException.STACK_SEGMENT_0; } int tempEIP = ss.getDoubleWord(r_esp.get32() & 0xFFFF); int tempCS = 0xffff & ss.getDoubleWord((r_esp.get32() + 4) & 0xFFFF); Segment returnSegment = getSegment(tempCS); if (returnSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; switch (returnSegment.getType()) { default: throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS, true); case 0x18: //Code, Execute-Only case 0x19: //Code, Execute-Only, Accessed case 0x1a: //Code, Execute/Read case 0x1b: //Code, Execute/Read, Accessed { if (returnSegment.getRPL() < getCPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS, true); if (!(returnSegment.isPresent())) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, tempCS, true); if (returnSegment.getRPL() > getCPL()) { //OUTER PRIVILEGE-LEVEL //esp += 8; LOGGING.log(Level.WARNING, "Non-conforming outer privilege level not implemented"); throw new IllegalStateException("Execute Failed"); } else { //SAME PRIVILEGE-LEVEL returnSegment.checkAddress(tempEIP); r_esp.set16(((r_esp.get32() + 8 + stackdelta) & 0xFFFF)); eip = tempEIP; cs(returnSegment); } } break; case 0x1c: //Code: Execute-Only, Conforming case 0x1d: //Code: Execute-Only, Conforming, Accessed case 0x1e: //Code: Execute/Read, Conforming case 0x1f: //Code: Execute/Read, Conforming, Accessed { if (returnSegment.getRPL() < getCPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS, true); if (returnSegment.getDPL() > returnSegment.getRPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS, true); if (!(returnSegment.isPresent())) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, tempCS, true); if (returnSegment.getRPL() > getCPL()) { //OUTER PRIVILEGE-LEVEL //esp += 8; LOGGING.log(Level.WARNING, "Conforming outer privilege level not implemented"); throw new IllegalStateException("Execute Failed"); } else { //SAME PRIVILEGE-LEVEL returnSegment.checkAddress(tempEIP); r_esp.set16(((r_esp.get32() + 8 + stackdelta) & 0xFFFF)); eip = tempEIP; cs(returnSegment); } } } } public final void ret_far_o32_a32(int stackdelta) { try { ss.checkAddress(r_esp.get32() + 7); } catch (ProcessorException e) { throw ProcessorException.STACK_SEGMENT_0; } int tempEIP = ss.getDoubleWord(r_esp.get32()); int tempCS = 0xffff & ss.getDoubleWord(r_esp.get32() + 4); Segment returnSegment = getSegment(tempCS); if (returnSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; switch (returnSegment.getType()) { default: throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS, true); case 0x18: //Code, Execute-Only case 0x19: //Code, Execute-Only, Accessed case 0x1a: //Code, Execute/Read case 0x1b: //Code, Execute/Read, Accessed { if (returnSegment.getRPL() < getCPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS, true); if (!(returnSegment.isPresent())) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, tempCS, true); if (returnSegment.getRPL() > getCPL()) { //OUTER PRIVILEGE-LEVEL try { ss.checkAddress(r_esp.get32() + 15); } catch (ProcessorException e) { throw ProcessorException.STACK_SEGMENT_0; } int returnESP = ss.getDoubleWord(r_esp.get32() + 8 + stackdelta); int tempSS = 0xffff & ss.getDoubleWord(r_esp.get32() + 12 + stackdelta); Segment returnStackSegment = getSegment(tempSS, true); if ((returnStackSegment.getRPL() != returnSegment.getRPL()) || ((returnStackSegment.getType() & 0x12) != 0x12) || (returnStackSegment.getDPL() != returnSegment.getRPL())) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempSS, true); if (!returnStackSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempSS, true); returnSegment.checkAddress(tempEIP); //esp += 20; //includes the 12 from earlier eip = tempEIP; cs(returnSegment); ss( returnStackSegment); r_esp.set32(returnESP); setCPL(cs.getRPL()); } else { //SAME PRIVILEGE-LEVEL returnSegment.checkAddress(tempEIP); r_esp.set32(r_esp.get32() + 8 + stackdelta); eip = tempEIP; cs(returnSegment); } } break; case 0x1c: //Code: Execute-Only, Conforming case 0x1d: //Code: Execute-Only, Conforming, Accessed case 0x1e: //Code: Execute/Read, Conforming case 0x1f: //Code: Execute/Read, Conforming, Accessed { if (returnSegment.getRPL() < getCPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS, true); if (returnSegment.getDPL() > returnSegment.getRPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, tempCS, true); if (!(returnSegment.isPresent())) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, tempCS, true); if (returnSegment.getRPL() > getCPL()) { //OUTER PRIVILEGE-LEVEL //esp += 8; LOGGING.log(Level.WARNING, "Conforming outer privilege level not implemented"); throw new IllegalStateException("Execute Failed"); } else { //SAME PRIVILEGE-LEVEL returnSegment.checkAddress(tempEIP); r_esp.set32(r_esp.get32() + 8); eip = tempEIP; cs(returnSegment); } } } } public void iret_pm_o32_a16() { if (eflagsNestedTask) iretFromTask(); else { int tmpESP = 0xffff & r_esp.get32(); int tempEIP = stack32(0); int tempCS = 0xffff & stack32(4); int tempEFlags = stack32(8); if ((tempEFlags & (1 << 17)) != 0) { if (getCPL() != 0) throw new IllegalStateException("Iret: VM set on stack CPL != 0!!"); iretToVirtual8086Mode(tempCS, tempEIP, tempEFlags); } else { iret32ProtectedMode(tempCS, tempEIP, tempEFlags, tmpESP); } } } public void iret_pm_o32_a32() { if (eflagsNestedTask) iretFromTask(); else { int tmpESP = r_esp.get32(); int tempEIP = stack32(0); int tempCS = 0xffff & stack32(4); int tempEFlags = stack32(8); if ((tempEFlags & (1 << 17)) != 0) { if (getCPL() != 0) throw new IllegalStateException("Iret: VM set on stack CPL != 0!!"); iretToVirtual8086Mode(tempCS, tempEIP, tempEFlags); } else { iret32ProtectedMode(tempCS, tempEIP, tempEFlags, tmpESP); } } } private final void iretFromTask() { throw new IllegalStateException("Unimplemented iret from task"); } private final void iretToVirtual8086Mode(int newCS, int newEIP, int newEFlags) { int newESP = stack32(12); int ssSelector = 0xffff & stack32(16); int esSelector = 0xffff & stack32(20); int dsSelector = 0xffff & stack32(24); int fsSelector = 0xffff & stack32(28); int gsSelector = 0xffff & stack32(32); cs(SegmentFactory.createVirtual8086ModeSegment(linearMemory, newCS, true)); eip = newEIP & 0xffff; es(SegmentFactory.createVirtual8086ModeSegment(linearMemory, esSelector, false)); ds(SegmentFactory.createVirtual8086ModeSegment(linearMemory, dsSelector, false)); fs(SegmentFactory.createVirtual8086ModeSegment(linearMemory, fsSelector, false)); gs(SegmentFactory.createVirtual8086ModeSegment(linearMemory, gsSelector, false)); ss(SegmentFactory.createVirtual8086ModeSegment(linearMemory, ssSelector, false)); r_esp.set32(newESP); // throws ModeSwitchException setEFlags(newEFlags, EFLAGS_VALID_MASK); //setCPL(3); } private final void iret32ProtectedMode(int newCS, int newEIP, int newEFlags, int tmpESP) { ProtectedModeSegment returnSegment = (ProtectedModeSegment) getSegment(newCS); if (returnSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; if (returnSegment.getRPL() < getCPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, newCS & 0xfffc, true); checkCS(returnSegment, 0, returnSegment.getRPL()); if (returnSegment.getRPL() == currentPrivilegeLevel) { // IRET to same level returnSegment.checkAddress(newEIP); cs(returnSegment); eip = newEIP; int changeMask = EFLAGS_OSZAPC_MASK | EFLAGS_TF_MASK | EFLAGS_DF_MASK | EFLAGS_NT_MASK | EFLAGS_RF_MASK; if (cpuLevel >= 4) changeMask |= EFLAGS_ID_MASK | EFLAGS_AC_MASK; if (currentPrivilegeLevel <= getIOPrivilegeLevel()) changeMask |= EFLAGS_IF_MASK; if (currentPrivilegeLevel == 0) changeMask |= EFLAGS_VIP_MASK | EFLAGS_VIF_MASK | EFLAGS_IOPL_MASK; setEFlags(newEFlags, changeMask); incrementStack(12); } else { // IRET to outer level /* 16-bit opsize | 32-bit opsize * ============================== * SS eSP+8 | SS eSP+16 * SP eSP+6 | ESP eSP+12 * FLAGS eSP+4 | EFLAGS eSP+8 * CS eSP+2 | CS eSP+4 * IP eSP+0 | EIP eSP+0 */ int ssSelector = 0xffff & ss.getWord(tmpESP+16); if ((ssSelector & 0xfffc) == 0) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true); ProtectedModeSegment returnStackSegment = (ProtectedModeSegment) getSegment(ssSelector, true); if (returnStackSegment.getRPL() != returnSegment.getRPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, ssSelector & 0xfffc, true); if (returnStackSegment.isCode() || !returnStackSegment.isDataWritable()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, ssSelector & 0xfffc, true); if (returnStackSegment.getDPL() != returnSegment.getRPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, ssSelector & 0xfffc, true); if (!returnStackSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, ssSelector & 0xfffc, true); int newESP = ss.getDoubleWord(tmpESP+12); int changeMask = EFLAGS_OSZAPC_MASK | EFLAGS_TF_MASK | EFLAGS_DF_MASK | EFLAGS_NT_MASK | EFLAGS_RF_MASK; if (cpuLevel >= 4) changeMask |= EFLAGS_ID_MASK | EFLAGS_AC_MASK; if (currentPrivilegeLevel <= getIOPrivilegeLevel()) changeMask |= EFLAGS_IF_MASK; if (currentPrivilegeLevel == 0) changeMask |= EFLAGS_VIP_MASK | EFLAGS_VIF_MASK | EFLAGS_IOPL_MASK; cs(returnSegment); eip = newEIP; setEFlags(newEFlags, changeMask); ss(returnStackSegment); if (ss.getDefaultSizeFlag()) r_esp.set32(newESP); else r_sp.set16(newESP); try { ProtectedModeSegment seg = (ProtectedModeSegment) es; if (getCPL() > seg.getDPL()) if (seg.isDataWritable() || (seg.isCode() && !seg.isConforming())) es(SegmentFactory.NULL_SEGMENT); } catch (ProcessorException e) { } catch (Exception e) { } try { ProtectedModeSegment seg = (ProtectedModeSegment) ds; if (getCPL() > seg.getDPL()) if (seg.isDataWritable() || (seg.isCode() && !seg.isConforming())) ds(SegmentFactory.NULL_SEGMENT); } catch (ProcessorException e) { } catch (Exception e) { } try { ProtectedModeSegment seg = (ProtectedModeSegment) fs; if (getCPL() > seg.getDPL()) if (seg.isDataWritable() || (seg.isCode() && !seg.isConforming())) fs(SegmentFactory.NULL_SEGMENT); } catch (ProcessorException e) { } catch (Exception e) { } try { ProtectedModeSegment seg = (ProtectedModeSegment) gs; if (getCPL() > seg.getDPL()) if (seg.isDataWritable() || (seg.isCode() && !seg.isConforming())) gs(SegmentFactory.NULL_SEGMENT); } catch (ProcessorException e) { } catch (Exception e) { } } } private void checkCS(ProtectedModeSegment newcs, int checkRPL, int checkCPL) { if (!newcs.isCode()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, newcs.getSelector() & 0xfffc, true); if (!newcs.isConforming()) { if (newcs.getDPL() != checkCPL) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, newcs.getSelector() & 0xfffc, true); if (checkRPL > checkCPL) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, newcs.getSelector() & 0xfffc, true); } else { if (newcs.getDPL() > checkCPL) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, newcs.getSelector() & 0xfffc, true); } if (!newcs.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, newcs.getSelector() & 0xfffc, true); } public void jumpFar_pm(int targetSelector, int targetEIP) { Segment newSegment = getSegment(targetSelector); //System.out.println("Far Jump: new CS: " + newSegment.getClass() + " at " + Integer.toHexString(newSegment.getBase()) + " with selector " + Integer.toHexString(newSegment.getSelector()) + " to address " + Integer.toHexString(targetEIP + newSegment.getBase())); if (newSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; switch (newSegment.getType()) { // segment type default: // not a valid segment descriptor for a jump LOGGING.log(Level.WARNING, "Invalid segment type {0,number,integer}", Integer.valueOf(newSegment.getType())); throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); case 0x05: // Task Gate LOGGING.log(Level.WARNING, "Task gate not implemented"); throw new IllegalStateException("Execute Failed"); case 0x0b: // TSS (Busy) case 0x09: // TSS (Not Busy) if ((newSegment.getDPL() < getCPL()) || (newSegment.getDPL() < newSegment.getRPL()) ) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); if (!newSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSelector, true); if (newSegment.getLimit() < 0x67) // large enough to read ? throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, targetSelector, true); if ((newSegment.getType() & 0x2) != 0) // busy ? if yes,error throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); newSegment.getByte(0); // new TSS paged into memory ? tss.getByte(0);// old TSS paged into memory ? if (tss.getLimit() < 0x5f) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, (tss.getSelector() & 0xfffc), true); //save current state into current TSS ((ProtectedModeSegment.AbstractTSS) tss).saveCPUState(this); //load new task state from new TSS int esSelector = 0xFFFF & newSegment.getWord(0x48); // read new registers int csSelector = 0xFFFF & newSegment.getWord(0x4c); int ssSelector = 0xFFFF & newSegment.getWord(0x50); int dsSelector = 0xFFFF & newSegment.getWord(0x54); int fsSelector = 0xFFFF & newSegment.getWord(0x58); int gsSelector = 0xFFFF & newSegment.getWord(0x5c); int ldtSelector = 0xFFFF & newSegment.getWord(0x60); int trapWord = 0xFFFF & newSegment.getWord(0x64); ((ProtectedModeSegment) es).supervisorSetSelector(esSelector); if (cs instanceof ProtectedModeSegment) { ((ProtectedModeSegment) cs).supervisorSetSelector(csSelector); ((ProtectedModeSegment) ss).supervisorSetSelector(ssSelector); ((ProtectedModeSegment) ds).supervisorSetSelector(dsSelector); if (fs != SegmentFactory.NULL_SEGMENT) ((ProtectedModeSegment) fs).supervisorSetSelector(fsSelector); if (gs != SegmentFactory.NULL_SEGMENT) ((ProtectedModeSegment) gs).supervisorSetSelector(gsSelector); } //clear busy bit for old task int descriptorHigh = readSupervisorDoubleWord(gdtr, (tss.getSelector() & 0xfff8) + 4); descriptorHigh &= ~0x200; setSupervisorDoubleWord(gdtr, (tss.getSelector() & 0xfff8) + 4, descriptorHigh); //set busy bit for new task descriptorHigh = readSupervisorDoubleWord(gdtr,(targetSelector & 0xfff8) + 4); descriptorHigh |= 0x200; setSupervisorDoubleWord(gdtr, (targetSelector & 0xfff8) + 4, descriptorHigh); //commit new TSS setCR0(getCR0() | 0x8); // set TS flag in CR0; tss = getSegment(targetSelector); //includes updated busy flag ((ProtectedModeSegment.AbstractTSS) tss).restoreCPUState(this); // Task switch clear LE/L3/L2/L1/L0 in dr7 dr7 &= ~0x155; int tempCPL = getCPL(); //set cpl to 3 to force a privilege level change and stack switch if SS isn't properly loaded setCPL(3); if((ldtSelector & 0x4) !=0) // not in gdt throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, ldtSelector, true); //load ldt if ((ldtSelector & 0xfffc ) != 0) { gdtr.checkAddress((ldtSelector & ~0x7) + 7 ) ;// check ldtr is valid if((readSupervisorByte(gdtr, ((ldtSelector & ~0x7) + 5 ))& 0xE) != 2) // not a ldt entry { System.out.println("Tried to load LDT in task switch with invalid segment type: 0x" + Integer.toHexString(readSupervisorByte(gdtr, ((ldtSelector & ~0x7) + 5 )& 0xF))); throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, ldtSelector & 0xfffc, true); } Segment newLdtr=getSegment(ldtSelector); // get new ldt if (!newLdtr.isSystem()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, ldtSelector & 0xfffc, true); if (!newLdtr.isPresent()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, ldtSelector & 0xfffc, true); ldtr = newLdtr; } if (isVirtual8086Mode()) { System.out.println("VM TSS"); //load vm86 segments setCPL(3); throw new IllegalStateException("Unimplemented task switch to VM86 mode"); } else { setCPL(csSelector & 3); //load SS if ((ssSelector & 0xfffc) != 0) { Segment newSS = getSegment(ssSelector, true); if (newSS.isSystem() || ((ProtectedModeSegment) newSS).isCode() || !((ProtectedModeSegment) newSS).isDataWritable()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, ssSelector & 0xfffc, true); if (!newSS.isPresent()) throw new ProcessorException(ProcessorException.Type.STACK_SEGMENT, ssSelector & 0xfffc, true); if (newSS.getDPL() != cs.getRPL()) { System.out.println("SS.dpl != cs.rpl : " + newSS.getDPL() + "!=" + cs.getRPL()); throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, ssSelector & 0xfffc, true); } if (newSS.getDPL() != newSS.getRPL()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, ssSelector & 0xfffc, true); ss(newSS); } else throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, ssSelector & 0xfffc, true); int newCsRpl = csSelector & 3; //load other data segments if ((dsSelector & 0xfffc) != 0) { ProtectedModeSegment newDS = (ProtectedModeSegment) getSegment(dsSelector); if (newDS.isSystem() || (newDS.isCode() && ((newDS.getType() & 2) == 0))) { System.out.println(newDS.isSystem()); throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, dsSelector & 0xfffc, true); } if (!newDS.isConforming() || newDS.isDataWritable()) if ((newDS.getRPL() > newDS.getDPL()) || (newCsRpl > newDS.getDPL())) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, dsSelector & 0xfffc, true); if (!newDS.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, dsSelector & 0xfffc, true); ds(newDS); } if ((esSelector & 0xfffc) != 0) { ProtectedModeSegment newES = (ProtectedModeSegment) getSegment(esSelector); if (newES.isSystem() || (newES.isCode() && ((newES.getType() & 2) == 0))) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, esSelector & 0xfffc, true); if (!newES.isConforming() || newES.isDataWritable()) if ((newES.getRPL() > newES.getDPL()) || (newCsRpl > newES.getDPL())) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, esSelector & 0xfffc, true); if (!newES.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, esSelector & 0xfffc, true); es(newES); } if ((fsSelector & 0xfffc) != 0) { ProtectedModeSegment newFS = (ProtectedModeSegment) getSegment(fsSelector); if (newFS.isSystem() || (newFS.isCode() && ((newFS.getType() & 2) == 0))) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, fsSelector & 0xfffc, true); if (!newFS.isConforming() || newFS.isDataWritable()) if ((newFS.getRPL() > newFS.getDPL()) || (newCsRpl > newFS.getDPL())) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, fsSelector & 0xfffc, true); if (!newFS.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, fsSelector & 0xfffc, true); fs(newFS); } if ((gsSelector & 0xfffc) != 0) { ProtectedModeSegment newGS = (ProtectedModeSegment) getSegment(gsSelector); if (newGS.isSystem() || (newGS.isCode() && ((newGS.getType() & 2) == 0))) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, gsSelector & 0xfffc, true); if (!newGS.isConforming() || newGS.isDataWritable()) if ((newGS.getRPL() > newGS.getDPL()) || (newCsRpl > newGS.getDPL())) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, gsSelector & 0xfffc, true); if (!newGS.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, gsSelector & 0xfffc, true); gs(newGS); } //load CS if ((csSelector & 0xfffc) != 0) { Segment newCS = getSegment(csSelector); if (newCS.isSystem() || ((ProtectedModeSegment) newCS).isDataWritable()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, csSelector & 0xfffc, true); if (!((ProtectedModeSegment) newCS).isConforming() && (newCS.getDPL() != newCS.getRPL())) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, csSelector & 0xfffc, true); if (((ProtectedModeSegment) newCS).isConforming() && (newCS.getDPL() > newCS.getRPL())) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, csSelector & 0xfffc, true); if (!newCS.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, csSelector & 0xfffc, true); cs(newCS); cs.checkAddress(eip); } else throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, csSelector & 0xfffc, true); } return; case 0x0c: // Call Gate LOGGING.log(Level.WARNING, "Call gate not implemented"); throw new IllegalStateException("Execute Failed"); case 0x18: // Non-conforming Code Segment case 0x19: // Non-conforming Code Segment case 0x1a: // Non-conforming Code Segment case 0x1b: { // Non-conforming Code Segment if ((newSegment.getRPL() != getCPL()) || (newSegment.getDPL() > getCPL())) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); if (!newSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSelector, true); newSegment.checkAddress(targetEIP); newSegment.setRPL(getCPL()); cs(newSegment); eip = targetEIP; return; } case 0x1c: // Conforming Code Segment (Not Readable & Not Accessed) case 0x1d: // Conforming Code Segment (Not Readable & Accessed) case 0x1e: // Conforming Code Segment (Readable & Not Accessed) case 0x1f: { // Conforming Code Segment (Readable & Accessed) if (newSegment.getDPL() > getCPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); if (!newSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSelector, true); newSegment.checkAddress(targetEIP); newSegment.setRPL(getCPL()); cs(newSegment); eip = targetEIP; return; } } } public void jumpFar(int seg, int eip) { cs.setSelector(seg & 0xffff); this.eip = eip; } public void callFar(int targetSelector, short targetEIP) { //System.out.printf("call far o16: %04x:%04x\n", targetSelector, targetEIP); if (((0xffff & r_sp.get16()) < 4) && (r_esp.get16() != 0)) throw ProcessorException.STACK_SEGMENT_0; ss.setWord((r_sp.get16() - 2) & 0xffff, (short)cs.getSelector()); ss.setWord((r_sp.get16() - 4) & 0xffff, (short)eip); r_sp.set16(r_sp.get16()-4); eip = targetEIP & 0xffff; cs.setSelector(targetSelector & 0xffff); } public final void call_far_pm_o16_a32(int targetSelector, int targetEIP) { Segment newSegment = getSegment(targetSelector); if (newSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; switch (newSegment.getType()) { // segment type default: // not a valid segment descriptor for a jump LOGGING.log(Level.WARNING, "Invalid segment type {0,number,integer}", Integer.valueOf(newSegment.getType())); throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); case 0x01: // TSS 16-bit (Not Busy) case 0x03: // TSS 16-bit (Busy) LOGGING.log(Level.WARNING, "16-bit TSS not implemented"); throw new IllegalStateException("Execute Failed"); case 0x04: // Call Gate 16-bit { if ((newSegment.getRPL() > getCPL()) || (newSegment.getDPL() < getCPL())) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); if (!newSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSelector, true); ProtectedModeSegment.GateSegment gate = (ProtectedModeSegment.GateSegment) newSegment; int targetSegmentSelector = gate.getTargetSegment(); Segment targetSegment; try { targetSegment = getSegment(targetSegmentSelector); } catch (ProcessorException e) { throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector, true); } if (targetSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; if (targetSegment.getDPL() > getCPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); switch (targetSegment.getType()) { default: throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector, true); case 0x18: //Code, Execute-Only case 0x19: //Code, Execute-Only, Accessed case 0x1a: //Code, Execute/Read case 0x1b: //Code, Execute/Read, Accessed { if (!targetSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSegmentSelector, true); if (targetSegment.getDPL() < getCPL()) { LOGGING.log(Level.WARNING, "16-bit call gate: jump to more privileged segment not implemented"); throw new IllegalStateException("Execute Failed"); //MORE-PRIVILEGE } else if (targetSegment.getDPL() == getCPL()) { LOGGING.log(Level.WARNING, "16-bit call gate: jump to same privilege segment not implemented"); throw new IllegalStateException("Execute Failed"); //SAME-PRIVILEGE } else throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector, true); } // break; case 0x1c: //Code: Execute-Only, Conforming case 0x1d: //Code: Execute-Only, Conforming, Accessed case 0x1e: //Code: Execute/Read, Conforming case 0x1f: //Code: Execute/Read, Conforming, Accessed { if (!targetSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSegmentSelector, true); LOGGING.log(Level.WARNING, "16-bit call gate: jump to same privilege conforming segment not implemented"); throw new IllegalStateException("Execute Failed"); //SAME-PRIVILEGE } // break; } } // break; case 0x05: // Task Gate LOGGING.log(Level.WARNING, "Task gate not implemented"); throw new IllegalStateException("Execute Failed"); case 0x09: // TSS (Not Busy) case 0x0b: // TSS (Busy) LOGGING.log(Level.WARNING, "TSS not implemented"); throw new IllegalStateException("Execute Failed"); case 0x0c: // Call Gate LOGGING.log(Level.WARNING, "Call gate not implemented"); throw new IllegalStateException("Execute Failed"); case 0x18: // Non-conforming Code Segment case 0x19: // Non-conforming Code Segment case 0x1a: // Non-conforming Code Segment case 0x1b: // Non-conforming Code Segment { if ((newSegment.getRPL() > getCPL()) || (newSegment.getDPL() != getCPL())) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); if (!newSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSelector, true); if ((r_esp.get32() < 4) && (r_esp.get32() > 0)) throw ProcessorException.STACK_SEGMENT_0; newSegment.checkAddress(targetEIP&0xFFFF); push16((short)cs.getSelector()); push16((short)eip); cs(newSegment); cs.setRPL(getCPL()); eip = targetEIP & 0xFFFF; return; } case 0x1c: // Conforming Code Segment (Not Readable & Not Accessed) case 0x1d: // Conforming Code Segment (Not Readable & Accessed) case 0x1e: // Conforming Code Segment (Readable & Not Accessed) case 0x1f: // Conforming Code Segment (Readable & Accessed) LOGGING.log(Level.WARNING, "Conforming code segment not implemented"); throw new IllegalStateException("Execute Failed"); } } public final void call_far_pm_o16_a16(int targetSelector, int targetEIP) { if ((targetSelector & 0xfffc) == 0) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; Segment newSegment = getSegment(targetSelector); if (newSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; switch (newSegment.getType()) { // segment type default: // not a valid segment descriptor for a jump LOGGING.log(Level.WARNING, "Invalid segment type {0,number,integer}", Integer.valueOf(newSegment.getType())); throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); case 0x01: // TSS 16-bit (Not Busy) case 0x03: // TSS 16-bit (Busy) LOGGING.log(Level.WARNING, "16-bit TSS not implemented"); throw new IllegalStateException("Execute Failed"); case 0x04: // Call Gate 16-bit { if ((newSegment.getDPL() < newSegment.getRPL()) || (newSegment.getDPL() < getCPL())) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector & 0xfffc, true); if (!newSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSelector & 0xfffc, true); ProtectedModeSegment.CallGate16Bit gate = (ProtectedModeSegment.CallGate16Bit) newSegment; int targetSegmentSelector = gate.getTargetSegment(); if ((targetSegmentSelector & 0xfffc) == 0) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, 0, true); Segment targetSegment; try { targetSegment = getSegment(targetSegmentSelector); } catch (ProcessorException e) { throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector & 0xfffc, true); } if (targetSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector & 0xfffc, true); if ((targetSegment.getDPL() > getCPL()) || (targetSegment.isSystem()) || ((targetSegment.getType() & 0x18) == 0x10)) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector & 0xfffc, true); if (!targetSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSegmentSelector & 0xfffc, true); switch (targetSegment.getType()) { default: throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector, true); case 0x18: //Code, Execute-Only case 0x19: //Code, Execute-Only, Accessed case 0x1a: //Code, Execute/Read case 0x1b: //Code, Execute/Read, Accessed { if (targetSegment.getDPL() < getCPL()) { //MORE-PRIVILEGE int newStackSelector = 0; int newESP = 0; if ((tss.getType() & 0x8) != 0) { int tssStackAddress = (targetSegment.getDPL() * 8) + 4; if ((tssStackAddress + 7) > tss.getLimit()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, tss.getSelector(), true); boolean isSup = linearMemory.isSupervisor(); try { linearMemory.setSupervisor(true); newStackSelector = 0xffff & tss.getWord(tssStackAddress + 4); newESP = tss.getDoubleWord(tssStackAddress); } finally { linearMemory.setSupervisor(isSup); } } else { int tssStackAddress = (targetSegment.getDPL() * 4) + 2; if ((tssStackAddress + 4) > tss.getLimit()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, tss.getSelector(), true); newStackSelector = 0xffff & tss.getWord(tssStackAddress + 2); newESP = 0xffff & tss.getWord(tssStackAddress); } if ((newStackSelector & 0xfffc) == 0) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, 0, true); Segment newStackSegment; try { newStackSegment = getSegment(newStackSelector, true); } catch (ProcessorException e) { throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, newStackSelector, true); } if (newStackSegment.getRPL() != targetSegment.getDPL()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, newStackSelector & 0xfffc, true); if ((newStackSegment.getDPL() != targetSegment.getDPL()) || ((newStackSegment.getType() & 0x1a) != 0x12)) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, newStackSelector & 0xfffc, true); if (!(newStackSegment.isPresent())) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, newStackSelector & 0xfffc, true); int parameters = gate.getParameterCount() & 0x1f; if ((newStackSegment.getDefaultSizeFlag() && (r_esp.get32() < 8 + 2 * parameters) && (r_esp.get32() > 0)) || !newStackSegment.getDefaultSizeFlag() && ((r_esp.get32() & 0xffff) < 8 + 2 * parameters)) throw ProcessorException.STACK_SEGMENT_0; int targetOffset = 0xffff & gate.getTargetOffset(); int returnSS = ss.getSelector(); Segment oldStack = ss; int returnESP; if (ss.getDefaultSizeFlag()) returnESP = r_esp.get32(); else returnESP = r_esp.get32() & 0xffff; int oldCS = cs.getSelector(); int oldEIP; if (cs.getDefaultSizeFlag()) oldEIP = eip; else oldEIP = eip & 0xffff; ss = newStackSegment; r_esp.set32(newESP); ss.setRPL(targetSegment.getDPL()); push16((short)returnSS); push16((short)returnESP); if (ss.getDefaultSizeFlag()) { for (int i = 0; i < parameters; i++) { push16(oldStack.getWord(returnESP + 2*parameters - 2*i -2)); } } else { for (int i = 0; i < parameters; i++) { push16(oldStack.getWord((returnESP + 2*parameters - 2*i -2) & 0xffff)); } } push16((short)oldCS); push16((short)oldEIP); targetSegment.checkAddress(targetOffset); cs(targetSegment); eip = targetOffset; setCPL(ss.getDPL()); cs.setRPL(getCPL()); } else if (targetSegment.getDPL() == getCPL()) { LOGGING.log(Level.WARNING, "16-bit call gate: jump to same privilege segment not implemented"); throw new IllegalStateException("Execute Failed"); //SAME-PRIVILEGE } else throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector, true); } break; case 0x1c: //Code: Execute-Only, Conforming case 0x1d: //Code: Execute-Only, Conforming, Accessed case 0x1e: //Code: Execute/Read, Conforming case 0x1f: //Code: Execute/Read, Conforming, Accessed { LOGGING.log(Level.WARNING, "16-bit call gate: jump to same privilege conforming segment not implemented"); throw new IllegalStateException("Execute Failed"); //SAME-PRIVILEGE } // break; } } break; case 0x05: // Task Gate LOGGING.log(Level.WARNING, "Task gate not implemented"); throw new IllegalStateException("Execute Failed"); case 0x09: // TSS (Not Busy) case 0x0b: // TSS (Busy) LOGGING.log(Level.WARNING, "TSS not implemented"); throw new IllegalStateException("Execute Failed"); case 0x0c: // Call Gate LOGGING.log(Level.WARNING, "Call gate not implemented"); throw new IllegalStateException("Execute Failed"); case 0x18: // Non-conforming Code Segment case 0x19: // Non-conforming Code Segment case 0x1a: // Non-conforming Code Segment case 0x1b: // Non-conforming Code Segment { if(!newSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, newSegment.getSelector(), true); if ((r_esp.get32() < 4) && (r_esp.get32() > 0)) throw ProcessorException.STACK_SEGMENT_0; newSegment.checkAddress(targetEIP&0xFFFF); int tempESP; if (ss.getDefaultSizeFlag()) tempESP = r_esp.get32(); else tempESP = r_esp.get32() & 0xffff; ss.setWord((tempESP - 2), (short) (0xFFFF & cs.getSelector())); ss.setWord((tempESP - 4), (short) (0xFFFF & eip)); r_esp.set16(((r_esp.get16()-4) & 0xFFFF)); cs(newSegment); cs.setRPL(getCPL()); eip = targetEIP & 0xFFFF; return; } case 0x1c: // Conforming Code Segment (Not Readable & Not Accessed) case 0x1d: // Conforming Code Segment (Not Readable & Accessed) case 0x1e: // Conforming Code Segment (Readable & Not Accessed) case 0x1f: // Conforming Code Segment (Readable & Accessed) LOGGING.log(Level.WARNING, "Conforming code segment not implemented"); throw new IllegalStateException("Execute Failed"); } } public final void call_far_pm_o32_a16(int targetSelector, int targetEIP) { Segment newSegment = getSegment(targetSelector); if (newSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; switch (newSegment.getType()) { // segment type default: // not a valid segment descriptor for a jump LOGGING.log(Level.WARNING, "Invalid segment type {0,number,integer}", Integer.valueOf(newSegment.getType())); throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); case 0x01: // TSS 16-bit (Not Busy) case 0x03: // TSS 16-bit (Busy) LOGGING.log(Level.WARNING, "16-bit TSS not implemented"); throw new IllegalStateException("Execute Failed"); case 0x04: // Call Gate 16-bit { if ((newSegment.getRPL() > getCPL()) || (newSegment.getDPL() < getCPL())) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); if (!newSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSelector, true); ProtectedModeSegment.GateSegment gate = (ProtectedModeSegment.GateSegment) newSegment; int targetSegmentSelector = gate.getTargetSegment(); Segment targetSegment; try { targetSegment = getSegment(targetSegmentSelector); } catch (ProcessorException e) { throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector, true); } if (targetSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; if (targetSegment.getDPL() > getCPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); switch (targetSegment.getType()) { default: throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector, true); case 0x18: //Code, Execute-Only case 0x19: //Code, Execute-Only, Accessed case 0x1a: //Code, Execute/Read case 0x1b: //Code, Execute/Read, Accessed { if (!targetSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSegmentSelector, true); if (targetSegment.getDPL() < getCPL()) { LOGGING.log(Level.WARNING, "16-bit call gate: jump to more privileged segment not implemented"); throw new IllegalStateException("Execute Failed"); //MORE-PRIVILEGE } else if (targetSegment.getDPL() == getCPL()) { LOGGING.log(Level.WARNING, "16-bit call gate: jump to same privilege segment not implemented"); throw new IllegalStateException("Execute Failed"); //SAME-PRIVILEGE } else throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector, true); } // break; case 0x1c: //Code: Execute-Only, Conforming case 0x1d: //Code: Execute-Only, Conforming, Accessed case 0x1e: //Code: Execute/Read, Conforming case 0x1f: //Code: Execute/Read, Conforming, Accessed { if (!targetSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSegmentSelector, true); LOGGING.log(Level.WARNING, "16-bit call gate: jump to same privilege conforming segment not implemented"); throw new IllegalStateException("Execute Failed"); //SAME-PRIVILEGE } // break; } } // break; case 0x05: // Task Gate LOGGING.log(Level.WARNING, "Task gate not implemented"); throw new IllegalStateException("Execute Failed"); case 0x09: // TSS (Not Busy) case 0x0b: // TSS (Busy) LOGGING.log(Level.WARNING, "TSS not implemented"); throw new IllegalStateException("Execute Failed"); case 0x0c: // Call Gate LOGGING.log(Level.WARNING, "Call gate not implemented"); throw new IllegalStateException("Execute Failed"); case 0x18: // Non-conforming Code Segment case 0x19: // Non-conforming Code Segment case 0x1a: // Non-conforming Code Segment case 0x1b: // Non-conforming Code Segment { if ((newSegment.getRPL() > getCPL()) || (newSegment.getDPL() != getCPL())) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); if (!newSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSelector, true); if ((r_esp.get16() & 0xffff) < 8) throw ProcessorException.STACK_SEGMENT_0; newSegment.checkAddress(targetEIP); push32(cs.getSelector()); push32(eip); cs(newSegment); cs.setRPL(getCPL()); eip = targetEIP; return; } case 0x1c: // Conforming Code Segment (Not Readable & Not Accessed) case 0x1d: // Conforming Code Segment (Not Readable & Accessed) case 0x1e: // Conforming Code Segment (Readable & Not Accessed) case 0x1f: // Conforming Code Segment (Readable & Accessed) LOGGING.log(Level.WARNING, "Conforming code segment not implemented"); throw new IllegalStateException("Execute Failed"); } } public final void call_far_pm_o32_a32(int targetSelector, int targetEIP) { Segment newSegment = getSegment(targetSelector); if (newSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; switch (newSegment.getType()) { // segment type default: // not a valid segment descriptor for a jump LOGGING.log(Level.WARNING, "Invalid segment type {0,number,integer}", Integer.valueOf(newSegment.getType())); throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); case 0x01: // TSS 16-bit (Not Busy) case 0x03: // TSS 16-bit (Busy) LOGGING.log(Level.WARNING, "16-bit TSS not implemented"); throw new IllegalStateException("Execute Failed"); case 0x04: // Call Gate 16-bit { if ((newSegment.getRPL() > getCPL()) || (newSegment.getDPL() < getCPL())) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); if (!newSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSelector, true); ProtectedModeSegment.GateSegment gate = (ProtectedModeSegment.GateSegment) newSegment; int targetSegmentSelector = gate.getTargetSegment(); Segment targetSegment; try { targetSegment = getSegment(targetSegmentSelector); } catch (ProcessorException e) { throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector, true); } if (targetSegment == SegmentFactory.NULL_SEGMENT) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; if (targetSegment.getDPL() > getCPL()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); switch (targetSegment.getType()) { default: throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector, true); case 0x18: //Code, Execute-Only case 0x19: //Code, Execute-Only, Accessed case 0x1a: //Code, Execute/Read case 0x1b: //Code, Execute/Read, Accessed { if (!targetSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSegmentSelector, true); if (targetSegment.getDPL() < getCPL()) { LOGGING.log(Level.WARNING, "16-bit call gate: jump to more privileged segment not implemented"); throw new IllegalStateException("Execute Failed"); //MORE-PRIVILEGE } else if (targetSegment.getDPL() == getCPL()) { LOGGING.log(Level.WARNING, "16-bit call gate: jump to same privilege segment not implemented"); throw new IllegalStateException("Execute Failed"); //SAME-PRIVILEGE } else throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector, true); } // break; case 0x1c: //Code: Execute-Only, Conforming case 0x1d: //Code: Execute-Only, Conforming, Accessed case 0x1e: //Code: Execute/Read, Conforming case 0x1f: //Code: Execute/Read, Conforming, Accessed { if (!targetSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSegmentSelector, true); LOGGING.log(Level.WARNING, "16-bit call gate: jump to same privilege conforming segment not implemented"); throw new IllegalStateException("Execute Failed"); //SAME-PRIVILEGE } // break; } } // break; case 0x05: // Task Gate LOGGING.log(Level.WARNING, "Task gate not implemented"); throw new IllegalStateException("Execute Failed"); case 0x09: // TSS (Not Busy) case 0x0b: // TSS (Busy) LOGGING.log(Level.WARNING, "TSS not implemented"); throw new IllegalStateException("Execute Failed"); case 0x0c: // Call Gate LOGGING.log(Level.WARNING, "Call gate not implemented"); throw new IllegalStateException("Execute Failed"); case 0x18: // Non-conforming Code Segment case 0x19: // Non-conforming Code Segment case 0x1a: // Non-conforming Code Segment case 0x1b: // Non-conforming Code Segment { if ((newSegment.getRPL() > getCPL()) || (newSegment.getDPL() != getCPL())) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSelector, true); if (!newSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSelector, true); if ((r_esp.get32() < 8) && (r_esp.get32() > 0)) throw ProcessorException.STACK_SEGMENT_0; newSegment.checkAddress(targetEIP); push32(cs.getSelector()); push32(eip); cs(newSegment); cs.setRPL(getCPL()); eip = targetEIP; return; } case 0x1c: // Conforming Code Segment (Not Readable & Not Accessed) case 0x1d: // Conforming Code Segment (Not Readable & Accessed) case 0x1e: // Conforming Code Segment (Readable & Not Accessed) case 0x1f: // Conforming Code Segment (Readable & Accessed) LOGGING.log(Level.WARNING, "Conforming code segment not implemented"); throw new IllegalStateException("Execute Failed"); } } public final void int_o16_a16(int vector) { //System.out.println("Real Mode exception " + Integer.toHexString(vector)); //if (vector == 0) // throw new IllegalStateException("INT 0 allowed? 0x" + Integer.toHexString(getInstructionPointer())); if (((0xffff & r_sp.get16()) < 6) && (r_sp.get16() != 0)) { throw ProcessorException.STACK_SEGMENT_0;//? //maybe just change vector value } int esp = push16(r_esp.get32(), (short)getEFlags()); eflagsInterruptEnable = false; eflagsTrap = false; eflagsAlignmentCheck = false; eflagsResume=false; esp = push16(esp, (short)cs.getSelector()); //System.out.printf("INT: saved cs=%04x to %04x\n", cs.getSelector(), esp); esp = push16(esp, (short)eip); //System.out.printf("INT: saved eip=%04x to %04x\n", (short)eip, esp); int debug = getInstructionPointer(); // read interrupt vector int neweip = 0xffff & idtr.getWord(4*vector); // now commit cs.setSelector(0xffff & idtr.getWord(4*vector+2)); eip = neweip; r_esp.set32(esp); //System.out.printf("INT: targeteip=%04x cs: %04x\n", (short)eip, cs()); } public void sysenter() { int csSelector = (int) getMSR(Processor.SYSENTER_CS_MSR); if (csSelector == 0) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; eflagsInterruptEnable = false; eflagsResume = false; eflagsVirtual8086Mode = false; cs(SegmentFactory.createProtectedModeSegment(linearMemory, csSelector & 0xfffc, 0x00cf9b000000ffffl)); // 0 base addr, G, D, P, S, Code, C, A setCPL(0); ss(SegmentFactory.createProtectedModeSegment(linearMemory, (csSelector + 8) & 0xfffc, 0x00cf93000000ffffl));// 0 base addr, G, D, P, S, Data, R, A r_esp.set32((int) getMSR(Processor.SYSENTER_ESP_MSR)); eip = (int) getMSR(Processor.SYSENTER_EIP_MSR); } public void sysexit() { int csSelector= (int)getMSR(Processor.SYSENTER_CS_MSR); if ((csSelector & RPL_MASK) == 0) throw ProcessorException.GENERAL_PROTECTION_0; if (getCPL() != 0) throw ProcessorException.GENERAL_PROTECTION_0; cs(SegmentFactory.createProtectedModeSegment(linearMemory, (csSelector + 16) | 3, 0x00cffb000000ffffl)); // 0 base, G, D, P, DPL=3, S, Code, C, A, setCPL(3); ss(SegmentFactory.createProtectedModeSegment(linearMemory, (csSelector + 24) | 3, 0x00cff3000000ffffl)); correctAlignmentChecking(ss); r_esp.set32(r_ecx.get32()); eip = r_edx.get32(); } public final void enter_o32_a32(int frameSize, int nestingLevel) { nestingLevel %= 32; int tempESP = r_esp.get32(); int tempEBP = r_ebp.get32(); if (nestingLevel == 0) { if ((tempESP < (4 + frameSize)) && (tempESP > 0)) throw ProcessorException.STACK_SEGMENT_0; } else { if ((tempESP < (4 + frameSize + 4 * nestingLevel)) && (tempESP > 0)) throw ProcessorException.STACK_SEGMENT_0; } tempESP -= 4; ss.setDoubleWord(tempESP, tempEBP); int frameTemp = tempESP; int tmplevel = nestingLevel; if (nestingLevel != 0) { while (--tmplevel != 0) { tempEBP -= 4; tempESP -= 4; ss.setDoubleWord(tempESP, ss.getDoubleWord(tempEBP)); } tempESP -= 4; ss.setDoubleWord(tempESP, frameTemp); } r_ebp.set32(frameTemp); r_esp.set32(frameTemp - frameSize - 4*nestingLevel); } public final void enter_o32_a16(int frameSize, int nestingLevel) { nestingLevel %= 32; int frameTemp = r_esp.get32(); int tempESP = frameTemp & 0xffff; int tempEBP = r_ebp.get32() & 0xffff; if (nestingLevel == 0) { if ((tempESP < (4 + frameSize)) && (tempESP > 0)) throw ProcessorException.STACK_SEGMENT_0; } else { if ((tempESP < (4 + frameSize + 4 * nestingLevel)) && (tempESP > 0)) throw ProcessorException.STACK_SEGMENT_0; } tempESP -= 4; ss.setDoubleWord(tempESP, tempEBP); int tmplevel = nestingLevel; if (nestingLevel != 0) { while (--tmplevel != 0) { tempEBP -= 4; tempESP -= 4; ss.setDoubleWord(tempESP, ss.getDoubleWord(tempEBP)); } tempESP -= 4; ss.setDoubleWord(tempESP, frameTemp); } r_ebp.set32(frameTemp); r_esp.set32(frameTemp - frameSize - 4*nestingLevel); } public void printState() { System.out.println("********************************"); System.out.println("CPU State:"); if (isProtectedMode()) if (isVirtual8086Mode()) System.out.println("Virtual8086 Mode"); else System.out.println("Protected Mode"); else System.out.println("Real Mode"); System.out.println("EAX: " + Integer.toHexString(r_eax.get32())); System.out.println("EBX: " + Integer.toHexString(r_ebx.get32())); System.out.println("EDX: " + Integer.toHexString(r_edx.get32())); System.out.println("ECX: " + Integer.toHexString(r_ecx.get32())); System.out.println("ESI: " + Integer.toHexString(r_esi.get32())); System.out.println("EDI: " + Integer.toHexString(r_edi.get32())); System.out.println("ESP: " + Integer.toHexString(r_esp.get32())); System.out.println("EBP: " + Integer.toHexString(r_ebp.get32())); System.out.println("EIP: " + Integer.toHexString(eip)); System.out.println("EFLAGS: " + Integer.toHexString(getEFlags())); System.out.println("CS selector-base: " + Integer.toHexString(cs.getSelector()) + "-" + Integer.toHexString(cs.getBase()) + " (" + cs.getClass().toString() + ")"); System.out.println("DS selector-base: " + Integer.toHexString(ds.getSelector()) + "-" + Integer.toHexString(ds.getBase()) + " (" + cs.getClass().toString() + ")"); System.out.println("ES selector-base: " + Integer.toHexString(es.getSelector()) + "-" + Integer.toHexString(es.getBase()) + " (" + cs.getClass().toString() + ")"); System.out.println("FS selector-base: " + Integer.toHexString(fs.getSelector()) + "-" + Integer.toHexString(fs.getBase()) + " (" + cs.getClass().toString() + ")"); System.out.println("GS selector-base: " + Integer.toHexString(gs.getSelector()) + "-" + Integer.toHexString(gs.getBase()) + " (" + cs.getClass().toString() + ")"); System.out.println("SS selector-base: " + Integer.toHexString(ss.getSelector()) + "-" + Integer.toHexString(ss.getBase()) + " (" + cs.getClass().toString() + ")"); System.out.println("GDTR base-limit: " + Integer.toHexString(gdtr.getBase()) + "-" + Integer.toHexString(gdtr.getLimit()) + " (" + cs.getClass().toString() + ")"); System.out.println("IDTR base-limit: " + Integer.toHexString(idtr.getBase()) + "-" + Integer.toHexString(idtr.getLimit()) + " (" + cs.getClass().toString() + ")"); if (ldtr == SegmentFactory.NULL_SEGMENT) System.out.println("Null LDTR"); else System.out.println("LDTR base-limit: " + Integer.toHexString(ldtr.getBase()) + "-" + Integer.toHexString(ldtr.getLimit()) + " (" + cs.getClass().toString() + ")"); if (tss == SegmentFactory.NULL_SEGMENT) System.out.println("Null TSS"); else System.out.println("TSS selector-base: " + Integer.toHexString(tss.getSelector()) + "-" + Integer.toHexString(tss.getBase()) + " (" + cs.getClass().toString() + ")"); System.out.println("CR0: " + Integer.toHexString(cr0)); System.out.println("CR1: " + Integer.toHexString(cr1)); System.out.println("CR2: " + Integer.toHexString(cr2)); System.out.println("CR3: " + Integer.toHexString(cr3)); System.out.println("CR4: " + Integer.toHexString(cr4)); System.out.println("********************************"); } public void saveState(DataOutput output) throws IOException { output.writeInt(this.r_eax.get32()); output.writeInt(this.r_ebx.get32()); output.writeInt(this.r_edx.get32()); output.writeInt(this.r_ecx.get32()); output.writeInt(this.r_esi.get32()); output.writeInt(this.r_edi.get32()); output.writeInt(this.r_esp.get32()); output.writeInt(this.r_ebp.get32()); output.writeInt(this.eip); output.writeInt(this.dr0); output.writeInt(this.dr1); output.writeInt(this.dr2); output.writeInt(this.dr3); output.writeInt(this.dr4); output.writeInt(this.dr5); output.writeInt(this.dr6); output.writeInt(this.dr7); output.writeInt(this.cr0); output.writeInt(this.cr1); output.writeInt(this.cr2); output.writeInt(this.cr3); output.writeInt(this.cr4); output.writeBoolean(getCarryFlag(flagStatus, cf, flagOp1, flagOp2, flagResult, flagIns)); output.writeBoolean(getParityFlag(flagStatus, pf, flagResult)); output.writeBoolean(getAuxCarryFlag(flagStatus, af, flagOp1, flagOp2, flagResult, flagIns)); output.writeBoolean(getZeroFlag(flagStatus, zf, flagResult)); output.writeBoolean(getSignFlag(flagStatus, sf, flagResult)); output.writeBoolean(this.eflagsTrap); output.writeBoolean(this.eflagsInterruptEnable); output.writeBoolean(df); output.writeBoolean(getOverflowFlag(flagStatus, of, flagOp1, flagOp2, flagResult, flagIns)); output.writeInt(this.eflagsIOPrivilegeLevel); output.writeBoolean(this.eflagsNestedTask); output.writeBoolean(this.eflagsResume); output.writeBoolean(this.eflagsVirtual8086Mode); output.writeBoolean(this.eflagsAlignmentCheck); output.writeBoolean(this.eflagsVirtualInterrupt); output.writeBoolean(this.eflagsVirtualInterruptPending); output.writeBoolean(this.eflagsID); output.writeBoolean(true); fpu.saveState(output); output.writeInt(interruptFlags); output.writeBoolean(alignmentChecking); output.writeLong(resetTime); output.writeInt(currentPrivilegeLevel); //modelSpecificRegisters map output.writeInt(modelSpecificRegisters.size()); for (Map.Entry<Integer, Long> entry : modelSpecificRegisters.entrySet()) { output.writeInt(entry.getKey().intValue()); output.writeLong(entry.getValue().longValue()); } cs.saveState(output); ds.saveState(output); ss.saveState(output); es.saveState(output); fs.saveState(output); gs.saveState(output); idtr.saveState(output); gdtr.saveState(output); ldtr.saveState(output); tss.saveState(output); } public void loadState(DataInput input) throws IOException { r_eax.set32(input.readInt()); r_ebx.set32(input.readInt()); r_edx.set32(input.readInt()); r_ecx.set32(input.readInt()); r_esi.set32(input.readInt()); r_edi.set32(input.readInt()); r_esp.set32(input.readInt()); r_ebp.set32(input.readInt()); eip = input.readInt(); dr0 = input.readInt(); dr1 = input.readInt(); dr2 = input.readInt(); dr3 = input.readInt(); dr4 = input.readInt(); dr5 = input.readInt(); dr6 = input.readInt(); dr7 = input.readInt(); cr0 = input.readInt(); cr1 = input.readInt(); cr2 = input.readInt(); cr3 = input.readInt(); cr4 = input.readInt(); flagStatus = 0; cf = input.readBoolean(); pf = input.readBoolean(); af = input.readBoolean(); zf = input.readBoolean(); sf = input.readBoolean(); eflagsTrap = input.readBoolean(); eflagsInterruptEnable = input.readBoolean(); df = input.readBoolean(); of = input.readBoolean(); eflagsIOPrivilegeLevel = input.readInt(); eflagsNestedTask = input.readBoolean(); eflagsResume = input.readBoolean(); eflagsVirtual8086Mode = input.readBoolean(); eflagsAlignmentCheck = input.readBoolean(); eflagsVirtualInterrupt = input.readBoolean(); eflagsVirtualInterruptPending = input.readBoolean(); eflagsID = input.readBoolean(); input.readBoolean(); fpu.loadState(input); interruptFlags = input.readInt(); alignmentChecking = input.readBoolean(); resetTime = input.readLong(); currentPrivilegeLevel = input.readInt(); //modelSpecificRegisters map int len = input.readInt(); modelSpecificRegisters = new HashMap<Integer, Long>(); int key; long value; for (int i=0; i<len; i++) { key = input.readInt(); value = input.readLong(); modelSpecificRegisters.put(Integer.valueOf(key), Long.valueOf(value)); } cs(loadSegment(input)); ds(loadSegment(input)); ss(loadSegment(input)); es(loadSegment(input)); fs(loadSegment(input)); gs(loadSegment(input)); idtr = loadSegment(input); gdtr = loadSegment(input); ldtr = loadSegment(input); tss = loadSegment(input); } private Segment loadSegment(DataInput input) throws IOException { //isProtectedMode() //alignmentChecking int type = input.readInt(); if (type == 0) //RM Segment { Segment s; int selector = input.readInt(); if (!isProtectedMode()) s = SegmentFactory.createRealModeSegment(physicalMemory, selector); else { if (alignmentChecking) s = SegmentFactory.createRealModeSegment(alignmentCheckedMemory, selector); else s = SegmentFactory.createRealModeSegment(linearMemory, selector); } s.loadState(input); return s; } else if (type == 1) //VM86 Segment { int selector = input.readInt(); boolean isCode = input.readBoolean(); int rpl = input.readInt(); Segment s; if (!isProtectedMode()) s = SegmentFactory.createVirtual8086ModeSegment(physicalMemory, selector, isCode); else { if (alignmentChecking) s = SegmentFactory.createVirtual8086ModeSegment(alignmentCheckedMemory, selector, isCode); else s = SegmentFactory.createVirtual8086ModeSegment(linearMemory, selector, isCode); } s.setRPL(rpl); return s; } else if (type == 2) { int base = input.readInt(); int limit = input.readInt(); if (!isProtectedMode()) return SegmentFactory.createDescriptorTableSegment(physicalMemory, base, limit); else { if (alignmentChecking) return SegmentFactory.createDescriptorTableSegment(alignmentCheckedMemory, base, limit); else return SegmentFactory.createDescriptorTableSegment(linearMemory, base, limit); } } else if (type == 3) { int selector = input.readInt(); long descriptor = input.readLong(); int rpl = input.readInt(); Segment result = SegmentFactory.createProtectedModeSegment(linearMemory, selector, descriptor); if (alignmentChecking) { if ((result.getType() & 0x18) == 0x10) // Should make this a data segment result.setAddressSpace(alignmentCheckedMemory); } result.setRPL(rpl); return result; } else if (type ==4) { return SegmentFactory.NULL_SEGMENT; } else throw new IOException("Invalid Segment type: " + type); } public int getIOPrivilegeLevel() { return eflagsIOPrivilegeLevel; } public boolean getVIP() { return (getEFlags() & (1 << 20)) == 0; } public int getEFlags() { int result = 0x2; if (getCarryFlag(flagStatus, cf, flagOp1, flagOp2, flagResult, flagIns)) result |= 0x1; if (getParityFlag(flagStatus, pf, flagResult)) result |= 0x4; if (getAuxCarryFlag(flagStatus, af, flagOp1, flagOp2, flagResult, flagIns)) result |= 0x10; if (getZeroFlag(flagStatus, zf, flagResult)) result |= 0x40; if (getSignFlag(flagStatus, sf, flagResult)) result |= 0x80; if (eflagsTrap) result |= 0x100; if (eflagsInterruptEnable) result |= 0x200; if (df) result |= 0x400; if (getOverflowFlag(flagStatus, of, flagOp1, flagOp2, flagResult, flagIns)) result |= 0x800; result |= (eflagsIOPrivilegeLevel << 12); if (eflagsNestedTask) result |= 0x4000; if (eflagsResume) result |= 0x10000; if (eflagsVirtual8086Mode) result |= 0x20000; if (eflagsAlignmentCheck) result |= 0x40000; if (eflagsVirtualInterrupt) result |= 0x80000; if (eflagsVirtualInterruptPending) result |= 0x100000; if (eflagsID) result |= 0x200000; return result; } public void setFlags(short flags) { flagStatus = 0; cf = ((flags & 1 ) != 0); pf = ((flags & (1 << 2)) != 0); af = ((flags & (1 << 4)) != 0); zf = ((flags & (1 << 6)) != 0); sf = ((flags & (1 << 7)) != 0); eflagsTrap = ((flags & (1 << 8)) != 0); eflagsInterruptEnable = ((flags & (1 << 9)) != 0); df = ((flags & (1 << 10)) != 0); of = ((flags & (1 << 11)) != 0); eflagsIOPrivilegeLevel = ((flags >> 12) & 3); eflagsNestedTask = ((flags & (1 << 14)) != 0); } public void setEFlags(int eflags, int changeMask) { setEFlags((getEFlags() & ~changeMask)| (eflags & changeMask)); } public void setEFlags(int eflags) { flagStatus = 0; cf = ((eflags & EFLAGS_CF_MASK ) != 0); pf = ((eflags & EFLAGS_PF_MASK) != 0); af = ((eflags & EFLAGS_AF_MASK) != 0); zf = ((eflags & EFLAGS_ZF_MASK) != 0); sf = ((eflags & EFLAGS_SF_MASK) != 0); eflagsTrap = ((eflags & EFLAGS_TF_MASK) != 0); eflagsInterruptEnable = ((eflags & EFLAGS_IF_MASK) != 0); df = ((eflags & EFLAGS_DF_MASK) != 0); of = ((eflags & EFLAGS_OF_MASK) != 0); eflagsIOPrivilegeLevel = ((eflags >> 12) & 3); eflagsNestedTask = ((eflags & EFLAGS_NT_MASK) != 0); eflagsResume = ((eflags & EFLAGS_RF_MASK) != 0); eflagsVirtualInterrupt = ((eflags & EFLAGS_VIF_MASK) != 0); eflagsVirtualInterruptPending = ((eflags & EFLAGS_VIP_MASK) != 0); eflagsID = ((eflags & (1 << 21)) != 0); if (eflagsAlignmentCheck != ((eflags & EFLAGS_AC_MASK) != 0)) { eflagsAlignmentCheck = ((eflags & EFLAGS_AC_MASK) != 0); checkAlignmentChecking(); } if (eflagsVirtual8086Mode != ((eflags & EFLAGS_VM_MASK) != 0)) { eflagsVirtual8086Mode = ((eflags & EFLAGS_VM_MASK) != 0); if (eflagsVirtual8086Mode) { throw ModeSwitchException.VIRTUAL8086_MODE_EXCEPTION; } else { throw ModeSwitchException.PROTECTED_MODE_EXCEPTION; } } } public void setCPL(int value) { currentPrivilegeLevel = value; linearMemory.setSupervisor(currentPrivilegeLevel == 0); checkAlignmentChecking(); } public int getCPL() { return currentPrivilegeLevel; } public void reportFPUException() { if ((cr0 & CR0_NUMERIC_ERROR) == 0) { LOGGING.log(Level.INFO, "Reporting FPU error via IRQ #13"); interruptController.setIRQ(13, 1); } else { LOGGING.log(Level.INFO, "Reporting FPU error via exception 0x10"); throw ProcessorException.FLOATING_POINT; } } public void raiseInterrupt() { interruptFlags |= IFLAGS_HARDWARE_INTERRUPT; } public void clearInterrupt() { interruptFlags &= ~IFLAGS_HARDWARE_INTERRUPT; } public void waitForInterrupt() { System.out.printf("*****START HALT ticks=%016x\n", vmClock.getTicks()); int ints = 0; while ((interruptFlags & IFLAGS_HARDWARE_INTERRUPT) == 0) { vmClock.updateNowAndProcess(!SKIP_SLEEPS); ints++; } System.out.printf("END HALT ticks=%016x, interrupts=%d\n", vmClock.getTicks(), ints); } public void requestReset() { interruptFlags |= IFLAGS_RESET_REQUEST; } public boolean isProtectedMode() { return (cr0 & CR0_PROTECTION_ENABLE) == 1; } public boolean isVirtual8086Mode() { return eflagsVirtual8086Mode; } // Need to think about the TS flag for when we have an FPU - Section 2.5 Vol 3 public void setCR0(int value) { value |= 0x10; int changedBits = value ^ cr0; if (changedBits == 0) return; //actually set the value! cr0 = value; boolean pagingChanged = (changedBits & CR0_PAGING) != 0; boolean cachingChanged = (changedBits & CR0_CACHE_DISABLE) != 0; boolean modeSwitch = (changedBits & CR0_PROTECTION_ENABLE) != 0; boolean wpUserPagesChanged = (changedBits & CR0_WRITE_PROTECT) != 0; boolean alignmentChanged = (changedBits & CR0_ALIGNMENT_MASK) != 0; if ((changedBits & CR0_NOT_WRITETHROUGH)!= 0) LOGGING.log(Level.FINE, "Unimplemented CR0 flags changed (0x{0}). Now 0x{1}", new Object[]{Integer.toHexString(changedBits),Integer.toHexString(value)}); if (pagingChanged) { if (((value & CR0_PROTECTION_ENABLE) == 0) && ((value & CR0_PAGING) != 0)) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; } if (alignmentChanged) checkAlignmentChecking(); if (pagingChanged || cachingChanged) { linearMemory.setPagingEnabled((value & CR0_PAGING) != 0); linearMemory.setPageCacheEnabled((value & CR0_CACHE_DISABLE) == 0); } if (wpUserPagesChanged) linearMemory.setWriteProtectPages((value & CR0_WRITE_PROTECT) != 0); if (modeSwitch) { if ((value & CR0_PROTECTION_ENABLE) != 0) { convertSegmentsToProtectedMode(); throw ModeSwitchException.PROTECTED_MODE_EXCEPTION; } else { // linearMemory.flush(); setCPL(0); convertSegmentsToRealMode(); throw ModeSwitchException.REAL_MODE_EXCEPTION; } } } public int getCR0() { return cr0; } public boolean pagingEnabled() { return ((cr0 & 0x80000000) != 0); } public void setCR3(int value) { cr3 = value; linearMemory.setPageWriteThroughEnabled((value & CR3_PAGE_WRITES_TRANSPARENT) != 0); linearMemory.setPageCacheEnabled((value & CR3_PAGE_CACHE_DISABLE) == 0); linearMemory.setPageDirectoryBaseAddress(value); } public int getCR3() { return cr3; } public int getCR2() { return cr2; } public void setCR2(int value) { cr2 = value; } public void setCR4(int value) { if (cr4 == value) return; cr4 = (cr4 & ~0x5f) | (value & 0x5f); if ((cr4 & CR4_VIRTUAL8086_MODE_EXTENSIONS) != 0) LOGGING.log(Level.WARNING, "Virtual-8086 mode extensions enabled in the processor"); if ((cr4 & CR4_PROTECTED_MODE_VIRTUAL_INTERRUPTS) != 0) LOGGING.log(Level.WARNING, "Protected mode virtual interrupts enabled in the processor"); if ((cr4 & CR4_OS_SUPPORT_UNMASKED_SIMD_EXCEPTIONS) != 0) LOGGING.log(Level.WARNING, "SIMD instruction support modified in the processor"); if ((cr4 & CR4_OS_SUPPORT_FXSAVE_FXSTORE) != 0) LOGGING.log(Level.WARNING, "FXSave and FXRStore enabled in the processor"); if ((cr4 & CR4_DEBUGGING_EXTENSIONS) != 0) LOGGING.log(Level.WARNING, "Debugging extensions enabled"); if ((cr4 & CR4_TIME_STAMP_DISABLE) != 0) LOGGING.log(Level.WARNING, "Timestamp restricted to CPL0"); if ((cr4 & CR4_PHYSICAL_ADDRESS_EXTENSION) != 0) { LOGGING.log(Level.SEVERE, "36-bit addressing enabled"); throw new IllegalStateException("36-bit addressing enabled"); } linearMemory.setGlobalPagesEnabled((value & CR4_PAGE_GLOBAL_ENABLE) != 0); linearMemory.setPageSizeExtensionsEnabled((cr4 & CR4_PAGE_SIZE_EXTENSIONS) != 0); } public boolean physicalAddressExtension() { return (cr4 & CR4_PHYSICAL_ADDRESS_EXTENSION) != 0; } public int getCR4() { return cr4; } public void setDR0(int value) { dr0 = value; } public void setDR1(int value) { dr1 = value; } public void setDR2(int value) { dr2 = value; } public void setDR3(int value) { dr3 = value; } public void setDR4(int value) { dr4 = value; } public void setDR5(int value) { dr5 = value; } public void setDR6(int value) { dr6 = value; } public void setDR7(int value) { dr7 = value; } public int getDR0() { return dr0; } public int getDR1() { return dr1; } public int getDR2() { return dr2; } public int getDR3() { return dr3; } public int getDR4() { return dr4; } public int getDR5() { return dr5; } public int getDR6() { return dr6; } public int getDR7() { return dr7; } public long getMSR(int index) { try { return modelSpecificRegisters.get(Integer.valueOf(index)).longValue(); } catch (NullPointerException e) { LOGGING.log(Level.INFO, "Reading unset MSR {0} : returning 0", Integer.valueOf(index)); return 0L; } } public void setMSR(int index, long value) { modelSpecificRegisters.put(Integer.valueOf(index), Long.valueOf(value)); } private void convertSegmentsToRealMode() { try { cs(SegmentFactory.createRealModeSegment(physicalMemory, cs)); } catch (ProcessorException e) { cs(SegmentFactory.createRealModeSegment(physicalMemory, 0)); } try { ds(SegmentFactory.createRealModeSegment(physicalMemory, ds)); } catch (ProcessorException e) { ds(SegmentFactory.createRealModeSegment(physicalMemory, 0)); } try { ss(SegmentFactory.createRealModeSegment(physicalMemory, ss)); } catch (ProcessorException e) { ss(SegmentFactory.createRealModeSegment(physicalMemory, 0)); } try { es(SegmentFactory.createRealModeSegment(physicalMemory, es)); } catch (ProcessorException e) { es(SegmentFactory.createRealModeSegment(physicalMemory, 0)); } try { fs(SegmentFactory.createRealModeSegment(physicalMemory, fs)); } catch (ProcessorException e) { fs(SegmentFactory.createRealModeSegment(physicalMemory, 0)); } try { gs(SegmentFactory.createRealModeSegment(physicalMemory, gs)); } catch (ProcessorException e) { gs(SegmentFactory.createRealModeSegment(physicalMemory, 0)); } } private void convertSegmentsToProtectedMode() { cs.setAddressSpace(linearMemory); ds.setAddressSpace(linearMemory); ss.setAddressSpace(linearMemory); es.setAddressSpace(linearMemory); fs.setAddressSpace(linearMemory); gs.setAddressSpace(linearMemory); } private void updateAlignmentCheckingInDataSegments() { if (alignmentChecking) { ds.setAddressSpace(alignmentCheckedMemory); ss.setAddressSpace(alignmentCheckedMemory); es.setAddressSpace(alignmentCheckedMemory); fs.setAddressSpace(alignmentCheckedMemory); gs.setAddressSpace(alignmentCheckedMemory); } else { ds.setAddressSpace(linearMemory); ss.setAddressSpace(linearMemory); es.setAddressSpace(linearMemory); fs.setAddressSpace(linearMemory); gs.setAddressSpace(linearMemory); } } public Segment createDescriptorTableSegment(int base, int limit) { return SegmentFactory.createDescriptorTableSegment(linearMemory, base, limit); } public void correctAlignmentChecking(Segment segment) { if (alignmentChecking) { if ((segment.getType() & 0x18) == 0x10) // Should make this a data segment segment.setAddressSpace(alignmentCheckedMemory); } } public Segment getSegment(int segmentSelector) { return getSegment(segmentSelector, false); } public Segment getSegment(int segmentSelector, boolean isStack) { boolean isSup = linearMemory.isSupervisor(); try { long segmentDescriptor; linearMemory.setSupervisor(true); if ((segmentSelector & 0x4) != 0) segmentDescriptor = ldtr.getQuadWord(segmentSelector & 0xfff8); else { if (segmentSelector < 0x4) return SegmentFactory.NULL_SEGMENT; segmentDescriptor = gdtr.getQuadWord(segmentSelector & 0xfff8); } Segment result = SegmentFactory.createProtectedModeSegment(linearMemory, segmentSelector, segmentDescriptor, isStack); if (isStack && !((ProtectedModeSegment)result).isDataWritable()) throw ProcessorException.GENERAL_PROTECTION_0; // mark segment descriptor as accessed (somehow this stops doom working) // if ((segmentSelector & 0x4) != 0) // ldtr.VMsetByte((segmentSelector & 0xfff8) + 5, (byte) (ldtr.getByte((segmentSelector & 0xfff8) + 5) | 1)); // else // gdtr.VMsetByte((segmentSelector & 0xfff8) + 5, (byte) (gdtr.getByte((segmentSelector & 0xfff8) + 5) | 1)); if (alignmentChecking) { if ((result.getType() & 0x18) == 0x10) // Should make this a data segment result.setAddressSpace(alignmentCheckedMemory); } return result; } finally { linearMemory.setSupervisor(isSup); } } public Segment getSegment(int segmentSelector, Segment local, Segment global) { boolean isSup = linearMemory.isSupervisor(); try { long segmentDescriptor = 0; linearMemory.setSupervisor(true); if ((segmentSelector & 0x4) != 0) segmentDescriptor = local.getQuadWord(segmentSelector & 0xfff8); else { if (segmentSelector < 0x4) return SegmentFactory.NULL_SEGMENT; segmentDescriptor = global.getQuadWord(segmentSelector & 0xfff8); } Segment result = SegmentFactory.createProtectedModeSegment(linearMemory, segmentSelector, segmentDescriptor); if (alignmentChecking) { if ((result.getType() & 0x18) == 0x10) // Should make this a data segment result.setAddressSpace(alignmentCheckedMemory); } return result; } finally { linearMemory.setSupervisor(isSup); } } public void reset() { resetTime = System.currentTimeMillis(); r_eax.set32(0); r_ebx.set32(0); r_ecx.set32(0); r_edx.set32(0); r_edi.set32(0); r_esi.set32(0); r_ebp.set32(0); r_esp.set32(0); int cpulevel = Option.cpulevel.intValue(5); if (cpulevel == 4) r_edx.set32(0x00000433); // 486 else if (cpulevel == 5) r_edx.set32(0x00000513); // Pentium else r_edx.set32(0x00000634); // Pentium II // r_edx.set32(0); // to comform with Bochs interruptFlags = 0; currentPrivilegeLevel = 0; linearMemory.reset(); alignmentChecking = false; eip = 0x0000fff0; cr0 = CR0_CACHE_DISABLE | CR0_NOT_WRITETHROUGH | 0x10; cr2 = cr3 = cr4 = 0x0; dr0 = dr1 = dr2 = dr3 = 0x0; dr6 = dr4 = 0xffff0ff0; dr7 = dr5 = 0x00000400; flagStatus = 0; of = sf = zf = af = pf =cf = false; eflagsTrap = eflagsInterruptEnable = false; df = eflagsNestedTask = eflagsResume = eflagsVirtual8086Mode = false; eflagsAlignmentCheck = eflagsVirtualInterrupt = eflagsVirtualInterruptPending = eflagsID = false; eflagsIOPrivilegeLevel = 0; cs(SegmentFactory.createRealModeSegment(physicalMemory, 0xf000)); ds(SegmentFactory.createRealModeSegment(physicalMemory, 0)); ss(SegmentFactory.createRealModeSegment(physicalMemory, 0)); es(SegmentFactory.createRealModeSegment(physicalMemory, 0)); fs(SegmentFactory.createRealModeSegment(physicalMemory, 0)); gs(SegmentFactory.createRealModeSegment(physicalMemory, 0)); idtr = SegmentFactory.createDescriptorTableSegment(physicalMemory, 0, 0xFFFF); ldtr = SegmentFactory.NULL_SEGMENT; gdtr = SegmentFactory.createDescriptorTableSegment(physicalMemory, 0, 0xFFFF); tss = SegmentFactory.NULL_SEGMENT; updateSegmentArray(); modelSpecificRegisters.clear(); //Will need to set any MSRs here fpu.init(); } public long getClockCount() { return vmClock.getTicks(); } public final int getInstructionPointer() { return cs.translateAddressRead(eip); } public final boolean processRealModeInterrupts(int instructions) { return processRealModeInterrupts(instructions, false); } public final boolean processRealModeInterrupts(int instructions, boolean bochsInPitInt) { //Note only hardware interrupts go here, software interrupts are handled in the codeblock vmClock.updateAndProcess(instructions); if (eflagsInterruptEnable) { if ((interruptFlags & IFLAGS_RESET_REQUEST) != 0) { reset(); return true; } if (!Option.useBochs.isSet() || bochsInPitInt || (interruptController.getMasterIRR() != 1)) if ((interruptFlags & IFLAGS_HARDWARE_INTERRUPT) != 0) { interruptFlags &= ~IFLAGS_HARDWARE_INTERRUPT; int vector = interruptController.cpuGetInterrupt(); handleRealModeInterrupt(vector); return true; } } return false; } private int lastPMVector = -1; public final void processProtectedModeInterrupts(int instructions) { processProtectedModeInterrupts(instructions, false); } public final boolean processProtectedModeInterrupts(int instructions, boolean bochsInPitInt) { vmClock.updateAndProcess(instructions); if (eflagsInterruptEnable) { if ((interruptFlags & IFLAGS_RESET_REQUEST) != 0) { reset(); return true; } if (lastPMVector != -1) { handleHardProtectedModeInterrupt(lastPMVector); lastPMVector = -1; return true; } if (!Option.useBochs.isSet() || bochsInPitInt || (interruptController.getMasterIRR() != 1)) if ((interruptFlags & IFLAGS_HARDWARE_INTERRUPT) != 0) { interruptFlags &= ~IFLAGS_HARDWARE_INTERRUPT; int vec = interruptController.cpuGetInterrupt(); //System.out.printf("JPC handling interrupt 0x%x\n", vec); if (USEBOCHS && (vec != interruptController.getIRQ0Vector()) && (vec != interruptController.getSpuriousVector()) && (vec != interruptController.getSpuriousMasterVector())) lastPMVector = vec; else { handleHardProtectedModeInterrupt(vec); return true; } } } return false; } public final boolean processVirtual8086ModeInterrupts(int instructions) { vmClock.updateAndProcess(instructions); if (eflagsInterruptEnable) { if ((interruptFlags & IFLAGS_RESET_REQUEST) != 0) { reset(); return true; } if ((interruptFlags & IFLAGS_HARDWARE_INTERRUPT) != 0) { interruptFlags &= ~IFLAGS_HARDWARE_INTERRUPT; if ((getCR4() & CR4_VIRTUAL8086_MODE_EXTENSIONS) != 0) throw new IllegalStateException(); else handleHardVirtual8086ModeInterrupt(interruptController.cpuGetInterrupt()); return true; } } return false; } public final void handleRealModeException(ProcessorException e) { System.out.printf("RM Exception vector=%x\n", e.getType().vector()); handleRealModeInterrupt(e.getType().vector()); } public final void handleRealModeInterrupt(int vector) { if (vector*4 +3 > idtr.getLimit()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true); vector *= 4; int newEip = 0xffff & idtr.getWord(vector); int newSelector = 0xffff & idtr.getWord(vector+2); if (Option.useBochs.isSet()) { if (vector == 32) { System.out.printf("** PIT int from eip=%08x to eip=%08x, ticks=%08x\n", eip, newEip, vmClock.getTicks()); } if (newEip != 0xfea5) System.out.println("non PIT int vector = "+vector/4); } int esp = push16(r_esp.get32(), (short)getEFlags()); eflagsInterruptEnable = false; eflagsTrap = false; eflagsAlignmentCheck = false; eflagsResume=false; esp = push16(esp, (short)cs.getSelector()); esp = push16(esp, (short)eip); // commit r_esp.set32(esp); eip = newEip; //System.out.printf("RM HW int to cs:eip = %08x:%08x = %08x\n", cs.getBase(), eip, cs.getBase()+eip); if (!cs.setSelector(newSelector)) { System.out.println("Setting CS to RM in RM interrupt"); cs(SegmentFactory.createRealModeSegment(physicalMemory, newSelector)); setCPL(0); } //System.out.printf("Hardware int with vector %d to %04x:%04x = %08x\n", vector/4, newSelector, newEip, cs.getBase()+newEip); } public final void handleProtectedModeException(ProcessorException pe) { int savedESP = r_esp.get32(); int savedEIP = eip; Segment savedCS = cs; Segment savedSS = ss; try { followProtectedModeException(pe.getType().vector(), pe.hasErrorCode(), pe.getErrorCode(), false, false); } catch (ProcessorException e) { LOGGING.log(Level.WARNING, "Double-Fault", e); //return cpu to original state r_esp.set32(savedESP); eip = savedEIP; cs(savedCS); ss(savedSS); if (pe.getType() == ProcessorException.Type.DOUBLE_FAULT) { LOGGING.log(Level.SEVERE, "Triple-Fault: Unhandleable, machine will halt!", e); throw new IllegalStateException("Triple Fault ", e); } else if (e.combinesToDoubleFault(pe)) handleProtectedModeException(ProcessorException.DOUBLE_FAULT_0); else handleProtectedModeException(e); } } public final void handleSoftProtectedModeInterrupt(int vector, int instructionLength) { int savedESP = r_esp.get32(); int savedEIP = eip; Segment savedCS = cs; Segment savedSS = ss; try { followProtectedModeException(vector, false, 0, false, true); } catch (ProcessorException e) { //return cpu to original state r_esp.set32(savedESP); eip = savedEIP; cs(savedCS); ss(savedSS); //make eip point at INT instruction which threw an exception if (e.pointsToSelf()) eip -= instructionLength; //if (e.getVector() == PROC_EXCEPTION_DF) { //System.err.println("Triple-Fault: Unhandleable, machine will halt!"); //throw new IllegalStateException("Triple Fault"); //else handleProtectedModeException(e); } } public final void handleHardProtectedModeInterrupt(int vector) { int savedESP = r_esp.get32(); int savedEIP = eip; Segment savedCS = cs; Segment savedSS = ss; try { followProtectedModeException(vector, false, 0, true, false); } catch (ProcessorException e) { //return cpu to original state r_esp.set32(savedESP); eip = savedEIP; cs(savedCS); ss(savedSS); //if (e.getVector() == PROC_EXCEPTION_DF) { //System.err.println("Triple-Fault: Unhandleable, machine will halt!"); //throw new IllegalStateException("Triple Fault"); //else handleProtectedModeException(e); } } private final void checkGate(Segment gate, int selector, boolean software) { if (software) { if (gate.getDPL() < currentPrivilegeLevel) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, selector + 2, true); } if (!gate.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, selector +2, true); } public final void setSupervisorQuadWord(Segment seg, int offset, long data) { boolean isSup = linearMemory.isSupervisor(); linearMemory.setSupervisor(true); seg.setQuadWord(offset, data); linearMemory.setSupervisor(isSup); } public final void setSupervisorDoubleWord(Segment seg, int offset, int data) { boolean isSup = linearMemory.isSupervisor(); linearMemory.setSupervisor(true); seg.setDoubleWord(offset, data); linearMemory.setSupervisor(isSup); } public final long readSupervisorQuadWord(Segment seg, int offset) { boolean isSup = linearMemory.isSupervisor(); linearMemory.setSupervisor(true); long data = seg.getQuadWord(offset); linearMemory.setSupervisor(isSup); return data; } public final int readSupervisorDoubleWord(Segment seg, int offset) { boolean isSup = linearMemory.isSupervisor(); linearMemory.setSupervisor(true); int data = seg.getDoubleWord(offset); linearMemory.setSupervisor(isSup); return data; } public final int readSupervisorWord(Segment seg, int offset) { boolean isSup = linearMemory.isSupervisor(); linearMemory.setSupervisor(true); int data = seg.getWord(offset); linearMemory.setSupervisor(isSup); return data; } public final int readSupervisorByte(Segment seg, int offset) { boolean isSup = linearMemory.isSupervisor(); linearMemory.setSupervisor(true); int data = seg.getByte(offset); linearMemory.setSupervisor(isSup); return data; } private final void followProtectedModeException(int vector, boolean hasErrorCode, int errorCode, boolean hardware, boolean software) { // System.out.println(); // System.out.println("protected Mode PF exception " + Integer.toHexString(vector) + (hasErrorCode ? "errorCode = " + errorCode:"") + ", hardware = " + hardware + ", software = " + software); if (USEBOCHS) System.out.printf("PM Exception vector=%x hw=%d sw=%d\n",vector, hardware?1:0, software?1:0); if (vector == ProcessorException.Type.PAGE_FAULT.vector()) { setCR2(linearMemory.getLastWalkedAddress()); } // if it is a fault, then RF is set on the eflags image on stack (except for debug exception) if ((vector < 32) && ProcessorException.isFault(vector) && (vector != ProcessorException.Type.DEBUG.vector())) rf(true); int selector = vector << 3; //multiply by 8 to get offset into idt int EXT = hardware ? 1 : 0; Segment gate; boolean isSup = linearMemory.isSupervisor(); try { linearMemory.setSupervisor(true); long descriptor = idtr.getQuadWord(selector); gate = SegmentFactory.createProtectedModeSegment(linearMemory, selector, descriptor); } catch (ProcessorException e) { System.out.println("Failed to create gate in PM excp: selector=" + Integer.toHexString(selector)); throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, selector + 2 + EXT, true); } finally { linearMemory.setSupervisor(isSup); } checkGate(gate, selector, software); switch (gate.getType()) { default: LOGGING.log(Level.INFO, "Invalid gate type for throwing interrupt: 0x{0}", Integer.toHexString(gate.getType())); throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, selector + 2 + EXT, true); case 0x05: //Interrupt Handler: Task Gate ProtectedModeSegment.GateSegment taskGate = (ProtectedModeSegment.GateSegment) gate; int tssSelector = taskGate.getTargetSegment(); // must specify global in the local/global bit if ((tssSelector & 0x4) != 0) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, selector & 0xfffc, true); ProtectedModeSegment newTss; try { newTss = (ProtectedModeSegment) getSegment(tssSelector); } catch (ProcessorException e) { throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, tssSelector, true); } if (!newTss.isSystem()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, selector & 0xfffc, true); if (!(newTss instanceof ProtectedModeSegment.Available16BitTSS) && !(newTss instanceof ProtectedModeSegment.Available32BitTSS)) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, selector & 0xfffc, true); if (!newTss.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, tssSelector & 0xfffc, true); Tasking.task_switch(this, Tasking.Source.INT, newTss, hasErrorCode, errorCode); break; case 0x06: //Interrupt Handler: 16-bit Interrupt Gate case 0x07: //Interrupt Handler: 16-bit Trap Gate case 0x0e: //Interrupt Handler: 32-bit Interrupt Gate case 0x0f: //Interrupt Handler: 32-bit Trap Gate { ProtectedModeSegment.GateSegment theGate = (ProtectedModeSegment.GateSegment) gate; int targetSegmentSelector = theGate.getTargetSegment(); if ((targetSegmentSelector & 0xfffc) == 0) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, EXT, true); ProtectedModeSegment targetSegment; try { targetSegment = (ProtectedModeSegment) getSegment(targetSegmentSelector); } catch (ProcessorException e) { throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector & 0xfffc + EXT, true); } if (!targetSegment.isCode() || targetSegment.getDPL() > currentPrivilegeLevel) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector & 0xfffc + EXT, true); if (!targetSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSegmentSelector & 0xfffc, true); if (!targetSegment.isConforming() && targetSegment.getDPL() < currentPrivilegeLevel) { // Interrupt to inner privilege level int newStackSelector = 0; int newESP = 0; if ((tss.getType() == 0x9) || (tss.getType() == 0xb)) // 32-bit TSS { int tssStackAddress = (targetSegment.getDPL() * 8) + 4; if ((tssStackAddress + 7) > tss.getLimit()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, tss.getSelector() & 0xfffc, true); isSup = linearMemory.isSupervisor(); try { linearMemory.setSupervisor(true); newStackSelector = 0xffff & tss.getWord(tssStackAddress + 4); newESP = tss.getDoubleWord(tssStackAddress); } finally { linearMemory.setSupervisor(isSup); } } else if ((tss.getType() == 0x1) || (tss.getType() == 0x3)) // 16-bit TSS { int tssStackAddress = (targetSegment.getDPL() * 4) + 2; if ((tssStackAddress + 3) > tss.getLimit()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, tss.getSelector() & 0xfffc, true); isSup = linearMemory.isSupervisor(); try { linearMemory.setSupervisor(true); newStackSelector = 0xffff & tss.getWord(tssStackAddress + 2); newESP = tss.getWord(tssStackAddress); } finally { linearMemory.setSupervisor(isSup); } } else throw new IllegalStateException("Illegal TSS type"); if ((newStackSelector & 0xfffc) == 0) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, EXT, true); ProtectedModeSegment newStackSegment; try { newStackSegment = (ProtectedModeSegment) getSegment(newStackSelector, true); } catch (ProcessorException e) { throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, newStackSelector & 0xfffc, true); } if (newStackSegment.getRPL() != targetSegment.getDPL()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, newStackSelector & 0xfffc + EXT, true); if (newStackSegment.isCode() || !newStackSegment.isDataWritable()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, newStackSelector & 0xfffc + EXT, true); if (!newStackSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.STACK_SEGMENT, newStackSelector & 0xfffc + EXT, true); int targetOffset = theGate.getTargetOffset(); targetSegment.checkAddress(targetOffset); int oldSS = ss.getSelector(); int oldESP = r_esp.get32(); int oldCS = cs.getSelector(); int oldEIP = eip; isSup = linearMemory.isSupervisor(); try { linearMemory.setSupervisor(true); if (newStackSegment.getDefaultSizeFlag()) { int tmpESP = newESP; if (theGate.getType() >= 0xe) // 32-bit int/trap gate { newStackSegment.setDoubleWord(tmpESP-4, oldSS); newStackSegment.setDoubleWord(tmpESP-8, oldESP); newStackSegment.setDoubleWord(tmpESP-12, getEFlags()); newStackSegment.setDoubleWord(tmpESP-16, oldCS); newStackSegment.setDoubleWord(tmpESP-20, oldEIP); tmpESP -= 20; if (hasErrorCode) { tmpESP -= 4; newStackSegment.setDoubleWord(tmpESP, errorCode); } } else // 16-bit int/trap gate { newStackSegment.setWord(tmpESP-2, (short)oldSS); newStackSegment.setWord(tmpESP-4, (short)oldESP); newStackSegment.setWord(tmpESP-6, (short)getEFlags()); newStackSegment.setWord(tmpESP-8, (short)oldCS); newStackSegment.setWord(tmpESP-10, (short)oldEIP); tmpESP -= 10; if (hasErrorCode) { tmpESP -= 2; newStackSegment.setWord(tmpESP, (short)errorCode); } } r_esp.set32(tmpESP); } else { int tmpSP = 0xffff & newESP; if (theGate.getType() >= 0xe) // 32-bit int/trap gate { newStackSegment.setDoubleWord(0xffff & (tmpSP-4), oldSS); newStackSegment.setDoubleWord(0xffff & (tmpSP-8), oldESP); newStackSegment.setDoubleWord(0xffff & (tmpSP-12), getEFlags()); newStackSegment.setDoubleWord(0xffff & (tmpSP-16), oldCS); newStackSegment.setDoubleWord(0xffff & (tmpSP-20), oldEIP); tmpSP -= 20; if (hasErrorCode) { tmpSP -= 4; newStackSegment.setDoubleWord(0xffff & tmpSP, errorCode); } } else // 16-bit int/trap gate { newStackSegment.setWord(0xffff & (tmpSP-2), (short)oldSS); newStackSegment.setWord(0xffff & (tmpSP-4), (short)oldESP); newStackSegment.setWord(0xffff & (tmpSP-6), (short)getEFlags()); newStackSegment.setWord(0xffff & (tmpSP-8), (short)oldCS); newStackSegment.setWord(0xffff & (tmpSP-10), (short)oldEIP); tmpSP -= 10; if (hasErrorCode) { tmpSP -= 2; newStackSegment.setWord(0xffff & tmpSP, (short)errorCode); } } r_esp.set16(tmpSP); } } finally { linearMemory.setSupervisor(isSup); } cs(targetSegment); cs.setRPL(currentPrivilegeLevel); ss(newStackSegment); ss.setRPL(targetSegment.getDPL()); } else { // interrupt to same privilege level int targetOffset = theGate.getTargetOffset(); targetSegment.checkAddress(targetOffset); if (theGate.getType() >= 0xe) // 32-bit gate { push32(getEFlags()); push32(cs.getSelector()); push32(eip); if (hasErrorCode) push32(errorCode); } else // 16-bit gate { push16((short)getEFlags()); push16((short)cs.getSelector()); push16((short)eip); if (hasErrorCode) push16((short)errorCode); } cs(targetSegment); cs.setRPL(currentPrivilegeLevel); } eip = theGate.getTargetOffset(); setCPL(cs.getDPL()); if ((theGate.getType() & 1) == 0) // int gate setIF(false); eflagsTrap = false; eflagsNestedTask = false; eflagsVirtual8086Mode = false; rf(false); } } } public final void handleVirtual8086ModeException(ProcessorException pe) { int savedESP = r_esp.get32(); int savedEIP = eip; Segment savedCS = cs; Segment savedSS = ss; try { followVirtual8086ModeException(pe.getType().vector(), pe.hasErrorCode(), pe.getErrorCode(), false, false); } catch (ProcessorException e) { LOGGING.log(Level.WARNING, "Double-Fault", e); //return cpu to original state r_esp.set32(savedESP); eip = savedEIP; cs(savedCS); ss(savedSS); if (pe.getType() == ProcessorException.Type.DOUBLE_FAULT) { LOGGING.log(Level.SEVERE, "Triple-Fault: Unhandleable, machine will halt!", e); throw new IllegalStateException("Triple Fault ", e); } else if (e.combinesToDoubleFault(pe)) handleVirtual8086ModeException(ProcessorException.DOUBLE_FAULT_0); else handleVirtual8086ModeException(e); } } public final void handleSoftVirtual8086ModeInterrupt(int vector, int instructionLength) { int savedESP = r_esp.get32(); int savedEIP = eip; Segment savedCS = cs; Segment savedSS = ss; if ((getCR4() & 0x1) != 0) { throw new IllegalStateException("VME not supported"); } else if (eflagsIOPrivilegeLevel < 3) { throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; } else { try { followVirtual8086ModeException(vector, false, 0, false, true); } catch (ProcessorException e) { //return cpu to original state r_esp.set32(savedESP); eip = savedEIP; cs(savedCS); ss(savedSS); //make eip point at INT instruction which threw an exception if (e.pointsToSelf()) eip -= instructionLength; if (e.getType() == ProcessorException.Type.DOUBLE_FAULT) { System.err.println("Triple-Fault: Unhandleable, machine will halt!"); throw new IllegalStateException("Triple Fault"); } else handleVirtual8086ModeException(e); } } } public final void handleHardVirtual8086ModeInterrupt(int vector) { int savedESP = r_esp.get32(); int savedEIP = eip; Segment savedCS = cs; Segment savedSS = ss; try { followVirtual8086ModeException(vector, false, 0, true, false); } catch (ProcessorException e) { //return cpu to original state r_esp.set32(savedESP); eip = savedEIP; cs(savedCS); ss(savedSS); //if (e.getVector() == PROC_EXCEPTION_DF) { //System.err.println("Triple-Fault: Unhandleable, machine will halt!"); //throw new IllegalStateException("Triple Fault"); //else handleVirtual8086ModeException(e); } } private final void followVirtual8086ModeException(int vector, boolean hasErrorCode, int errorCode, boolean hardware, boolean software) { //System.out.println(); //System.out.println("VM8086 Mode exception " + Integer.toHexString(vector) + (hasErrorCode ? ", errorCode = " + errorCode:"") + ", hardware = " + hardware + ", software = " + software); //System.out.println("CS:EIP " + Integer.toHexString(cs.getBase()) +":" +Integer.toHexString(eip)); if (vector == ProcessorException.Type.PAGE_FAULT.vector()) setCR2(linearMemory.getLastWalkedAddress()); // if it is a fault, then RF is set on the eflags image on stack (excpet for debug exception) if ((vector < 32) && ProcessorException.isFault(vector) && (vector != ProcessorException.Type.DEBUG.vector())) rf(true); int selector = vector << 3; //multiply by 8 to get offset into idt int EXT = hardware ? 1 : 0; if (selector +7 > idtr.getLimit()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, selector + 2 + EXT, true); Segment gate; boolean isSup = linearMemory.isSupervisor(); try { linearMemory.setSupervisor(true); long descriptor = idtr.getQuadWord(selector); gate = SegmentFactory.createProtectedModeSegment(linearMemory, selector, descriptor); } catch (ProcessorException e) { throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, selector + 2 + EXT, true); } finally { linearMemory.setSupervisor(isSup); } if (!gate.isSystem()) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, selector + 2, true); checkGate(gate, selector, software); switch (gate.getType()) { default: LOGGING.log(Level.INFO, "Invalid gate type for throwing interrupt: 0x{0}", Integer.toHexString(gate.getType())); throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, selector + 2 + EXT, true); case 0x05: //Interrupt Handler: Task Gate throw new IllegalStateException("Unimplemented Interrupt Handler: Task Gate"); case 0x06: //Interrupt Handler: 16-bit Interrupt Gate case 0x07: //Interrupt Handler: 16-bit Trap Gate case 0x0e: //Interrupt Handler: 32-bit Interrupt Gate case 0x0f: //Interrupt Handler: 32-bit Trap Gate { ProtectedModeSegment.GateSegment theGate = (ProtectedModeSegment.GateSegment) gate; int targetSegmentSelector = theGate.getTargetSegment(); if ((targetSegmentSelector & 0xfffc) == 0) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, EXT, true); ProtectedModeSegment targetSegment; try { targetSegment = (ProtectedModeSegment) getSegment(targetSegmentSelector); } catch (ProcessorException e) { throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector & 0xfffc + EXT, true); } if (!targetSegment.isCode() || (targetSegment.getDPL() > currentPrivilegeLevel)) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector & 0xfffc + EXT, true); if (!targetSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.NOT_PRESENT, targetSegmentSelector & 0xfffc, true); if (!targetSegment.isConforming() && targetSegment.getDPL() < currentPrivilegeLevel) { // Interrupt to inner privilege level int newStackSelector = 0; int newESP = 0; if ((tss.getType() == 0x9) || (tss.getType() == 0xb)) // 32-bit TSS { int tssStackAddress = (targetSegment.getDPL() * 8) + 4; if ((tssStackAddress + 7) > tss.getLimit()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, tss.getSelector() & 0xfffc, true); isSup = linearMemory.isSupervisor(); try { linearMemory.setSupervisor(true); newStackSelector = 0xffff & tss.getWord(tssStackAddress + 4); newESP = tss.getDoubleWord(tssStackAddress); } finally { linearMemory.setSupervisor(isSup); } } else if ((tss.getType() == 0x1) || (tss.getType() == 0x3)) // 16-bit TSS { int tssStackAddress = (targetSegment.getDPL() * 4) + 2; if ((tssStackAddress + 3) > tss.getLimit()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, tss.getSelector() & 0xfffc, true); isSup = linearMemory.isSupervisor(); try { linearMemory.setSupervisor(true); newStackSelector = 0xffff & tss.getWord(tssStackAddress + 2); newESP = tss.getWord(tssStackAddress); } finally { linearMemory.setSupervisor(isSup); } } else throw new IllegalStateException("Illegal TSS type"); if (targetSegment.getDPL() != 0) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector & 0xfffc, true); if ((newStackSelector & 0xfffc) == 0) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, EXT, true); ProtectedModeSegment newStackSegment; try { newStackSegment = (ProtectedModeSegment) getSegment(newStackSelector, true); } catch (ProcessorException e) { throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, newStackSelector & 0xfffc, true); } if (newStackSegment.getRPL() != targetSegment.getDPL()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, newStackSelector & 0xfffc + EXT, true); if (newStackSegment.isCode() || !newStackSegment.isDataWritable()) throw new ProcessorException(ProcessorException.Type.TASK_SWITCH, newStackSelector & 0xfffc + EXT, true); if (!newStackSegment.isPresent()) throw new ProcessorException(ProcessorException.Type.STACK_SEGMENT, newStackSelector & 0xfffc + EXT, true); int targetOffset = theGate.getTargetOffset(); targetSegment.checkAddress(targetOffset); int oldSS = ss.getSelector() & 0xffff; int oldESP = r_esp.get32(); int oldCS = cs.getSelector() & 0xffff; int oldEIP = eip; isSup = linearMemory.isSupervisor(); try { linearMemory.setSupervisor(true); if (newStackSegment.getDefaultSizeFlag()) { int tmpESP = newESP; if (theGate.getType() >= 0xe) // 32-bit int/trap gate { newStackSegment.setDoubleWord(tmpESP-4, gs.getSelector()); newStackSegment.setDoubleWord(tmpESP-8, fs.getSelector()); newStackSegment.setDoubleWord(tmpESP-12, ds.getSelector()); newStackSegment.setDoubleWord(tmpESP-16, es.getSelector()); tmpESP -= 16; newStackSegment.setDoubleWord(tmpESP-4, oldSS); newStackSegment.setDoubleWord(tmpESP-8, oldESP); newStackSegment.setDoubleWord(tmpESP-12, getEFlags()); newStackSegment.setDoubleWord(tmpESP-16, oldCS); newStackSegment.setDoubleWord(tmpESP-20, oldEIP); tmpESP -= 20; if (hasErrorCode) { tmpESP -= 4; newStackSegment.setDoubleWord(tmpESP, errorCode); } } else // 16-bit int/trap gate { newStackSegment.setWord(tmpESP-2, (short)gs.getSelector()); newStackSegment.setWord(tmpESP-4, (short)fs.getSelector()); newStackSegment.setWord(tmpESP-6, (short)ds.getSelector()); newStackSegment.setWord(tmpESP-8, (short)es.getSelector()); tmpESP -= 8; newStackSegment.setWord(tmpESP-2, (short)oldSS); newStackSegment.setWord(tmpESP-4, (short)oldESP); newStackSegment.setWord(tmpESP-6, (short)getEFlags()); newStackSegment.setWord(tmpESP-8, (short)oldCS); newStackSegment.setWord(tmpESP-10, (short)oldEIP); tmpESP -= 10; if (hasErrorCode) { tmpESP -= 2; newStackSegment.setWord(tmpESP, (short)errorCode); } } r_esp.set32(tmpESP); } else { int tmpSP = 0xffff & newESP; if (theGate.getType() >= 0xe) // 32-bit int/trap gate { newStackSegment.setDoubleWord(0xffff & (tmpSP-4), gs.getSelector()); newStackSegment.setDoubleWord(0xffff & (tmpSP-8), fs.getSelector()); newStackSegment.setDoubleWord(0xffff & (tmpSP-12), ds.getSelector()); newStackSegment.setDoubleWord(0xffff & (tmpSP-16), es.getSelector()); tmpSP -= 16; newStackSegment.setDoubleWord(0xffff & (tmpSP-4), oldSS); newStackSegment.setDoubleWord(0xffff & (tmpSP-8), oldESP); newStackSegment.setDoubleWord(0xffff & (tmpSP-12), getEFlags()); newStackSegment.setDoubleWord(0xffff & (tmpSP-16), oldCS); newStackSegment.setDoubleWord(0xffff & (tmpSP-20), oldEIP); tmpSP -= 20; if (hasErrorCode) { tmpSP -= 4; newStackSegment.setDoubleWord(0xffff & tmpSP, errorCode); } } else // 16-bit int/trap gate { newStackSegment.setWord(0xffff & (tmpSP-2), (short)gs.getSelector()); newStackSegment.setWord(0xffff & (tmpSP-4), (short)fs.getSelector()); newStackSegment.setWord(0xffff & (tmpSP-6), (short)ds.getSelector()); newStackSegment.setWord(0xffff & (tmpSP-8), (short)es.getSelector()); tmpSP -= 8; newStackSegment.setWord(0xffff & (tmpSP-2), (short)oldSS); newStackSegment.setWord(0xffff & (tmpSP-4), (short)oldESP); newStackSegment.setWord(0xffff & (tmpSP-6), (short)getEFlags()); newStackSegment.setWord(0xffff & (tmpSP-8), (short)oldCS); newStackSegment.setWord(0xffff & (tmpSP-10), (short)oldEIP); tmpSP -= 10; if (hasErrorCode) { tmpSP -= 2; newStackSegment.setWord(0xffff & tmpSP, (short)errorCode); } } r_esp.set16(tmpSP); } } finally { linearMemory.setSupervisor(isSup); } cs(targetSegment); cs.setRPL(currentPrivilegeLevel); ss(newStackSegment); ss.setRPL(targetSegment.getDPL()); gs(SegmentFactory.NULL_SEGMENT); fs(SegmentFactory.NULL_SEGMENT); ds(SegmentFactory.NULL_SEGMENT); es(SegmentFactory.NULL_SEGMENT); } else { // interrupt to same privilege level if (targetSegment.isConforming() || (targetSegment.getDPL() != 0)) throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, targetSegmentSelector & 0xfffc, true); int targetOffset = theGate.getTargetOffset(); targetSegment.checkAddress(targetOffset); if (theGate.getType() >= 0xe) // 32-bit gate { push32(getEFlags()); push32(cs.getSelector()); push32(eip); if (hasErrorCode) push32(errorCode); } else // 16-bit gate { push16((short)getEFlags()); push16((short)cs.getSelector()); push16((short)eip); if (hasErrorCode) push16((short)errorCode); } cs(targetSegment); cs.setRPL(currentPrivilegeLevel); } eip = theGate.getTargetOffset(); setCPL(cs.getDPL()); if ((theGate.getType() & 1) == 0) // int gate setIF(false); eflagsTrap = false; eflagsNestedTask = false; eflagsVirtual8086Mode = false; rf(false); throw ModeSwitchException.PROTECTED_MODE_EXCEPTION; } } } protected void checkAlignmentChecking() { if ((getCPL() == 3) && eflagsAlignmentCheck && ((cr0 & CR0_ALIGNMENT_MASK) != 0)) { if (!alignmentChecking) { LOGGING.log(Level.FINE, "Alignment checking enabled"); alignmentChecking = true; updateAlignmentCheckingInDataSegments(); //checking now enabled } } else { if (alignmentChecking) { LOGGING.log(Level.FINE, "Alignment checking disabled"); alignmentChecking = false; updateAlignmentCheckingInDataSegments(); //checking now disabled } } } public boolean initialised() { boolean result = ((physicalMemory != null) && (linearMemory != null) && (ioports != null) && (interruptController != null)); if (result && !started) { reset(); started = true; } return result; } public void acceptComponent(HardwareComponent component) { if (component instanceof LinearAddressSpace) { linearMemory = (LinearAddressSpace) component; alignmentCheckedMemory = new AlignmentCheckedAddressSpace(linearMemory); } if (component instanceof PhysicalAddressSpace) physicalMemory = (PhysicalAddressSpace) component; if (component instanceof IOPortHandler) ioports = (IOPortHandler) component; if ((component instanceof InterruptController) && component.initialised()) interruptController = (InterruptController)component; } public static boolean getSignFlag(int status, boolean sf, int result) { if ((status & SF) == 0) return sf; else return getSignFlag(result); } public static boolean getZeroFlag(int status, boolean zf, int result) { if ((status & ZF) == 0) return zf; else return getZeroFlag(result); } public static boolean getParityFlag(int status, boolean pf, int result) { if ((status & PF) == 0) return pf; else return getParityFlag(result); } public static boolean getCarryFlag(int status, boolean cf, int op1, int op2, int result, int instr) { if ((status & CF) == 0) return cf; else return getCarryFlag(op1, op2, result, instr); } public static boolean getAuxCarryFlag(int status, boolean af, int op1, int op2, int result, int instr) { if ((status & AF) == 0) return af; else return getAuxCarryFlag(op1, op2, result, instr); } public static boolean getOverflowFlag(int status, boolean of, int op1, int op2, int result, int instr) { if ((status & OF) == 0) return of; else return getOverflowFlag(op1, op2, result, instr); } // lazy flag methods public static boolean getSignFlag(int result) { return result < 0; } public static boolean getZeroFlag(int result) { return result == 0; } public static boolean getParityFlag(int result) { return parityMap[result & 0xff]; } public static boolean getCarryFlag(int op1, int op2, int result, int instr) { switch (instr) { case ADC8: if ((result & 0xff) != (op1 & 0xff) + (op2 & 0xff)) return (op1 & 0xff) + (op2 & 0xff) +1 > 0xff; else return (op1 & 0xff) + (op2 & 0xff) > 0xff; case ADC16: if ((result & 0xffff) != (op1 & 0xffff) + (op2 & 0xffff)) return (op1 & 0xffff) + (op2 & 0xffff) +1 > 0xffff; else return (op1 & 0xffff) + (op2 & 0xffff) > 0xffff; case ADC32: if (result != op1 + op2) return (op1 & 0xffffffffL) + (op2 & 0xffffffffL) +1 > 0xffffffffL; else return (op1 & 0xffffffffL) + (op2 & 0xffffffffL) > 0xffffffffL; case ADD8: return (result & 0xff) < (op1 & 0xff); case ADD16: return (result & 0xffff) < (op1 & 0xffff); case ADD32: return (result & 0xffffffffL) < (op1 & 0xffffffffL); case SUB8: return (op1 & 0xff) < (op2 & 0xff); case SUB16: return (op1 & 0xffff) < (op2 & 0xffff); case SUB32: return (op1 & 0xffffffffL) < (op2 & 0xffffffffL); case SBB8: if ((byte)result-(byte)op1+(byte)op2 != 0) return ((op1 & 0xFF) < (result & 0xFF)) || ((op2 & 0xFF) == 0xFF); else return (op1 & 0xff) < (op2 & 0xff); case SBB16: if ((short)result-(short)op1+(short)op2 != 0) return ((op1 & 0xFFFF) < (result & 0xFFFF)) || ((op2 & 0xFFFF) == 0xFFFF); else return (op1 & 0xFFFF) < (op2 & 0xFFFF); case SBB32: if (result-op1+op2 != 0) return ((op1 & 0xFFFFFFFFL) < (result & 0xFFFFFFFFL)) || (op2 == 0xFFFFFFFF); else return (op1 & 0xffffffffL) < (op2 & 0xffffffffL); case NEG8: case NEG16: case NEG32: return result != 0; case SAR8: case SAR16: case SAR32: return ((op1 >> (op2-1)) & 1) != 0; case SHL8: return ((op1 >> (8 - op2)) & 0x1) != 0; case SHL16: return ((op1 >> (16 - op2)) & 0x1) != 0; case SHL32: return ((op1 >> (32 - op2)) & 0x1) != 0; case SHLD16: if (op2 <= 16) return ((op1 >> (16 - op2)) & 0x1) != 0; else return ((op1 >> (32 - op2)) & 0x1) != 0; case SHLD32: return ((op1 >> (32 - op2)) & 0x1) != 0; case IMUL8: return (((op1 & 0x80) == (op2 & 0x80)) && ((result & 0xff00) != 0)); case IMUL16: return (((op1 & 0x8000) == (op2 & 0x8000)) && (((op1 * op2) & 0xffff0000) != 0)); case IMUL32: return (((op1 & 0x80000000) == (op2 & 0x80000000)) && (((((long)op1) * op2) & 0xffffffff00000000L) != 0)); case SHRD16: if (op2 <=16) return ((op1 >> (op2 - 1)) & 0x1) != 0; else return ((op1 >> (op2 - 17)) & 0x1) != 0; case SHRD32: case SHR8: case SHR16: case SHR32: return ((op1 >> (op2 - 1)) & 0x1) != 0; default: throw new IllegalStateException("Unknown flag method: " + instr); } } public static boolean getAuxCarryFlag(int op1, int op2, int result, int instr) { switch (instr) { case ADC8: case ADC16: case ADC32: case ADD8: case ADD16: case ADD32: case SUB8: case SUB16: case SUB32: case SBB8: case SBB16: case SBB32: return (((op1 ^ op2) ^ result) & 0x10) != 0; case NEG8: case NEG16: case NEG32: return (result & 0xF) != 0; case INC: return (result & 0xF) == 0; case DEC: return (result & 0xF) == 0xF; case SAR8: case SAR16: case SAR32: //(c, 5) -> t return (result & 1) != 0; //guessed from real CPU case IMUL8: case IMUL16: case IMUL32: //(10, 83, 810) -> t //(2, 4d8, 9b0) -> f case SHL8: case SHL16: case SHL32: return (result & (0x8000000 >> op2)) != 0; //(1, 4, 10) - > t, (6, 5, c0) -> f //(2, 8, 200) -> f, (206, 8, 20600) -> f //(1, 4, 10) -> f //(8c102c00, 4, c102c000)-> t //(1, 1) -> f case SHRD16: case SHRD32: case SHLD16: case SHLD32: return false;// strictly undefined, check this case SHR8: case SHR16: case SHR32: //(838, 6) -> t //(6d8, 6) -> t //(9d0, 6) -> f //(60, 3) -> t //(1e158 ,6 ) -> t //(1e158 ,9 ) -> t //(1e158 ,c ) -> t //(9b8 = 1001 1011 1000, 6, 26 = 10 0110 # 1) -> t //(9b8 = 1001 1011 1000, 3, 137 = 1 0011 0111 # 0)-> f //(81, 1, 40) -> t //(50 = 0101 0000, 3, a = 1010 # 0) -> t //(58 = 0101 1000, 3, b = 1011 # 0) -> f //(05 = 0000 0101, 2, 1 # 0) -> f //(0d = 0000 1101, 2, 3 = 11 # 0) -> f //(0e = 0000 1110, 2, 3 = 11 # 1) -> f //(0f = 0000 1111, 2, 3 = 11 # 1) -> f //(94 = 1001 0100, 2, 25 = 10 0101 # 0) -> f //(1a = 0001 1010, 1, d = 1101 # 0) -> f //(2e = 0010 1110, 1, 17 = 1 0111 # 0) -> f //(18 = 0001 1000, 3, 3 = 11 # 0) -> f/t //(17 = 0001 0111, 1, b = 1011 # 1) -> f return false; default: throw new IllegalStateException("Unknown flag method: " + instr); } } public static boolean getOverflowFlag(int op1, int op2, int result, int instr) { switch (instr) { case ADC8: case ADD8: return (((~((op1) ^ (op2)) & ((op2) ^ (result))) & (0x80)) != 0); case ADC16: case ADD16: return (((~((op1) ^ (op2)) & ((op2) ^ (result))) & (0x8000)) != 0); case ADC32: case ADD32: return (((~((op1) ^ (op2)) & ((op2) ^ (result))) & (0x80000000)) != 0); case SUB8: case SBB8: return (((((op1) ^ (op2)) & ((op1) ^ (result))) & (0x80)) != 0); case SUB16: case SBB16: return (((((op1) ^ (op2)) & ((op1) ^ (result))) & (0x8000)) != 0); case SUB32: case SBB32: return (((((op1) ^ (op2)) & ((op1) ^ (result))) & (0x80000000)) != 0); case NEG8: return (result & 0xff) == 0x80; case NEG16: return (result & 0xffff) == 0x8000; case NEG32: case INC: return result == 0x80000000; case DEC: return result == 0x7FFFFFFF; case SAR8: case SAR16: case SAR32: return false; //(3, 1f, 0) -> t case SHL8: return ((result >> 7) != 0) ^ (((op1 >> (8 - op2)) & 0x1) != 0); case SHL16: return ((result >> 15) != 0) ^ (((op1 >> (16 - op2)) & 0x1) != 0); case SHL32: return ((result >> 31) != 0) ^ (((op1 >> (32 - op2)) & 0x1) != 0); //(8c102c00, 4, c102c000)->f //(1, 1f, 80000000) -> f //(1, 1f) -> f case SHLD16: case SHLD32: return getCarryFlag(op1, op2, result, instr) ^ ((result >> 31) != 0); case SHRD16: // if (op2 == 1) commented because despite the Intel spec, this is what Bochs does return (((result << 1) ^ result) & (1 << 15)) != 0; // return false; case SHRD32: // if (op2 == 1) commented because despite the Intel spec, this is what Bochs does return (((result << 1) ^ result) >> 31) != 0; // return false; case SHR8: return (((result << 1) ^ result) >> 7) != 0; case SHR16: return (((result << 1) ^ result) >> 15) != 0; case SHR32: return (((result << 1) ^ result) >> 31) != 0; // (22, 4, 2) -> t case IMUL8: return (((op1 & 0x80) == (op2 & 0x80)) && ((result & 0xff00) != 0)); case IMUL16: return (((op1 & 0x8000) == (op2 & 0x8000)) && (((op1 * op2) & 0xffff0000) != 0)); case IMUL32: return (((op1 & 0x80000000) == (op2 & 0x80000000)) && (((((long)op1) * op2) & 0xffffffff00000000L) != 0)); default: throw new IllegalStateException("Unknown flag method: " + instr + " = " + (instr)); } } public boolean updated() { return (physicalMemory.updated() && linearMemory.updated() && ioports.updated() && interruptController.updated()); } public void updateComponent(HardwareComponent component) { if (component instanceof LinearAddressSpace) { alignmentCheckedMemory = new AlignmentCheckedAddressSpace(linearMemory); } } }