2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/region.c
5 * PURPOSE: No purpose listed.
7 * PROGRAMMERS: David Welch
10 /* INCLUDE *****************************************************************/
16 /* FUNCTIONS *****************************************************************/
19 InsertAfterEntry(PLIST_ENTRY Previous
,
22 * FUNCTION: Insert a list entry after another entry in the list
25 Previous
->Flink
->Blink
= Entry
;
27 Entry
->Flink
= Previous
->Flink
;
28 Entry
->Blink
= Previous
;
30 Previous
->Flink
= Entry
;
34 MmSplitRegion(PMM_REGION InitialRegion
, PVOID InitialBaseAddress
,
35 PVOID StartAddress
, ULONG Length
, ULONG NewType
,
36 ULONG NewProtect
, PMMSUPPORT AddressSpace
,
37 PMM_ALTER_REGION_FUNC AlterFunc
)
39 PMM_REGION NewRegion1
;
40 PMM_REGION NewRegion2
;
43 /* Allocate this in front otherwise the failure case is too difficult. */
44 NewRegion2
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_REGION
),
46 if (NewRegion2
== NULL
)
51 /* Create the new region. */
52 NewRegion1
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_REGION
),
54 if (NewRegion1
== NULL
)
56 ExFreePool(NewRegion2
);
59 NewRegion1
->Type
= NewType
;
60 NewRegion1
->Protect
= NewProtect
;
61 InternalLength
= ((char*)InitialBaseAddress
+ InitialRegion
->Length
) - (char*)StartAddress
;
62 InternalLength
= min(InternalLength
, Length
);
63 NewRegion1
->Length
= InternalLength
;
64 InsertAfterEntry(&InitialRegion
->RegionListEntry
,
65 &NewRegion1
->RegionListEntry
);
68 * Call our helper function to do the changes on the addresses contained
69 * in the initial region.
71 AlterFunc(AddressSpace
, StartAddress
, InternalLength
, InitialRegion
->Type
,
72 InitialRegion
->Protect
, NewType
, NewProtect
);
75 * If necessary create a new region for the portion of the initial region
76 * beyond the range of addresses to alter.
78 if (((char*)InitialBaseAddress
+ InitialRegion
->Length
) > ((char*)StartAddress
+ Length
))
80 NewRegion2
->Type
= InitialRegion
->Type
;
81 NewRegion2
->Protect
= InitialRegion
->Protect
;
82 NewRegion2
->Length
= ((char*)InitialBaseAddress
+ InitialRegion
->Length
) -
83 ((char*)StartAddress
+ Length
);
84 InsertAfterEntry(&NewRegion1
->RegionListEntry
,
85 &NewRegion2
->RegionListEntry
);
89 ExFreePool(NewRegion2
);
92 /* Either remove or shrink the initial region. */
93 if (InitialBaseAddress
== StartAddress
)
95 RemoveEntryList(&InitialRegion
->RegionListEntry
);
96 ExFreePool(InitialRegion
);
100 InitialRegion
->Length
= (char*)StartAddress
- (char*)InitialBaseAddress
;
108 MmAlterRegion(PMMSUPPORT 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
= NULL
;
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
);
174 CurrentBaseAddress
= (PVOID
)((ULONG_PTR
)CurrentBaseAddress
+ CurrentRegion
->Length
);
175 NewRegion
->Length
+= CurrentRegion
->Length
;
176 RemainingLength
-= CurrentRegion
->Length
;
177 CurrentEntry
= CurrentEntry
->Flink
;
178 RemoveEntryList(&CurrentRegion
->RegionListEntry
);
179 ExFreePool(CurrentRegion
);
180 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
185 * Split any final region.
187 if (RemainingLength
> 0 && CurrentEntry
!= RegionListHead
)
189 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
191 if (CurrentRegion
->Type
!= NewType
&&
192 CurrentRegion
->Protect
!= NewProtect
)
194 AlterFunc(AddressSpace
, CurrentBaseAddress
, CurrentRegion
->Length
,
195 CurrentRegion
->Type
, CurrentRegion
->Protect
,
196 NewType
, NewProtect
);
198 NewRegion
->Length
+= RemainingLength
;
199 CurrentRegion
->Length
-= RemainingLength
;
203 * If the region after the new region has the same type then merge them.
205 if (NewRegion
->RegionListEntry
.Flink
!= RegionListHead
)
207 CurrentEntry
= NewRegion
->RegionListEntry
.Flink
;
208 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
210 if (CurrentRegion
->Type
== NewRegion
->Type
&&
211 CurrentRegion
->Protect
== NewRegion
->Protect
)
213 NewRegion
->Length
+= CurrentRegion
->Length
;
214 RemoveEntryList(&CurrentRegion
->RegionListEntry
);
215 ExFreePool(CurrentRegion
);
220 * If the region before the new region has the same type then merge them.
222 if (NewRegion
->RegionListEntry
.Blink
!= RegionListHead
)
224 CurrentEntry
= NewRegion
->RegionListEntry
.Blink
;
225 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
227 if (CurrentRegion
->Type
== NewRegion
->Type
&&
228 CurrentRegion
->Protect
== NewRegion
->Protect
)
230 NewRegion
->Length
+= CurrentRegion
->Length
;
231 RemoveEntryList(&CurrentRegion
->RegionListEntry
);
232 ExFreePool(CurrentRegion
);
236 return(STATUS_SUCCESS
);
241 MmInitializeRegion(PLIST_ENTRY RegionListHead
, SIZE_T Length
, ULONG Type
,
246 Region
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_REGION
),
251 Region
->Protect
= Protect
;
252 Region
->Length
= Length
;
253 InitializeListHead(RegionListHead
);
254 InsertHeadList(RegionListHead
, &Region
->RegionListEntry
);
259 MmFindRegion(PVOID BaseAddress
, PLIST_ENTRY RegionListHead
, PVOID Address
,
260 PVOID
* RegionBaseAddress
)
262 PLIST_ENTRY current_entry
;
264 PVOID StartAddress
= BaseAddress
;
266 current_entry
= RegionListHead
->Flink
;
267 while (current_entry
!= RegionListHead
)
269 current
= CONTAINING_RECORD(current_entry
, MM_REGION
, RegionListEntry
);
271 if (StartAddress
<= Address
&&
272 ((char*)StartAddress
+ current
->Length
) > (char*)Address
)
274 if (RegionBaseAddress
!= NULL
)
276 *RegionBaseAddress
= StartAddress
;
281 current_entry
= current_entry
->Flink
;
283 StartAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ current
->Length
);