/* 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.pci; import org.jpc.emulator.*; import java.io.*; /** * Provides a default implementations for the core features of a standard PCI * device. This includes assignment of device/function numbers, handling of * interrupts and implementation of the PCI configuration space for this device. * @author Chris Dennis */ public abstract class AbstractPCIDevice extends AbstractHardwareComponent implements PCIDevice { private int deviceFunctionNumber; private byte[] configuration; private int irq; private IRQBouncer irqBouncer; private boolean pciRegistered; public AbstractPCIDevice() { pciRegistered = false; configuration = new byte[256]; } public void saveState(DataOutput output) throws IOException { output.writeInt(irq); output.writeInt(deviceFunctionNumber); output.writeInt(configuration.length); output.write(configuration); } public void loadState(DataInput input) throws IOException { irq = input.readInt(); deviceFunctionNumber = input.readInt(); int len = input.readInt(); configuration = new byte[len]; input.readFully(configuration, 0, len); } //PCI Bus Registering public int getDeviceFunctionNumber() { return deviceFunctionNumber; } public void assignDeviceFunctionNumber(int devFN) { deviceFunctionNumber = devFN; } public boolean autoAssignDeviceFunctionNumber() { return true; } public void deassignDeviceFunctionNumber() { pciRegistered = false; assignDeviceFunctionNumber(-1); } private boolean checkConfigWrite(int address) { switch (0xff & configReadByte(PCI_CONFIG_HEADER)) { case PCI_HEADER_SINGLE_FUNCTION: case PCI_HEADER_MULTI_FUNCTION: switch (address) { case PCI_CONFIG_VENDOR_ID: case PCI_CONFIG_VENDOR_ID + 1: case PCI_CONFIG_DEVICE_ID: case PCI_CONFIG_DEVICE_ID + 1: case PCI_CONFIG_REVISION: case PCI_CONFIG_REVISION + 1: case PCI_CONFIG_CLASS_DEVICE: case PCI_CONFIG_CLASS_DEVICE + 1: case PCI_CONFIG_HEADER: case PCI_CONFIG_BASE_ADDRESS: case PCI_CONFIG_BASE_ADDRESS + 0x01: case PCI_CONFIG_BASE_ADDRESS + 0x02: case PCI_CONFIG_BASE_ADDRESS + 0x03: case PCI_CONFIG_BASE_ADDRESS + 0x04: case PCI_CONFIG_BASE_ADDRESS + 0x05: case PCI_CONFIG_BASE_ADDRESS + 0x06: case PCI_CONFIG_BASE_ADDRESS + 0x07: case PCI_CONFIG_BASE_ADDRESS + 0x08: case PCI_CONFIG_BASE_ADDRESS + 0x09: case PCI_CONFIG_BASE_ADDRESS + 0x0a: case PCI_CONFIG_BASE_ADDRESS + 0x0b: case PCI_CONFIG_BASE_ADDRESS + 0x0c: case PCI_CONFIG_BASE_ADDRESS + 0x0d: case PCI_CONFIG_BASE_ADDRESS + 0x0e: case PCI_CONFIG_BASE_ADDRESS + 0x0f: case PCI_CONFIG_BASE_ADDRESS + 0x10: case PCI_CONFIG_BASE_ADDRESS + 0x11: case PCI_CONFIG_BASE_ADDRESS + 0x12: case PCI_CONFIG_BASE_ADDRESS + 0x13: case PCI_CONFIG_BASE_ADDRESS + 0x14: case PCI_CONFIG_BASE_ADDRESS + 0x15: case PCI_CONFIG_BASE_ADDRESS + 0x16: case PCI_CONFIG_BASE_ADDRESS + 0x17: case PCI_CONFIG_EXPANSION_ROM_BASE_ADDRESS: case PCI_CONFIG_EXPANSION_ROM_BASE_ADDRESS + 0x1: case PCI_CONFIG_EXPANSION_ROM_BASE_ADDRESS + 0x2: case PCI_CONFIG_EXPANSION_ROM_BASE_ADDRESS + 0x3: case PCI_CONFIG_INTERRUPT_PIN: return false; default: return true; } default: case PCI_HEADER_PCI_PCI_BRIDGE: switch (address) { case PCI_CONFIG_VENDOR_ID: case PCI_CONFIG_VENDOR_ID + 1: case PCI_CONFIG_DEVICE_ID: case PCI_CONFIG_DEVICE_ID + 1: case PCI_CONFIG_REVISION: case PCI_CONFIG_REVISION + 1: case PCI_CONFIG_CLASS_DEVICE: case PCI_CONFIG_CLASS_DEVICE + 1: case PCI_CONFIG_HEADER: case 0x38: //RESERVED case 0x39: //RESERVED case 0x3a: //RESERVED case 0x3b: //RESERVED case PCI_CONFIG_INTERRUPT_PIN: return false; default: return true; } } } public boolean configWriteByte(int address, byte data) //returns true if device needs remapping { if (checkConfigWrite(address)) putConfigByte(address, data); if (address >= PCI_CONFIG_COMMAND && address < (PCI_CONFIG_COMMAND + 2)) /* if the command register is modified, we must modify the mappings */ return true; return false; } public final boolean configWriteWord(int address, short data) //returns true if device needs remapping { int modAddress = address; for (int i = 0; i < 2; i++) { if (checkConfigWrite(modAddress)) putConfigByte(modAddress, (byte) data); modAddress++; data >>>= 8; } if ((modAddress > PCI_CONFIG_COMMAND) && (address < (PCI_CONFIG_COMMAND + 2))) // if the command register is modified, we must modify the mappings return true; return false; } public final boolean configWriteLong(int address, int data) { if (((address >= PCI_CONFIG_BASE_ADDRESS && address < (PCI_CONFIG_BASE_ADDRESS + 4 * 6)) || (address >= PCI_CONFIG_EXPANSION_ROM_BASE_ADDRESS && address < (PCI_CONFIG_EXPANSION_ROM_BASE_ADDRESS + 4)))) { int regionIndex; if (address >= PCI_CONFIG_EXPANSION_ROM_BASE_ADDRESS) regionIndex = PCI_ROM_SLOT; else regionIndex = (address - PCI_CONFIG_BASE_ADDRESS) >>> 2; IORegion r = getIORegion(regionIndex); if (r != null) { if (regionIndex == PCI_ROM_SLOT) data &= (~(r.getSize() - 1)) | 1; else { data &= ~(r.getSize() - 1); data |= r.getType(); } putConfigLong(address, data); return true; } } int modAddress = address; for (int i = 0; i < 4; i++) { if (checkConfigWrite(modAddress)) putConfigByte(modAddress, (byte) data); modAddress++; data = data >>> 8; } if (modAddress > PCI_CONFIG_COMMAND && address < (PCI_CONFIG_COMMAND + 2)) /* if the command register is modified, we must modify the mappings */ return true; return false; } public final byte configReadByte(int address) { return configuration[address]; } public final short configReadWord(int address) { short result = configReadByte(address + 1); result <<= 8; result |= (0xff & configReadByte(address)); return result; } public final int configReadLong(int address) { int result = 0xffff & configReadWord(address + 2); result <<= 16; result |= (0xffff & configReadWord(address)); return result; } public final void putConfigByte(int address, byte data) { configuration[address] = data; } public final void putConfigWord(int address, short data) { putConfigByte(address, (byte) data); address++; data >>= 8; putConfigByte(address, (byte) data); } public final void putConfigLong(int address, int data) { putConfigWord(address, (short) data); address += 2; data >>= 16; putConfigWord(address, (short) data); } public void setIRQIndex(int irqIndex) { irq = irqIndex; } public int getIRQIndex() { return irq; } public void addIRQBouncer(IRQBouncer bouncer) { irqBouncer = bouncer; } public IRQBouncer getIRQBouncer() { return irqBouncer; } public boolean initialised() { return pciRegistered; } public void reset() { pciRegistered = false; } public void acceptComponent(HardwareComponent component) { if ((component instanceof PCIBus) && component.initialised() && !pciRegistered) pciRegistered = ((PCIBus) component).registerDevice(this); } public void updateComponent(org.jpc.emulator.HardwareComponent component) { if ((component instanceof PCIBus) && component.updated() && !pciRegistered) pciRegistered = ((PCIBus) component).registerDevice(this); } public boolean updated() { return initialised(); } }