Make WinCVS look a little cleaner.
[reactos.git] / reactos / ntoskrnl / mm / kmap.c
1 /* $Id: kmap.c,v 1.21 2002/10/01 19:27:22 chorns Exp $
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 (NONPAGED_POOL_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 ULONG AllocMap[ALLOC_MAP_SIZE/32]={0,};
30 static KSPIN_LOCK AllocMapLock;
31 static ULONG AllocMapHint = 1;
32
33 static PVOID NonPagedPoolBase;
34
35 /* FUNCTIONS ***************************************************************/
36
37 VOID
38 ExUnmapPage(PVOID Addr)
39 {
40 KIRQL oldIrql;
41 ULONG i = (Addr - NonPagedPoolBase) / PAGE_SIZE;
42
43 DPRINT("ExUnmapPage(Addr %x)\n",Addr);
44 DPRINT("i %x\n",i);
45
46 MmDeleteVirtualMapping(NULL, (PVOID)Addr, FALSE, NULL, NULL);
47 KeAcquireSpinLock(&AllocMapLock, &oldIrql);
48 AllocMap[i / 32] &= (~(1 << (i % 32)));
49 AllocMapHint = min(AllocMapHint, i);
50 KeReleaseSpinLock(&AllocMapLock, oldIrql);
51 }
52
53 PVOID
54 ExAllocatePage(VOID)
55 {
56 PHYSICAL_ADDRESS PhysPage;
57 NTSTATUS Status;
58
59 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &PhysPage);
60 if (!NT_SUCCESS(Status))
61 {
62 return(NULL);
63 }
64
65 return(ExAllocatePageWithPhysPage(PhysPage));
66 }
67
68 NTSTATUS
69 MiZeroPage(PHYSICAL_ADDRESS PhysPage)
70 {
71 PVOID TempAddress;
72
73 TempAddress = ExAllocatePageWithPhysPage(PhysPage);
74 if (TempAddress == NULL)
75 {
76 return(STATUS_NO_MEMORY);
77 }
78 memset(TempAddress, 0, PAGE_SIZE);
79 ExUnmapPage(TempAddress);
80 return(STATUS_SUCCESS);
81 }
82
83 NTSTATUS
84 MiCopyFromUserPage(PHYSICAL_ADDRESS DestPhysPage, PVOID SourceAddress)
85 {
86 PVOID TempAddress;
87
88 TempAddress = ExAllocatePageWithPhysPage(DestPhysPage);
89 if (TempAddress == NULL)
90 {
91 return(STATUS_NO_MEMORY);
92 }
93 memcpy(TempAddress, SourceAddress, PAGE_SIZE);
94 ExUnmapPage(TempAddress);
95 return(STATUS_SUCCESS);
96 }
97
98 PVOID
99 ExAllocatePageWithPhysPage(PHYSICAL_ADDRESS PhysPage)
100 {
101 KIRQL oldlvl;
102 ULONG addr;
103 ULONG i;
104 NTSTATUS Status;
105
106 KeAcquireSpinLock(&AllocMapLock, &oldlvl);
107 for (i = AllocMapHint; i < ALLOC_MAP_SIZE; i++)
108 {
109 if (!(AllocMap[i / 32] & (1 << (i % 32))))
110 {
111 DPRINT("i %x\n",i);
112 AllocMap[i / 32] |= (1 << (i % 32));
113 AllocMapHint = i + 1;
114 addr = (ULONG)(NonPagedPoolBase + (i*PAGE_SIZE));
115 Status = MmCreateVirtualMapping(NULL,
116 (PVOID)addr,
117 PAGE_READWRITE | PAGE_SYSTEM,
118 PhysPage,
119 FALSE);
120 if (!NT_SUCCESS(Status))
121 {
122 DbgPrint("Unable to create virtual mapping\n");
123 KeBugCheck(0);
124 }
125 KeReleaseSpinLock(&AllocMapLock, oldlvl);
126 return((PVOID)addr);
127 }
128 }
129 KeReleaseSpinLock(&AllocMapLock, oldlvl);
130 return(NULL);
131 }
132
133 VOID
134 MmInitKernelMap(PVOID BaseAddress)
135 {
136 NonPagedPoolBase = BaseAddress;
137 KeInitializeSpinLock(&AllocMapLock);
138 }
139
140 VOID
141 MiFreeNonPagedPoolRegion(PVOID Addr, ULONG Count, BOOLEAN Free)
142 {
143 ULONG i;
144 ULONG Base = (Addr - NonPagedPoolBase) / PAGE_SIZE;
145 ULONG Offset;
146 KIRQL oldlvl;
147
148 KeAcquireSpinLock(&AllocMapLock, &oldlvl);
149 AllocMapHint = min(AllocMapHint, Base);
150 for (i = 0; i < Count; i++)
151 {
152 Offset = Base + i;
153 AllocMap[Offset / 32] &= (~(1 << (Offset % 32)));
154 MmDeleteVirtualMapping(NULL,
155 Addr + (i * PAGE_SIZE),
156 Free,
157 NULL,
158 NULL);
159 }
160 KeReleaseSpinLock(&AllocMapLock, oldlvl);
161 }
162
163 PVOID
164 MiAllocNonPagedPoolRegion(ULONG nr_pages)
165 /*
166 * FUNCTION: Allocates a region of pages within the nonpaged pool area
167 */
168 {
169 unsigned int start = 0;
170 unsigned int length = 0;
171 unsigned int i,j;
172 KIRQL oldlvl;
173
174 KeAcquireSpinLock(&AllocMapLock, &oldlvl);
175 for (i=AllocMapHint; i<ALLOC_MAP_SIZE;i++)
176 {
177 if (!(AllocMap[i/32] & (1 << (i % 32))))
178 {
179 if (length == 0)
180 {
181 start=i;
182 length = 1;
183 }
184 else
185 {
186 length++;
187 }
188 if (length==nr_pages)
189 {
190 AllocMapHint = start + length;
191 for (j=start;j<(start+length);j++)
192 {
193 AllocMap[j / 32] |= (1 << (j % 32));
194 }
195 DPRINT("returning %x\n",((start*PAGE_SIZE)+NonPagedPoolBase));
196 KeReleaseSpinLock(&AllocMapLock, oldlvl);
197 return(((start*PAGE_SIZE)+NonPagedPoolBase));
198 }
199 }
200 else
201 {
202 start=0;
203 length=0;
204 }
205 }
206 DbgPrint("CRITICAL: Out of non-paged pool space\n");
207 KeBugCheck(0);
208 return(0);
209 }