* Patch by Thomas Frieden, 13 Nov 2002:
[oweals/u-boot.git] / board / MAI / bios_emulator / scitech / src / pm / ntdrv / mem.c
diff --git a/board/MAI/bios_emulator/scitech/src/pm/ntdrv/mem.c b/board/MAI/bios_emulator/scitech/src/pm/ntdrv/mem.c
new file mode 100644 (file)
index 0000000..b30d2be
--- /dev/null
@@ -0,0 +1,519 @@
+/****************************************************************************
+*
+*                   SciTech OS Portability Manager Library
+*                                                                                                                                                                                                                                                                                      
+*  ========================================================================
+*
+*    The contents of this file are subject to the SciTech MGL Public
+*    License Version 1.0 (the "License"); you may not use this file
+*    except in compliance with the License. You may obtain a copy of
+*    the License at http://www.scitechsoft.com/mgl-license.txt
+*
+*    Software distributed under the License is distributed on an
+*    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+*    implied. See the License for the specific language governing
+*    rights and limitations under the License.
+*
+*    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
+*
+*    The Initial Developer of the Original Code is SciTech Software, Inc.
+*    All Rights Reserved.
+*
+*  ========================================================================
+*
+* Language:     ANSI C
+* Environment:  32-bit Windows NT device drivers.
+*
+* Description:  Implementation for the NT driver memory management functions
+*               for the PM library.
+*
+****************************************************************************/
+
+#include "pmapi.h"
+#include "drvlib/os/os.h"
+#include "sdd/sddhelp.h"
+#include "mtrr.h"
+#include "oshdr.h"
+
+/*--------------------------- Global variables ----------------------------*/
+
+#define MAX_MEMORY_SHARED           100
+#define MAX_MEMORY_MAPPINGS         100
+#define MAX_MEMORY_LOCKED           100
+
+typedef struct {
+    void    *linear;
+    ulong   length;
+    PMDL    pMdl;
+    } memshared;
+
+typedef struct {
+    void    *linear;
+    void    *mmIoMapped;
+    ulong   length;
+    PMDL    pMdl;
+    } memlocked;
+
+typedef struct {
+    ulong   physical;
+    ulong   linear;
+    ulong   length;
+    ibool   isCached;
+    } mmapping;
+
+static int          numMappings = 0;
+static memshared    shared[MAX_MEMORY_MAPPINGS] = {0};
+static mmapping     maps[MAX_MEMORY_MAPPINGS];
+static memlocked    locked[MAX_MEMORY_LOCKED];
+
+/*----------------------------- Implementation ----------------------------*/
+
+ulong   PMAPI _PM_getPDB(void);
+
+// Page table entry flags
+
+#define PAGE_FLAGS_PRESENT                     0x00000001
+#define PAGE_FLAGS_WRITEABLE           0x00000002
+#define PAGE_FLAGS_USER                                0x00000004
+#define PAGE_FLAGS_WRITE_THROUGH       0x00000008
+#define PAGE_FLAGS_CACHE_DISABLE       0x00000010
+#define PAGE_FLAGS_ACCESSED                    0x00000020
+#define PAGE_FLAGS_DIRTY                       0x00000040
+#define PAGE_FLAGS_4MB             0x00000080
+
+/****************************************************************************
+PARAMETERS:
+base        - Physical base address of the memory to maps in
+limit       - Limit of physical memory to region to maps in
+
+RETURNS:
+Linear address of the newly mapped memory.
+
+REMARKS:
+Maps a physical memory range to a linear memory range.
+****************************************************************************/
+static ulong _PM_mapPhysicalToLinear(
+    ulong base,
+    ulong limit,
+    ibool isCached)
+{
+    ulong               length = limit+1;
+    PHYSICAL_ADDRESS    paIoBase = {0};
+
+    // NT loves large Ints
+    paIoBase = RtlConvertUlongToLargeInteger( base );
+
+    // Map IO space into Kernel
+    if (isCached)
+        return (ULONG)MmMapIoSpace(paIoBase, length, MmCached );
+    else
+        return (ULONG)MmMapIoSpace(paIoBase, length, MmNonCached );
+}
+
+/****************************************************************************
+REMARKS:
+Adjust the page table caching bits directly. Requires ring 0 access and
+only works with DOS4GW and compatible extenders (CauseWay also works since
+it has direct support for the ring 0 instructions we need from ring 3). Will
+not work in a DOS box, but we call into the ring 0 helper VxD so we should
+never get here in a DOS box anyway (assuming the VxD is present). If we
+do get here and we are in windows, this code will be skipped.
+****************************************************************************/
+static void _PM_adjustPageTables(
+    ulong linear,
+    ulong limit,
+       ibool isGlobal,
+    ibool isCached)
+{
+    int     startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;
+    ulong   pageTable,*pPDB,*pPageTable;
+       ulong   mask = 0xFFFFFFFF;
+       ulong   bits = 0x00000000;
+
+       /* Enable user level access for page table entry */
+       if (isGlobal) {
+               mask &= ~PAGE_FLAGS_USER;
+               bits |= PAGE_FLAGS_USER;
+               }
+               
+       /* Disable PCD bit if page table entry should be uncached */
+       if (!isCached) {
+               mask &= ~(PAGE_FLAGS_CACHE_DISABLE | PAGE_FLAGS_WRITE_THROUGH);
+               bits |= (PAGE_FLAGS_CACHE_DISABLE | PAGE_FLAGS_WRITE_THROUGH);
+               }
+
+    pPDB = (ulong*)_PM_mapPhysicalToLinear(_PM_getPDB(),0xFFF,true);
+    if (pPDB) {
+        startPDB = (linear >> 22) & 0x3FF;
+        startPage = (linear >> 12) & 0x3FF;
+        endPDB = ((linear+limit) >> 22) & 0x3FF;
+        endPage = ((linear+limit) >> 12) & 0x3FF;
+        for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {
+            // Set the bits in the page directory entry - required as per
+            // Pentium 4 manual. This also takes care of the 4MB page entries
+            pPDB[iPDB] = (pPDB[iPDB] & mask) | bits;
+            if (!(pPDB[iPDB] & PAGE_FLAGS_4MB)) {
+                // If we are dealing with 4KB pages then we need to iterate
+                // through each of the page table entries
+                pageTable = pPDB[iPDB] & ~0xFFF;
+                pPageTable = (ulong*)_PM_mapPhysicalToLinear(pageTable,0xFFF,true);
+                start = (iPDB == startPDB) ? startPage : 0;
+                end = (iPDB == endPDB) ? endPage : 0x3FF;
+                for (iPage = start; iPage <= end; iPage++) {
+                    pPageTable[iPage] = (pPageTable[iPage] & mask) | bits;
+                    }
+                MmUnmapIoSpace(pPageTable,0xFFF);
+                }
+            }
+        MmUnmapIoSpace(pPDB,0xFFF);
+        PM_flushTLB();
+        }
+}
+
+/****************************************************************************
+REMARKS:
+Allocate a block of shared memory. For NT we allocate shared memory
+as locked, global memory that is accessible from any memory context
+(including interrupt time context), which allows us to load our important
+data structure and code such that we can access it directly from a ring
+0 interrupt context.
+****************************************************************************/
+void * PMAPI PM_mallocShared(
+    long size)
+{
+    int         i;
+
+    // First find a free slot in our shared memory table
+    for (i = 0; i < MAX_MEMORY_SHARED; i++) {
+        if (shared[i].linear == 0)
+            break;
+        }
+    if (i == MAX_MEMORY_SHARED)
+        return NULL;
+
+    // Allocate the paged pool
+    shared[i].linear = ExAllocatePool(PagedPool, size);
+
+    // Create a list to manage this allocation
+    shared[i].pMdl = IoAllocateMdl(shared[i].linear,size,FALSE,FALSE,(PIRP) NULL);
+
+    // Lock this allocation in memory
+    MmProbeAndLockPages(shared[i].pMdl,KernelMode,IoModifyAccess);
+
+    // Modify bits to grant user access
+    _PM_adjustPageTables((ulong)shared[i].linear, size, true, true);
+    return (void*)shared[i].linear;
+}
+
+/****************************************************************************
+REMARKS:
+Free a block of shared memory
+****************************************************************************/
+void PMAPI PM_freeShared(
+    void *p)
+{
+    int i;
+
+    // Find a shared memory block in our table and free it
+    for (i = 0; i < MAX_MEMORY_SHARED; i++) {
+        if (shared[i].linear == p) {
+            // Unlock what we locked
+            MmUnlockPages(shared[i].pMdl);
+
+            // Free our MDL
+            IoFreeMdl(shared[i].pMdl);
+
+            // Free our mem
+            ExFreePool(shared[i].linear);
+
+            // Flag that is entry is available
+            shared[i].linear = 0;
+            break;
+            }
+        }
+}
+
+/****************************************************************************
+REMARKS:
+Map a physical address to a linear address in the callers process.
+****************************************************************************/
+void * PMAPI PM_mapPhysicalAddr(
+    ulong base,
+    ulong limit,
+    ibool isCached)
+{
+    ulong   linear,length = limit+1;
+    int     i;
+
+    // Search table of existing mappings to see if we have already mapped
+    // a region of memory that will serve this purpose.
+    for (i = 0; i < numMappings; i++) {
+        if (maps[i].physical == base && maps[i].length == length && maps[i].isCached == isCached) {
+            _PM_adjustPageTables((ulong)maps[i].linear, maps[i].length, true, isCached);
+            return (void*)maps[i].linear;
+            }
+        }
+    if (numMappings == MAX_MEMORY_MAPPINGS)
+        return NULL;
+
+    // We did not find any previously mapped memory region, so maps it in.
+    if ((linear = _PM_mapPhysicalToLinear(base,limit,isCached)) == 0xFFFFFFFF)
+        return NULL;
+    maps[numMappings].physical = base;
+    maps[numMappings].length = length;
+    maps[numMappings].linear = linear;
+    maps[numMappings].isCached = isCached;
+    numMappings++;
+
+    // Grant user access to this I/O space
+    _PM_adjustPageTables((ulong)linear, length, true, isCached);
+    return (void*)linear;
+}
+
+/****************************************************************************
+REMARKS:
+Free a physical address mapping allocated by PM_mapPhysicalAddr.
+****************************************************************************/
+void PMAPI PM_freePhysicalAddr(
+    void *ptr,
+    ulong limit)
+{
+    // We don't free the memory mappings in here because we cache all
+    // the memory mappings we create in the system for later use.
+}
+
+/****************************************************************************
+REMARKS:
+Called when the device driver unloads to free all the page table mappings!
+****************************************************************************/
+void PMAPI _PM_freeMemoryMappings(void)
+{
+    int i;
+
+    for (i = 0; i < numMappings; i++)
+        MmUnmapIoSpace((void *)maps[i].linear,maps[i].length);
+}
+
+/****************************************************************************
+REMARKS:
+Find the physical address of a linear memory address in current process.
+****************************************************************************/
+ulong PMAPI PM_getPhysicalAddr(
+    void *p)
+{
+    PHYSICAL_ADDRESS    paOurAddress;
+
+    paOurAddress = MmGetPhysicalAddress(p);
+    return paOurAddress.LowPart;
+}
+
+/****************************************************************************
+REMARKS:
+Find the physical address of a linear memory address in current process.
+****************************************************************************/
+ibool PMAPI PM_getPhysicalAddrRange(
+    void *p,
+    ulong length,
+    ulong *physAddress)
+{
+    int     i;
+    ulong   linear = (ulong)p & ~0xFFF;
+
+    for (i = (length + 0xFFF) >> 12; i > 0; i--) {
+        if ((*physAddress++ = PM_getPhysicalAddr((void*)linear)) == 0xFFFFFFFF)
+            return false;
+        linear += 4096;
+        }
+    return true;
+}
+
+/****************************************************************************
+REMARKS:
+Allocates a block of locked physical memory.
+****************************************************************************/
+void * PMAPI PM_allocLockedMem(
+    uint size,
+    ulong *physAddr,
+    ibool contiguous,
+    ibool below16M)
+{
+    int                 i;
+    PHYSICAL_ADDRESS    paOurAddress;
+
+    // First find a free slot in our shared memory table
+    for (i = 0; i < MAX_MEMORY_LOCKED; i++) {
+        if (locked[i].linear == 0)
+            break;
+        }
+    if (i == MAX_MEMORY_LOCKED)
+        return NULL;
+
+    // HighestAcceptableAddress - Specifies the highest valid physical address
+    // the driver can use. For example, if a device can only reference physical
+    // memory in the lower 16MB, this value would be set to 0x00000000FFFFFF.
+    paOurAddress.HighPart = 0;
+    if (below16M)
+        paOurAddress.LowPart = 0x00FFFFFF;
+    else
+        paOurAddress.LowPart = 0xFFFFFFFF;
+
+    if (contiguous) {
+        // Allocate from the non-paged pool (unfortunately 4MB pages)
+        locked[i].linear = MmAllocateContiguousMemory(size, paOurAddress);
+        if (!locked[i].linear)
+            return NULL;
+
+        // Flag no MDL
+        locked[i].pMdl = NULL;
+
+        // Map the physical address for the memory so we can manage
+        // the page tables in 4KB chunks mapped into user space.
+
+        // TODO: Map this with the physical address to the linear addresss
+        locked[i].mmIoMapped = locked[i].linear;
+
+        // Modify bits to grant user access, flag not cached
+        _PM_adjustPageTables((ulong)locked[i].mmIoMapped, size, true, false);
+        return (void*)locked[i].mmIoMapped;
+        }
+    else {
+        // Allocate from the paged pool
+        locked[i].linear = ExAllocatePool(PagedPool, size);
+        if (!locked[i].linear)
+            return NULL;
+
+        // Create a list to manage this allocation
+        locked[i].pMdl = IoAllocateMdl(locked[i].linear,size,FALSE,FALSE,(PIRP) NULL);
+
+        // Lock this allocation in memory
+        MmProbeAndLockPages(locked[i].pMdl,KernelMode,IoModifyAccess);
+
+        // Modify bits to grant user access, flag not cached
+        _PM_adjustPageTables((ulong)locked[i].linear, size, true, false);
+        return (void*)locked[i].linear;
+        }
+}
+
+/****************************************************************************
+REMARKS:
+Frees a block of locked physical memory.
+****************************************************************************/
+void PMAPI PM_freeLockedMem(
+    void *p,
+    uint size,
+    ibool contiguous)
+{
+    int i;
+
+    /* Find a locked memory block in our table and free it */
+    for (i = 0; i < MAX_MEMORY_LOCKED; i++) {
+        if (locked[i].linear == p) {
+            // An Mdl indicates that we used the paged pool, and locked it,
+            // so now we have to unlock, free the MDL, and free paged
+            if (locked[i].pMdl) {
+                // Unlock what we locked and free the Mdl
+                MmUnlockPages(locked[i].pMdl);
+                IoFreeMdl(locked[i].pMdl);
+                ExFreePool(locked[i].linear);
+                }
+            else {
+                // TODO: Free the mmIoMap mapping for the memory!
+
+                // Free non-paged pool
+                MmFreeContiguousMemory(locked[i].linear);
+                }
+
+            // Flag that is entry is available
+            locked[i].linear = 0;
+            break;
+            }
+        }
+}
+
+/****************************************************************************
+REMARKS:
+Allocates a page aligned and page sized block of memory
+****************************************************************************/
+void * PMAPI PM_allocPage(
+    ibool locked)
+{
+    // Allocate the memory from the non-paged pool if we want the memory
+    // to be locked.
+    return ExAllocatePool(
+        locked ? NonPagedPoolCacheAligned : PagedPoolCacheAligned,
+        PAGE_SIZE);
+}
+
+/****************************************************************************
+REMARKS:
+Free a page aligned and page sized block of memory
+****************************************************************************/
+void PMAPI PM_freePage(
+    void *p)
+{
+    if (p) ExFreePool(p);
+}
+
+/****************************************************************************
+REMARKS:
+Lock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_lockDataPages(
+    void *p,
+    uint len,
+    PM_lockHandle *lh)
+{
+    MDL *pMdl;
+
+    // Create a list to manage this allocation
+    if ((pMdl = IoAllocateMdl(p,len,FALSE,FALSE,(PIRP)NULL)) == NULL)
+        return false;
+
+    // Lock this allocation in memory
+    MmProbeAndLockPages(pMdl,KernelMode,IoModifyAccess);
+    *((PMDL*)(&lh->h)) = pMdl;
+    return true;
+}
+
+/****************************************************************************
+REMARKS:
+Unlock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_unlockDataPages(
+    void *p,
+    uint len,
+    PM_lockHandle *lh)
+{
+    if (p && lh) {
+        // Unlock what we locked
+        MDL *pMdl = *((PMDL*)(&lh->h));
+        MmUnlockPages(pMdl);
+        IoFreeMdl(pMdl);
+        }
+    return true;
+}
+
+/****************************************************************************
+REMARKS:
+Lock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_lockCodePages(
+    void (*p)(),
+    uint len,
+    PM_lockHandle *lh)
+{
+    return PM_lockDataPages((void*)p,len,lh);
+}
+
+/****************************************************************************
+REMARKS:
+Unlock linear memory so it won't be paged.
+****************************************************************************/
+int PMAPI PM_unlockCodePages(
+    void (*p)(),
+    uint len,
+    PM_lockHandle *lh)
+{
+    return PM_unlockDataPages((void*)p,len,lh);
+}
+