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
);
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
);
240 MmInitialiseRegion(PLIST_ENTRY RegionListHead
, ULONG Length
, ULONG Type
,
245 Region
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_REGION
),
248 Region
->Protect
= Protect
;
249 Region
->Length
= Length
;
250 InitializeListHead(RegionListHead
);
251 InsertHeadList(RegionListHead
, &Region
->RegionListEntry
);
255 MmFindRegion(PVOID BaseAddress
, PLIST_ENTRY RegionListHead
, PVOID Address
,
256 PVOID
* RegionBaseAddress
)
258 PLIST_ENTRY current_entry
;
260 PVOID StartAddress
= BaseAddress
;
262 current_entry
= RegionListHead
->Flink
;
263 while (current_entry
!= RegionListHead
)
265 current
= CONTAINING_RECORD(current_entry
, MM_REGION
, RegionListEntry
);
267 if (StartAddress
<= Address
&&
268 ((char*)StartAddress
+ current
->Length
) > (char*)Address
)
270 if (RegionBaseAddress
!= NULL
)
272 *RegionBaseAddress
= StartAddress
;
277 current_entry
= current_entry
->Flink
;
279 StartAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ current
->Length
);