/* JPC: An x86 PC Hardware Emulator for a pure Java Virtual Machine Release Version 2.4 A project from the Physics Dept, The University of Oxford Copyright (C) 2007-2010 The University of Oxford 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/ Conceived and Developed by: Rhys Newman, Ian Preston, Chris Dennis End of licence header */ package org.jpc.emulator.processor; import java.io.*; import java.util.logging.*; import org.jpc.emulator.memory.AddressSpace; import org.jpc.emulator.memory.LinearAddressSpace; public abstract class ProtectedModeSegment extends Segment { private static final Logger LOGGING = Logger.getLogger(ProtectedModeSegment.class.getName()); public static final int TYPE_ACCESSED = 0x1; public static final int TYPE_CODE = 0x8; public static final int TYPE_DATA_WRITABLE = 0x2; public static final int TYPE_DATA_EXPAND_DOWN = 0x4; public static final int TYPE_CODE_READABLE = 0x2; public static final int TYPE_CODE_CONFORMING = 0x4; public static final int DESCRIPTOR_TYPE_CODE_DATA = 0x10; public static final int TYPE_AVAILABLE_32_TSS = 0x9; public static final int TYPE_BUSY_32_TSS = 0xb; protected final boolean defaultSize; private final boolean granularity; private final boolean present; private final boolean system; private int selector; protected final int base; private final int dpl; protected final long limit; private final long descriptor; private int rpl; public ProtectedModeSegment(AddressSpace memory, int selector, long descriptor) { super(memory); this.selector = selector; this.descriptor = descriptor; granularity = (descriptor & 0x80000000000000L) != 0; if (granularity) limit = ((descriptor << 12) & 0xffff000L) | ((descriptor >>> 20) & 0xf0000000L) | 0xfffL; else limit = (descriptor & 0xffffL) | ((descriptor >>> 32) & 0xf0000L); base = (int) ((0xffffffL & (descriptor >> 16)) | ((descriptor >> 32) & 0xffffffffff000000L)); rpl = selector & 0x3; dpl = (int) ((descriptor >> 45) & 0x3); defaultSize = (descriptor & (1L << 54)) != 0; present = (descriptor & (1L << 47)) != 0; system = (descriptor & (1L << 44)) != 0; } public void saveState(DataOutput output) throws IOException { output.writeInt(3); output.writeInt(selector); output.writeLong(descriptor); output.writeInt(rpl); } public boolean isPresent() { return present; } public boolean isSystem() { return !system; } public boolean isAccessed() { return (getType() & TYPE_ACCESSED) != 0; } public boolean isConforming() { return (getType() & TYPE_CODE_CONFORMING) != 0; } public boolean isCode() { return (getType() & TYPE_CODE) != 0; } public boolean isCodeReadable() { return (getType() & TYPE_CODE_READABLE) != 0; } public boolean isDataWritable() { return !isCode() && ((getType() & TYPE_DATA_WRITABLE) != 0); } public int translateAddressRead(int offset) { checkAddress(offset); return base + offset; } public int translateAddressWrite(int offset) { checkAddress(offset); return base + offset; } public void checkAddress(int offset) { if ((0xffffffffL & offset) > limit) { LOGGING.log(Level.INFO, this + "segment limit exceeded: 0x{0} > 0x{1}", new Object[]{Integer.toHexString(offset), Integer.toHexString((int) limit)}); throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION,0,true);//ProcessorException.GENERAL_PROTECTION_0; //ProcessorException.GENERAL_PROTECTION_0; } } public boolean getDefaultSizeFlag() { return defaultSize; } public int getLimit() { return (int) limit; } public int getBase() { return base; } public int getSelector() { return (selector & 0xFFFC) | rpl; } public int getRPL() { return rpl; } public int getDPL() { return dpl; } public void setRPL(int cpl) { rpl = cpl; } public void supervisorSetSelector(int selector) { this.selector = selector; rpl = selector & 3; } public boolean setSelector(int selector) { throw new IllegalStateException("Cannot set a selector for a descriptor table segment"); } static abstract class StackSegment extends ProtectedModeSegment { public StackSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public void checkAddress(int offset) { if ((0xffffffffL & offset) > limit) { LOGGING.log(Level.INFO, this + "Stack segment limit exceeded: 0x{0} > 0x{1}", new Object[]{Integer.toHexString(offset), Integer.toHexString((int) limit)}); throw new ProcessorException(ProcessorException.Type.STACK_SEGMENT,0,true); } } } static abstract class ReadOnlyProtectedModeSegment extends ProtectedModeSegment { public ReadOnlyProtectedModeSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } void writeAttempted() { throw new IllegalStateException(); } public final void setByte(int offset, byte data) { writeAttempted(); } public final void setWord(int offset, short data) { writeAttempted(); } public final void setDoubleWord(int offset, int data) { writeAttempted(); } public final void setQuadWord(int offset, long data) { writeAttempted(); } } static abstract class ReadOnlyStackSegment extends StackSegment { public ReadOnlyStackSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } void writeAttempted() { throw new IllegalStateException(); } public final void setByte(int offset, byte data) { writeAttempted(); } public final void setWord(int offset, short data) { writeAttempted(); } public final void setDoubleWord(int offset, int data) { writeAttempted(); } public final void setQuadWord(int offset, long data) { writeAttempted(); } } static final class ReadOnlyDataSegment extends ReadOnlyProtectedModeSegment { public ReadOnlyDataSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA; } void writeAttempted() { throw ProcessorException.GENERAL_PROTECTION_0; } } static final class ReadOnlyDataStackSegment extends ReadOnlyStackSegment { public ReadOnlyDataStackSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA; } void writeAttempted() { throw ProcessorException.GENERAL_PROTECTION_0; } } static final class ReadOnlyAccessedDataSegment extends ReadOnlyProtectedModeSegment { public ReadOnlyAccessedDataSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA | TYPE_ACCESSED; } void writeAttempted() { throw ProcessorException.GENERAL_PROTECTION_0; } } static final class ReadOnlyAccessedStackSegment extends ReadOnlyStackSegment { public ReadOnlyAccessedStackSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA | TYPE_ACCESSED; } void writeAttempted() { throw ProcessorException.GENERAL_PROTECTION_0; } } static final class ReadWriteDataSegment extends ProtectedModeSegment { public ReadWriteDataSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA | TYPE_DATA_WRITABLE; } } static final class ReadWriteStackSegment extends StackSegment { public ReadWriteStackSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA | TYPE_DATA_WRITABLE; } } static final class DownReadWriteDataSegment extends ProtectedModeSegment { public DownReadWriteDataSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA | TYPE_DATA_WRITABLE; } public final int translateAddressRead(int offset) { checkAddress(offset); return super.base + offset; } public final int translateAddressWrite(int offset) { checkAddress(offset); return super.base + offset; } public final void checkAddress(int offset) { if ((0xffffffffL & offset) > super.limit) { throw new ProcessorException(ProcessorException.Type.GENERAL_PROTECTION, 0, true);//ProcessorException.GENERAL_PROTECTION_0; } } } static final class ReadWriteAccessedDataSegment extends ProtectedModeSegment { public ReadWriteAccessedDataSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA | TYPE_DATA_WRITABLE | TYPE_ACCESSED; } } static final class ReadWriteAccessedStackSegment extends StackSegment { public ReadWriteAccessedStackSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA | TYPE_DATA_WRITABLE | TYPE_ACCESSED; } } static final class ExecuteOnlyCodeSegment extends ReadOnlyProtectedModeSegment { public ExecuteOnlyCodeSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA | TYPE_CODE; } } static final class ExecuteReadAccessedCodeSegment extends ProtectedModeSegment { public ExecuteReadAccessedCodeSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA | TYPE_CODE | TYPE_CODE_READABLE | TYPE_ACCESSED; } } static final class ExecuteReadCodeSegment extends ProtectedModeSegment { public ExecuteReadCodeSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA | TYPE_CODE | TYPE_CODE_READABLE; } } static final class ExecuteOnlyConformingAccessedCodeSegment extends ReadOnlyProtectedModeSegment { public ExecuteOnlyConformingAccessedCodeSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA | TYPE_CODE | TYPE_CODE_CONFORMING | TYPE_ACCESSED; } } static final class ExecuteReadConformingAccessedCodeSegment extends ProtectedModeSegment { public ExecuteReadConformingAccessedCodeSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA | TYPE_CODE | TYPE_CODE_CONFORMING | TYPE_CODE_READABLE | TYPE_ACCESSED; } } static final class ExecuteReadConformingCodeSegment extends ProtectedModeSegment { public ExecuteReadConformingCodeSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return DESCRIPTOR_TYPE_CODE_DATA | TYPE_CODE | TYPE_CODE_CONFORMING | TYPE_CODE_READABLE; } } static public abstract class AbstractTSS extends ReadOnlyProtectedModeSegment { public AbstractTSS(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public void saveCPUState(Processor cpu) { int initialAddress = translateAddressWrite(0); memory.setDoubleWord(initialAddress + 28, cpu.getCR3()); memory.setDoubleWord(initialAddress + 32, cpu.eip); memory.setDoubleWord(initialAddress + 36, cpu.getEFlags()); memory.setDoubleWord(initialAddress + 40, cpu.r_eax.get32()); memory.setDoubleWord(initialAddress + 44, cpu.r_ecx.get32()); memory.setDoubleWord(initialAddress + 48, cpu.r_edx.get32()); memory.setDoubleWord(initialAddress + 52, cpu.r_ebx.get32()); memory.setDoubleWord(initialAddress + 56, cpu.r_esp.get32()); memory.setDoubleWord(initialAddress + 60, cpu.r_ebp.get32()); memory.setDoubleWord(initialAddress + 64, cpu.r_esi.get32()); memory.setDoubleWord(initialAddress + 68, cpu.r_edi.get32()); memory.setDoubleWord(initialAddress + 72, cpu.es.getSelector()); memory.setDoubleWord(initialAddress + 76, cpu.cs.getSelector()); memory.setDoubleWord(initialAddress + 80, cpu.ss.getSelector()); memory.setDoubleWord(initialAddress + 84, cpu.ds.getSelector()); memory.setDoubleWord(initialAddress + 88, cpu.fs.getSelector()); memory.setDoubleWord(initialAddress + 92, cpu.gs.getSelector()); } public void restoreCPUState(Processor cpu) { int initialAddress = translateAddressRead(0); cpu.eip = memory.getDoubleWord(initialAddress + 32); cpu.setEFlags(memory.getDoubleWord(initialAddress + 36)); cpu.r_eax.set32(memory.getDoubleWord(initialAddress + 40)); cpu.r_ecx.set32(memory.getDoubleWord(initialAddress + 44)); cpu.r_edx.set32(memory.getDoubleWord(initialAddress + 48)); cpu.r_ebx.set32(memory.getDoubleWord(initialAddress + 52)); cpu.r_esp.set32(memory.getDoubleWord(initialAddress + 56)); cpu.r_ebp.set32(memory.getDoubleWord(initialAddress + 60)); cpu.r_esi.set32(memory.getDoubleWord(initialAddress + 64)); cpu.r_edi.set32(memory.getDoubleWord(initialAddress + 68)); // non dynamic fields //cpu.ldtr = cpu.getSegment(0xFFFF & memory.getDoubleWord(initialAddress + 96)); if (cpu.pagingEnabled()) cpu.setCR3(memory.getDoubleWord(initialAddress + 28)); } public byte getByte(int offset) { boolean isSup = ((LinearAddressSpace) memory).isSupervisor(); try { ((LinearAddressSpace) memory).setSupervisor(true); return super.getByte(offset); } finally { ((LinearAddressSpace) memory).setSupervisor(isSup); } } public short getWord(int offset) { boolean isSup = ((LinearAddressSpace) memory).isSupervisor(); try { ((LinearAddressSpace) memory).setSupervisor(true); return super.getWord(offset); } finally { ((LinearAddressSpace) memory).setSupervisor(isSup); } } public int getDoubleWord(int offset) { boolean isSup = ((LinearAddressSpace) memory).isSupervisor(); try { ((LinearAddressSpace) memory).setSupervisor(true); return super.getDoubleWord(offset); } finally { ((LinearAddressSpace) memory).setSupervisor(isSup); } } public long getQuadWord(int offset) { boolean isSup = ((LinearAddressSpace) memory).isSupervisor(); try { ((LinearAddressSpace) memory).setSupervisor(true); return super.getQuadWord(offset); } finally { ((LinearAddressSpace) memory).setSupervisor(isSup); } } } static final class Available32BitTSS extends AbstractTSS { public Available32BitTSS(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return TYPE_AVAILABLE_32_TSS; } } static final class Busy32BitTSS extends AbstractTSS { public Busy32BitTSS(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return TYPE_BUSY_32_TSS; } } static final class LDT extends ReadOnlyProtectedModeSegment { public LDT(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return 0x02; } } public static abstract class GateSegment extends ReadOnlyProtectedModeSegment { private int targetSegment, targetOffset; public GateSegment(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); targetSegment = (int) ((descriptor >> 16) & 0xffff); targetOffset = (int) ((descriptor & 0xffff) | ((descriptor >>> 32) & 0xffff0000)); } public int getTargetSegment() { return targetSegment; } public int getTargetOffset() { return targetOffset; } } static final class TaskGate extends GateSegment { public TaskGate(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public final int getTargetOffset() { throw new IllegalStateException(); } public int getType() { return 0x05; } } static final class InterruptGate32Bit extends GateSegment { public InterruptGate32Bit(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return 0x0e; } } static final class InterruptGate16Bit extends GateSegment { public InterruptGate16Bit(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return 0x06; } } static final class TrapGate32Bit extends GateSegment { public TrapGate32Bit(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return 0x0f; } } static final class TrapGate16Bit extends GateSegment { public TrapGate16Bit(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return 0x07; } } public static final class CallGate32Bit extends GateSegment { private final int parameterCount; public CallGate32Bit(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); parameterCount = (int) ((descriptor >> 32) & 0xF); } public int getType() { return 0x0c; } public final int getParameterCount() { return parameterCount; } } public static final class CallGate16Bit extends GateSegment { private final int parameterCount; public CallGate16Bit(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); parameterCount = (int) ((descriptor >> 32) & 0xF); } public int getType() { return 0x04; } public final int getParameterCount() { return parameterCount; } } static final class Available16BitTSS extends ProtectedModeSegment { public Available16BitTSS(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return 0x01; } } static final class Busy16BitTSS extends ProtectedModeSegment { public Busy16BitTSS(AddressSpace memory, int selector, long descriptor) { super(memory, selector, descriptor); } public int getType() { return 0x03; } } public void printState() { System.out.println("PM Mode segment"); System.out.println("selector: " + Integer.toHexString(selector)); System.out.println("base: " + Integer.toHexString(base)); System.out.println("dpl: " + Integer.toHexString(dpl)); System.out.println("rpl: " + Integer.toHexString(rpl)); System.out.println("limit: " + Long.toHexString(limit)); System.out.println("descriptor: " + Long.toHexString(descriptor)); } }