ReactOS  0.4.14-dev-293-g2b39b42
region.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS kernel
4  * FILE: ntoskrnl/mm/region.c
5  * PURPOSE: No purpose listed.
6  *
7  * PROGRAMMERS: David Welch
8  */
9 
10 /* INCLUDE *****************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* FUNCTIONS *****************************************************************/
17 
18 static VOID
21 /*
22  * FUNCTION: Insert a list entry after another entry in the list
23  */
24 {
25  Previous->Flink->Blink = Entry;
26 
27  Entry->Flink = Previous->Flink;
28  Entry->Blink = Previous;
29 
30  Previous->Flink = Entry;
31 }
32 
33 static PMM_REGION
34 MmSplitRegion(PMM_REGION InitialRegion, PVOID InitialBaseAddress,
35  PVOID StartAddress, SIZE_T Length, ULONG NewType,
37  PMM_ALTER_REGION_FUNC AlterFunc)
38 {
39  PMM_REGION NewRegion1;
40  PMM_REGION NewRegion2;
41  SIZE_T InternalLength;
42 
43  /* Allocate this in front otherwise the failure case is too difficult. */
44  NewRegion2 = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_REGION),
46  if (NewRegion2 == NULL)
47  {
48  return(NULL);
49  }
50 
51  /* Create the new region. */
52  NewRegion1 = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_REGION),
54  if (NewRegion1 == NULL)
55  {
56  ExFreePoolWithTag(NewRegion2, TAG_MM_REGION);
57  return(NULL);
58  }
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);
66 
67  /*
68  * Call our helper function to do the changes on the addresses contained
69  * in the initial region.
70  */
71  AlterFunc(AddressSpace, StartAddress, InternalLength, InitialRegion->Type,
72  InitialRegion->Protect, NewType, NewProtect);
73 
74  /*
75  * If necessary create a new region for the portion of the initial region
76  * beyond the range of addresses to alter.
77  */
78  if (((char*)InitialBaseAddress + InitialRegion->Length) > ((char*)StartAddress + Length))
79  {
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);
86  }
87  else
88  {
89  ExFreePoolWithTag(NewRegion2, TAG_MM_REGION);
90  }
91 
92  /* Either remove or shrink the initial region. */
93  if (InitialBaseAddress == StartAddress)
94  {
95  RemoveEntryList(&InitialRegion->RegionListEntry);
96  ExFreePoolWithTag(InitialRegion, TAG_MM_REGION);
97  }
98  else
99  {
100  InitialRegion->Length = (char*)StartAddress - (char*)InitialBaseAddress;
101  }
102 
103  return(NewRegion1);
104 }
105 
106 NTSTATUS
107 NTAPI
109  PLIST_ENTRY RegionListHead, PVOID StartAddress, SIZE_T Length,
110  ULONG NewType, ULONG NewProtect, PMM_ALTER_REGION_FUNC AlterFunc)
111 {
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;
119 
120  /*
121  * Find the first region containing part of the range of addresses to
122  * be altered.
123  */
124  InitialRegion = MmFindRegion(BaseAddress, RegionListHead, StartAddress,
125  &InitialBaseAddress);
126  /*
127  * If necessary then split the region into the affected and unaffected parts.
128  */
129  if (InitialRegion->Type != NewType || InitialRegion->Protect != NewProtect)
130  {
131  NewRegion = MmSplitRegion(InitialRegion, InitialBaseAddress,
132  StartAddress, Length, NewType, NewProtect,
133  AddressSpace, AlterFunc);
134  if (NewRegion == NULL)
135  {
136  return(STATUS_NO_MEMORY);
137  }
138  if(NewRegion->Length < Length)
139  RemainingLength = Length - NewRegion->Length;
140  else
141  RemainingLength = 0;
142  }
143  else
144  {
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);
149  else
150  RemainingLength = 0;
151  }
152 
153  /*
154  * Free any complete regions that are containing in the range of addresses
155  * and call the helper function to actually do the changes.
156  */
157  CurrentEntry = NewRegion->RegionListEntry.Flink;
158  CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION,
159  RegionListEntry);
160  CurrentBaseAddress = (char*)StartAddress + NewRegion->Length;
161  while (RemainingLength > 0 && CurrentRegion->Length <= RemainingLength &&
162  CurrentEntry != RegionListHead)
163  {
164  if (CurrentRegion->Type != NewType ||
165  CurrentRegion->Protect != NewProtect)
166  {
167  AlterFunc(AddressSpace, CurrentBaseAddress, CurrentRegion->Length,
168  CurrentRegion->Type, CurrentRegion->Protect,
169  NewType, NewProtect);
170  }
171 
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,
179  RegionListEntry);
180  }
181 
182  /*
183  * Split any final region.
184  */
185  if (RemainingLength > 0 && CurrentEntry != RegionListHead)
186  {
187  CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION,
188  RegionListEntry);
189  if (CurrentRegion->Type != NewType ||
190  CurrentRegion->Protect != NewProtect)
191  {
192  AlterFunc(AddressSpace, CurrentBaseAddress, RemainingLength,
193  CurrentRegion->Type, CurrentRegion->Protect,
194  NewType, NewProtect);
195  }
196  NewRegion->Length += RemainingLength;
197  CurrentRegion->Length -= RemainingLength;
198  }
199 
200  /*
201  * If the region after the new region has the same type then merge them.
202  */
203  if (NewRegion->RegionListEntry.Flink != RegionListHead)
204  {
205  CurrentEntry = NewRegion->RegionListEntry.Flink;
206  CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION,
207  RegionListEntry);
208  if (CurrentRegion->Type == NewRegion->Type &&
209  CurrentRegion->Protect == NewRegion->Protect)
210  {
211  NewRegion->Length += CurrentRegion->Length;
212  RemoveEntryList(&CurrentRegion->RegionListEntry);
213  ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION);
214  }
215  }
216 
217  /*
218  * If the region before the new region has the same type then merge them.
219  */
220  if (NewRegion->RegionListEntry.Blink != RegionListHead)
221  {
222  CurrentEntry = NewRegion->RegionListEntry.Blink;
223  CurrentRegion = CONTAINING_RECORD(CurrentEntry, MM_REGION,
224  RegionListEntry);
225  if (CurrentRegion->Type == NewRegion->Type &&
226  CurrentRegion->Protect == NewRegion->Protect)
227  {
228  NewRegion->Length += CurrentRegion->Length;
229  RemoveEntryList(&CurrentRegion->RegionListEntry);
230  ExFreePoolWithTag(CurrentRegion, TAG_MM_REGION);
231  }
232  }
233 
234  return(STATUS_SUCCESS);
235 }
236 
237 VOID
238 NTAPI
240  ULONG Protect)
241 {
243 
245  TAG_MM_REGION);
246  if (!Region) return;
247 
248  Region->Type = Type;
249  Region->Protect = Protect;
250  Region->Length = Length;
251  InitializeListHead(RegionListHead);
252  InsertHeadList(RegionListHead, &Region->RegionListEntry);
253 }
254 
256 NTAPI
258  PVOID* RegionBaseAddress)
259 {
260  PLIST_ENTRY current_entry;
262  PVOID StartAddress = BaseAddress;
263 
264  current_entry = RegionListHead->Flink;
265  while (current_entry != RegionListHead)
266  {
267  current = CONTAINING_RECORD(current_entry, MM_REGION, RegionListEntry);
268 
269  if (StartAddress <= Address &&
270  ((char*)StartAddress + current->Length) > (char*)Address)
271  {
272  if (RegionBaseAddress != NULL)
273  {
274  *RegionBaseAddress = StartAddress;
275  }
276  return(current);
277  }
278 
279  current_entry = current_entry->Flink;
280 
281  StartAddress = (PVOID)((ULONG_PTR)StartAddress + current->Length);
282 
283  }
284  return(NULL);
285 }
VOID(* PMM_ALTER_REGION_FUNC)(PMMSUPPORT AddressSpace, PVOID BaseAddress, SIZE_T Length, ULONG OldType, ULONG OldProtect, ULONG NewType, ULONG NewProtect)
Definition: mm.h:444
Type
Definition: Type.h:6
struct _Entry Entry
Definition: kefuncs.h:640
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID _In_ ULONG_PTR _In_ SIZE_T _Inout_opt_ PLARGE_INTEGER _Inout_ PSIZE_T _In_ SECTION_INHERIT _In_ ULONG _In_ ULONG Protect
Definition: zwfuncs.h:214
struct _LIST_ENTRY * Blink
Definition: typedefs.h:120
FORCEINLINE VOID InsertHeadList(_Inout_ PLIST_ENTRY ListHead, _Inout_ __drv_aliasesMem PLIST_ENTRY Entry)
Definition: rtlfuncs.h:201
#define TAG_MM_REGION
Definition: tag.h:130
_In_ ULONG _In_ PHYSICAL_ADDRESS _Inout_ PULONG AddressSpace
Definition: iofuncs.h:2268
Definition: mm.h:390
LONG NTSTATUS
Definition: precomp.h:26
VOID NTAPI MmInitializeRegion(PLIST_ENTRY RegionListHead, SIZE_T Length, ULONG Type, ULONG Protect)
Definition: region.c:239
uint32_t ULONG_PTR
Definition: typedefs.h:63
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
while(1)
Definition: macro.lex.yy.c:740
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
ULONG Type
Definition: mm.h:392
smooth NULL
Definition: ftsmooth.c:416
static WCHAR Address[46]
Definition: ping.c:68
SIZE_T Length
Definition: mm.h:394
void * PVOID
Definition: retypes.h:9
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
ULONG Protect
Definition: mm.h:393
static PMM_REGION MmSplitRegion(PMM_REGION InitialRegion, PVOID InitialBaseAddress, PVOID StartAddress, SIZE_T Length, ULONG NewType, ULONG NewProtect, PMMSUPPORT AddressSpace, PMM_ALTER_REGION_FUNC AlterFunc)
Definition: region.c:34
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
PMM_REGION NTAPI MmFindRegion(PVOID BaseAddress, PLIST_ENTRY RegionListHead, PVOID Address, PVOID *RegionBaseAddress)
Definition: region.c:257
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
Definition: typedefs.h:117
static VOID InsertAfterEntry(PLIST_ENTRY Previous, PLIST_ENTRY Entry)
Definition: region.c:19
ULONG_PTR SIZE_T
Definition: typedefs.h:78
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
_Must_inspect_result_ _In_ ULONG NewProtect
Definition: mmfuncs.h:683
#define min(a, b)
Definition: monoChain.cc:55
unsigned int ULONG
Definition: retypes.h:1
LIST_ENTRY RegionListEntry
Definition: mm.h:395
#define ULONG_PTR
Definition: config.h:101
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
return STATUS_SUCCESS
Definition: btrfs.c:2966
base of all file and directory entries
Definition: entries.h:82
NTSTATUS NTAPI MmAlterRegion(PMMSUPPORT AddressSpace, PVOID BaseAddress, PLIST_ENTRY RegionListHead, PVOID StartAddress, SIZE_T Length, ULONG NewType, ULONG NewProtect, PMM_ALTER_REGION_FUNC AlterFunc)
Definition: region.c:108
struct task_struct * current
Definition: linux.c:32