3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/region.c
6 * PURPOSE: No purpose listed.
8 * PROGRAMMERS: David Welch
11 /* INCLUDE *****************************************************************/
15 #include <internal/debug.h>
17 /* FUNCTIONS *****************************************************************/
20 InsertAfterEntry(PLIST_ENTRY Previous
,
23 * FUNCTION: Insert a list entry after another entry in the list
26 Previous
->Flink
->Blink
= Entry
;
28 Entry
->Flink
= Previous
->Flink
;
29 Entry
->Blink
= Previous
;
31 Previous
->Flink
= Entry
;
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
)
40 PMM_REGION NewRegion1
;
41 PMM_REGION NewRegion2
;
44 /* Allocate this in front otherwise the failure case is too difficult. */
45 NewRegion2
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_REGION
),
47 if (NewRegion2
== NULL
)
52 /* Create the new region. */
53 NewRegion1
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_REGION
),
55 if (NewRegion1
== NULL
)
57 ExFreePool(NewRegion2
);
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
);
69 * Call our helper function to do the changes on the addresses contained
70 * in the initial region.
72 AlterFunc(AddressSpace
, StartAddress
, InternalLength
, InitialRegion
->Type
,
73 InitialRegion
->Protect
, NewType
, NewProtect
);
76 * If necessary create a new region for the portion of the initial region
77 * beyond the range of addresses to alter.
79 if (((char*)InitialBaseAddress
+ InitialRegion
->Length
) > ((char*)StartAddress
+ Length
))
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
);
90 ExFreePool(NewRegion2
);
93 /* Either remove or shrink the initial region. */
94 if (InitialBaseAddress
== StartAddress
)
96 RemoveEntryList(&InitialRegion
->RegionListEntry
);
97 ExFreePool(InitialRegion
);
101 InitialRegion
->Length
= (char*)StartAddress
- (char*)InitialBaseAddress
;
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
)
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
;
121 * Find the first region containing part of the range of addresses to
124 InitialRegion
= MmFindRegion(BaseAddress
, RegionListHead
, StartAddress
,
125 &InitialBaseAddress
);
126 if (((char*)StartAddress
+ Length
) >
127 ((char*)InitialBaseAddress
+ InitialRegion
->Length
))
129 RemainingLength
= ((char*)StartAddress
+ Length
) -
130 ((char*)InitialBaseAddress
+ InitialRegion
->Length
);
138 * If necessary then split the region into the affected and unaffected parts.
140 if (InitialRegion
->Type
!= NewType
|| InitialRegion
->Protect
!= NewProtect
)
142 NewRegion
= MmSplitRegion(InitialRegion
, InitialBaseAddress
,
143 StartAddress
, Length
, NewType
, NewProtect
,
144 AddressSpace
, AlterFunc
);
145 if (NewRegion
== NULL
)
147 return(STATUS_NO_MEMORY
);
152 NewRegion
= InitialRegion
;
156 * Free any complete regions that are containing in the range of addresses
157 * and call the helper function to actually do the changes.
159 CurrentEntry
= NewRegion
->RegionListEntry
.Flink
;
160 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
162 CurrentBaseAddress
= (char*)StartAddress
+ NewRegion
->Length
;
163 while (RemainingLength
> 0 && CurrentRegion
->Length
<= RemainingLength
&&
164 CurrentEntry
!= RegionListHead
)
166 if (CurrentRegion
->Type
!= NewType
&&
167 CurrentRegion
->Protect
!= NewProtect
)
169 AlterFunc(AddressSpace
, CurrentBaseAddress
, CurrentRegion
->Length
,
170 CurrentRegion
->Type
, CurrentRegion
->Protect
,
171 NewType
, NewProtect
);
173 #if defined(__GNUC__)
174 CurrentBaseAddress
+= CurrentRegion
->Length
;
178 char* pTemp
= CurrentBaseAddress
;
179 pTemp
+= CurrentRegion
->Length
;
180 CurrentBaseAddress
= pTemp
;
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
,
193 * Split any final region.
195 if (RemainingLength
> 0 && CurrentEntry
!= RegionListHead
)
197 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
199 if (CurrentRegion
->Type
!= NewType
&&
200 CurrentRegion
->Protect
!= NewProtect
)
202 AlterFunc(AddressSpace
, CurrentBaseAddress
, CurrentRegion
->Length
,
203 CurrentRegion
->Type
, CurrentRegion
->Protect
,
204 NewType
, NewProtect
);
206 NewRegion
->Length
+= RemainingLength
;
207 CurrentRegion
->Length
-= RemainingLength
;
211 * If the region after the new region has the same type then merge them.
213 if (NewRegion
->RegionListEntry
.Flink
!= RegionListHead
)
215 CurrentEntry
= NewRegion
->RegionListEntry
.Flink
;
216 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
218 if (CurrentRegion
->Type
== NewRegion
->Type
&&
219 CurrentRegion
->Protect
== NewRegion
->Protect
)
221 NewRegion
->Length
+= CurrentRegion
->Length
;
222 RemoveEntryList(&CurrentRegion
->RegionListEntry
);
223 ExFreePool(CurrentRegion
);
228 * If the region before the new region has the same type then merge them.
230 if (NewRegion
->RegionListEntry
.Blink
!= RegionListHead
)
232 CurrentEntry
= NewRegion
->RegionListEntry
.Blink
;
233 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
235 if (CurrentRegion
->Type
== NewRegion
->Type
&&
236 CurrentRegion
->Protect
== NewRegion
->Protect
)
238 NewRegion
->Length
+= CurrentRegion
->Length
;
239 RemoveEntryList(&CurrentRegion
->RegionListEntry
);
240 ExFreePool(CurrentRegion
);
244 return(STATUS_SUCCESS
);
248 MmInitialiseRegion(PLIST_ENTRY RegionListHead
, ULONG Length
, ULONG Type
,
253 Region
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_REGION
),
256 Region
->Protect
= Protect
;
257 Region
->Length
= Length
;
258 InitializeListHead(RegionListHead
);
259 InsertHeadList(RegionListHead
, &Region
->RegionListEntry
);
263 MmFindRegion(PVOID BaseAddress
, PLIST_ENTRY RegionListHead
, PVOID Address
,
264 PVOID
* RegionBaseAddress
)
266 PLIST_ENTRY current_entry
;
268 PVOID StartAddress
= BaseAddress
;
270 current_entry
= RegionListHead
->Flink
;
271 while (current_entry
!= RegionListHead
)
273 current
= CONTAINING_RECORD(current_entry
, MM_REGION
, RegionListEntry
);
275 if (StartAddress
<= Address
&&
276 ((char*)StartAddress
+ current
->Length
) > (char*)Address
)
278 if (RegionBaseAddress
!= NULL
)
280 *RegionBaseAddress
= StartAddress
;
285 current_entry
= current_entry
->Flink
;
286 #if defined(__GNUC__)
288 StartAddress
+= current
->Length
;
292 char* pTemp
= StartAddress
;
293 pTemp
+= current
->Length
;
294 StartAddress
= pTemp
;