3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/kmap.c
6 * PURPOSE: Implements the kernel memory pool
7 * PROGRAMMER: David Welch (welch@cwcom.net)
10 /* INCLUDES ****************************************************************/
12 #include <ddk/ntddk.h>
13 #include <internal/mm.h>
14 #include <internal/ntoskrnl.h>
15 #include <internal/pool.h>
16 #include <ntos/minmax.h>
19 #include <internal/debug.h>
21 /* GLOBALS *****************************************************************/
23 #define ALLOC_MAP_SIZE (NONPAGED_POOL_SIZE / PAGE_SIZE)
26 * One bit for each page in the kmalloc region
27 * If set then the page is used by a kmalloc block
29 static UCHAR AllocMapBuffer[ROUND_UP(ALLOC_MAP_SIZE, 8) / 8];
30 static RTL_BITMAP AllocMap;
31 static KSPIN_LOCK AllocMapLock;
32 static ULONG AllocMapHint = 0;
34 static PVOID NonPagedPoolBase;
36 /* FUNCTIONS ***************************************************************/
39 ExUnmapPage(PVOID Addr)
42 ULONG Base = (Addr - NonPagedPoolBase) / PAGE_SIZE;
44 DPRINT("ExUnmapPage(Addr %x)\n",Addr);
46 MmDeleteVirtualMapping(NULL, (PVOID)Addr, FALSE, NULL, NULL);
47 KeAcquireSpinLock(&AllocMapLock, &oldIrql);
48 RtlClearBits(&AllocMap, Base, 1);
49 AllocMapHint = min(AllocMapHint, Base);
50 KeReleaseSpinLock(&AllocMapLock, oldIrql);
56 PHYSICAL_ADDRESS PhysPage;
59 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &PhysPage);
60 if (!NT_SUCCESS(Status))
65 return(ExAllocatePageWithPhysPage(PhysPage));
69 MiZeroPage(PHYSICAL_ADDRESS PhysPage)
73 TempAddress = ExAllocatePageWithPhysPage(PhysPage);
74 if (TempAddress == NULL)
76 return(STATUS_NO_MEMORY);
78 memset(TempAddress, 0, PAGE_SIZE);
79 ExUnmapPage(TempAddress);
80 return(STATUS_SUCCESS);
84 MiCopyFromUserPage(PHYSICAL_ADDRESS DestPhysPage, PVOID SourceAddress)
88 TempAddress = ExAllocatePageWithPhysPage(DestPhysPage);
89 if (TempAddress == NULL)
91 return(STATUS_NO_MEMORY);
93 memcpy(TempAddress, SourceAddress, PAGE_SIZE);
94 ExUnmapPage(TempAddress);
95 return(STATUS_SUCCESS);
99 ExAllocatePageWithPhysPage(PHYSICAL_ADDRESS PhysPage)
106 KeAcquireSpinLock(&AllocMapLock, &oldlvl);
107 Base = RtlFindClearBitsAndSet(&AllocMap, 1, AllocMapHint);
108 if (Base != 0xFFFFFFFF)
110 AllocMapHint = Base + 1;
111 KeReleaseSpinLock(&AllocMapLock, oldlvl);
112 Addr = NonPagedPoolBase + Base * PAGE_SIZE;
113 Status = MmCreateVirtualMapping(NULL,
115 PAGE_READWRITE | PAGE_SYSTEM,
118 if (!NT_SUCCESS(Status))
120 DbgPrint("Unable to create virtual mapping\n");
125 KeReleaseSpinLock(&AllocMapLock, oldlvl);
130 MmInitKernelMap(PVOID BaseAddress)
132 NonPagedPoolBase = BaseAddress;
133 KeInitializeSpinLock(&AllocMapLock);
134 RtlInitializeBitMap(&AllocMap, (PVOID)&AllocMapBuffer, ALLOC_MAP_SIZE);
135 RtlClearAllBits(&AllocMap);
139 MiFreeNonPagedPoolRegion(PVOID Addr, ULONG Count, BOOLEAN Free)
142 ULONG Base = (Addr - NonPagedPoolBase) / PAGE_SIZE;
145 for (i = 0; i < Count; i++)
147 MmDeleteVirtualMapping(NULL,
148 Addr + (i * PAGE_SIZE),
153 KeAcquireSpinLock(&AllocMapLock, &oldlvl);
154 RtlClearBits(&AllocMap, Base, Count);
155 AllocMapHint = min(AllocMapHint, Base);
156 KeReleaseSpinLock(&AllocMapLock, oldlvl);
160 MiAllocNonPagedPoolRegion(ULONG nr_pages)
162 * FUNCTION: Allocates a region of pages within the nonpaged pool area
168 KeAcquireSpinLock(&AllocMapLock, &oldlvl);
169 Base = RtlFindClearBitsAndSet(&AllocMap, nr_pages, AllocMapHint);
170 if (Base == 0xFFFFFFFF)
172 DbgPrint("CRITICAL: Out of non-paged pool space\n");
175 if (AllocMapHint == Base)
177 AllocMapHint += nr_pages;
179 KeReleaseSpinLock(&AllocMapLock, oldlvl);
180 DPRINT("returning %x\n",NonPagedPoolBase + Base * PAGE_SIZE);
181 return NonPagedPoolBase + Base * PAGE_SIZE;