1 /****************************************************************************
3 * SciTech OS Portability Manager Library
5 * ========================================================================
7 * The contents of this file are subject to the SciTech MGL Public
8 * License Version 1.0 (the "License"); you may not use this file
9 * except in compliance with the License. You may obtain a copy of
10 * the License at http://www.scitechsoft.com/mgl-license.txt
12 * Software distributed under the License is distributed on an
13 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * rights and limitations under the License.
17 * The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
19 * The Initial Developer of the Original Code is SciTech Software, Inc.
20 * All Rights Reserved.
22 * ========================================================================
25 * Environment: 32-bit Windows NT device drivers.
27 * Description: Implementation for the NT driver memory management functions
30 ****************************************************************************/
33 #include "drvlib/os/os.h"
34 #include "sdd/sddhelp.h"
38 /*--------------------------- Global variables ----------------------------*/
40 #define MAX_MEMORY_SHARED 100
41 #define MAX_MEMORY_MAPPINGS 100
42 #define MAX_MEMORY_LOCKED 100
64 static int numMappings = 0;
65 static memshared shared[MAX_MEMORY_MAPPINGS] = {0};
66 static mmapping maps[MAX_MEMORY_MAPPINGS];
67 static memlocked locked[MAX_MEMORY_LOCKED];
69 /*----------------------------- Implementation ----------------------------*/
71 ulong PMAPI _PM_getPDB(void);
73 /* Page table entry flags */
75 #define PAGE_FLAGS_PRESENT 0x00000001
76 #define PAGE_FLAGS_WRITEABLE 0x00000002
77 #define PAGE_FLAGS_USER 0x00000004
78 #define PAGE_FLAGS_WRITE_THROUGH 0x00000008
79 #define PAGE_FLAGS_CACHE_DISABLE 0x00000010
80 #define PAGE_FLAGS_ACCESSED 0x00000020
81 #define PAGE_FLAGS_DIRTY 0x00000040
82 #define PAGE_FLAGS_4MB 0x00000080
84 /****************************************************************************
86 base - Physical base address of the memory to maps in
87 limit - Limit of physical memory to region to maps in
90 Linear address of the newly mapped memory.
93 Maps a physical memory range to a linear memory range.
94 ****************************************************************************/
95 static ulong _PM_mapPhysicalToLinear(
100 ulong length = limit+1;
101 PHYSICAL_ADDRESS paIoBase = {0};
103 /* NT loves large Ints */
104 paIoBase = RtlConvertUlongToLargeInteger( base );
106 /* Map IO space into Kernel */
108 return (ULONG)MmMapIoSpace(paIoBase, length, MmCached );
110 return (ULONG)MmMapIoSpace(paIoBase, length, MmNonCached );
113 /****************************************************************************
115 Adjust the page table caching bits directly. Requires ring 0 access and
116 only works with DOS4GW and compatible extenders (CauseWay also works since
117 it has direct support for the ring 0 instructions we need from ring 3). Will
118 not work in a DOS box, but we call into the ring 0 helper VxD so we should
119 never get here in a DOS box anyway (assuming the VxD is present). If we
120 do get here and we are in windows, this code will be skipped.
121 ****************************************************************************/
122 static void _PM_adjustPageTables(
128 int startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;
129 ulong pageTable,*pPDB,*pPageTable;
130 ulong mask = 0xFFFFFFFF;
131 ulong bits = 0x00000000;
133 /* Enable user level access for page table entry */
135 mask &= ~PAGE_FLAGS_USER;
136 bits |= PAGE_FLAGS_USER;
139 /* Disable PCD bit if page table entry should be uncached */
141 mask &= ~(PAGE_FLAGS_CACHE_DISABLE | PAGE_FLAGS_WRITE_THROUGH);
142 bits |= (PAGE_FLAGS_CACHE_DISABLE | PAGE_FLAGS_WRITE_THROUGH);
145 pPDB = (ulong*)_PM_mapPhysicalToLinear(_PM_getPDB(),0xFFF,true);
147 startPDB = (linear >> 22) & 0x3FF;
148 startPage = (linear >> 12) & 0x3FF;
149 endPDB = ((linear+limit) >> 22) & 0x3FF;
150 endPage = ((linear+limit) >> 12) & 0x3FF;
151 for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {
152 /* Set the bits in the page directory entry - required as per */
153 /* Pentium 4 manual. This also takes care of the 4MB page entries */
154 pPDB[iPDB] = (pPDB[iPDB] & mask) | bits;
155 if (!(pPDB[iPDB] & PAGE_FLAGS_4MB)) {
156 /* If we are dealing with 4KB pages then we need to iterate */
157 /* through each of the page table entries */
158 pageTable = pPDB[iPDB] & ~0xFFF;
159 pPageTable = (ulong*)_PM_mapPhysicalToLinear(pageTable,0xFFF,true);
160 start = (iPDB == startPDB) ? startPage : 0;
161 end = (iPDB == endPDB) ? endPage : 0x3FF;
162 for (iPage = start; iPage <= end; iPage++) {
163 pPageTable[iPage] = (pPageTable[iPage] & mask) | bits;
165 MmUnmapIoSpace(pPageTable,0xFFF);
168 MmUnmapIoSpace(pPDB,0xFFF);
173 /****************************************************************************
175 Allocate a block of shared memory. For NT we allocate shared memory
176 as locked, global memory that is accessible from any memory context
177 (including interrupt time context), which allows us to load our important
178 data structure and code such that we can access it directly from a ring
180 ****************************************************************************/
181 void * PMAPI PM_mallocShared(
186 /* First find a free slot in our shared memory table */
187 for (i = 0; i < MAX_MEMORY_SHARED; i++) {
188 if (shared[i].linear == 0)
191 if (i == MAX_MEMORY_SHARED)
194 /* Allocate the paged pool */
195 shared[i].linear = ExAllocatePool(PagedPool, size);
197 /* Create a list to manage this allocation */
198 shared[i].pMdl = IoAllocateMdl(shared[i].linear,size,FALSE,FALSE,(PIRP) NULL);
200 /* Lock this allocation in memory */
201 MmProbeAndLockPages(shared[i].pMdl,KernelMode,IoModifyAccess);
203 /* Modify bits to grant user access */
204 _PM_adjustPageTables((ulong)shared[i].linear, size, true, true);
205 return (void*)shared[i].linear;
208 /****************************************************************************
210 Free a block of shared memory
211 ****************************************************************************/
212 void PMAPI PM_freeShared(
217 /* Find a shared memory block in our table and free it */
218 for (i = 0; i < MAX_MEMORY_SHARED; i++) {
219 if (shared[i].linear == p) {
220 /* Unlock what we locked */
221 MmUnlockPages(shared[i].pMdl);
224 IoFreeMdl(shared[i].pMdl);
227 ExFreePool(shared[i].linear);
229 /* Flag that is entry is available */
230 shared[i].linear = 0;
236 /****************************************************************************
238 Map a physical address to a linear address in the callers process.
239 ****************************************************************************/
240 void * PMAPI PM_mapPhysicalAddr(
245 ulong linear,length = limit+1;
248 /* Search table of existing mappings to see if we have already mapped */
249 /* a region of memory that will serve this purpose. */
250 for (i = 0; i < numMappings; i++) {
251 if (maps[i].physical == base && maps[i].length == length && maps[i].isCached == isCached) {
252 _PM_adjustPageTables((ulong)maps[i].linear, maps[i].length, true, isCached);
253 return (void*)maps[i].linear;
256 if (numMappings == MAX_MEMORY_MAPPINGS)
259 /* We did not find any previously mapped memory region, so maps it in. */
260 if ((linear = _PM_mapPhysicalToLinear(base,limit,isCached)) == 0xFFFFFFFF)
262 maps[numMappings].physical = base;
263 maps[numMappings].length = length;
264 maps[numMappings].linear = linear;
265 maps[numMappings].isCached = isCached;
268 /* Grant user access to this I/O space */
269 _PM_adjustPageTables((ulong)linear, length, true, isCached);
270 return (void*)linear;
273 /****************************************************************************
275 Free a physical address mapping allocated by PM_mapPhysicalAddr.
276 ****************************************************************************/
277 void PMAPI PM_freePhysicalAddr(
281 /* We don't free the memory mappings in here because we cache all */
282 /* the memory mappings we create in the system for later use. */
285 /****************************************************************************
287 Called when the device driver unloads to free all the page table mappings!
288 ****************************************************************************/
289 void PMAPI _PM_freeMemoryMappings(void)
293 for (i = 0; i < numMappings; i++)
294 MmUnmapIoSpace((void *)maps[i].linear,maps[i].length);
297 /****************************************************************************
299 Find the physical address of a linear memory address in current process.
300 ****************************************************************************/
301 ulong PMAPI PM_getPhysicalAddr(
304 PHYSICAL_ADDRESS paOurAddress;
306 paOurAddress = MmGetPhysicalAddress(p);
307 return paOurAddress.LowPart;
310 /****************************************************************************
312 Find the physical address of a linear memory address in current process.
313 ****************************************************************************/
314 ibool PMAPI PM_getPhysicalAddrRange(
320 ulong linear = (ulong)p & ~0xFFF;
322 for (i = (length + 0xFFF) >> 12; i > 0; i--) {
323 if ((*physAddress++ = PM_getPhysicalAddr((void*)linear)) == 0xFFFFFFFF)
330 /****************************************************************************
332 Allocates a block of locked physical memory.
333 ****************************************************************************/
334 void * PMAPI PM_allocLockedMem(
341 PHYSICAL_ADDRESS paOurAddress;
343 /* First find a free slot in our shared memory table */
344 for (i = 0; i < MAX_MEMORY_LOCKED; i++) {
345 if (locked[i].linear == 0)
348 if (i == MAX_MEMORY_LOCKED)
351 /* HighestAcceptableAddress - Specifies the highest valid physical address */
352 /* the driver can use. For example, if a device can only reference physical */
353 /* memory in the lower 16MB, this value would be set to 0x00000000FFFFFF. */
354 paOurAddress.HighPart = 0;
356 paOurAddress.LowPart = 0x00FFFFFF;
358 paOurAddress.LowPart = 0xFFFFFFFF;
361 /* Allocate from the non-paged pool (unfortunately 4MB pages) */
362 locked[i].linear = MmAllocateContiguousMemory(size, paOurAddress);
363 if (!locked[i].linear)
367 locked[i].pMdl = NULL;
369 /* Map the physical address for the memory so we can manage */
370 /* the page tables in 4KB chunks mapped into user space. */
372 /* TODO: Map this with the physical address to the linear addresss */
373 locked[i].mmIoMapped = locked[i].linear;
375 /* Modify bits to grant user access, flag not cached */
376 _PM_adjustPageTables((ulong)locked[i].mmIoMapped, size, true, false);
377 return (void*)locked[i].mmIoMapped;
380 /* Allocate from the paged pool */
381 locked[i].linear = ExAllocatePool(PagedPool, size);
382 if (!locked[i].linear)
385 /* Create a list to manage this allocation */
386 locked[i].pMdl = IoAllocateMdl(locked[i].linear,size,FALSE,FALSE,(PIRP) NULL);
388 /* Lock this allocation in memory */
389 MmProbeAndLockPages(locked[i].pMdl,KernelMode,IoModifyAccess);
391 /* Modify bits to grant user access, flag not cached */
392 _PM_adjustPageTables((ulong)locked[i].linear, size, true, false);
393 return (void*)locked[i].linear;
397 /****************************************************************************
399 Frees a block of locked physical memory.
400 ****************************************************************************/
401 void PMAPI PM_freeLockedMem(
408 /* Find a locked memory block in our table and free it */
409 for (i = 0; i < MAX_MEMORY_LOCKED; i++) {
410 if (locked[i].linear == p) {
411 /* An Mdl indicates that we used the paged pool, and locked it, */
412 /* so now we have to unlock, free the MDL, and free paged */
413 if (locked[i].pMdl) {
414 /* Unlock what we locked and free the Mdl */
415 MmUnlockPages(locked[i].pMdl);
416 IoFreeMdl(locked[i].pMdl);
417 ExFreePool(locked[i].linear);
420 /* TODO: Free the mmIoMap mapping for the memory! */
422 /* Free non-paged pool */
423 MmFreeContiguousMemory(locked[i].linear);
426 /* Flag that is entry is available */
427 locked[i].linear = 0;
433 /****************************************************************************
435 Allocates a page aligned and page sized block of memory
436 ****************************************************************************/
437 void * PMAPI PM_allocPage(
440 /* Allocate the memory from the non-paged pool if we want the memory */
442 return ExAllocatePool(
443 locked ? NonPagedPoolCacheAligned : PagedPoolCacheAligned,
447 /****************************************************************************
449 Free a page aligned and page sized block of memory
450 ****************************************************************************/
451 void PMAPI PM_freePage(
454 if (p) ExFreePool(p);
457 /****************************************************************************
459 Lock linear memory so it won't be paged.
460 ****************************************************************************/
461 int PMAPI PM_lockDataPages(
468 /* Create a list to manage this allocation */
469 if ((pMdl = IoAllocateMdl(p,len,FALSE,FALSE,(PIRP)NULL)) == NULL)
472 /* Lock this allocation in memory */
473 MmProbeAndLockPages(pMdl,KernelMode,IoModifyAccess);
474 *((PMDL*)(&lh->h)) = pMdl;
478 /****************************************************************************
480 Unlock linear memory so it won't be paged.
481 ****************************************************************************/
482 int PMAPI PM_unlockDataPages(
488 /* Unlock what we locked */
489 MDL *pMdl = *((PMDL*)(&lh->h));
496 /****************************************************************************
498 Lock linear memory so it won't be paged.
499 ****************************************************************************/
500 int PMAPI PM_lockCodePages(
505 return PM_lockDataPages((void*)p,len,lh);
508 /****************************************************************************
510 Unlock linear memory so it won't be paged.
511 ****************************************************************************/
512 int PMAPI PM_unlockCodePages(
517 return PM_unlockDataPages((void*)p,len,lh);