Revert 15473 and 15474 as Alex doesn't like them
[reactos.git] / reactos / ntoskrnl / mm / region.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/region.c
6 * PURPOSE: No purpose listed.
7 *
8 * PROGRAMMERS: David Welch
9 */
10
11 /* INCLUDE *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* FUNCTIONS *****************************************************************/
18
19 VOID STATIC
20 InsertAfterEntry(PLIST_ENTRY Previous,
21 PLIST_ENTRY Entry)
22 /*
23 * FUNCTION: Insert a list entry after another entry in the list
24 */
25 {
26 Previous->Flink->Blink = Entry;
27
28 Entry->Flink = Previous->Flink;
29 Entry->Blink = Previous;
30
31 Previous->Flink = Entry;
32 }
33
34 PMM_REGION STATIC
35 MmSplitRegion(PMM_REGION InitialRegion, PVOID InitialBaseAddress,
36 PVOID StartAddress, ULONG Length, ULONG NewType,
37 ULONG NewProtect, PMADDRESS_SPACE AddressSpace,
38 PMM_ALTER_REGION_FUNC AlterFunc)
39 {
40 PMM_REGION NewRegion1;
41 PMM_REGION NewRegion2;
42 ULONG InternalLength;
43
44 /* Allocate this in front otherwise the failure case is too difficult. */
45 NewRegion2 = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_REGION),
46 TAG_MM_REGION);
47 if (NewRegion2 == NULL)
48 {
49 return(NULL);
50 }
51
52 /* Create the new region. */
53 NewRegion1 = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_REGION),
54 TAG_MM_REGION);
55 if (NewRegion1 == NULL)
56 {
57 ExFreePool(NewRegion2);
58 return(NULL);
59 }
60 NewRegion1->Type = NewType;
61 NewRegion1->Protect = NewProtect;
62 InternalLength = ((char*)InitialBaseAddress + InitialRegion->Length) - (char*)StartAddress;
63 InternalLength = min(InternalLength, Length);
64 NewRegion1->Length = InternalLength;
65 InsertAfterEntry(&InitialRegion->RegionListEntry,
66 &NewRegion1->RegionListEntry);
67
68 /*
69 * Call our helper function to do the changes on the addresses contained
70 * in the initial region.
71 */
72 AlterFunc(AddressSpace, StartAddress, InternalLength, InitialRegion->Type,
73 InitialRegion->Protect, NewType, NewProtect);
74
75 /*
76 * If necessary create a new region for the portion of the initial region
77 * beyond the range of addresses to alter.
78 */
79 if (((char*)InitialBaseAddress + InitialRegion->Length) > ((char*)StartAddress + Length))
80 {
81 NewRegion2->Type = InitialRegion->Type;
82 NewRegion2->Protect = InitialRegion->Protect;
83 NewRegion2->Length = ((char*)InitialBaseAddress + InitialRegion->Length) -
84 ((char*)StartAddress + Length);
85 InsertAfterEntry(&NewRegion1->RegionListEntry,
86 &NewRegion2->RegionListEntry);
87 }
88 else
89 {
90 ExFreePool(NewRegion2);
91 }
92
93 /* Either remove or shrink the initial region. */
94 if (InitialBaseAddress == StartAddress)
95 {
96 RemoveEntryList(&InitialRegion->RegionListEntry);
97 ExFreePool(InitialRegion);
98 }
99 else
100 {
101 InitialRegion->Length = (char*)StartAddress - (char*)InitialBaseAddress;
102 }
103
104 return(NewRegion1);
105 }
106
107 NTSTATUS
108 MmAlterRegion(PMADDRESS_SPACE AddressSpace, PVOID BaseAddress,
109 PLIST_ENTRY RegionListHead, PVOID StartAddress, ULONG Length,
110 ULONG NewType, ULONG NewProtect, PMM_ALTER_REGION_FUNC AlterFunc)
111 {
112 PMM_REGION InitialRegion;
113 PVOID InitialBaseAddress;
114 PMM_REGION NewRegion;
115 PLIST_ENTRY CurrentEntry;
116 PMM_REGION CurrentRegion = NULL;
117 PVOID CurrentBaseAddress;
118 ULONG RemainingLength;
119
120 /*
121 * Find the first region containing part of the range of addresses to
122 * be altered.
123 */
124 InitialRegion = MmFindRegion(BaseAddress, RegionListHead, StartAddress,
125 &InitialBaseAddress);
126 if (((char*)StartAddress + Length) >
127 ((char*)InitialBaseAddress + InitialRegion->Length))
128 {
129 RemainingLength = ((char*)StartAddress + Length) -
130 ((char*)InitialBaseAddress + InitialRegion->Length);
131 }
132 else
133 {
134 RemainingLength = 0;
135 }
136
137 /*
138 * If necessary then split the region into the affected and unaffected parts.
139 */
140 if (InitialRegion->Type != NewType || InitialRegion->Protect != NewProtect)
141 {
142 NewRegion = MmSplitRegion(InitialRegion, InitialBaseAddress,
143 StartAddress, Length, NewType, NewProtect,
144 AddressSpace, AlterFunc);
145 if (NewRegion == NULL)
146 {
147 return(STATUS_NO_MEMORY);
148 }
149 }
150 else
151 {
152 NewRegion = InitialRegion;
153 }
154
155 /*
156 * Free any complete regions that are containing in the range of addresses
157 * and call the helper function to actually do the changes.
158 */
159 CurrentEntry = NewRegion->RegionListEntry.Flink;
160 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION,
161 RegionListEntry);
162 CurrentBaseAddress = (char*)StartAddress + NewRegion->Length;
163 while (RemainingLength > 0 && CurrentRegion->Length <= RemainingLength &&
164 CurrentEntry != RegionListHead)
165 {
166 if (CurrentRegion->Type != NewType &&
167 CurrentRegion->Protect != NewProtect)
168 {
169 AlterFunc(AddressSpace, CurrentBaseAddress, CurrentRegion->Length,
170 CurrentRegion->Type, CurrentRegion->Protect,
171 NewType, NewProtect);
172 }
173 #if defined(__GNUC__)
174 CurrentBaseAddress += CurrentRegion->Length;
175 #else
176
177 {
178 char* pTemp = CurrentBaseAddress;
179 pTemp += CurrentRegion->Length;
180 CurrentBaseAddress = pTemp;
181 }
182 #endif
183 NewRegion->Length += CurrentRegion->Length;
184 RemainingLength -= CurrentRegion->Length;
185 CurrentEntry = CurrentEntry->Flink;
186 RemoveEntryList(&CurrentRegion->RegionListEntry);
187 ExFreePool(CurrentRegion);
188 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION,
189 RegionListEntry);
190 }
191
192 /*
193 * Split any final region.
194 */
195 if (RemainingLength > 0 && CurrentEntry != RegionListHead)
196 {
197 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION,
198 RegionListEntry);
199 if (CurrentRegion->Type != NewType &&
200 CurrentRegion->Protect != NewProtect)
201 {
202 AlterFunc(AddressSpace, CurrentBaseAddress, CurrentRegion->Length,
203 CurrentRegion->Type, CurrentRegion->Protect,
204 NewType, NewProtect);
205 }
206 NewRegion->Length += RemainingLength;
207 CurrentRegion->Length -= RemainingLength;
208 }
209
210 /*
211 * If the region after the new region has the same type then merge them.
212 */
213 if (NewRegion->RegionListEntry.Flink != RegionListHead)
214 {
215 CurrentEntry = NewRegion->RegionListEntry.Flink;
216 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION,
217 RegionListEntry);
218 if (CurrentRegion->Type == NewRegion->Type &&
219 CurrentRegion->Protect == NewRegion->Protect)
220 {
221 NewRegion->Length += CurrentRegion->Length;
222 RemoveEntryList(&CurrentRegion->RegionListEntry);
223 ExFreePool(CurrentRegion);
224 }
225 }
226
227 /*
228 * If the region before the new region has the same type then merge them.
229 */
230 if (NewRegion->RegionListEntry.Blink != RegionListHead)
231 {
232 CurrentEntry = NewRegion->RegionListEntry.Blink;
233 CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION,
234 RegionListEntry);
235 if (CurrentRegion->Type == NewRegion->Type &&
236 CurrentRegion->Protect == NewRegion->Protect)
237 {
238 NewRegion->Length += CurrentRegion->Length;
239 RemoveEntryList(&CurrentRegion->RegionListEntry);
240 ExFreePool(CurrentRegion);
241 }
242 }
243
244 return(STATUS_SUCCESS);
245 }
246
247 VOID
248 MmInitialiseRegion(PLIST_ENTRY RegionListHead, ULONG Length, ULONG Type,
249 ULONG Protect)
250 {
251 PMM_REGION Region;
252
253 Region = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_REGION),
254 TAG_MM_REGION);
255 Region->Type = Type;
256 Region->Protect = Protect;
257 Region->Length = Length;
258 InitializeListHead(RegionListHead);
259 InsertHeadList(RegionListHead, &Region->RegionListEntry);
260 }
261
262 PMM_REGION
263 MmFindRegion(PVOID BaseAddress, PLIST_ENTRY RegionListHead, PVOID Address,
264 PVOID* RegionBaseAddress)
265 {
266 PLIST_ENTRY current_entry;
267 PMM_REGION current;
268 PVOID StartAddress = BaseAddress;
269
270 current_entry = RegionListHead->Flink;
271 while (current_entry != RegionListHead)
272 {
273 current = CONTAINING_RECORD(current_entry, MM_REGION, RegionListEntry);
274
275 if (StartAddress <= Address &&
276 ((char*)StartAddress + current->Length) > (char*)Address)
277 {
278 if (RegionBaseAddress != NULL)
279 {
280 *RegionBaseAddress = StartAddress;
281 }
282 return(current);
283 }
284
285 current_entry = current_entry->Flink;
286 #if defined(__GNUC__)
287
288 StartAddress += current->Length;
289 #else
290
291 {
292 char* pTemp = StartAddress;
293 pTemp += current->Length;
294 StartAddress = pTemp;
295 }
296 #endif
297
298 }
299 return(NULL);
300 }