/* 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.peripheral; import org.jpc.emulator.pci.*; import org.jpc.emulator.motherboard.*; import org.jpc.support.*; import org.jpc.emulator.HardwareComponent; import org.jpc.emulator.memory.PhysicalAddressSpace; import java.io.*; import java.util.logging.*; /** * * @author Chris Dennis */ public class PIIX3IDEInterface extends AbstractPCIDevice { private static final Logger LOGGING = Logger.getLogger(PIIX3IDEInterface.class.getName()); private InterruptController irqDevice; private IDEChannel[] channels; private boolean drivesUpdated; private BMDMAIORegion[] bmdmaRegions; private BlockDevice[] drives; public PIIX3IDEInterface() { devfnSet = false; ioportRegistered = false; pciRegistered = false; dmaRegistered = false; this.assignDeviceFunctionNumber(-1); putConfigWord(PCI_CONFIG_VENDOR_ID, (short)0x8086); // Intel putConfigWord(PCI_CONFIG_DEVICE_ID, (short)0x7010); putConfigByte(0x09, (byte)0x80); // legacy ATA mode putConfigWord(PCI_CONFIG_CLASS_DEVICE, (short)0x0101); // PCI IDE putConfigByte(PCI_CONFIG_HEADER, (byte)0x00); // header_type channels = new IDEChannel[2]; bmdmaRegions = new BMDMAIORegion[2]; //Run BMDMARegion constructors Remember 0=1 and 2=3 bmdmaRegions[1] = new BMDMAIORegion(null); bmdmaRegions[0] = new BMDMAIORegion(bmdmaRegions[1]); } public void saveState(DataOutput output) throws IOException { channels[0].saveState(output); channels[1].saveState(output); for (BMDMAIORegion bmdma : bmdmaRegions) { if (bmdma != null) bmdma.saveState(output); } } public void loadState(DataInput input) throws IOException { channels[0].loadState(input); channels[1].loadState(input); bmdmaRegions[0].loadState(input); bmdmaRegions[1].loadState(input); } public void loadIOPorts(IOPortHandler ioportHandler, DataInput input) throws IOException { drivesUpdated = false; devfnSet = true; pciRegistered = false; ioportRegistered = false; dmaRegistered = false; loadState(input); ioportHandler.registerIOPortCapable(channels[0]); ioportHandler.registerIOPortCapable(channels[1]); if (!(bmdmaRegions[0].ioPortsRequested()[0] == -1)) ioportHandler.registerIOPortCapable(bmdmaRegions[0]); if (!(bmdmaRegions[1].ioPortsRequested()[0] == -1)) ioportHandler.registerIOPortCapable(bmdmaRegions[1]); } public boolean autoAssignDeviceFunctionNumber() { return false; } public void deassignDeviceFunctionNumber() { LOGGING.log(Level.WARNING, "PCI device/function number conflict."); } public IORegion[] getIORegions() { return new IORegion[]{bmdmaRegions[0]}; } public IORegion getIORegion(int index) { if (index == 4) { return bmdmaRegions[0]; } else { return null; } } private boolean ioportRegistered; private boolean pciRegistered; private boolean dmaRegistered; public boolean initialised() { return ioportRegistered && pciRegistered && dmaRegistered && (irqDevice != null) && (drives != null); } public void reset() { devfnSet = false; ioportRegistered = false; pciRegistered = false; this.assignDeviceFunctionNumber(-1); putConfigWord(PCI_CONFIG_VENDOR_ID, (short)0x8086); // Intel putConfigWord(PCI_CONFIG_DEVICE_ID, (short)0x7010); putConfigByte(0x09, (byte)0x80); // legacy ATA mode putConfigWord(PCI_CONFIG_CLASS_DEVICE, (short)0x0101); // PCI IDE putConfigByte(PCI_CONFIG_HEADER, (byte)0x00); // header_type channels = new IDEChannel[2]; dmaRegistered = false; bmdmaRegions = new BMDMAIORegion[2]; //Run BMDMARegion constructors Remember 0=1 and 2=3 bmdmaRegions[1] = new BMDMAIORegion(null); bmdmaRegions[0] = new BMDMAIORegion(bmdmaRegions[1]); irqDevice = null; drives = null; super.reset(); } private boolean devfnSet; public boolean updated() { return ioportRegistered && pciRegistered && dmaRegistered && irqDevice.updated() && drivesUpdated; } public void updateComponent(HardwareComponent component) { if ((component instanceof IOPortHandler) && irqDevice.updated() && drivesUpdated) { //Run IDEChannel Constructors // channels[0] = new IDEChannel(14, irqDevice, 0x1f0, 0x3f6, new BlockDevice[]{drives[0], drives[1]}, bmdmaRegions[0]); // channels[1] = new IDEChannel(15, irqDevice, 0x170, 0x376, new BlockDevice[]{drives[2], drives[3]}, bmdmaRegions[1]); channels[0].setDrives(new BlockDevice[]{drives[0], drives[1]}); channels[1].setDrives(new BlockDevice[]{drives[2], drives[3]}); ((IOPortHandler) component).registerIOPortCapable(channels[0]); ((IOPortHandler) component).registerIOPortCapable(channels[1]); ioportRegistered = true; } if ((component instanceof PCIBus) && component.updated() && !pciRegistered && devfnSet) { pciRegistered = ((PCIBus) component).registerDevice(this); } if ((component instanceof PCIISABridge) && component.updated()) { this.assignDeviceFunctionNumber(((PCIDevice) component).getDeviceFunctionNumber() + 1); devfnSet = true; } if ((component instanceof DriveSet) && component.updated()) { // drives = new BlockDevice[4]; drives[0] = ((DriveSet) component).getHardDrive(0); drives[1] = ((DriveSet) component).getHardDrive(1); drives[2] = ((DriveSet) component).getHardDrive(2); drives[3] = ((DriveSet) component).getHardDrive(3); drivesUpdated = true; } if (component instanceof PhysicalAddressSpace) { dmaRegistered = true; bmdmaRegions[0].setAddressSpace((PhysicalAddressSpace) component); bmdmaRegions[1].setAddressSpace((PhysicalAddressSpace) component); } } public void acceptComponent(HardwareComponent component) { if ((component instanceof InterruptController) && component.initialised()) irqDevice = (InterruptController)component; if ((component instanceof IOPortHandler) && component.initialised() && (irqDevice != null) && (drives != null)) { //Run IDEChannel Constructors channels[0] = new IDEChannel(14, irqDevice, 0x1f0, 0x3f6, new BlockDevice[]{drives[0], drives[1]}, bmdmaRegions[0]); channels[1] = new IDEChannel(15, irqDevice, 0x170, 0x376, new BlockDevice[]{drives[2], drives[3]}, bmdmaRegions[1]); ((IOPortHandler)component).registerIOPortCapable(channels[0]); ((IOPortHandler)component).registerIOPortCapable(channels[1]); ioportRegistered = true; } if ((component instanceof PCIBus) && component.initialised() && !pciRegistered && devfnSet) { pciRegistered = ((PCIBus)component).registerDevice(this); } if ((component instanceof PCIISABridge) && component.initialised()) { this.assignDeviceFunctionNumber(((PCIDevice)component).getDeviceFunctionNumber() + 1); devfnSet = true; } if ((component instanceof DriveSet) && component.initialised()) { drives = new BlockDevice[4]; drives[0] = ((DriveSet)component).getHardDrive(0); drives[1] = ((DriveSet)component).getHardDrive(1); drives[2] = ((DriveSet)component).getHardDrive(2); drives[3] = ((DriveSet)component).getHardDrive(3); } if (component instanceof PhysicalAddressSpace) { dmaRegistered = true; bmdmaRegions[0].setAddressSpace((PhysicalAddressSpace)component); bmdmaRegions[1].setAddressSpace((PhysicalAddressSpace)component); } } public String toString() { return "Intel PIIX3 IDE Interface"; } }