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
;
109 MmAlterRegion(PMADDRESS_SPACE AddressSpace
, PVOID BaseAddress
,
110 PLIST_ENTRY RegionListHead
, PVOID StartAddress
, ULONG Length
,
111 ULONG NewType
, ULONG NewProtect
, PMM_ALTER_REGION_FUNC AlterFunc
)
113 PMM_REGION InitialRegion
;
114 PVOID InitialBaseAddress
= NULL
;
115 PMM_REGION NewRegion
;
116 PLIST_ENTRY CurrentEntry
;
117 PMM_REGION CurrentRegion
= NULL
;
118 PVOID CurrentBaseAddress
;
119 ULONG RemainingLength
;
122 * Find the first region containing part of the range of addresses to
125 InitialRegion
= MmFindRegion(BaseAddress
, RegionListHead
, StartAddress
,
126 &InitialBaseAddress
);
127 if (((char*)StartAddress
+ Length
) >
128 ((char*)InitialBaseAddress
+ InitialRegion
->Length
))
130 RemainingLength
= ((char*)StartAddress
+ Length
) -
131 ((char*)InitialBaseAddress
+ InitialRegion
->Length
);
139 * If necessary then split the region into the affected and unaffected parts.
141 if (InitialRegion
->Type
!= NewType
|| InitialRegion
->Protect
!= NewProtect
)
143 NewRegion
= MmSplitRegion(InitialRegion
, InitialBaseAddress
,
144 StartAddress
, Length
, NewType
, NewProtect
,
145 AddressSpace
, AlterFunc
);
146 if (NewRegion
== NULL
)
148 return(STATUS_NO_MEMORY
);
153 NewRegion
= InitialRegion
;
157 * Free any complete regions that are containing in the range of addresses
158 * and call the helper function to actually do the changes.
160 CurrentEntry
= NewRegion
->RegionListEntry
.Flink
;
161 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
163 CurrentBaseAddress
= (char*)StartAddress
+ NewRegion
->Length
;
164 while (RemainingLength
> 0 && CurrentRegion
->Length
<= RemainingLength
&&
165 CurrentEntry
!= RegionListHead
)
167 if (CurrentRegion
->Type
!= NewType
&&
168 CurrentRegion
->Protect
!= NewProtect
)
170 AlterFunc(AddressSpace
, CurrentBaseAddress
, CurrentRegion
->Length
,
171 CurrentRegion
->Type
, CurrentRegion
->Protect
,
172 NewType
, NewProtect
);
175 CurrentBaseAddress
= (PVOID
)((ULONG_PTR
)CurrentBaseAddress
+ CurrentRegion
->Length
);
176 NewRegion
->Length
+= CurrentRegion
->Length
;
177 RemainingLength
-= CurrentRegion
->Length
;
178 CurrentEntry
= CurrentEntry
->Flink
;
179 RemoveEntryList(&CurrentRegion
->RegionListEntry
);
180 ExFreePool(CurrentRegion
);
181 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
186 * Split any final region.
188 if (RemainingLength
> 0 && CurrentEntry
!= RegionListHead
)
190 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
192 if (CurrentRegion
->Type
!= NewType
&&
193 CurrentRegion
->Protect
!= NewProtect
)
195 AlterFunc(AddressSpace
, CurrentBaseAddress
, CurrentRegion
->Length
,
196 CurrentRegion
->Type
, CurrentRegion
->Protect
,
197 NewType
, NewProtect
);
199 NewRegion
->Length
+= RemainingLength
;
200 CurrentRegion
->Length
-= RemainingLength
;
204 * If the region after the new region has the same type then merge them.
206 if (NewRegion
->RegionListEntry
.Flink
!= RegionListHead
)
208 CurrentEntry
= NewRegion
->RegionListEntry
.Flink
;
209 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
211 if (CurrentRegion
->Type
== NewRegion
->Type
&&
212 CurrentRegion
->Protect
== NewRegion
->Protect
)
214 NewRegion
->Length
+= CurrentRegion
->Length
;
215 RemoveEntryList(&CurrentRegion
->RegionListEntry
);
216 ExFreePool(CurrentRegion
);
221 * If the region before the new region has the same type then merge them.
223 if (NewRegion
->RegionListEntry
.Blink
!= RegionListHead
)
225 CurrentEntry
= NewRegion
->RegionListEntry
.Blink
;
226 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
228 if (CurrentRegion
->Type
== NewRegion
->Type
&&
229 CurrentRegion
->Protect
== NewRegion
->Protect
)
231 NewRegion
->Length
+= CurrentRegion
->Length
;
232 RemoveEntryList(&CurrentRegion
->RegionListEntry
);
233 ExFreePool(CurrentRegion
);
237 return(STATUS_SUCCESS
);
242 MmInitialiseRegion(PLIST_ENTRY RegionListHead
, ULONG Length
, ULONG Type
,
247 Region
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_REGION
),
250 Region
->Protect
= Protect
;
251 Region
->Length
= Length
;
252 InitializeListHead(RegionListHead
);
253 InsertHeadList(RegionListHead
, &Region
->RegionListEntry
);
258 MmFindRegion(PVOID BaseAddress
, PLIST_ENTRY RegionListHead
, PVOID Address
,
259 PVOID
* RegionBaseAddress
)
261 PLIST_ENTRY current_entry
;
263 PVOID StartAddress
= BaseAddress
;
265 current_entry
= RegionListHead
->Flink
;
266 while (current_entry
!= RegionListHead
)
268 current
= CONTAINING_RECORD(current_entry
, MM_REGION
, RegionListEntry
);
270 if (StartAddress
<= Address
&&
271 ((char*)StartAddress
+ current
->Length
) > (char*)Address
)
273 if (RegionBaseAddress
!= NULL
)
275 *RegionBaseAddress
= StartAddress
;
280 current_entry
= current_entry
->Flink
;
282 StartAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ current
->Length
);