/* * $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.driver.system.acpi; import java.io.PrintWriter; import java.security.AccessController; import java.security.PrivilegedAction; import javax.naming.NameNotFoundException; import org.apache.log4j.Logger; import org.jnode.driver.Driver; import org.jnode.driver.DriverException; import org.jnode.driver.system.acpi.aml.Aml; import org.jnode.driver.system.acpi.aml.NameString; import org.jnode.driver.system.acpi.aml.ParseNode; import org.jnode.driver.system.acpi.vm.NameSpace; import org.jnode.driver.system.firmware.AcpiDevice; import org.jnode.driver.system.firmware.AcpiRSDPInfo; import org.jnode.naming.InitialNaming; import org.jnode.system.resource.MemoryResource; import org.jnode.system.resource.ResourceManager; import org.jnode.system.resource.ResourceNotFreeException; import org.jnode.system.resource.ResourceOwner; import org.jnode.system.resource.SimpleResourceOwner; import org.jnode.util.NumberUtils; import org.jnode.vm.facade.MemoryMapEntry; import org.jnode.vm.facade.VmArchitecture; import org.jnode.vm.facade.VmUtils; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Extent; import org.vmmagic.unboxed.MagicUtils; import org.vmmagic.unboxed.Word; import static org.jnode.vm.VirtualMemoryRegion.ACPI; /** * AcpiDriver. * * @author Francois-Frederic Ozog * @author Ewout Prangsma (epr@users.sourceforge.net) */ final class AcpiDriver extends Driver implements AcpiAPI { private static final Logger log = Logger.getLogger(AcpiDriver.class); private SystemDescriptionTable sdt; private NameSpace root; private RSDP rsdp; /** * Physical address of the first ACPI memory map entry */ private Address acpiPhysStart; /** * Virtual address of the first ACPI memory map entry */ private Address acpiVirtStart; public void reset() { } /** * Initialize this instance. */ public AcpiDriver() { } /** * @see org.jnode.driver.Driver#startDevice() */ protected void startDevice() throws DriverException { final AcpiDevice dev = (AcpiDevice) getDevice(); try { final ResourceManager rm; rm = InitialNaming.lookup(ResourceManager.NAME); mmapAcpiRegion(); AcpiRSDPInfo acpiInfo = dev.getRsdpInfo(); loadRootTable(rm, acpiInfo); } catch (NameNotFoundException ex) { throw new DriverException("Could not find ResourceManager", ex); } catch (ResourceNotFreeException ex) { throw new DriverException("Cannot load ACPI info", ex); } // Register the API's dev.registerAPI(AcpiAPI.class, this); } /** * @see org.jnode.driver.Driver#stopDevice() */ protected void stopDevice() throws DriverException { final AcpiDevice dev = (AcpiDevice) getDevice(); // Unregister the API's dev.unregisterAPI(AcpiAPI.class); // Reset the values root = null; if (sdt != null) { sdt.release(); sdt = null; } if (rsdp != null) { rsdp.release(); rsdp = null; } } /** * Dump the namespace. * * @see org.jnode.driver.system.acpi.AcpiAPI#dump(java.io.PrintWriter) */ public void dump(PrintWriter out) { if (sdt != null) { out.println("Tables:"); out.println(sdt); for (AcpiTable table : sdt.getTables()) { out.println(table); } out.println(); } if (root != null) { out.println("Namespace:"); root.dump(out); } } public void dumpBattery(PrintWriter out) { ParseNode battery; battery = sdt.getParsedAml().findName(new NameString("BAT0"), Aml.AML_DEVICE); if (battery != null) { out.println(battery.toString()); } battery = sdt.getParsedAml().findName(new NameString("BAT1"), Aml.AML_DEVICE); if (battery != null) { out.println(battery.toString()); } } /** * Map the ACPI virtual memory region. */ private void mmapAcpiRegion() throws DriverException { final VmArchitecture arch = VmUtils.getVm().getArch(); final MemoryMapEntry[] mmap = AccessController.doPrivileged(new PrivilegedAction<MemoryMapEntry[]>() { public MemoryMapEntry[] run() { return arch.getMemoryMap(); } }); final Address acpiStart = arch.getStart(ACPI); final Address acpiEnd = arch.getEnd(ACPI); // First unmap the entire ACPI region arch.munmap(ACPI, acpiStart, acpiEnd.toWord().sub(acpiStart.toWord()).toExtent()); this.acpiVirtStart = acpiStart; MemoryMapEntry lastAcpiEntry = null; Address start = acpiStart; for (MemoryMapEntry e : mmap) { if (e.isAcpi() || e.isAcpiNVS()) { // Calculate page aligned boundaries & sizes final Address alignedPhysStart = arch.pageAlign(ACPI, e.getStart(), false); final Word diff = e.getStart().toWord().sub(alignedPhysStart.toWord()); final Extent size = e.getSize().add(diff); // Check for adjacent memory blocks if (lastAcpiEntry != null) { Address expected = lastAcpiEntry.getStart().add(lastAcpiEntry.getSize()); if (e.getStart().NE(expected)) { throw new DriverException("ACPI memory map entries are not adjacent"); } } else { this.acpiPhysStart = alignedPhysStart; } // Map entry log.info("Mapping ACPI memory map entry to " + MagicUtils.toString(start)); arch.mmap(ACPI, start, size, alignedPhysStart); start = start.add(e.getSize()); lastAcpiEntry = e; } } if (lastAcpiEntry == null) { throw new DriverException("No ACPI memory map entries found"); } } private void loadRootTable(ResourceManager rm, AcpiRSDPInfo acpiInfo) throws ResourceNotFreeException { if (acpiInfo != null) { final ResourceOwner owner = new SimpleResourceOwner("ACPI"); final MemoryResource rsdtptrRes; rsdtptrRes = rm.claimMemoryResource(owner, acpiInfo.getRsdpStart(), acpiInfo.getLength(), ResourceManager.MEMMODE_NORMAL); this.rsdp = new RSDP(this, rsdtptrRes); this.root = NameSpace.getRoot(); Address ptr = rsdp.getXsdtAddress(); if (ptr.isZero()) { log.info("Using RSDT, length " + NumberUtils.hex(rsdp.getLength())); ptr = rsdp.getRsdtAddress(); // Use the RSDT (ACPI 1.0) sdt = (RootSystemDescriptionTable) AcpiTable.getTable(this, owner, rm, ptr); root.parse(sdt.getParsedAml()); } else { // Use the XSDT (ACPI >= 2.0) sdt = (ExtendedSystemDescriptionTable) AcpiTable.getTable(this, owner, rm, ptr); root.parse(sdt.getParsedAml()); } } } /** * Convert a physical address of an ACPI table to a virtual address * in the ACPI virtual memory region. * * @param physAddr * @return */ final Address physToVirtual(Address physAddr) { final Word offset = physAddr.toWord().sub(acpiPhysStart.toWord()); return acpiVirtStart.add(offset); } public String toString() { StringBuffer buffer = new StringBuffer(); /* FixedAcpiDescriptionTable facp = */ sdt.getFACP(); buffer.append(rsdp.getOemId()); buffer.append(' '); buffer.append(sdt.getOemTableId()); buffer.append(": ACPI version "); final int revision = rsdp.getRevision(); buffer.append(revision == 0 ? "1.0" : (revision == 2 ? "2.0" : "unknown-" + revision)); return buffer.toString(); } public String toDetailedString() { StringBuffer buffer = new StringBuffer(); FixedAcpiDescriptionTable facp = sdt.getFACP(); buffer.append(rsdp.getOemId()); buffer.append(' '); buffer.append(sdt.getOemTableId()); buffer.append(" ACPI version "); final int revision = rsdp.getRevision(); buffer.append(revision == 0 ? "1.0" : (revision == 2 ? "2.0" : "unknown-" + revision)); buffer.append("\n PM1A("); buffer.append(Integer.toHexString(facp.getPm1aControl())); buffer.append(", "); buffer.append(Integer.toHexString(facp.getPm1aEvent())); buffer.append("), PM1B("); buffer.append(Integer.toHexString(facp.getPm1bControl())); buffer.append(", "); buffer.append(Integer.toHexString(facp.getPm1bEvent())); buffer.append("), PM2("); buffer.append(Integer.toHexString(facp.getPm2Control())); buffer.append("), Timer("); buffer.append(Integer.toHexString(facp.getPmTimer())); buffer.append("), Events("); buffer.append(Integer.toHexString(facp.getGeneralPurposeEvent0())); buffer.append(", "); buffer.append(Integer.toHexString(facp.getGeneralPurposeEvent1())); buffer.append("), Flags("); buffer.append(Integer.toHexString(facp.getFlags())); buffer.append(')'); return buffer.toString(); } }