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 (MM_KERNEL_MAP_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, 32) / 8];
30 static RTL_BITMAP AllocMap;
31 static KSPIN_LOCK AllocMapLock;
32 static ULONG AllocMapHint = 0;
34 extern PVOID MiKernelMapStart;
35 extern ULONG MiKernelMapLength;
37 /* FUNCTIONS ***************************************************************/
40 ExUnmapPage(PVOID Addr)
43 ULONG Base = (Addr - MiKernelMapStart) / PAGE_SIZE;
45 DPRINT("ExUnmapPage(Addr %x)\n",Addr);
47 MmDeleteVirtualMapping(NULL, (PVOID)Addr, FALSE, NULL, NULL);
48 KeAcquireSpinLock(&AllocMapLock, &oldIrql);
49 RtlClearBits(&AllocMap, Base, 1);
50 AllocMapHint = min(AllocMapHint, Base);
51 KeReleaseSpinLock(&AllocMapLock, oldIrql);
57 PHYSICAL_ADDRESS PhysPage;
60 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &PhysPage);
61 if (!NT_SUCCESS(Status))
66 return(ExAllocatePageWithPhysPage(PhysPage));
70 MiZeroPage(PHYSICAL_ADDRESS PhysPage)
74 TempAddress = ExAllocatePageWithPhysPage(PhysPage);
75 if (TempAddress == NULL)
77 return(STATUS_NO_MEMORY);
79 memset(TempAddress, 0, PAGE_SIZE);
80 ExUnmapPage(TempAddress);
81 return(STATUS_SUCCESS);
85 MiCopyFromUserPage(PHYSICAL_ADDRESS DestPhysPage, PVOID SourceAddress)
89 TempAddress = ExAllocatePageWithPhysPage(DestPhysPage);
90 if (TempAddress == NULL)
92 return(STATUS_NO_MEMORY);
94 memcpy(TempAddress, SourceAddress, PAGE_SIZE);
95 ExUnmapPage(TempAddress);
96 return(STATUS_SUCCESS);
100 ExAllocatePageWithPhysPage(PHYSICAL_ADDRESS PhysPage)
107 KeAcquireSpinLock(&AllocMapLock, &oldlvl);
108 Base = RtlFindClearBitsAndSet(&AllocMap, 1, AllocMapHint);
109 if (Base != 0xFFFFFFFF)
111 AllocMapHint = Base + 1;
112 KeReleaseSpinLock(&AllocMapLock, oldlvl);
113 Addr = MiKernelMapStart + Base * PAGE_SIZE;
114 Status = MmCreateVirtualMapping(NULL,
116 PAGE_READWRITE | PAGE_SYSTEM,
119 if (!NT_SUCCESS(Status))
121 DbgPrint("Unable to create virtual mapping\n");
126 KeReleaseSpinLock(&AllocMapLock, oldlvl);
131 MiInitKernelMap(VOID)
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 - MiKernelMapStart) / 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 MiKernelMapStart + Base * PAGE_SIZE;