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
, SIZE_T Length
, ULONG NewType
,
36 ULONG NewProtect
, PMMSUPPORT AddressSpace
,
37 PMM_ALTER_REGION_FUNC AlterFunc
)
39 PMM_REGION NewRegion1
;
40 PMM_REGION NewRegion2
;
41 SIZE_T InternalLength
;
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 ExFreePoolWithTag(NewRegion2
, TAG_MM_REGION
);
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 ExFreePoolWithTag(NewRegion2
, TAG_MM_REGION
);
92 /* Either remove or shrink the initial region. */
93 if (InitialBaseAddress
== StartAddress
)
95 RemoveEntryList(&InitialRegion
->RegionListEntry
);
96 ExFreePoolWithTag(InitialRegion
, TAG_MM_REGION
);
100 InitialRegion
->Length
= (char*)StartAddress
- (char*)InitialBaseAddress
;
108 MmAlterRegion(PMMSUPPORT AddressSpace
, PVOID BaseAddress
,
109 PLIST_ENTRY RegionListHead
, PVOID StartAddress
, SIZE_T 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 SIZE_T RemainingLength
;
121 * Find the first region containing part of the range of addresses to
124 InitialRegion
= MmFindRegion(BaseAddress
, RegionListHead
, StartAddress
,
125 &InitialBaseAddress
);
127 * If necessary then split the region into the affected and unaffected parts.
129 if (InitialRegion
->Type
!= NewType
|| InitialRegion
->Protect
!= NewProtect
)
131 NewRegion
= MmSplitRegion(InitialRegion
, InitialBaseAddress
,
132 StartAddress
, Length
, NewType
, NewProtect
,
133 AddressSpace
, AlterFunc
);
134 if (NewRegion
== NULL
)
136 return(STATUS_NO_MEMORY
);
138 if(NewRegion
->Length
< Length
)
139 RemainingLength
= Length
- NewRegion
->Length
;
145 NewRegion
= InitialRegion
;
146 if(((ULONG_PTR
)InitialBaseAddress
+ NewRegion
->Length
) <
147 ((ULONG_PTR
)StartAddress
+ Length
))
148 RemainingLength
= ((ULONG_PTR
)StartAddress
+ Length
) - ((ULONG_PTR
)InitialBaseAddress
+ NewRegion
->Length
);
154 * Free any complete regions that are containing in the range of addresses
155 * and call the helper function to actually do the changes.
157 CurrentEntry
= NewRegion
->RegionListEntry
.Flink
;
158 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
160 CurrentBaseAddress
= (char*)StartAddress
+ NewRegion
->Length
;
161 while (RemainingLength
> 0 && CurrentRegion
->Length
<= RemainingLength
&&
162 CurrentEntry
!= RegionListHead
)
164 if (CurrentRegion
->Type
!= NewType
||
165 CurrentRegion
->Protect
!= NewProtect
)
167 AlterFunc(AddressSpace
, CurrentBaseAddress
, CurrentRegion
->Length
,
168 CurrentRegion
->Type
, CurrentRegion
->Protect
,
169 NewType
, NewProtect
);
172 CurrentBaseAddress
= (PVOID
)((ULONG_PTR
)CurrentBaseAddress
+ CurrentRegion
->Length
);
173 NewRegion
->Length
+= CurrentRegion
->Length
;
174 RemainingLength
-= CurrentRegion
->Length
;
175 CurrentEntry
= CurrentEntry
->Flink
;
176 RemoveEntryList(&CurrentRegion
->RegionListEntry
);
177 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
178 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
183 * Split any final region.
185 if (RemainingLength
> 0 && CurrentEntry
!= RegionListHead
)
187 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
189 if (CurrentRegion
->Type
!= NewType
||
190 CurrentRegion
->Protect
!= NewProtect
)
192 AlterFunc(AddressSpace
, CurrentBaseAddress
, RemainingLength
,
193 CurrentRegion
->Type
, CurrentRegion
->Protect
,
194 NewType
, NewProtect
);
196 NewRegion
->Length
+= RemainingLength
;
197 CurrentRegion
->Length
-= RemainingLength
;
201 * If the region after the new region has the same type then merge them.
203 if (NewRegion
->RegionListEntry
.Flink
!= RegionListHead
)
205 CurrentEntry
= NewRegion
->RegionListEntry
.Flink
;
206 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
208 if (CurrentRegion
->Type
== NewRegion
->Type
&&
209 CurrentRegion
->Protect
== NewRegion
->Protect
)
211 NewRegion
->Length
+= CurrentRegion
->Length
;
212 RemoveEntryList(&CurrentRegion
->RegionListEntry
);
213 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
218 * If the region before the new region has the same type then merge them.
220 if (NewRegion
->RegionListEntry
.Blink
!= RegionListHead
)
222 CurrentEntry
= NewRegion
->RegionListEntry
.Blink
;
223 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
,
225 if (CurrentRegion
->Type
== NewRegion
->Type
&&
226 CurrentRegion
->Protect
== NewRegion
->Protect
)
228 NewRegion
->Length
+= CurrentRegion
->Length
;
229 RemoveEntryList(&CurrentRegion
->RegionListEntry
);
230 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
234 return(STATUS_SUCCESS
);
239 MmInitializeRegion(PLIST_ENTRY RegionListHead
, SIZE_T Length
, ULONG Type
,
244 Region
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_REGION
),
249 Region
->Protect
= Protect
;
250 Region
->Length
= Length
;
251 InitializeListHead(RegionListHead
);
252 InsertHeadList(RegionListHead
, &Region
->RegionListEntry
);
257 MmFindRegion(PVOID BaseAddress
, PLIST_ENTRY RegionListHead
, PVOID Address
,
258 PVOID
* RegionBaseAddress
)
260 PLIST_ENTRY current_entry
;
262 PVOID StartAddress
= BaseAddress
;
264 current_entry
= RegionListHead
->Flink
;
265 while (current_entry
!= RegionListHead
)
267 current
= CONTAINING_RECORD(current_entry
, MM_REGION
, RegionListEntry
);
269 if (StartAddress
<= Address
&&
270 ((char*)StartAddress
+ current
->Length
) > (char*)Address
)
272 if (RegionBaseAddress
!= NULL
)
274 *RegionBaseAddress
= StartAddress
;
279 current_entry
= current_entry
->Flink
;
281 StartAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ current
->Length
);