update for HEAD-2003091401
[reactos.git] / ntoskrnl / mm / kmap.c
1 /* $Id$
2  *
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)
8  */
9
10 /* INCLUDES ****************************************************************/
11
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>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 /* GLOBALS *****************************************************************/
22
23 #define ALLOC_MAP_SIZE (MM_KERNEL_MAP_SIZE / PAGE_SIZE)
24
25 /*
26  * One bit for each page in the kmalloc region
27  *      If set then the page is used by a kmalloc block
28  */
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;
33
34 extern PVOID MiKernelMapStart;
35 extern ULONG MiKernelMapLength;
36
37 /* FUNCTIONS ***************************************************************/
38
39 VOID 
40 ExUnmapPage(PVOID Addr)
41 {
42    KIRQL oldIrql;
43    ULONG Base = (Addr - MiKernelMapStart) / PAGE_SIZE;
44    
45    DPRINT("ExUnmapPage(Addr %x)\n",Addr);
46    
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);
52 }
53
54 PVOID 
55 ExAllocatePage(VOID)
56 {
57   PHYSICAL_ADDRESS PhysPage;
58   NTSTATUS Status;
59
60   Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &PhysPage);
61   if (!NT_SUCCESS(Status))
62     {
63       return(NULL);
64     }
65
66   return(ExAllocatePageWithPhysPage(PhysPage));
67 }
68
69 NTSTATUS
70 MiZeroPage(PHYSICAL_ADDRESS PhysPage)
71 {
72   PVOID TempAddress;
73
74   TempAddress = ExAllocatePageWithPhysPage(PhysPage);
75   if (TempAddress == NULL)
76     {
77       return(STATUS_NO_MEMORY);
78     }
79   memset(TempAddress, 0, PAGE_SIZE);
80   ExUnmapPage(TempAddress);
81   return(STATUS_SUCCESS);
82 }
83
84 NTSTATUS
85 MiCopyFromUserPage(PHYSICAL_ADDRESS DestPhysPage, PVOID SourceAddress)
86 {
87   PVOID TempAddress;
88
89   TempAddress = ExAllocatePageWithPhysPage(DestPhysPage);
90   if (TempAddress == NULL)
91     {
92       return(STATUS_NO_MEMORY);
93     }
94   memcpy(TempAddress, SourceAddress, PAGE_SIZE);
95   ExUnmapPage(TempAddress);
96   return(STATUS_SUCCESS);
97 }
98
99 PVOID
100 ExAllocatePageWithPhysPage(PHYSICAL_ADDRESS PhysPage)
101 {
102    KIRQL oldlvl;
103    PVOID Addr;
104    ULONG Base;
105    NTSTATUS Status;
106
107    KeAcquireSpinLock(&AllocMapLock, &oldlvl);
108    Base = RtlFindClearBitsAndSet(&AllocMap, 1, AllocMapHint);
109    if (Base != 0xFFFFFFFF)
110    {
111       AllocMapHint = Base + 1;
112       KeReleaseSpinLock(&AllocMapLock, oldlvl);
113       Addr = MiKernelMapStart + Base * PAGE_SIZE;
114       Status = MmCreateVirtualMapping(NULL, 
115                                       Addr, 
116                                       PAGE_READWRITE | PAGE_SYSTEM, 
117                                       PhysPage,
118                                       TRUE);
119       if (!NT_SUCCESS(Status))
120       {
121           DbgPrint("Unable to create virtual mapping\n");
122           KEBUGCHECK(0);
123       }
124       return Addr;
125    }
126    KeReleaseSpinLock(&AllocMapLock, oldlvl);
127    return NULL;
128 }
129
130 VOID 
131 MiInitKernelMap(VOID)
132 {
133    KeInitializeSpinLock(&AllocMapLock);
134    RtlInitializeBitMap(&AllocMap, (PVOID)&AllocMapBuffer, ALLOC_MAP_SIZE);
135    RtlClearAllBits(&AllocMap);
136 }
137
138 VOID
139 MiFreeNonPagedPoolRegion(PVOID Addr, ULONG Count, BOOLEAN Free)
140 {
141   ULONG i;
142   ULONG Base = (Addr - MiKernelMapStart) / PAGE_SIZE;
143   KIRQL oldlvl;
144   
145   for (i = 0; i < Count; i++)
146   {
147       MmDeleteVirtualMapping(NULL, 
148                              Addr + (i * PAGE_SIZE), 
149                              Free, 
150                              NULL, 
151                              NULL);
152   }
153   KeAcquireSpinLock(&AllocMapLock, &oldlvl);
154   RtlClearBits(&AllocMap, Base, Count);
155   AllocMapHint = min(AllocMapHint, Base);
156   KeReleaseSpinLock(&AllocMapLock, oldlvl);
157 }
158
159 PVOID
160 MiAllocNonPagedPoolRegion(ULONG nr_pages)
161 /*
162  * FUNCTION: Allocates a region of pages within the nonpaged pool area
163  */
164 {
165    ULONG Base;
166    KIRQL oldlvl;
167
168    KeAcquireSpinLock(&AllocMapLock, &oldlvl);
169    Base = RtlFindClearBitsAndSet(&AllocMap, nr_pages, AllocMapHint);
170    if (Base == 0xFFFFFFFF)
171    {
172       DbgPrint("CRITICAL: Out of non-paged pool space\n");
173       KEBUGCHECK(0);
174    }
175    if (AllocMapHint == Base)
176    {
177       AllocMapHint += nr_pages;
178    }
179    KeReleaseSpinLock(&AllocMapLock, oldlvl);
180    //DPRINT("returning %x\n",NonPagedPoolBase + Base * PAGE_SIZE);
181    return MiKernelMapStart + Base * PAGE_SIZE;
182 }
183
184