/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.vm.x86; import org.jnode.system.resource.MemoryResource; import org.jnode.system.resource.MemoryScanner; import org.jnode.system.resource.ResourceManager; import org.jnode.system.resource.ResourceNotFreeException; import org.jnode.system.resource.ResourceOwner; import org.jnode.util.NumberUtils; import org.jnode.annotation.MagicPermission; import org.jnode.bootlog.BootLogInstance; import org.vmmagic.unboxed.Address; /** * @author Ewout Prangsma (epr@users.sourceforge.net) */ @MagicPermission final class MPFloatingPointerStructure { private MemoryResource mem; private static final int MAGIC = 0x5F504D5F; // _MP_ private MPConfigTable configTable; /** * Find the MP floating pointer structure. * * @return The found structure, or null if not found. */ public static MPFloatingPointerStructure find(ResourceManager rm, ResourceOwner owner) { MPFloatingPointerStructure mp; mp = find(rm, owner, 639 * 1024, 640 * 1024); if (mp == null) { mp = find(rm, owner, 0xF0000, 0xFFFFF); } if (mp == null) { return null; } return mp; } /** * Release the resources hold by this structure. */ public void release() { mem.release(); } /** * Gets the length of this structure in bytes. * * @return the length */ final int getLength() { return (16 * (mem.getByte(0x08) & 0xFF)); } /** * Gets the specification revision level */ final int getSpecRevision() { return mem.getByte(0x09); } /** * Gets the MP system configuration type. When non-zero, a default * configuration is present, when zero an MP configuration table must be * present. * * @return */ final int getSystemConfigurationType() { return mem.getByte(0x0B); } /** * Is the IMCR register present. This flag can be used to determine whether * PIC Mode or Virtual Wire mode is implemented by the system. * * @return */ final boolean isIMCRPresent() { return ((mem.getByte(0x0C) & 0x80) != 0); } /** * @see java.lang.Object#toString() */ public String toString() { return "MP 1." + getSpecRevision() + ", config-type 0x" + NumberUtils.hex(getSystemConfigurationType(), 2) + ", IMCR " + (isIMCRPresent() ? "present" : "not present") + ", ConfigTableAt 0x" + NumberUtils.hex(mem.getInt(0x04)); } /** * Gets the physical address of the MP configuration table. * * @return the address */ final Address getMPConfigTablePtr() { return Address.fromIntZeroExtend(mem.getInt(0x04)); } /** * Gets the MPConfig table. */ final MPConfigTable getMPConfigTable() { return configTable; } /** * Initialize this instance. * * @param mem */ private MPFloatingPointerStructure(MemoryResource mem) { this.mem = mem; } /** * Is this a valid MPFP structure? */ private final boolean isValid() { // Length should be 16 if (getLength() != 16) { return false; } // Check checksum int sum = 0; for (int i = 0; i < 16; i++) { sum += mem.getByte(i) & 0xFF; sum &= 0xFF; } if (sum != 0) { return false; } return true; } private final boolean initConfigTable(ResourceManager rm, ResourceOwner owner) { final Address tablePtr = getMPConfigTablePtr(); int size = 0x2C; // Base table length try { MemoryResource mem = rm.claimMemoryResource(owner, tablePtr, size, ResourceManager.MEMMODE_NORMAL); // Read the table length int baseTableLen = mem.getChar(4); mem.release(); // Claim the full table. // BootLogInstance.get().info("baseTableLength " + baseTableLen); size = baseTableLen; mem = rm.claimMemoryResource(owner, tablePtr, size, ResourceManager.MEMMODE_NORMAL); this.configTable = new MPConfigTable(mem); if (configTable.isValid()) { return true; } else { configTable.release(); configTable = null; return false; } } catch (ResourceNotFreeException ex) { BootLogInstance.get().warn("Cannot claim MP config table region"); ex.printStackTrace(); return false; } } /** * Find the structure between to pointers. * * @param rm * @param owner * @param startPtr * @param endPtr * @return The structure found, or null if not found */ private static MPFloatingPointerStructure find(ResourceManager rm, ResourceOwner owner, int startPtr, int endPtr) { final MemoryScanner ms = rm.getMemoryScanner(); Address ptr = Address.fromIntZeroExtend(startPtr); int size = endPtr - startPtr; final int stepSize = 16; while (size > 0) { Address res = ms.findInt32(ptr, size, MAGIC, stepSize); if (res != null) { try { final MemoryResource mem; mem = rm.claimMemoryResource(owner, ptr, 16, ResourceManager.MEMMODE_NORMAL); final MPFloatingPointerStructure mp = new MPFloatingPointerStructure( mem); if (mp.isValid()) { if (mp.initConfigTable(rm, owner)) { return mp; } } mp.release(); } catch (ResourceNotFreeException ex) { BootLogInstance.get().warn("Cannot claim MP region"); } } ptr = ptr.add(stepSize); size -= stepSize; } return null; } }