Package org.jnode.vm.x86

Source Code of org.jnode.vm.x86.VmX86Architecture32

/*
* $Id$
*
* Copyright (C) 2003-2014 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 static org.jnode.vm.VirtualMemoryRegion.ACPI;

import org.jnode.annotation.MagicPermission;
import org.jnode.vm.Unsafe;
import org.jnode.vm.VirtualMemoryRegion;
import org.jnode.vm.classmgr.VmIsolatedStatics;
import org.jnode.vm.classmgr.VmSharedStatics;
import org.jnode.vm.compiler.IMTCompiler;
import org.jnode.vm.facade.TypeSizeInfo;
import org.jnode.vm.scheduler.VmProcessor;
import org.jnode.vm.scheduler.VmScheduler;
import org.jnode.vm.x86.compiler.X86IMTCompiler32;
import org.vmmagic.pragma.UninterruptiblePragma;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Extent;
import org.vmmagic.unboxed.Word;

/**
* Architecture description for the x86 (32-bit) architecture.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
@MagicPermission
public final class VmX86Architecture32 extends VmX86Architecture {

    /**
     * Start address of the virtual memory region  available to devices (3Gb)
     */
    public static final int DEVICE_START = 0xC0000000;

    /**
     * End address of the virtual memory region  available to devices (4Gb-4Mb)
     */
    public static final int DEVICE_END = 0xFFC00000;

    /**
     * Start address of the virtual memory region available to ACPI (3Gb - 4Mb)
     */
    public static final int ACPI_START = DEVICE_START - 0x400000;

    /**
     * Start address of the virtual memory region available to ACPI (3Gb)
     */
    public static final int ACPI_END = DEVICE_START;

    /**
     * Start address of the virtual memory region available to the memory manager (256Mb).
     * This address must be 4Mb aligned.
     */
    public static final int AVAILABLE_START = 0x10000000;

    /**
     * End address of the virtual memory region  available to the memory manager.
     * This address must be 4Mb aligned.
     */
    public static final int AVAILABLE_END = ACPI_START;

    // Log of page size per region
    private static final byte LOG_DEFAULT_PAGE_SIZE = 22;
    private static final byte LOG_AVAILABLE_PAGE_SIZE = LOG_DEFAULT_PAGE_SIZE;
    private static final byte LOG_HEAP_PAGE_SIZE = LOG_AVAILABLE_PAGE_SIZE;
    private static final byte LOG_ACPI_PAGE_SIZE = 22;
    private static final byte LOG_DEVICE_PAGE_SIZE = LOG_DEFAULT_PAGE_SIZE;

    // Page sizes per region
    private static final int AVAILABLE_PAGE_SIZE = 1 << LOG_AVAILABLE_PAGE_SIZE;
    private static final int HEAP_PAGE_SIZE = 1 << LOG_HEAP_PAGE_SIZE;
    private static final int ACPI_PAGE_SIZE = 1 << LOG_ACPI_PAGE_SIZE;
    private static final int DEVICE_PAGE_SIZE = 1 << LOG_DEVICE_PAGE_SIZE;

    /**
     * Size of an object reference
     */
    public static final int SLOT_SIZE = 4;

    /**
     * The IMT compiler
     */
    private final X86IMTCompiler32 imtCompiler;

    /**
     * The type size information
     */
    private final TypeSizeInfo typeSizeInfo;

    /**
     * The next physical page address to be mmaped
     */
    private Word pageCursor;

    /**
     * Default page entry flags
     */
    private static final int PF_DEFAULT = PF_PRESENT | PF_WRITE | PF_USER | PF_PSE;

    /**
     * Initialize this instance.
     */
    public VmX86Architecture32() {
        this("L1A");
    }

    /**
     * Initialize this instance.
     *
     * @param compiler
     */
    public VmX86Architecture32(String compiler) {
        super(SLOT_SIZE, compiler);
        this.imtCompiler = new X86IMTCompiler32();
        this.typeSizeInfo = new TypeSizeInfo(1, 1, 2, 2, 1);
    }

    /**
     * Create a processor instance for this architecture.
     *
     * @return The processor
     */
    public VmProcessor createProcessor(int id, VmSharedStatics sharedStatics, VmIsolatedStatics isolatedStatics,
                                       VmScheduler scheduler) {
        return new VmX86Processor32(id, this, sharedStatics, isolatedStatics, scheduler, null);
    }

    public final IMTCompiler getIMTCompiler() {
        return imtCompiler;
    }

    public final TypeSizeInfo getTypeSizeInfo() {
        return typeSizeInfo;
    }

    public final byte getLogPageSize(int region) {
        switch (region) {
            case VirtualMemoryRegion.AVAILABLE:
                return LOG_AVAILABLE_PAGE_SIZE;
            case VirtualMemoryRegion.HEAP:
                return LOG_HEAP_PAGE_SIZE;
            case VirtualMemoryRegion.ACPI:
                return LOG_ACPI_PAGE_SIZE;
            case VirtualMemoryRegion.DEVICE:
                return LOG_DEVICE_PAGE_SIZE;
            default:
                return LOG_DEFAULT_PAGE_SIZE;
        }
    }

    public Address getEnd(int space) {
        switch (space) {
            case VirtualMemoryRegion.HEAP:
                return Address.fromIntZeroExtend(AVAILABLE_END);
            case VirtualMemoryRegion.AVAILABLE:
                return Address.fromIntZeroExtend(AVAILABLE_END);
            case VirtualMemoryRegion.DEVICE:
                return Address.fromIntZeroExtend(DEVICE_END);
            case VirtualMemoryRegion.ACPI:
                return Address.fromIntZeroExtend(ACPI_END);
            default:
                return super.getEnd(space);
        }
    }

    public Address getStart(int space) {
        switch (space) {
            case VirtualMemoryRegion.HEAP:
                return Address.fromIntZeroExtend(BOOT_IMAGE_START);
            case VirtualMemoryRegion.AVAILABLE:
                return Address.fromIntZeroExtend(AVAILABLE_START);
            case VirtualMemoryRegion.DEVICE:
                return Address.fromIntZeroExtend(DEVICE_START);
            case VirtualMemoryRegion.ACPI:
                return Address.fromIntZeroExtend(ACPI_START);
            default:
                return super.getStart(space);
        }
    }

    /**
     * Map a region of the virtual memory space. Note that you cannot allocate
     * memory in this memory, because it is used very early in the boot process.
     *
     * @param region   Memory region
     * @param start    The start of the virtual memory region to map
     * @param size     The size of the virtual memory region to map
     * @param physAddr The physical address to map the virtual address to. If this is
     *                 Address.max(), free pages are used instead.
     * @return true for success, false otherwise.
     */
    public final boolean mmap(int region, Address start,
                              Extent size, Address physAddr) throws UninterruptiblePragma {
        switch (region) {
            case VirtualMemoryRegion.HEAP:
                if (!physAddr.isMax()) {
                    return false;
                }
                break;
            case VirtualMemoryRegion.ACPI:
                if (physAddr.isMax()) {
                    return false;
                }
                break;
            default:
                return false;
        }

        final Word alignedStart = pageAlign(region, start.toWord(), false);
        if (!alignedStart.EQ(start.toWord())) {
            // Make adjustments on size & physAddr
            final Word diff = start.sub(alignedStart).toWord();
            start = alignedStart.toAddress();
            size = size.add(diff);
            if (!physAddr.isMax()) {
                physAddr = physAddr.sub(diff);
            }
        }
        size = pageAlign(region, size.toWord(), true).toExtent();

        if (pageCursor.isZero()) {
            Unsafe.debug("pageCursor is zero");
        }

        final Extent pageSize = getPageSize(region);
        while (!size.isZero()) {
            mapPage(start, physAddr, pageSize, (region == ACPI));
            start = start.add(pageSize);
            size = size.sub(pageSize);
            if (!physAddr.isMax()) {
                physAddr = physAddr.add(pageSize);
            }
        }

        return true;
    }

    /**
     * Unmap a region of the virtual memory space. Note that you cannot allocate
     * memory in this memory, because it is used very early in the boot process.
     *
     * @param region Memory region
     * @param start  The start of the virtual memory region to unmap. This value is
     *               aligned down on pagesize.
     * @param size   The size of the virtual memory region to unmap. This value is
     *               aligned up on pagesize.
     * @return true for success, false otherwise.
     */
    public boolean munmap(int region, Address start, Extent size)
        throws UninterruptiblePragma {
        switch (region) {
            case VirtualMemoryRegion.HEAP:
            case VirtualMemoryRegion.ACPI:
                break;
            default:
                return false;
        }

        final Word alignedStart = pageAlign(region, start.toWord(), false);
        if (!alignedStart.EQ(start.toWord())) {
            // Make adjustments on size & physAddr
            final Word diff = start.sub(alignedStart).toWord();
            start = alignedStart.toAddress();
            size = size.add(diff);
        }
        size = pageAlign(region, size.toWord(), true).toExtent();
        final Extent pageSize = getPageSize(region);

        removeVirtualMMap(start.toWord(), start.add(size).toWord(), pageSize);
        return true;
    }

    /**
     * Map a page at the given virtual address.
     *
     * @param vmAddress
     */
    private final void mapPage(Address vmAddress, Address physAddr, Extent pageSize, boolean debug) {
        // Setup the pdir structures
        final Word pdirIdx = vmAddress.toWord().rshl(22);
        final Address pdirEntryPtr = UnsafeX86.getCR3().add(pdirIdx.lsh(2));
        Word entry = pdirEntryPtr.loadWord();
        if (entry.and(Word.fromIntZeroExtend(PF_PRESENT)).isZero()) {
            final Word pagePtr;
            if (physAddr.isMax()) {
                // Get a free page
                pagePtr = pageCursor;
                pageCursor = pageCursor.add(pageSize);
            } else {
                pagePtr = physAddr.toWord();
            }

            // There is currently no present page, so do the mapping
            entry = pagePtr.or(Word.fromIntZeroExtend(PF_DEFAULT));
            pdirEntryPtr.store(entry);

            if (debug) {
                Unsafe.debug("mapPage ");
                Unsafe.debug(entry);
                Unsafe.debug('\n');
            }
        } else {
            if (debug) {
                Unsafe.debug("mapPage: page present\n");
            }
        }

    }

    protected void boot(boolean emptyMMap) {
        Unsafe.debug("VmArchitecture32#boot\n");
        dumpMultibootMMap();
        pageCursor = getFirstAvailableHeapPage();

        if (emptyMMap) {
            // Remove all page mappings between AVAILABLE_START-END
            final Word start = Word.fromIntZeroExtend(AVAILABLE_START);
            final Word end = Word.fromIntZeroExtend(AVAILABLE_END);
            final Extent pageSize = Extent.fromIntZeroExtend(AVAILABLE_PAGE_SIZE);
            removeVirtualMMap(start, end, pageSize);
        }
    }

    /**
     * Remove all virtual memory mappings in a given address range.
     *
     * @param start
     * @param end
     */
    private final void removeVirtualMMap(Word start, Word end, Extent pageSize) {
        final Address pdir = UnsafeX86.getCR3();

        for (Word ptr = start; ptr.LT(end); ptr = ptr.add(pageSize)) {
            final Word pdirIdx = ptr.rshl(22);
            pdir.add(pdirIdx.lsh(2)).store(Word.zero());
        }
    }
}
TOP

Related Classes of org.jnode.vm.x86.VmX86Architecture32

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.