/*
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.support;
import org.jpc.j2se.Option;
import java.util.logging.*;
/**
* Hard-drive block device implementation.
* <p>
* Subclass of <code>RawBlockDevice</code> with the ability to auto-detect drive
* geometries from DOS paritition or fallback to guessing from the drive size.
* @author Chris Dennis
*/
public class HDBlockDevice extends RawBlockDevice
{
private static final Logger LOGGING = Logger.getLogger(HDBlockDevice.class.getName());
private static final int PART_END_CHS = 0x5;
private static final int PART_SIZE = 0xc;
private static final int PART_1 = 0x1be;
private static final int PART_MAGIC = 0x1fe;
private final int cylinders;
private final int heads;
private final int sectors;
/**
* Constructs an instance backed by the given <code>SeekableIODevice</code>.
* @param data backing
*/
public HDBlockDevice(SeekableIODevice data)
{
super(data);
int detectedCylinders = 0;
int detectedHeads = 0;
int detectedSectors = 0;
byte[] mbr = new byte[512];
if ((read(0, mbr, 1) >= 0) && (mbr[PART_MAGIC] == (byte) 0x55) && (mbr[PART_MAGIC + 1] == (byte) 0xaa)) {
for (int i = PART_1; i < PART_MAGIC; i += 0x10) {
int numberSectors = (mbr[i + PART_SIZE] & 0xff) |
((mbr[i + PART_SIZE + 1] & 0xff) << 8) |
((mbr[i + PART_SIZE + 2] & 0xff) << 16) |
((mbr[i + PART_SIZE + 3] & 0xff) << 24);
if (numberSectors != 0) {
detectedHeads = 1 + (mbr[i + PART_END_CHS] & 0xff);
detectedSectors = mbr[i + PART_END_CHS + 1] & 0x3f;
if (detectedSectors == 0) continue;
detectedCylinders = (int) (this.getTotalSectors() / (detectedHeads * detectedSectors));
if (detectedCylinders < 1 || detectedCylinders > 16383) {
detectedCylinders = 0;
continue;
}
}
}
}
if (detectedCylinders == 0) { //no geometry information?
//We'll use a standard LBA geometry
detectedCylinders = (int) (this.getTotalSectors() / (16 * 63));
if (detectedCylinders > 16383)
detectedCylinders = 16383;
else if (detectedCylinders < 2)
detectedCylinders = 2;
detectedHeads = 16;
detectedSectors = 63;
if (Option.printCHS.isSet())
LOGGING.log(Level.INFO, "no geometry information, guessing CHS {0,number,integer}:{1,number,integer}:{2,number,integer}",
new Object[]{Integer.valueOf(detectedCylinders), Integer.valueOf(detectedHeads), Integer.valueOf(detectedSectors)
});
}
cylinders = detectedCylinders;
heads = detectedHeads;
sectors = detectedSectors;
}
public boolean isLocked()
{
return false;
}
public void setLock(boolean locked)
{
}
public int getCylinders()
{
return cylinders;
}
public int getHeads()
{
return heads;
}
public int getSectors()
{
return sectors;
}
public Type getType()
{
return Type.HARDDRIVE;
}
public String toString()
{
return "HD: " + super.toString();
}
}