Synchronize with trunk r58606.
[reactos.git] / ntoskrnl / mm / ARM3 / vadnode.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/vadnode.c
5 * PURPOSE: ARM Memory Manager VAD Node Algorithms
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 * Timo Kreuzer (timo.kreuzer@reactos.org)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
18
19 /* Include Mm version of AVL support */
20 #include "../ARM3/miavl.h"
21 #include "../../../lib/rtl/avlsupp.c"
22
23 /* GLOBALS ********************************************************************/
24
25 CHAR MmReadWrite[32] =
26 {
27 MM_NO_ACCESS_ALLOWED, MM_READ_ONLY_ALLOWED, MM_READ_ONLY_ALLOWED,
28 MM_READ_ONLY_ALLOWED, MM_READ_WRITE_ALLOWED, MM_READ_WRITE_ALLOWED,
29 MM_READ_WRITE_ALLOWED, MM_READ_WRITE_ALLOWED,
30
31 MM_NO_ACCESS_ALLOWED, MM_READ_ONLY_ALLOWED, MM_READ_ONLY_ALLOWED,
32 MM_READ_ONLY_ALLOWED, MM_READ_WRITE_ALLOWED, MM_READ_WRITE_ALLOWED,
33 MM_READ_WRITE_ALLOWED, MM_READ_WRITE_ALLOWED,
34
35 MM_NO_ACCESS_ALLOWED, MM_READ_ONLY_ALLOWED, MM_READ_ONLY_ALLOWED,
36 MM_READ_ONLY_ALLOWED, MM_READ_WRITE_ALLOWED, MM_READ_WRITE_ALLOWED,
37 MM_READ_WRITE_ALLOWED, MM_READ_WRITE_ALLOWED,
38
39 MM_NO_ACCESS_ALLOWED, MM_READ_ONLY_ALLOWED, MM_READ_ONLY_ALLOWED,
40 MM_READ_ONLY_ALLOWED, MM_READ_WRITE_ALLOWED, MM_READ_WRITE_ALLOWED,
41 MM_READ_WRITE_ALLOWED, MM_READ_WRITE_ALLOWED,
42 };
43
44 /* FUNCTIONS ******************************************************************/
45
46 PMMVAD
47 NTAPI
48 MiLocateAddress(IN PVOID VirtualAddress)
49 {
50 PMMVAD FoundVad;
51 ULONG_PTR Vpn;
52 PMM_AVL_TABLE Table = &PsGetCurrentProcess()->VadRoot;
53 TABLE_SEARCH_RESULT SearchResult;
54
55 /* Start with the the hint */
56 FoundVad = (PMMVAD)Table->NodeHint;
57 if (!FoundVad) return NULL;
58
59 /* Check if this VPN is in the hint, if so, use it */
60 Vpn = (ULONG_PTR)VirtualAddress >> PAGE_SHIFT;
61 if ((Vpn >= FoundVad->StartingVpn) && (Vpn <= FoundVad->EndingVpn)) return FoundVad;
62
63 /* VAD hint didn't work, go look for it */
64 SearchResult = RtlpFindAvlTableNodeOrParent(Table,
65 (PVOID)Vpn,
66 (PMMADDRESS_NODE*)&FoundVad);
67 if (SearchResult != TableFoundNode) return NULL;
68
69 /* We found it, update the hint */
70 ASSERT(FoundVad != NULL);
71 ASSERT((Vpn >= FoundVad->StartingVpn) && (Vpn <= FoundVad->EndingVpn));
72 Table->NodeHint = FoundVad;
73 return FoundVad;
74 }
75
76 PMMADDRESS_NODE
77 NTAPI
78 MiCheckForConflictingNode(IN ULONG_PTR StartVpn,
79 IN ULONG_PTR EndVpn,
80 IN PMM_AVL_TABLE Table)
81 {
82 PMMADDRESS_NODE CurrentNode;
83
84 /* If the tree is empty, there is no conflict */
85 if (!Table->NumberGenericTableElements) return NULL;
86
87 /* Start looping from the right */
88 CurrentNode = RtlRightChildAvl(&Table->BalancedRoot);
89 ASSERT(CurrentNode != NULL);
90 while (CurrentNode)
91 {
92 /* This address comes after */
93 if (StartVpn > CurrentNode->EndingVpn)
94 {
95 /* Keep searching on the right */
96 CurrentNode = RtlRightChildAvl(CurrentNode);
97 }
98 else if (EndVpn < CurrentNode->StartingVpn)
99 {
100 /* This address ends before the node starts, search on the left */
101 CurrentNode = RtlLeftChildAvl(CurrentNode);
102 }
103 else
104 {
105 /* This address is part of this node, return it */
106 break;
107 }
108 }
109
110 /* Return either the conflicting node, or no node at all */
111 return CurrentNode;
112 }
113
114 VOID
115 NTAPI
116 MiInsertNode(IN PMM_AVL_TABLE Table,
117 IN PMMADDRESS_NODE NewNode,
118 IN PMMADDRESS_NODE Parent,
119 IN TABLE_SEARCH_RESULT Result)
120 {
121 PMMVAD_LONG Vad;
122
123 /* Insert it into the tree */
124 RtlpInsertAvlTreeNode(Table, NewNode, Parent, Result);
125
126 /* Now insert an ARM3 MEMORY_AREA for this node, unless the insert was already from the MEMORY_AREA code */
127 Vad = (PMMVAD_LONG)NewNode;
128 if (Vad->u.VadFlags.Spare == 0)
129 {
130 NTSTATUS Status;
131 PMEMORY_AREA MemoryArea;
132 PHYSICAL_ADDRESS BoundaryAddressMultiple;
133 SIZE_T Size;
134 PEPROCESS Process = CONTAINING_RECORD(Table, EPROCESS, VadRoot);
135 PVOID AllocatedBase = (PVOID)(Vad->StartingVpn << PAGE_SHIFT);
136 BoundaryAddressMultiple.QuadPart = 0;
137 Size = ((Vad->EndingVpn + 1) - Vad->StartingVpn) << PAGE_SHIFT;
138 Status = MmCreateMemoryArea(&Process->Vm,
139 MEMORY_AREA_OWNED_BY_ARM3,
140 &AllocatedBase,
141 Size,
142 PAGE_READWRITE,
143 &MemoryArea,
144 TRUE,
145 0,
146 BoundaryAddressMultiple);
147 ASSERT(NT_SUCCESS(Status));
148
149 /* Check if this is VM VAD */
150 if (Vad->ControlArea == NULL)
151 {
152 /* We store the reactos MEMORY_AREA here */
153 Vad->FirstPrototypePte = (PMMPTE)MemoryArea;
154 }
155 else
156 {
157 /* This is a section VAD. Store the MAREA here for now */
158 ASSERT(Vad->u4.Banked == (PVOID)0xDEADBABE);
159 Vad->u4.Banked = (PVOID)MemoryArea;
160 }
161 }
162 }
163
164 VOID
165 NTAPI
166 MiInsertVad(IN PMMVAD Vad,
167 IN PEPROCESS Process)
168 {
169 TABLE_SEARCH_RESULT Result;
170 PMMADDRESS_NODE Parent = NULL;
171
172 /* Validate the VAD and set it as the current hint */
173 ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
174 Process->VadRoot.NodeHint = Vad;
175
176 /* Find the parent VAD and where this child should be inserted */
177 Result = RtlpFindAvlTableNodeOrParent(&Process->VadRoot, (PVOID)Vad->StartingVpn, &Parent);
178 ASSERT(Result != TableFoundNode);
179 ASSERT((Parent != NULL) || (Result == TableEmptyTree));
180
181 /* Do the actual insert operation */
182 MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
183 }
184
185 VOID
186 NTAPI
187 MiInsertBasedSection(IN PSECTION Section)
188 {
189 TABLE_SEARCH_RESULT Result;
190 PMMADDRESS_NODE Parent = NULL;
191 ASSERT(Section->Address.EndingVpn >= Section->Address.StartingVpn);
192
193 /* Find the parent VAD and where this child should be inserted */
194 Result = RtlpFindAvlTableNodeOrParent(&MmSectionBasedRoot, (PVOID)Section->Address.StartingVpn, &Parent);
195 ASSERT(Result != TableFoundNode);
196 ASSERT((Parent != NULL) || (Result == TableEmptyTree));
197 MiInsertNode(&MmSectionBasedRoot, &Section->Address, Parent, Result);
198 }
199
200 VOID
201 NTAPI
202 MiRemoveNode(IN PMMADDRESS_NODE Node,
203 IN PMM_AVL_TABLE Table)
204 {
205 PMMVAD_LONG Vad;
206
207 /* Call the AVL code */
208 RtlpDeleteAvlTreeNode(Table, Node);
209
210 /* Decrease element count */
211 Table->NumberGenericTableElements--;
212
213 /* Check if this node was the hint */
214 if (Table->NodeHint == Node)
215 {
216 /* Get a new hint, unless we're empty now, in which case nothing */
217 if (!Table->NumberGenericTableElements) Table->NodeHint = NULL;
218 else Table->NodeHint = Table->BalancedRoot.RightChild;
219 }
220
221 /* Free the node from ReactOS view as well */
222 Vad = (PMMVAD_LONG)Node;
223 if (Vad->u.VadFlags.Spare == 0)
224 {
225 PMEMORY_AREA MemoryArea;
226 PEPROCESS Process;
227
228 /* Check if this is VM VAD */
229 if (Vad->ControlArea == NULL)
230 {
231 /* We store the ReactOS MEMORY_AREA here */
232 MemoryArea = (PMEMORY_AREA)Vad->FirstPrototypePte;
233 }
234 else
235 {
236 /* This is a section VAD. We store the ReactOS MEMORY_AREA here */
237 MemoryArea = (PMEMORY_AREA)Vad->u4.Banked;
238 }
239
240 /* Make sure one actually still exists */
241 if (MemoryArea)
242 {
243 /* Make sure we have not already freed it */
244 ASSERT(MemoryArea != (PVOID)0xDEADBAB1);
245
246 /* Get the process */
247 Process = CONTAINING_RECORD(Table, EPROCESS, VadRoot);
248
249 /* We only create fake memory-areas for ARM3 VADs */
250 ASSERT(MemoryArea->Type == MEMORY_AREA_OWNED_BY_ARM3);
251 ASSERT(MemoryArea->Vad == NULL);
252
253 /* Free it */
254 MmFreeMemoryArea(&Process->Vm, MemoryArea, NULL, NULL);
255
256 /* Check if this is VM VAD */
257 if (Vad->ControlArea == NULL)
258 {
259 /* Delete the pointer to it */
260 Vad->FirstPrototypePte = (PVOID)0xDEADBAB1;
261 }
262 else
263 {
264 /* Delete the pointer to it */
265 Vad->u4.Banked = (PVOID)0xDEADBAB1;
266 }
267 }
268 }
269 }
270
271 PMMADDRESS_NODE
272 NTAPI
273 MiGetPreviousNode(IN PMMADDRESS_NODE Node)
274 {
275 PMMADDRESS_NODE Parent;
276
277 /* Get the left child */
278 if (RtlLeftChildAvl(Node))
279 {
280 /* Get right-most child */
281 Node = RtlLeftChildAvl(Node);
282 while (RtlRightChildAvl(Node)) Node = RtlRightChildAvl(Node);
283 return Node;
284 }
285
286 Parent = RtlParentAvl(Node);
287 ASSERT(Parent != NULL);
288 while (Parent != Node)
289 {
290 /* The parent should be a right child, return the real predecessor */
291 if (RtlIsRightChildAvl(Node))
292 {
293 /* Return it unless it's the root */
294 if (Parent == RtlParentAvl(Parent)) Parent = NULL;
295 return Parent;
296 }
297
298 /* Keep lopping until we find our parent */
299 Node = Parent;
300 Parent = RtlParentAvl(Node);
301 }
302
303 /* Nothing found */
304 return NULL;
305 }
306
307 PMMADDRESS_NODE
308 NTAPI
309 MiGetNextNode(IN PMMADDRESS_NODE Node)
310 {
311 PMMADDRESS_NODE Parent;
312
313 /* Get the right child */
314 if (RtlRightChildAvl(Node))
315 {
316 /* Get left-most child */
317 Node = RtlRightChildAvl(Node);
318 while (RtlLeftChildAvl(Node)) Node = RtlLeftChildAvl(Node);
319 return Node;
320 }
321
322 Parent = RtlParentAvl(Node);
323 ASSERT(Parent != NULL);
324 while (Parent != Node)
325 {
326 /* The parent should be a left child, return the real predecessor */
327 if (RtlIsLeftChildAvl(Node))
328 {
329 /* Return it */
330 return Parent;
331 }
332
333 /* Keep lopping until we find our parent */
334 Node = Parent;
335 Parent = RtlParentAvl(Node);
336 }
337
338 /* Nothing found */
339 return NULL;
340 }
341
342 NTSTATUS
343 NTAPI
344 MiFindEmptyAddressRangeInTree(IN SIZE_T Length,
345 IN ULONG_PTR Alignment,
346 IN PMM_AVL_TABLE Table,
347 OUT PMMADDRESS_NODE *PreviousVad,
348 OUT PULONG_PTR Base)
349 {
350 PMMADDRESS_NODE Node;
351 PMMADDRESS_NODE NextNode;
352 ULONG_PTR StartingVpn, HighestVpn, AlignmentVpn, LengthVpn, LowVpn;
353 ASSERT(Length != 0);
354
355 /* Precompute page numbers for the length, alignment, and starting address */
356 LengthVpn = (Length + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
357 AlignmentVpn = Alignment >> PAGE_SHIFT;
358 StartingVpn = ROUND_UP((ULONG_PTR)MM_LOWEST_USER_ADDRESS >> PAGE_SHIFT,
359 AlignmentVpn);
360
361 /* Check if the table is free, so the lowest possible address is available */
362 if (!Table->NumberGenericTableElements) goto FoundAtBottom;
363
364 /* Otherwise, follow the leftmost child of the right root node's child */
365 Node = RtlRightChildAvl(&Table->BalancedRoot);
366 while (RtlLeftChildAvl(Node)) Node = RtlLeftChildAvl(Node);
367
368 /* This is the node for the remaining gap at the bottom, can it be used? */
369 if ((Node->StartingVpn > StartingVpn) &&
370 (LengthVpn < Node->StartingVpn - StartingVpn))
371 {
372 FoundAtBottom:
373 /* Use this VAD to store the allocation */
374 *PreviousVad = NULL;
375 *Base = StartingVpn << PAGE_SHIFT;
376 return STATUS_SUCCESS;
377 }
378
379 /* Otherwise, we start a search to find a gap */
380 while (TRUE)
381 {
382 /* The last aligned page number in this entry */
383 LowVpn = ROUND_UP(Node->EndingVpn + 1, AlignmentVpn);
384
385 /* Keep going as long as there's still a next node */
386 NextNode = MiGetNextNode(Node);
387 if (!NextNode) break;
388
389 /* Can this allocation fit in this node? */
390 if ((LengthVpn <= (NextNode->StartingVpn - LowVpn)) &&
391 (NextNode->StartingVpn > LowVpn))
392 {
393 Found:
394 /* Yes! Use this VAD to store the allocation */
395 *PreviousVad = Node;
396 *Base = ROUND_UP((Node->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1),
397 Alignment);
398 return STATUS_SUCCESS;
399 }
400
401 /* Try the next node */
402 Node = NextNode;
403 }
404
405 /* We're down to the last (top) VAD, will this allocation fit inside it? */
406 HighestVpn = ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) >> PAGE_SHIFT;
407 if ((HighestVpn > LowVpn) && (LengthVpn <= HighestVpn - LowVpn)) goto Found;
408
409 /* Nyet, there's no free address space for this allocation, so we'll fail */
410 return STATUS_NO_MEMORY;
411 }
412
413 TABLE_SEARCH_RESULT
414 NTAPI
415 MiFindEmptyAddressRangeDownTree(IN SIZE_T Length,
416 IN ULONG_PTR BoundaryAddress,
417 IN ULONG_PTR Alignment,
418 IN PMM_AVL_TABLE Table,
419 OUT PULONG_PTR Base,
420 OUT PMMADDRESS_NODE *Parent)
421 {
422 PMMADDRESS_NODE Node, LowestNode, Child;
423 ULONG_PTR LowVpn, HighVpn;
424 PFN_NUMBER PageCount;
425
426 /* Sanity checks */
427 ASSERT(BoundaryAddress);
428 ASSERT(BoundaryAddress <= ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
429
430 /* Compute page length, make sure the boundary address is valid */
431 Length = ROUND_TO_PAGES(Length);
432 PageCount = Length >> PAGE_SHIFT;
433 if ((BoundaryAddress + 1) < Length) return TableFoundNode;
434
435 /* Check if the table is empty */
436 if (Table->NumberGenericTableElements == 0)
437 {
438 /* Tree is empty, the candidate address is already the best one */
439 *Base = ROUND_UP(BoundaryAddress + 1 - Length, Alignment);
440 return TableEmptyTree;
441 }
442
443 /* Calculate the initial upper margin */
444 HighVpn = BoundaryAddress >> PAGE_SHIFT;
445
446 /* Starting from the root, go down until the right-most child
447 * which is just behind the boundary*/
448 LowestNode = Node = RtlRightChildAvl(&Table->BalancedRoot);
449 while (((Child = RtlRightChildAvl(Node)) != 0 )
450 && (Node->EndingVpn < HighVpn )) Node = Child;
451
452 /* Now loop the Vad nodes */
453 while (Node)
454 {
455 /* Keep track of the lowest node */
456 LowestNode = Node;
457
458 /* Calculate the lower margin */
459 LowVpn = ROUND_UP(Node->EndingVpn + 1, Alignment >> PAGE_SHIFT);
460
461 /* Check if the current bounds are suitable */
462 if ((HighVpn > LowVpn) && ((HighVpn - LowVpn) >= PageCount))
463 {
464 /* There is enough space to add our node */
465 LowVpn = HighVpn - PageCount;
466 *Base = LowVpn << PAGE_SHIFT;
467
468 /* Can we use the current node as parent? */
469 Child = RtlRightChildAvl(Node);
470 if (!Child)
471 {
472 /* Node has no right child, so use it as parent */
473 *Parent = Node;
474 return TableInsertAsRight;
475 }
476 else
477 {
478 /* Node has a right child, find most left grand child */
479 Node = Child;
480 while ((Child = RtlLeftChildAvl(Node))) Node = Child;
481 *Parent = Node;
482 return TableInsertAsLeft;
483 }
484 }
485
486 /* Update the upper margin if neccessary */
487 if (Node->StartingVpn < HighVpn) HighVpn = Node->StartingVpn;
488
489 /* Go to the next lower node */
490 Node = MiGetPreviousNode(Node);
491 }
492
493 /* Check if there's enough space before the lowest Vad */
494 LowVpn = ROUND_UP((ULONG_PTR)MI_LOWEST_VAD_ADDRESS, Alignment) >> PAGE_SHIFT;
495 if ((HighVpn > LowVpn) && ((HighVpn - LowVpn) >= PageCount))
496 {
497 /* There is enough space to add our address */
498 LowVpn = HighVpn - PageCount;
499 *Base = LowVpn << PAGE_SHIFT;
500 *Parent = LowestNode;
501 return TableInsertAsLeft;
502 }
503
504 /* No address space left at all */
505 *Base = 0;
506 *Parent = NULL;
507 return TableFoundNode;
508 }
509
510 NTSTATUS
511 NTAPI
512 MiFindEmptyAddressRangeDownBasedTree(IN SIZE_T Length,
513 IN ULONG_PTR BoundaryAddress,
514 IN ULONG_PTR Alignment,
515 IN PMM_AVL_TABLE Table,
516 OUT PULONG_PTR Base)
517 {
518 PMMADDRESS_NODE Node, LowestNode;
519 ULONG_PTR LowVpn, BestVpn;
520
521 /* Sanity checks */
522 ASSERT(Table == &MmSectionBasedRoot);
523 ASSERT(BoundaryAddress);
524 ASSERT(BoundaryAddress <= ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
525
526 /* Compute page length, make sure the boundary address is valid */
527 Length = ROUND_TO_PAGES(Length);
528 if ((BoundaryAddress + 1) < Length) return STATUS_NO_MEMORY;
529
530 /* Check if the table is empty */
531 BestVpn = ROUND_UP(BoundaryAddress + 1 - Length, Alignment);
532 if (Table->NumberGenericTableElements == 0)
533 {
534 /* Tree is empty, the candidate address is already the best one */
535 *Base = BestVpn;
536 return STATUS_SUCCESS;
537 }
538
539 /* Go to the right-most node which should be the biggest address */
540 Node = Table->BalancedRoot.RightChild;
541 while (RtlRightChildAvl(Node)) Node = RtlRightChildAvl(Node);
542
543 /* Check if we can fit in here */
544 LowVpn = ROUND_UP(Node->EndingVpn, Alignment);
545 if ((LowVpn < BoundaryAddress) && (Length < (BoundaryAddress - LowVpn)))
546 {
547 /* Return the address */
548 *Base = ROUND_UP(BoundaryAddress - Length, Alignment);
549 return STATUS_SUCCESS;
550 }
551
552 /* Now loop the Vad nodes */
553 do
554 {
555 /* Break out if we've reached the last node */
556 LowestNode = MiGetPreviousNode(Node);
557 if (!LowestNode) break;
558
559 /* Check if this node could contain the requested address */
560 LowVpn = ROUND_UP(LowestNode->EndingVpn + 1, Alignment);
561 if ((LowestNode->EndingVpn < BestVpn) &&
562 (Length <= (Node->StartingVpn - LowVpn)))
563 {
564 /* Check if it fits in perfectly */
565 if ((BestVpn > LowestNode->EndingVpn) &&
566 (BoundaryAddress < Node->StartingVpn))
567 {
568 /* Return the optimal VPN address */
569 *Base = BestVpn;
570 return STATUS_SUCCESS;
571 }
572
573 /* It doesn't, check if it can partly fit */
574 if (Node->StartingVpn > LowVpn)
575 {
576 /* Return an aligned base address within this node */
577 *Base = ROUND_UP(Node->StartingVpn - Length, Alignment);
578 return STATUS_SUCCESS;
579 }
580 }
581
582 /* Move to the next node */
583 Node = LowestNode;
584 } while (TRUE);
585
586 /* Check if there's enough space before the lowest Vad */
587 if ((Node->StartingVpn > (ULONG_PTR)MI_LOWEST_VAD_ADDRESS) &&
588 ((Node->StartingVpn - (ULONG_PTR)MI_LOWEST_VAD_ADDRESS) > Length))
589 {
590 /* Check if it fits in perfectly */
591 if (BoundaryAddress < Node->StartingVpn)
592 {
593 /* Return the optimal VPN address */
594 *Base = BestVpn;
595 return STATUS_SUCCESS;
596 }
597
598 /* Return an aligned base address within this node */
599 *Base = ROUND_UP(Node->StartingVpn - Length, Alignment);
600 return STATUS_SUCCESS;
601 }
602
603 /* No address space left at all */
604 return STATUS_NO_MEMORY;
605 }
606
607 NTSTATUS
608 NTAPI
609 MiCheckSecuredVad(IN PMMVAD Vad,
610 IN PVOID Base,
611 IN SIZE_T Size,
612 IN ULONG ProtectionMask)
613 {
614 ULONG_PTR StartAddress, EndAddress;
615
616 /* Compute start and end address */
617 StartAddress = (ULONG_PTR)Base;
618 EndAddress = StartAddress + Size - 1;
619
620 /* Are we deleting/unmapping, or changing? */
621 if (ProtectionMask < MM_DELETE_CHECK)
622 {
623 /* Changing... are we allowed to do so? */
624 if ((Vad->u.VadFlags.NoChange == 1) &&
625 (Vad->u2.VadFlags2.SecNoChange == 1) &&
626 (Vad->u.VadFlags.Protection != ProtectionMask))
627 {
628 /* Nope, bail out */
629 DPRINT1("Trying to mess with a no-change VAD!\n");
630 return STATUS_INVALID_PAGE_PROTECTION;
631 }
632 }
633 else
634 {
635 /* This is allowed */
636 ProtectionMask = 0;
637 }
638
639 /* ARM3 doesn't support this yet */
640 ASSERT(Vad->u2.VadFlags2.MultipleSecured == 0);
641
642 /* Is this a one-secured VAD, like a TEB or PEB? */
643 if (Vad->u2.VadFlags2.OneSecured)
644 {
645 /* Is this allocation being described by the VAD? */
646 if ((StartAddress <= ((PMMVAD_LONG)Vad)->u3.Secured.EndVpn) &&
647 (EndAddress >= ((PMMVAD_LONG)Vad)->u3.Secured.StartVpn))
648 {
649 /* Guard page? */
650 if (ProtectionMask && MM_DECOMMIT)
651 {
652 DPRINT1("Not allowed to change protection on guard page!\n");
653 return STATUS_INVALID_PAGE_PROTECTION;
654 }
655
656 /* ARM3 doesn't have read-only VADs yet */
657 ASSERT(Vad->u2.VadFlags2.ReadOnly == 0);
658
659 /* Check if read-write protections are allowed */
660 if (MmReadWrite[ProtectionMask] < MM_READ_WRITE_ALLOWED)
661 {
662 DPRINT1("Invalid protection mask for RW access!\n");
663 return STATUS_INVALID_PAGE_PROTECTION;
664 }
665 }
666 }
667
668 /* All good, allow the change */
669 return STATUS_SUCCESS;
670 }
671
672 /* EOF */