f06428116c1fa803e057518c07b448228705df61
[reactos.git] / reactos / ntoskrnl / mm / kmap.c
1 /* $Id: kmap.c,v 1.10 2001/05/05 19:13:10 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/bitops.h>
15 #include <internal/ntoskrnl.h>
16 #include <internal/pool.h>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 /* GLOBALS *****************************************************************/
22
23 #define ALLOC_MAP_SIZE (NONPAGED_POOL_SIZE / PAGESIZE)
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 unsigned int AllocMap[ALLOC_MAP_SIZE/32]={0,};
30 static KSPIN_LOCK AllocMapLock;
31
32 static PVOID NonPagedPoolBase;
33
34 /* FUNCTIONS ***************************************************************/
35
36 VOID
37 ExUnmapPage(PVOID Addr)
38 {
39 KIRQL oldIrql;
40 ULONG i = (Addr - NonPagedPoolBase) / PAGESIZE;
41
42 DPRINT("ExUnmapPage(Addr %x)\n",Addr);
43 DPRINT("i %x\n",i);
44
45 KeAcquireSpinLock(&AllocMapLock, &oldIrql);
46 MmDeleteVirtualMapping(NULL, (PVOID)Addr, FALSE, NULL, NULL);
47 clear_bit(i%32, &AllocMap[i/32]);
48 KeReleaseSpinLock(&AllocMapLock, oldIrql);
49 }
50
51 PVOID
52 ExAllocatePage(VOID)
53 {
54 ULONG PhysPage;
55
56 PhysPage = (ULONG)MmAllocPage(0);
57 if (PhysPage == 0)
58 {
59 return(NULL);
60 }
61
62 return(ExAllocatePageWithPhysPage(PhysPage));
63 }
64
65 NTSTATUS
66 MiZeroPage(ULONG PhysPage)
67 {
68 PVOID TempAddress;
69
70 TempAddress = ExAllocatePageWithPhysPage(PhysPage);
71 if (TempAddress == NULL)
72 {
73 return(STATUS_NO_MEMORY);
74 }
75 memset(TempAddress, 0, PAGESIZE);
76 ExUnmapPage(TempAddress);
77 return(STATUS_SUCCESS);
78 }
79
80 NTSTATUS
81 MiCopyFromUserPage(ULONG DestPhysPage, PVOID SourceAddress)
82 {
83 PVOID TempAddress;
84
85 TempAddress = ExAllocatePageWithPhysPage(DestPhysPage);
86 if (TempAddress == NULL)
87 {
88 return(STATUS_NO_MEMORY);
89 }
90 memcpy(TempAddress, SourceAddress, PAGESIZE);
91 ExUnmapPage(TempAddress);
92 return(STATUS_SUCCESS);
93 }
94
95 PVOID
96 ExAllocatePageWithPhysPage(ULONG PhysPage)
97 {
98 KIRQL oldlvl;
99 ULONG addr;
100 ULONG i;
101 NTSTATUS Status;
102
103 KeAcquireSpinLock(&AllocMapLock, &oldlvl);
104 for (i=1; i<ALLOC_MAP_SIZE;i++)
105 {
106 if (!test_bit(i%32,&AllocMap[i/32]))
107 {
108 DPRINT("i %x\n",i);
109 set_bit(i%32,&AllocMap[i/32]);
110 addr = (ULONG)(NonPagedPoolBase + (i*PAGESIZE));
111 Status = MmCreateVirtualMapping(NULL,
112 (PVOID)addr,
113 PAGE_READWRITE | PAGE_SYSTEM,
114 PhysPage);
115 if (!NT_SUCCESS(Status))
116 {
117 DbgPrint("Unable to create virtual mapping\n");
118 KeBugCheck(0);
119 }
120 KeReleaseSpinLock(&AllocMapLock, oldlvl);
121 return((PVOID)addr);
122 }
123 }
124 KeReleaseSpinLock(&AllocMapLock, oldlvl);
125 return(NULL);
126 }
127
128 VOID
129 MmInitKernelMap(PVOID BaseAddress)
130 {
131 NonPagedPoolBase = BaseAddress;
132 KeInitializeSpinLock(&AllocMapLock);
133 }
134
135 PVOID
136 MiAllocNonPagedPoolRegion(ULONG nr_pages)
137 /*
138 * FUNCTION: Allocates a region of pages within the nonpaged pool area
139 */
140 {
141 unsigned int start = 0;
142 unsigned int length = 0;
143 unsigned int i,j;
144
145 for (i=1; i<ALLOC_MAP_SIZE;i++)
146 {
147 if (!test_bit(i%32,&AllocMap[i/32]))
148 {
149 if (length == 0)
150 {
151 start=i;
152 length = 1;
153 }
154 else
155 {
156 length++;
157 }
158 if (length==nr_pages)
159 {
160 for (j=start;j<(start+length);j++)
161 {
162 set_bit(j%32,&AllocMap[j/32]);
163 }
164 DPRINT("returning %x\n",((start*PAGESIZE)+NonPagedPoolBase));
165 return(((start*PAGESIZE)+NonPagedPoolBase));
166 }
167 }
168 else
169 {
170 start=0;
171 length=0;
172 }
173 }
174 DbgPrint("CRITICAL: Out of non-paged pool space\n");
175 for(;;);
176 return(0);
177 }