sync with trunk (r49238)
[reactos.git] / ntoskrnl / mm / ARM3 / section.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/sectopm.c
5 * PURPOSE: ARM Memory Manager Section Support
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #line 15 "ARMĀ³::SECTION"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
18
19 /* GLOBALS ********************************************************************/
20
21 ACCESS_MASK MmMakeSectionAccess[8] =
22 {
23 SECTION_MAP_READ,
24 SECTION_MAP_READ,
25 SECTION_MAP_EXECUTE,
26 SECTION_MAP_EXECUTE | SECTION_MAP_READ,
27 SECTION_MAP_WRITE,
28 SECTION_MAP_READ,
29 SECTION_MAP_EXECUTE | SECTION_MAP_WRITE,
30 SECTION_MAP_EXECUTE | SECTION_MAP_READ
31 };
32
33 CHAR MmUserProtectionToMask1[16] =
34 {
35 0,
36 MM_NOACCESS,
37 MM_READONLY,
38 (CHAR)MM_INVALID_PROTECTION,
39 MM_READWRITE,
40 (CHAR)MM_INVALID_PROTECTION,
41 (CHAR)MM_INVALID_PROTECTION,
42 (CHAR)MM_INVALID_PROTECTION,
43 MM_WRITECOPY,
44 (CHAR)MM_INVALID_PROTECTION,
45 (CHAR)MM_INVALID_PROTECTION,
46 (CHAR)MM_INVALID_PROTECTION,
47 (CHAR)MM_INVALID_PROTECTION,
48 (CHAR)MM_INVALID_PROTECTION,
49 (CHAR)MM_INVALID_PROTECTION,
50 (CHAR)MM_INVALID_PROTECTION
51 };
52
53 CHAR MmUserProtectionToMask2[16] =
54 {
55 0,
56 MM_EXECUTE,
57 MM_EXECUTE_READ,
58 (CHAR)MM_INVALID_PROTECTION,
59 MM_EXECUTE_READWRITE,
60 (CHAR)MM_INVALID_PROTECTION,
61 (CHAR)MM_INVALID_PROTECTION,
62 (CHAR)MM_INVALID_PROTECTION,
63 MM_EXECUTE_WRITECOPY,
64 (CHAR)MM_INVALID_PROTECTION,
65 (CHAR)MM_INVALID_PROTECTION,
66 (CHAR)MM_INVALID_PROTECTION,
67 (CHAR)MM_INVALID_PROTECTION,
68 (CHAR)MM_INVALID_PROTECTION,
69 (CHAR)MM_INVALID_PROTECTION,
70 (CHAR)MM_INVALID_PROTECTION
71 };
72
73 MMSESSION MmSession;
74
75 /* PRIVATE FUNCTIONS **********************************************************/
76
77 ULONG
78 NTAPI
79 MiMakeProtectionMask(IN ULONG Protect)
80 {
81 ULONG Mask1, Mask2, ProtectMask;
82
83 /* PAGE_EXECUTE_WRITECOMBINE is theoretically the maximum */
84 if (Protect >= (PAGE_WRITECOMBINE * 2)) return MM_INVALID_PROTECTION;
85
86 /*
87 * Windows API protection mask can be understood as two bitfields, differing
88 * by whether or not execute rights are being requested
89 */
90 Mask1 = Protect & 0xF;
91 Mask2 = (Protect >> 4) & 0xF;
92
93 /* Check which field is there */
94 if (!Mask1)
95 {
96 /* Mask2 must be there, use it to determine the PTE protection */
97 if (!Mask2) return MM_INVALID_PROTECTION;
98 ProtectMask = MmUserProtectionToMask2[Mask2];
99 }
100 else
101 {
102 /* Mask2 should not be there, use Mask1 to determine the PTE mask */
103 if (Mask2) return MM_INVALID_PROTECTION;
104 ProtectMask = MmUserProtectionToMask1[Mask1];
105 }
106
107 /* Make sure the final mask is a valid one */
108 if (ProtectMask == MM_INVALID_PROTECTION) return MM_INVALID_PROTECTION;
109
110 /* Check for PAGE_GUARD option */
111 if (Protect & PAGE_GUARD)
112 {
113 /* It's not valid on no-access, nocache, or writecombine pages */
114 if ((ProtectMask == MM_NOACCESS) ||
115 (Protect & (PAGE_NOCACHE | PAGE_WRITECOMBINE)))
116 {
117 /* Fail such requests */
118 return MM_INVALID_PROTECTION;
119 }
120
121 /* This actually turns on guard page in this scenario! */
122 ProtectMask |= MM_DECOMMIT;
123 }
124
125 /* Check for nocache option */
126 if (Protect & PAGE_NOCACHE)
127 {
128 /* The earlier check should've eliminated this possibility */
129 ASSERT((Protect & PAGE_GUARD) == 0);
130
131 /* Check for no-access page or write combine page */
132 if ((ProtectMask == MM_NOACCESS) || (Protect & PAGE_WRITECOMBINE))
133 {
134 /* Such a request is invalid */
135 return MM_INVALID_PROTECTION;
136 }
137
138 /* Add the PTE flag */
139 ProtectMask |= MM_NOCACHE;
140 }
141
142 /* Check for write combine option */
143 if (Protect & PAGE_WRITECOMBINE)
144 {
145 /* The two earlier scenarios should've caught this */
146 ASSERT((Protect & (PAGE_GUARD | PAGE_NOACCESS)) == 0);
147
148 /* Don't allow on no-access pages */
149 if (ProtectMask == MM_NOACCESS) return MM_INVALID_PROTECTION;
150
151 /* This actually turns on write-combine in this scenario! */
152 ProtectMask |= MM_NOACCESS;
153 }
154
155 /* Return the final MM PTE protection mask */
156 return ProtectMask;
157 }
158
159 BOOLEAN
160 NTAPI
161 MiInitializeSystemSpaceMap(IN PVOID InputSession OPTIONAL)
162 {
163 SIZE_T AllocSize, BitmapSize;
164 PMMSESSION Session;
165
166 /* For now, always use the global session */
167 ASSERT(InputSession == NULL);
168 Session = &MmSession;
169
170 /* Initialize the system space lock */
171 Session->SystemSpaceViewLockPointer = &Session->SystemSpaceViewLock;
172 KeInitializeGuardedMutex(Session->SystemSpaceViewLockPointer);
173
174 /* Set the start address */
175 Session->SystemSpaceViewStart = MiSystemViewStart;
176
177 /* Create a bitmap to describe system space */
178 BitmapSize = sizeof(RTL_BITMAP) + ((((MmSystemViewSize / MI_SYSTEM_VIEW_BUCKET_SIZE) + 31) / 32) * sizeof(ULONG));
179 Session->SystemSpaceBitMap = ExAllocatePoolWithTag(NonPagedPool,
180 BitmapSize,
181 ' mM');
182 ASSERT(Session->SystemSpaceBitMap);
183 RtlInitializeBitMap(Session->SystemSpaceBitMap,
184 (PULONG)(Session->SystemSpaceBitMap + 1),
185 MmSystemViewSize / MI_SYSTEM_VIEW_BUCKET_SIZE);
186
187 /* Set system space fully empty to begin with */
188 RtlClearAllBits(Session->SystemSpaceBitMap);
189
190 /* Set default hash flags */
191 Session->SystemSpaceHashSize = 31;
192 Session->SystemSpaceHashKey = Session->SystemSpaceHashSize - 1;
193 Session->SystemSpaceHashEntries = 0;
194
195 /* Calculate how much space for the hash views we'll need */
196 AllocSize = sizeof(MMVIEW) * Session->SystemSpaceHashSize;
197 ASSERT(AllocSize < PAGE_SIZE);
198
199 /* Allocate and zero the view table */
200 Session->SystemSpaceViewTable = ExAllocatePoolWithTag(NonPagedPool,
201 AllocSize,
202 ' mM');
203 ASSERT(Session->SystemSpaceViewTable != NULL);
204 RtlZeroMemory(Session->SystemSpaceViewTable, AllocSize);
205
206 /* Success */
207 return TRUE;
208 }
209
210 PVOID
211 NTAPI
212 MiInsertInSystemSpace(IN PMMSESSION Session,
213 IN ULONG Buckets,
214 IN PCONTROL_AREA ControlArea)
215 {
216 PVOID Base;
217 ULONG Entry, Hash, i;
218 PAGED_CODE();
219
220 /* Only global mappings supported for now */
221 ASSERT(Session == &MmSession);
222
223 /* Stay within 4GB and don't go past the number of hash entries available */
224 ASSERT(Buckets < MI_SYSTEM_VIEW_BUCKET_SIZE);
225 ASSERT(Session->SystemSpaceHashEntries < Session->SystemSpaceHashSize);
226
227 /* Find space where to map this view */
228 i = RtlFindClearBitsAndSet(Session->SystemSpaceBitMap, Buckets, 0);
229 ASSERT(i != 0xFFFFFFFF);
230 Base = (PVOID)((ULONG_PTR)Session->SystemSpaceViewStart + (i * MI_SYSTEM_VIEW_BUCKET_SIZE));
231
232 /* Get the hash entry for this allocation */
233 Entry = ((ULONG_PTR)Base & ~(MI_SYSTEM_VIEW_BUCKET_SIZE - 1)) + Buckets;
234 Hash = (Entry >> 16) % Session->SystemSpaceHashKey;
235
236 /* Loop hash entries until a free one is found */
237 while (Session->SystemSpaceViewTable[Hash].Entry)
238 {
239 /* Unless we overflow, in which case loop back at hash o */
240 if (++Hash >= Session->SystemSpaceHashSize) Hash = 0;
241 }
242
243 /* Add this entry into the hash table */
244 Session->SystemSpaceViewTable[Hash].Entry = Entry;
245 Session->SystemSpaceViewTable[Hash].ControlArea = ControlArea;
246
247 /* Hash entry found, increment total and return the base address */
248 Session->SystemSpaceHashEntries++;
249 return Base;
250 }
251
252 NTSTATUS
253 NTAPI
254 MiAddMappedPtes(IN PMMPTE FirstPte,
255 IN PFN_NUMBER PteCount,
256 IN PCONTROL_AREA ControlArea)
257 {
258 MMPTE TempPte;
259 PMMPTE PointerPte, ProtoPte, LastProtoPte, LastPte;
260 PSUBSECTION Subsection;
261
262 /* ARM3 doesn't support this yet */
263 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
264 ASSERT(ControlArea->u.Flags.Rom == 0);
265 ASSERT(ControlArea->FilePointer == NULL);
266
267 /* Sanity checks */
268 ASSERT(PteCount != 0);
269 ASSERT(ControlArea->NumberOfMappedViews >= 1);
270 ASSERT(ControlArea->NumberOfUserReferences >= 1);
271 ASSERT(ControlArea->NumberOfSectionReferences != 0);
272 ASSERT(ControlArea->u.Flags.BeingCreated == 0);
273 ASSERT(ControlArea->u.Flags.BeingDeleted == 0);
274 ASSERT(ControlArea->u.Flags.BeingPurged == 0);
275
276 /* Get the PTEs for the actual mapping */
277 PointerPte = FirstPte;
278 LastPte = FirstPte + PteCount;
279
280 /* Get the prototype PTEs that desribe the section mapping in the subsection */
281 Subsection = (PSUBSECTION)(ControlArea + 1);
282 ProtoPte = Subsection->SubsectionBase;
283 LastProtoPte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
284
285 /* Loop the PTEs for the mapping */
286 while (PointerPte < LastPte)
287 {
288 /* We may have run out of prototype PTEs in this subsection */
289 if (ProtoPte >= LastProtoPte)
290 {
291 /* But we don't handle this yet */
292 UNIMPLEMENTED;
293 while (TRUE);
294 }
295
296 /* The PTE should be completely clear */
297 ASSERT(PointerPte->u.Long == 0);
298
299 /* Build the prototype PTE and write it */
300 MI_MAKE_PROTOTYPE_PTE(&TempPte, ProtoPte);
301 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
302
303 /* Keep going */
304 PointerPte++;
305 ProtoPte++;
306 }
307
308 /* No failure path */
309 return STATUS_SUCCESS;
310 }
311
312 #if (_MI_PAGING_LEVELS == 2)
313 VOID
314 NTAPI
315 MiFillSystemPageDirectory(IN PVOID Base,
316 IN SIZE_T NumberOfBytes)
317 {
318 PMMPDE PointerPde, LastPde, SystemMapPde;
319 MMPDE TempPde;
320 PFN_NUMBER PageFrameIndex;
321 KIRQL OldIrql;
322 PAGED_CODE();
323
324 /* Find the PDEs needed for this mapping */
325 PointerPde = MiAddressToPde(Base);
326 LastPde = MiAddressToPde((PVOID)((ULONG_PTR)Base + NumberOfBytes - 1));
327
328 /* Find the system double-mapped PDE that describes this mapping */
329 SystemMapPde = &MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)];
330
331 /* Use the PDE template and loop the PDEs */
332 TempPde = ValidKernelPde;
333 while (PointerPde <= LastPde)
334 {
335 /* Lock the PFN database */
336 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
337
338 /* Check if we don't already have this PDE mapped */
339 if (SystemMapPde->u.Hard.Valid == 0)
340 {
341 /* Grab a page for it */
342 PageFrameIndex = MiRemoveZeroPage(MI_GET_NEXT_COLOR());
343 ASSERT(PageFrameIndex);
344 TempPde.u.Hard.PageFrameNumber = PageFrameIndex;
345
346 /* Initialize its PFN entry, with the parent system page directory page table */
347 MiInitializePfnForOtherProcess(PageFrameIndex,
348 PointerPde,
349 MmSystemPageDirectory[(PointerPde - MiAddressToPde(NULL)) / PDE_COUNT]);
350
351 /* Make the system PDE entry valid */
352 MI_WRITE_VALID_PTE(SystemMapPde, TempPde);
353
354 /* The system PDE entry might be the PDE itself, so check for this */
355 if (PointerPde->u.Hard.Valid == 0)
356 {
357 /* It's different, so make the real PDE valid too */
358 MI_WRITE_VALID_PTE(PointerPde, TempPde);
359 }
360 }
361
362 /* Release the lock and keep going with the next PDE */
363 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
364 SystemMapPde++;
365 PointerPde++;
366 }
367 }
368 #endif
369
370 NTSTATUS
371 NTAPI
372 MiCheckPurgeAndUpMapCount(IN PCONTROL_AREA ControlArea,
373 IN BOOLEAN FailIfSystemViews)
374 {
375 KIRQL OldIrql;
376
377 /* Flag not yet supported */
378 ASSERT(FailIfSystemViews == FALSE);
379
380 /* Lock the PFN database */
381 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
382
383 /* State not yet supported */
384 ASSERT(ControlArea->u.Flags.BeingPurged == 0);
385
386 /* Increase the reference counts */
387 ControlArea->NumberOfMappedViews++;
388 ControlArea->NumberOfUserReferences++;
389 ASSERT(ControlArea->NumberOfSectionReferences != 0);
390
391 /* Release the PFN lock and return success */
392 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
393 return STATUS_SUCCESS;
394 }
395
396 PSUBSECTION
397 NTAPI
398 MiLocateSubsection(IN PMMVAD Vad,
399 IN ULONG_PTR Vpn)
400 {
401 PSUBSECTION Subsection;
402 PCONTROL_AREA ControlArea;
403 ULONG PteOffset;
404
405 /* Get the control area */
406 ControlArea = Vad->ControlArea;
407 ASSERT(ControlArea->u.Flags.Rom == 0);
408 ASSERT(ControlArea->u.Flags.Image == 0);
409 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
410
411 /* Get the subsection */
412 Subsection = (PSUBSECTION)(ControlArea + 1);
413
414 /* We only support single-subsection segments */
415 ASSERT(Subsection->SubsectionBase != NULL);
416 ASSERT(Vad->FirstPrototypePte >= Subsection->SubsectionBase);
417 ASSERT(Vad->FirstPrototypePte < &Subsection->SubsectionBase[Subsection->PtesInSubsection]);
418
419 /* Compute the PTE offset */
420 PteOffset = (ULONG_PTR)Vpn - Vad->StartingVpn;
421 PteOffset += Vad->FirstPrototypePte - Subsection->SubsectionBase;
422
423 /* Again, we only support single-subsection segments */
424 ASSERT(PteOffset < 0xF0000000);
425 ASSERT(PteOffset < Subsection->PtesInSubsection);
426
427 /* Return the subsection */
428 return Subsection;
429 }
430
431 VOID
432 NTAPI
433 MiSegmentDelete(IN PSEGMENT Segment)
434 {
435 PCONTROL_AREA ControlArea;
436 SEGMENT_FLAGS SegmentFlags;
437 PSUBSECTION Subsection;
438 PMMPTE PointerPte, LastPte, PteForProto;
439 MMPTE TempPte;
440 KIRQL OldIrql;
441
442 /* Capture data */
443 SegmentFlags = Segment->SegmentFlags;
444 ControlArea = Segment->ControlArea;
445
446 /* Make sure control area is on the right delete path */
447 ASSERT(ControlArea->u.Flags.BeingDeleted == 1);
448 ASSERT(ControlArea->WritableUserReferences == 0);
449
450 /* These things are not supported yet */
451 ASSERT(ControlArea->DereferenceList.Flink == NULL);
452 ASSERT(!(ControlArea->u.Flags.Image) & !(ControlArea->u.Flags.File));
453 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
454 ASSERT(ControlArea->u.Flags.Rom == 0);
455
456 /* Get the subsection and PTEs for this segment */
457 Subsection = (PSUBSECTION)(ControlArea + 1);
458 PointerPte = Subsection->SubsectionBase;
459 LastPte = PointerPte + Segment->NonExtendedPtes;
460
461 /* Lock the PFN database */
462 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
463
464 /* Check if the master PTE is invalid */
465 PteForProto = MiAddressToPte(PointerPte);
466 if (!PteForProto->u.Hard.Valid)
467 {
468 /* Fault it in */
469 MiMakeSystemAddressValidPfn(PointerPte, OldIrql);
470 }
471
472 /* Loop all the segment PTEs */
473 while (PointerPte < LastPte)
474 {
475 /* Check if it's time to switch master PTEs if we passed a PDE boundary */
476 if (!((ULONG_PTR)PointerPte & (PD_SIZE - 1)) &&
477 (PointerPte != Subsection->SubsectionBase))
478 {
479 /* Check if the master PTE is invalid */
480 PteForProto = MiAddressToPte(PointerPte);
481 if (!PteForProto->u.Hard.Valid)
482 {
483 /* Fault it in */
484 MiMakeSystemAddressValidPfn(PointerPte, OldIrql);
485 }
486 }
487
488 /* This should be a prototype PTE */
489 TempPte = *PointerPte;
490 ASSERT(SegmentFlags.LargePages == 0);
491 ASSERT(TempPte.u.Hard.Valid == 0);
492 ASSERT(TempPte.u.Soft.Prototype == 1);
493
494 /* Zero the PTE and keep going */
495 PointerPte->u.Long = 0;
496 PointerPte++;
497 }
498
499 /* Release the PFN lock */
500 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
501
502 /* Free the structures */
503 ExFreePool(ControlArea);
504 ExFreePool(Segment);
505 }
506
507 VOID
508 NTAPI
509 MiCheckControlArea(IN PCONTROL_AREA ControlArea,
510 IN KIRQL OldIrql)
511 {
512 BOOLEAN DeleteSegment = FALSE;
513 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
514
515 /* Check if this is the last reference or view */
516 if (!(ControlArea->NumberOfMappedViews) &&
517 !(ControlArea->NumberOfSectionReferences))
518 {
519 /* There should be no more user references either */
520 ASSERT(ControlArea->NumberOfUserReferences == 0);
521
522 /* Not yet supported */
523 ASSERT(ControlArea->FilePointer == NULL);
524
525 /* The control area is being destroyed */
526 ControlArea->u.Flags.BeingDeleted = TRUE;
527 DeleteSegment = TRUE;
528 }
529
530 /* Release the PFN lock */
531 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
532
533 /* Delete the segment if needed */
534 if (DeleteSegment)
535 {
536 /* No more user write references at all */
537 ASSERT(ControlArea->WritableUserReferences == 0);
538 MiSegmentDelete(ControlArea->Segment);
539 }
540 }
541
542 VOID
543 NTAPI
544 MiRemoveMappedView(IN PEPROCESS CurrentProcess,
545 IN PMMVAD Vad)
546 {
547 KIRQL OldIrql;
548 PCONTROL_AREA ControlArea;
549
550 /* Get the control area */
551 ControlArea = Vad->ControlArea;
552
553 /* We only support non-extendable, non-image, pagefile-backed regular sections */
554 ASSERT(Vad->u.VadFlags.VadType == VadNone);
555 ASSERT(Vad->u2.VadFlags2.ExtendableFile == FALSE);
556 ASSERT(ControlArea);
557 ASSERT(ControlArea->FilePointer == NULL);
558
559 /* Delete the actual virtual memory pages */
560 MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT,
561 (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1),
562 Vad);
563
564 /* Release the working set */
565 MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
566
567 /* Lock the PFN database */
568 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
569
570 /* Remove references */
571 ControlArea->NumberOfMappedViews--;
572 ControlArea->NumberOfUserReferences--;
573
574 /* Check if it should be destroyed */
575 MiCheckControlArea(ControlArea, OldIrql);
576 }
577
578 NTSTATUS
579 NTAPI
580 MiMapViewInSystemSpace(IN PVOID Section,
581 IN PMMSESSION Session,
582 OUT PVOID *MappedBase,
583 IN OUT PSIZE_T ViewSize)
584 {
585 PVOID Base;
586 PCONTROL_AREA ControlArea;
587 ULONG Buckets, SectionSize;
588 NTSTATUS Status;
589 PAGED_CODE();
590
591 /* Only global mappings for now */
592 ASSERT(Session == &MmSession);
593
594 /* Get the control area, check for any flags ARM3 doesn't yet support */
595 ControlArea = ((PSECTION)Section)->Segment->ControlArea;
596 ASSERT(ControlArea->u.Flags.Image == 0);
597 ASSERT(ControlArea->FilePointer == NULL);
598 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
599 ASSERT(ControlArea->u.Flags.Rom == 0);
600 ASSERT(ControlArea->u.Flags.WasPurged == 0);
601
602 /* Increase the reference and map count on the control area, no purges yet */
603 Status = MiCheckPurgeAndUpMapCount(ControlArea, FALSE);
604 ASSERT(NT_SUCCESS(Status));
605
606 /* Get the section size at creation time */
607 SectionSize = ((PSECTION)Section)->SizeOfSection.LowPart;
608
609 /* If the caller didn't specify a view size, assume the whole section */
610 if (!(*ViewSize)) *ViewSize = SectionSize;
611
612 /* Check if the caller wanted a larger section than the view */
613 if (*ViewSize > SectionSize)
614 {
615 /* We should probably fail. FIXME TODO */
616 UNIMPLEMENTED;
617 while (TRUE);
618 }
619
620 /* Get the number of 64K buckets required for this mapping */
621 Buckets = *ViewSize / MI_SYSTEM_VIEW_BUCKET_SIZE;
622 if (*ViewSize & (MI_SYSTEM_VIEW_BUCKET_SIZE - 1)) Buckets++;
623
624 /* Check if the view is more than 4GB large */
625 if (Buckets >= MI_SYSTEM_VIEW_BUCKET_SIZE)
626 {
627 /* We should probably fail */
628 UNIMPLEMENTED;
629 while (TRUE);
630 }
631
632 /* Insert this view into system space and get a base address for it */
633 Base = MiInsertInSystemSpace(Session, Buckets, ControlArea);
634 ASSERT(Base);
635
636 #if (_MI_PAGING_LEVELS == 2)
637 /* Create the PDEs needed for this mapping, and double-map them if needed */
638 MiFillSystemPageDirectory(Base, Buckets * MI_SYSTEM_VIEW_BUCKET_SIZE);
639 #endif
640
641 /* Create the actual prototype PTEs for this mapping */
642 Status = MiAddMappedPtes(MiAddressToPte(Base),
643 BYTES_TO_PAGES(*ViewSize),
644 ControlArea);
645 ASSERT(NT_SUCCESS(Status));
646
647 /* Return the base adress of the mapping and success */
648 *MappedBase = Base;
649 return STATUS_SUCCESS;
650 }
651
652 NTSTATUS
653 NTAPI
654 MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
655 IN PEPROCESS Process,
656 IN PVOID *BaseAddress,
657 IN PLARGE_INTEGER SectionOffset,
658 IN PSIZE_T ViewSize,
659 IN PSECTION Section,
660 IN SECTION_INHERIT InheritDisposition,
661 IN ULONG ProtectionMask,
662 IN ULONG CommitSize,
663 IN ULONG_PTR ZeroBits,
664 IN ULONG AllocationType)
665 {
666 PMMVAD Vad;
667 PETHREAD Thread = PsGetCurrentThread();
668 ULONG_PTR StartAddress, EndingAddress;
669 PSUBSECTION Subsection;
670 PSEGMENT Segment;
671 PFN_NUMBER PteOffset;
672 NTSTATUS Status;
673
674 /* Get the segment and subection for this section */
675 Segment = ControlArea->Segment;
676 Subsection = (PSUBSECTION)(ControlArea + 1);
677
678 /* Non-pagefile-backed sections not supported */
679 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
680 ASSERT(ControlArea->u.Flags.Rom == 0);
681 ASSERT(ControlArea->FilePointer == NULL);
682 ASSERT(Segment->SegmentFlags.TotalNumberOfPtes4132 == 0);
683
684 /* Based sections not supported */
685 ASSERT(Section->Address.StartingVpn == 0);
686
687 /* These flags/parameters are not supported */
688 ASSERT((AllocationType & MEM_DOS_LIM) == 0);
689 ASSERT((AllocationType & MEM_RESERVE) == 0);
690 ASSERT(Process->VmTopDown == 0);
691 ASSERT(Section->u.Flags.CopyOnWrite == FALSE);
692 ASSERT(ZeroBits == 0);
693
694 /* First, increase the map count. No purging is supported yet */
695 Status = MiCheckPurgeAndUpMapCount(ControlArea, FALSE);
696 ASSERT(NT_SUCCESS(Status));
697
698 /* Check if the caller specified the view size */
699 if (!(*ViewSize))
700 {
701 /* The caller did not, so pick a 64K aligned view size based on the offset */
702 SectionOffset->LowPart &= ~(_64K - 1);
703 *ViewSize = Section->SizeOfSection.QuadPart - SectionOffset->QuadPart;
704 }
705 else
706 {
707 /* A size was specified, align it to a 64K boundary */
708 *ViewSize += SectionOffset->LowPart & (_64K - 1);
709
710 /* Align the offset as well to make this an aligned map */
711 SectionOffset->LowPart &= ~((ULONG)_64K - 1);
712 }
713
714 /* We must be dealing with a 64KB aligned offset */
715 ASSERT((SectionOffset->LowPart & ((ULONG)_64K - 1)) == 0);
716
717 /* It's illegal to try to map more than 2GB */
718 if (*ViewSize >= 0x80000000) return STATUS_INVALID_VIEW_SIZE;
719
720 /* Within this section, figure out which PTEs will describe the view */
721 PteOffset = SectionOffset->QuadPart >> PAGE_SHIFT;
722
723 /* The offset must be in this segment's PTE chunk and it must be valid */
724 ASSERT(PteOffset < Segment->TotalNumberOfPtes);
725 ASSERT(((SectionOffset->QuadPart + *ViewSize + PAGE_SIZE - 1) >> PAGE_SHIFT) >= PteOffset);
726
727 /* In ARM3, only one subsection is used for now. It must contain these PTEs */
728 ASSERT(PteOffset < Subsection->PtesInSubsection);
729 ASSERT(Subsection->SubsectionBase != NULL);
730
731 /* In ARM3, only MEM_COMMIT is supported for now. The PTEs must've been committed */
732 ASSERT(Segment->NumberOfCommittedPages >= Segment->TotalNumberOfPtes);
733
734 /* Did the caller specify an address? */
735 if (!(*BaseAddress))
736 {
737 /* Which way should we search? */
738 if (AllocationType & MEM_TOP_DOWN)
739 {
740 /* No, find an address top-down */
741 Status = MiFindEmptyAddressRangeDownTree(*ViewSize,
742 (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS,
743 _64K,
744 &Process->VadRoot,
745 &StartAddress,
746 (PMMADDRESS_NODE*)&Process->VadFreeHint);
747 ASSERT(NT_SUCCESS(Status));
748 }
749 else
750 {
751 /* No, find an address bottom-up */
752 Status = MiFindEmptyAddressRangeInTree(*ViewSize,
753 _64K,
754 &Process->VadRoot,
755 (PMMADDRESS_NODE*)&Process->VadFreeHint,
756 &StartAddress);
757 ASSERT(NT_SUCCESS(Status));
758 }
759 }
760 else
761 {
762 /* This (rather easy) code path is not yet implemented */
763 UNIMPLEMENTED;
764 while (TRUE);
765 }
766
767 /* Get the ending address, which is the last piece we need for the VAD */
768 EndingAddress = (StartAddress + *ViewSize - 1) | (PAGE_SIZE - 1);
769
770 /* A VAD can now be allocated. Do so and zero it out */
771 Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD), 'ldaV');
772 ASSERT(Vad);
773 RtlZeroMemory(Vad, sizeof(MMVAD));
774
775 /* Write all the data required in the VAD for handling a fault */
776 Vad->StartingVpn = StartAddress >> PAGE_SHIFT;
777 Vad->EndingVpn = EndingAddress >> PAGE_SHIFT;
778 Vad->ControlArea = ControlArea;
779 Vad->u.VadFlags.Protection = ProtectionMask;
780 Vad->u2.VadFlags2.FileOffset = SectionOffset->QuadPart >> 16;
781 Vad->u2.VadFlags2.Inherit = (InheritDisposition == ViewShare);
782 if ((AllocationType & SEC_NO_CHANGE) || (Section->u.Flags.NoChange))
783 {
784 /* This isn't really implemented yet, but handle setting the flag */
785 Vad->u.VadFlags.NoChange = 1;
786 Vad->u2.VadFlags2.SecNoChange = 1;
787 }
788
789 /* Finally, write down the first and last prototype PTE */
790 Vad->FirstPrototypePte = &Subsection->SubsectionBase[PteOffset];
791 PteOffset += (Vad->EndingVpn - Vad->StartingVpn);
792 Vad->LastContiguousPte = &Subsection->SubsectionBase[PteOffset];
793
794 /* Make sure the last PTE is valid and still within the subsection */
795 ASSERT(PteOffset < Subsection->PtesInSubsection);
796 ASSERT(Vad->FirstPrototypePte <= Vad->LastContiguousPte);
797
798 /* FIXME: Should setup VAD bitmap */
799 Status = STATUS_SUCCESS;
800
801 /* Pretend as if we own the working set */
802 MiLockProcessWorkingSet(Process, Thread);
803
804 /* Insert the VAD */
805 MiInsertVad(Vad, Process);
806
807 /* Release the working set */
808 MiUnlockProcessWorkingSet(Process, Thread);
809
810 /* Windows stores this for accounting purposes, do so as well */
811 if (!Segment->u2.FirstMappedVa) Segment->u2.FirstMappedVa = (PVOID)StartAddress;
812
813 /* Finally, let the caller know where, and for what size, the view was mapped */
814 *ViewSize = (ULONG_PTR)EndingAddress - (ULONG_PTR)StartAddress + 1;
815 *BaseAddress = (PVOID)StartAddress;
816 return STATUS_SUCCESS;
817 }
818
819 NTSTATUS
820 NTAPI
821 MiCreatePagingFileMap(OUT PSEGMENT *Segment,
822 IN PSIZE_T MaximumSize,
823 IN ULONG ProtectionMask,
824 IN ULONG AllocationAttributes)
825 {
826 SIZE_T SizeLimit;
827 PFN_NUMBER PteCount;
828 PMMPTE PointerPte;
829 MMPTE TempPte;
830 PCONTROL_AREA ControlArea;
831 PSEGMENT NewSegment;
832 PSUBSECTION Subsection;
833 PAGED_CODE();
834
835 /* No large pages in ARM3 yet */
836 ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0);
837
838 /* Pagefile-backed sections need a known size */
839 if (!(*MaximumSize)) return STATUS_INVALID_PARAMETER_4;
840
841 /* Calculate the maximum size possible, given the Prototype PTEs we'll need */
842 SizeLimit = MAXULONG_PTR - sizeof(SEGMENT);
843 SizeLimit /= sizeof(MMPTE);
844 SizeLimit <<= PAGE_SHIFT;
845
846 /* Fail if this size is too big */
847 if (*MaximumSize > SizeLimit) return STATUS_SECTION_TOO_BIG;
848
849 /* Calculate how many Prototype PTEs will be needed */
850 PteCount = (*MaximumSize + PAGE_SIZE - 1) >> PAGE_SHIFT;
851
852 /* For commited memory, we must have a valid protection mask */
853 if (AllocationAttributes & SEC_COMMIT) ASSERT(ProtectionMask != 0);
854
855 /* The segment contains all the Prototype PTEs, allocate it in paged pool */
856 NewSegment = ExAllocatePoolWithTag(PagedPool,
857 sizeof(SEGMENT) +
858 sizeof(MMPTE) * (PteCount - 1),
859 'tSmM');
860 ASSERT(NewSegment);
861 *Segment = NewSegment;
862
863 /* Now allocate the control area, which has the subsection structure */
864 ControlArea = ExAllocatePoolWithTag(NonPagedPool,
865 sizeof(CONTROL_AREA) + sizeof(SUBSECTION),
866 'tCmM');
867 ASSERT(ControlArea);
868
869 /* And zero it out, filling the basic segmnet pointer and reference fields */
870 RtlZeroMemory(ControlArea, sizeof(CONTROL_AREA) + sizeof(SUBSECTION));
871 ControlArea->Segment = NewSegment;
872 ControlArea->NumberOfSectionReferences = 1;
873 ControlArea->NumberOfUserReferences = 1;
874
875 /* Convert allocation attributes to control area flags */
876 if (AllocationAttributes & SEC_BASED) ControlArea->u.Flags.Based = 1;
877 if (AllocationAttributes & SEC_RESERVE) ControlArea->u.Flags.Reserve = 1;
878 if (AllocationAttributes & SEC_COMMIT) ControlArea->u.Flags.Commit = 1;
879
880 /* The subsection follows, write the mask, PTE count and point back to the CA */
881 Subsection = (PSUBSECTION)(ControlArea + 1);
882 Subsection->ControlArea = ControlArea;
883 Subsection->PtesInSubsection = PteCount;
884 Subsection->u.SubsectionFlags.Protection = ProtectionMask;
885
886 /* Zero out the segment's prototype PTEs, and link it with the control area */
887 PointerPte = &NewSegment->ThePtes[0];
888 RtlZeroMemory(NewSegment, sizeof(SEGMENT));
889 NewSegment->PrototypePte = PointerPte;
890 NewSegment->ControlArea = ControlArea;
891
892 /* Save some extra accounting data for the segment as well */
893 NewSegment->u1.CreatingProcess = PsGetCurrentProcess();
894 NewSegment->SizeOfSegment = PteCount * PAGE_SIZE;
895 NewSegment->TotalNumberOfPtes = PteCount;
896 NewSegment->NonExtendedPtes = PteCount;
897
898 /* The subsection's base address is the first Prototype PTE in the segment */
899 Subsection->SubsectionBase = PointerPte;
900
901 /* Start with an empty PTE, unless this is a commit operation */
902 TempPte.u.Long = 0;
903 if (AllocationAttributes & SEC_COMMIT)
904 {
905 /* In which case, write down the protection mask in the Prototype PTEs */
906 TempPte.u.Soft.Protection = ProtectionMask;
907
908 /* For accounting, also mark these pages as being committed */
909 NewSegment->NumberOfCommittedPages = PteCount;
910 }
911
912 /* The template PTE itself for the segment should also have the mask set */
913 NewSegment->SegmentPteTemplate.u.Soft.Protection = ProtectionMask;
914
915 /* Write out the prototype PTEs, for now they're simply demand zero */
916 RtlFillMemoryUlong(PointerPte, PteCount * sizeof(MMPTE), TempPte.u.Long);
917 return STATUS_SUCCESS;
918 }
919
920 PFILE_OBJECT
921 NTAPI
922 MmGetFileObjectForSection(IN PVOID SectionObject)
923 {
924 PSECTION_OBJECT Section;
925 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
926 ASSERT(SectionObject != NULL);
927
928 /* Check if it's an ARM3, or ReactOS section */
929 if ((ULONG_PTR)SectionObject & 1)
930 {
931 /* Return the file pointer stored in the control area */
932 Section = (PVOID)((ULONG_PTR)SectionObject & ~1);
933 return Section->Segment->ControlArea->FilePointer;
934 }
935
936 /* Return the file object */
937 return ((PROS_SECTION_OBJECT)SectionObject)->FileObject;
938 }
939
940 NTSTATUS
941 NTAPI
942 MmGetFileNameForFileObject(IN PFILE_OBJECT FileObject,
943 OUT POBJECT_NAME_INFORMATION *ModuleName)
944 {
945 POBJECT_NAME_INFORMATION ObjectNameInfo;
946 NTSTATUS Status;
947 ULONG ReturnLength;
948
949 /* Allocate memory for our structure */
950 ObjectNameInfo = ExAllocatePoolWithTag(PagedPool, 1024, ' mM');
951 if (!ObjectNameInfo) return STATUS_NO_MEMORY;
952
953 /* Query the name */
954 Status = ObQueryNameString(FileObject,
955 ObjectNameInfo,
956 1024,
957 &ReturnLength);
958 if (!NT_SUCCESS(Status))
959 {
960 /* Failed, free memory */
961 DPRINT1("Name query failed\n");
962 ExFreePoolWithTag(ObjectNameInfo, ' mM');
963 *ModuleName = NULL;
964 return Status;
965 }
966
967 /* Success */
968 *ModuleName = ObjectNameInfo;
969 return STATUS_SUCCESS;
970 }
971
972 NTSTATUS
973 NTAPI
974 MmGetFileNameForSection(IN PVOID Section,
975 OUT POBJECT_NAME_INFORMATION *ModuleName)
976 {
977 PFILE_OBJECT FileObject;
978
979 /* Make sure it's an image section */
980 if ((ULONG_PTR)Section & 1)
981 {
982 /* Check ARM3 Section flag */
983 if (((PSECTION)((ULONG_PTR)Section & ~1))->u.Flags.Image == 0)
984 {
985 /* It's not, fail */
986 DPRINT1("Not an image section\n");
987 return STATUS_SECTION_NOT_IMAGE;
988 }
989 }
990 else if (!(((PROS_SECTION_OBJECT)Section)->AllocationAttributes & SEC_IMAGE))
991 {
992 /* It's not, fail */
993 DPRINT1("Not an image section\n");
994 return STATUS_SECTION_NOT_IMAGE;
995 }
996
997 /* Get the file object */
998 FileObject = MmGetFileObjectForSection(Section);
999 return MmGetFileNameForFileObject(FileObject, ModuleName);
1000 }
1001
1002 NTSTATUS
1003 NTAPI
1004 MmGetFileNameForAddress(IN PVOID Address,
1005 OUT PUNICODE_STRING ModuleName)
1006 {
1007 PVOID Section;
1008 PMEMORY_AREA MemoryArea;
1009 POBJECT_NAME_INFORMATION ModuleNameInformation;
1010 PVOID AddressSpace;
1011 NTSTATUS Status;
1012 PFILE_OBJECT FileObject = NULL;
1013 PMMVAD Vad;
1014 PCONTROL_AREA ControlArea;
1015
1016 /* Lock address space */
1017 AddressSpace = MmGetCurrentAddressSpace();
1018 MmLockAddressSpace(AddressSpace);
1019
1020 /* Locate the memory area for the process by address */
1021 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
1022 if (!MemoryArea)
1023 {
1024 /* Fail, the address does not exist */
1025 InvalidAddress:
1026 DPRINT1("Invalid address\n");
1027 MmUnlockAddressSpace(AddressSpace);
1028 return STATUS_INVALID_ADDRESS;
1029 }
1030
1031 /* Check if it's a section view (RosMm section) or ARM3 section */
1032 if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
1033 {
1034 /* Get the section pointer to the SECTION_OBJECT */
1035 Section = MemoryArea->Data.SectionData.Section;
1036
1037 /* Unlock address space */
1038 MmUnlockAddressSpace(AddressSpace);
1039
1040 /* Get the filename of the section */
1041 Status = MmGetFileNameForSection(Section, &ModuleNameInformation);
1042 }
1043 else if (MemoryArea->Type == MEMORY_AREA_OWNED_BY_ARM3)
1044 {
1045 /* Get the VAD */
1046 Vad = MiLocateAddress(Address);
1047 if (!Vad) goto InvalidAddress;
1048
1049 /* Make sure it's not a VM VAD */
1050 if (Vad->u.VadFlags.PrivateMemory == 1)
1051 {
1052 NotSection:
1053 DPRINT1("Address is not a section\n");
1054 MmUnlockAddressSpace(AddressSpace);
1055 return STATUS_SECTION_NOT_IMAGE;
1056 }
1057
1058 /* Get the control area */
1059 ControlArea = Vad->ControlArea;
1060 if (!(ControlArea) || !(ControlArea->u.Flags.Image)) goto NotSection;
1061
1062 /* Get the file object */
1063 FileObject = ControlArea->FilePointer;
1064 ASSERT(FileObject != NULL);
1065 ObReferenceObject(FileObject);
1066
1067 /* Unlock address space */
1068 MmUnlockAddressSpace(AddressSpace);
1069
1070 /* Get the filename of the file object */
1071 Status = MmGetFileNameForFileObject(FileObject, &ModuleNameInformation);
1072
1073 /* Dereference it */
1074 ObDereferenceObject(FileObject);
1075 }
1076 else
1077 {
1078 /* Trying to access virtual memory or something */
1079 goto InvalidAddress;
1080 }
1081
1082 /* Check if we were able to get the file object name */
1083 if (NT_SUCCESS(Status))
1084 {
1085 /* Init modulename */
1086 RtlCreateUnicodeString(ModuleName,
1087 ModuleNameInformation->Name.Buffer);
1088
1089 /* Free temp taged buffer from MmGetFileNameForFileObject() */
1090 ExFreePoolWithTag(ModuleNameInformation, ' mM');
1091 DPRINT("Found ModuleName %S by address %p\n", ModuleName->Buffer, Address);
1092 }
1093
1094 /* Return status */
1095 return Status;
1096 }
1097
1098 /* PUBLIC FUNCTIONS ***********************************************************/
1099
1100 /*
1101 * @implemented
1102 */
1103 NTSTATUS
1104 NTAPI
1105 MmCreateArm3Section(OUT PVOID *SectionObject,
1106 IN ACCESS_MASK DesiredAccess,
1107 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
1108 IN PLARGE_INTEGER InputMaximumSize,
1109 IN ULONG SectionPageProtection,
1110 IN ULONG AllocationAttributes,
1111 IN HANDLE FileHandle OPTIONAL,
1112 IN PFILE_OBJECT FileObject OPTIONAL)
1113 {
1114 SECTION Section;
1115 PSECTION NewSection;
1116 PSUBSECTION Subsection;
1117 PSEGMENT NewSegment;
1118 NTSTATUS Status;
1119 PCONTROL_AREA ControlArea;
1120 ULONG ProtectionMask;
1121
1122 /* ARM3 does not yet support this */
1123 ASSERT(FileHandle == NULL);
1124 ASSERT(FileObject == NULL);
1125 ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0);
1126 ASSERT((AllocationAttributes & SEC_BASED) == 0);
1127
1128 /* Make the same sanity checks that the Nt interface should've validated */
1129 ASSERT((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED |
1130 SEC_LARGE_PAGES | SEC_IMAGE | SEC_NOCACHE |
1131 SEC_NO_CHANGE)) == 0);
1132 ASSERT((AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_IMAGE)) != 0);
1133 ASSERT(!((AllocationAttributes & SEC_IMAGE) &&
1134 (AllocationAttributes & (SEC_COMMIT | SEC_RESERVE |
1135 SEC_NOCACHE | SEC_NO_CHANGE))));
1136 ASSERT(!((AllocationAttributes & SEC_COMMIT) && (AllocationAttributes & SEC_RESERVE)));
1137 ASSERT(!((SectionPageProtection & PAGE_NOCACHE) ||
1138 (SectionPageProtection & PAGE_WRITECOMBINE) ||
1139 (SectionPageProtection & PAGE_GUARD) ||
1140 (SectionPageProtection & PAGE_NOACCESS)));
1141
1142 /* Convert section flag to page flag */
1143 if (AllocationAttributes & SEC_NOCACHE) SectionPageProtection |= PAGE_NOCACHE;
1144
1145 /* Check to make sure the protection is correct. Nt* does this already */
1146 ProtectionMask = MiMakeProtectionMask(SectionPageProtection);
1147 if (ProtectionMask == MM_INVALID_PROTECTION) return STATUS_INVALID_PAGE_PROTECTION;
1148
1149 /* A handle must be supplied with SEC_IMAGE, and this is the no-handle path */
1150 if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION;
1151
1152 /* So this must be a pagefile-backed section, create the mappings needed */
1153 Status = MiCreatePagingFileMap(&NewSegment,
1154 (PSIZE_T)InputMaximumSize,
1155 ProtectionMask,
1156 AllocationAttributes);
1157 ASSERT(NT_SUCCESS(Status));
1158
1159 /* Set the initial section object data */
1160 Section.InitialPageProtection = SectionPageProtection;
1161 Section.Segment = NULL;
1162 Section.SizeOfSection.QuadPart = NewSegment->SizeOfSegment;
1163 Section.Segment = NewSegment;
1164
1165 /* THe mapping created a control area and segment, save the flags */
1166 ControlArea = NewSegment->ControlArea;
1167 Section.u.LongFlags = ControlArea->u.LongFlags;
1168
1169 /* ARM3 cannot support these right now, make sure they're not being set */
1170 ASSERT(ControlArea->u.Flags.Image == 0);
1171 ASSERT(ControlArea->FilePointer == NULL);
1172 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
1173 ASSERT(ControlArea->u.Flags.Rom == 0);
1174 ASSERT(ControlArea->u.Flags.WasPurged == 0);
1175
1176 /* A pagefile-backed mapping only has one subsection, and this is all ARM3 supports */
1177 Subsection = (PSUBSECTION)(ControlArea + 1);
1178 ASSERT(Subsection->NextSubsection == NULL);
1179
1180 /* Create the actual section object, with enough space for the prototype PTEs */
1181 Status = ObCreateObject(ExGetPreviousMode(),
1182 MmSectionObjectType,
1183 ObjectAttributes,
1184 ExGetPreviousMode(),
1185 NULL,
1186 sizeof(SECTION),
1187 sizeof(SECTION) +
1188 NewSegment->TotalNumberOfPtes * sizeof(MMPTE),
1189 sizeof(CONTROL_AREA) + sizeof(SUBSECTION),
1190 (PVOID*)&NewSection);
1191 ASSERT(NT_SUCCESS(Status));
1192
1193 /* Now copy the local section object from the stack into this new object */
1194 RtlCopyMemory(NewSection, &Section, sizeof(SECTION));
1195 NewSection->Address.StartingVpn = 0;
1196
1197 /* Return the object and the creation status */
1198 *SectionObject = (PVOID)NewSection;
1199 return Status;
1200 }
1201
1202 /*
1203 * @implemented
1204 */
1205 NTSTATUS
1206 NTAPI
1207 MmMapViewOfArm3Section(IN PVOID SectionObject,
1208 IN PEPROCESS Process,
1209 IN OUT PVOID *BaseAddress,
1210 IN ULONG_PTR ZeroBits,
1211 IN SIZE_T CommitSize,
1212 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
1213 IN OUT PSIZE_T ViewSize,
1214 IN SECTION_INHERIT InheritDisposition,
1215 IN ULONG AllocationType,
1216 IN ULONG Protect)
1217 {
1218 KAPC_STATE ApcState;
1219 BOOLEAN Attached = FALSE;
1220 PSECTION Section;
1221 PCONTROL_AREA ControlArea;
1222 ULONG ProtectionMask;
1223 NTSTATUS Status;
1224 PAGED_CODE();
1225
1226 /* Get the segment and control area */
1227 Section = (PSECTION)SectionObject;
1228 ControlArea = Section->Segment->ControlArea;
1229
1230 /* These flags/states are not yet supported by ARM3 */
1231 ASSERT(Section->u.Flags.Image == 0);
1232 ASSERT(Section->u.Flags.NoCache == 0);
1233 ASSERT(Section->u.Flags.WriteCombined == 0);
1234 ASSERT((AllocationType & MEM_RESERVE) == 0);
1235 ASSERT(ControlArea->u.Flags.PhysicalMemory == 0);
1236
1237
1238 #if 0
1239 /* FIXME: Check if the mapping protection is compatible with the create */
1240 if (!MiIsProtectionCompatible(Section->InitialPageProtection, Protect))
1241 {
1242 DPRINT1("Mapping protection is incompatible\n");
1243 return STATUS_SECTION_PROTECTION;
1244 }
1245 #endif
1246
1247 /* Check if the offset and size would cause an overflow */
1248 if ((SectionOffset->QuadPart + *ViewSize) < SectionOffset->QuadPart)
1249 {
1250 DPRINT1("Section offset overflows\n");
1251 return STATUS_INVALID_VIEW_SIZE;
1252 }
1253
1254 /* Check if the offset and size are bigger than the section itself */
1255 if ((SectionOffset->QuadPart + *ViewSize) > Section->SizeOfSection.QuadPart)
1256 {
1257 DPRINT1("Section offset is larger than section\n");
1258 return STATUS_INVALID_VIEW_SIZE;
1259 }
1260
1261 /* Check if the caller did not specify a view size */
1262 if (!(*ViewSize))
1263 {
1264 /* Compute it for the caller */
1265 *ViewSize = Section->SizeOfSection.QuadPart - SectionOffset->QuadPart;
1266
1267 /* Check if it's larger than 4GB or overflows into kernel-mode */
1268 if ((*ViewSize > 0xFFFFFFFF) ||
1269 (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)*BaseAddress) < *ViewSize))
1270 {
1271 DPRINT1("Section view won't fit\n");
1272 return STATUS_INVALID_VIEW_SIZE;
1273 }
1274 }
1275
1276 /* Check if the commit size is larger than the view size */
1277 if (CommitSize > *ViewSize)
1278 {
1279 DPRINT1("Attempting to commit more than the view itself\n");
1280 return STATUS_INVALID_PARAMETER_5;
1281 }
1282
1283 /* Check if the view size is larger than the section */
1284 if (*ViewSize > Section->SizeOfSection.QuadPart)
1285 {
1286 DPRINT1("The view is larger than the section\n");
1287 return STATUS_INVALID_VIEW_SIZE;
1288 }
1289
1290 /* Compute and validate the protection mask */
1291 ProtectionMask = MiMakeProtectionMask(Protect);
1292 if (ProtectionMask == MM_INVALID_PROTECTION)
1293 {
1294 DPRINT1("The protection is invalid\n");
1295 return STATUS_INVALID_PAGE_PROTECTION;
1296 }
1297
1298 /* We only handle pagefile-backed sections, which cannot be writecombined */
1299 if (Protect & PAGE_WRITECOMBINE)
1300 {
1301 DPRINT1("Cannot write combine a pagefile-backed section\n");
1302 return STATUS_INVALID_PARAMETER_10;
1303 }
1304
1305 /* Start by attaching to the current process if needed */
1306 if (PsGetCurrentProcess() != Process)
1307 {
1308 KeStackAttachProcess(&Process->Pcb, &ApcState);
1309 Attached = TRUE;
1310 }
1311
1312 /* Lock the address space and make sure the process is alive */
1313 MmLockAddressSpace(&Process->Vm);
1314 if (!Process->VmDeleted)
1315 {
1316 /* Do the actual mapping */
1317 Status = MiMapViewOfDataSection(ControlArea,
1318 Process,
1319 BaseAddress,
1320 SectionOffset,
1321 ViewSize,
1322 Section,
1323 InheritDisposition,
1324 ProtectionMask,
1325 CommitSize,
1326 ZeroBits,
1327 AllocationType);
1328 }
1329 else
1330 {
1331 /* The process is being terminated, fail */
1332 DPRINT1("The process is dying\n");
1333 Status = STATUS_PROCESS_IS_TERMINATING;
1334 }
1335
1336 /* Unlock the address space and detatch if needed, then return status */
1337 MmUnlockAddressSpace(&Process->Vm);
1338 if (Attached) KeUnstackDetachProcess(&ApcState);
1339 return Status;
1340 }
1341
1342 /* SYSTEM CALLS ***************************************************************/
1343
1344 NTSTATUS
1345 NTAPI
1346 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage,
1347 IN PVOID File2MappedAsFile)
1348 {
1349 UNIMPLEMENTED;
1350 return STATUS_NOT_IMPLEMENTED;
1351 }
1352
1353 /*
1354 * @implemented
1355 */
1356 NTSTATUS
1357 NTAPI
1358 NtCreateSection(OUT PHANDLE SectionHandle,
1359 IN ACCESS_MASK DesiredAccess,
1360 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
1361 IN PLARGE_INTEGER MaximumSize OPTIONAL,
1362 IN ULONG SectionPageProtection OPTIONAL,
1363 IN ULONG AllocationAttributes,
1364 IN HANDLE FileHandle OPTIONAL)
1365 {
1366 LARGE_INTEGER SafeMaximumSize;
1367 PVOID SectionObject;
1368 HANDLE Handle;
1369 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1370 NTSTATUS Status;
1371 PAGED_CODE();
1372
1373 /* Check for non-existing flags */
1374 if ((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED |
1375 SEC_LARGE_PAGES | SEC_IMAGE | SEC_NOCACHE |
1376 SEC_NO_CHANGE)))
1377 {
1378 if (!(AllocationAttributes & 1))
1379 {
1380 DPRINT1("Bogus allocation attribute: %lx\n", AllocationAttributes);
1381 return STATUS_INVALID_PARAMETER_6;
1382 }
1383 }
1384
1385 /* Check for no allocation type */
1386 if (!(AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_IMAGE)))
1387 {
1388 DPRINT1("Missing allocation type in allocation attributes\n");
1389 return STATUS_INVALID_PARAMETER_6;
1390 }
1391
1392 /* Check for image allocation with invalid attributes */
1393 if ((AllocationAttributes & SEC_IMAGE) &&
1394 (AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_LARGE_PAGES |
1395 SEC_NOCACHE | SEC_NO_CHANGE)))
1396 {
1397 DPRINT1("Image allocation with invalid attributes\n");
1398 return STATUS_INVALID_PARAMETER_6;
1399 }
1400
1401 /* Check for allocation type is both commit and reserve */
1402 if ((AllocationAttributes & SEC_COMMIT) && (AllocationAttributes & SEC_RESERVE))
1403 {
1404 DPRINT1("Commit and reserve in the same time\n");
1405 return STATUS_INVALID_PARAMETER_6;
1406 }
1407
1408 /* Now check for valid protection */
1409 if ((SectionPageProtection & PAGE_NOCACHE) ||
1410 (SectionPageProtection & PAGE_WRITECOMBINE) ||
1411 (SectionPageProtection & PAGE_GUARD) ||
1412 (SectionPageProtection & PAGE_NOACCESS))
1413 {
1414 DPRINT1("Sections don't support these protections\n");
1415 return STATUS_INVALID_PAGE_PROTECTION;
1416 }
1417
1418 /* Use a maximum size of zero, if none was specified */
1419 SafeMaximumSize.QuadPart = 0;
1420
1421 /* Check for user-mode caller */
1422 if (PreviousMode != KernelMode)
1423 {
1424 /* Enter SEH */
1425 _SEH2_TRY
1426 {
1427 /* Safely check user-mode parameters */
1428 if (MaximumSize) SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
1429 MaximumSize = &SafeMaximumSize;
1430 ProbeForWriteHandle(SectionHandle);
1431 }
1432 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1433 {
1434 /* Return the exception code */
1435 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1436 }
1437 _SEH2_END;
1438 }
1439 else if (!MaximumSize) MaximumSize = &SafeMaximumSize;
1440
1441 /* Create the section */
1442 Status = MmCreateSection(&SectionObject,
1443 DesiredAccess,
1444 ObjectAttributes,
1445 MaximumSize,
1446 SectionPageProtection,
1447 AllocationAttributes,
1448 FileHandle,
1449 NULL);
1450 if (!NT_SUCCESS(Status)) return Status;
1451
1452 /* FIXME: Should zero last page for a file mapping */
1453
1454 /* Now insert the object */
1455 Status = ObInsertObject(SectionObject,
1456 NULL,
1457 DesiredAccess,
1458 0,
1459 NULL,
1460 &Handle);
1461 if (NT_SUCCESS(Status))
1462 {
1463 /* Enter SEH */
1464 _SEH2_TRY
1465 {
1466 /* Return the handle safely */
1467 *SectionHandle = Handle;
1468 }
1469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1470 {
1471 /* Nothing here */
1472 }
1473 _SEH2_END;
1474 }
1475
1476 /* Return the status */
1477 return Status;
1478 }
1479
1480 NTSTATUS
1481 NTAPI
1482 NtOpenSection(OUT PHANDLE SectionHandle,
1483 IN ACCESS_MASK DesiredAccess,
1484 IN POBJECT_ATTRIBUTES ObjectAttributes)
1485 {
1486 HANDLE Handle;
1487 NTSTATUS Status;
1488 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1489 PAGED_CODE();
1490
1491 /* Check for user-mode caller */
1492 if (PreviousMode != KernelMode)
1493 {
1494 /* Enter SEH */
1495 _SEH2_TRY
1496 {
1497 /* Safely check user-mode parameters */
1498 ProbeForWriteHandle(SectionHandle);
1499 }
1500 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1501 {
1502 /* Return the exception code */
1503 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1504 }
1505 _SEH2_END;
1506 }
1507
1508 /* Try opening the object */
1509 Status = ObOpenObjectByName(ObjectAttributes,
1510 MmSectionObjectType,
1511 PreviousMode,
1512 NULL,
1513 DesiredAccess,
1514 NULL,
1515 &Handle);
1516
1517 /* Enter SEH */
1518 _SEH2_TRY
1519 {
1520 /* Return the handle safely */
1521 *SectionHandle = Handle;
1522 }
1523 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1524 {
1525 /* Nothing here */
1526 }
1527 _SEH2_END;
1528
1529 /* Return the status */
1530 return Status;
1531 }
1532
1533 NTSTATUS
1534 NTAPI
1535 NtMapViewOfSection(IN HANDLE SectionHandle,
1536 IN HANDLE ProcessHandle,
1537 IN OUT PVOID* BaseAddress,
1538 IN ULONG_PTR ZeroBits,
1539 IN SIZE_T CommitSize,
1540 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
1541 IN OUT PSIZE_T ViewSize,
1542 IN SECTION_INHERIT InheritDisposition,
1543 IN ULONG AllocationType,
1544 IN ULONG Protect)
1545 {
1546 PVOID SafeBaseAddress;
1547 LARGE_INTEGER SafeSectionOffset;
1548 SIZE_T SafeViewSize;
1549 PROS_SECTION_OBJECT Section;
1550 PEPROCESS Process;
1551 NTSTATUS Status;
1552 ACCESS_MASK DesiredAccess;
1553 ULONG ProtectionMask;
1554 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1555
1556 /* Check for invalid zero bits */
1557 if (ZeroBits > 21) // per-arch?
1558 {
1559 DPRINT1("Invalid zero bits\n");
1560 return STATUS_INVALID_PARAMETER_4;
1561 }
1562
1563 /* Check for invalid inherit disposition */
1564 if ((InheritDisposition > ViewUnmap) || (InheritDisposition < ViewShare))
1565 {
1566 DPRINT1("Invalid inherit disposition\n");
1567 return STATUS_INVALID_PARAMETER_8;
1568 }
1569
1570 /* Allow only valid allocation types */
1571 if ((AllocationType & ~(MEM_TOP_DOWN | MEM_LARGE_PAGES | MEM_DOS_LIM |
1572 SEC_NO_CHANGE | MEM_RESERVE)))
1573 {
1574 DPRINT1("Invalid allocation type\n");
1575 return STATUS_INVALID_PARAMETER_9;
1576 }
1577
1578 /* Convert the protection mask, and validate it */
1579 ProtectionMask = MiMakeProtectionMask(Protect);
1580 if (ProtectionMask == MM_INVALID_PROTECTION)
1581 {
1582 DPRINT1("Invalid page protection\n");
1583 return STATUS_INVALID_PAGE_PROTECTION;
1584 }
1585
1586 /* Now convert the protection mask into desired section access mask */
1587 DesiredAccess = MmMakeSectionAccess[ProtectionMask & 0x7];
1588
1589 /* Assume no section offset */
1590 SafeSectionOffset.QuadPart = 0;
1591
1592 /* Enter SEH */
1593 _SEH2_TRY
1594 {
1595 /* Check for unsafe parameters */
1596 if (PreviousMode != KernelMode)
1597 {
1598 /* Probe the parameters */
1599 ProbeForWritePointer(BaseAddress);
1600 ProbeForWriteSize_t(ViewSize);
1601 }
1602
1603 /* Check if a section offset was given */
1604 if (SectionOffset)
1605 {
1606 /* Check for unsafe parameters and capture section offset */
1607 if (PreviousMode != KernelMode) ProbeForWriteLargeInteger(SectionOffset);
1608 SafeSectionOffset = *SectionOffset;
1609 }
1610
1611 /* Capture the other parameters */
1612 SafeBaseAddress = *BaseAddress;
1613 SafeViewSize = *ViewSize;
1614 }
1615 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1616 {
1617 /* Return the exception code */
1618 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1619 }
1620 _SEH2_END;
1621
1622 /* Check for kernel-mode address */
1623 if (SafeBaseAddress > MM_HIGHEST_VAD_ADDRESS)
1624 {
1625 DPRINT1("Kernel base not allowed\n");
1626 return STATUS_INVALID_PARAMETER_3;
1627 }
1628
1629 /* Check for range entering kernel-mode */
1630 if (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)SafeBaseAddress) < SafeViewSize)
1631 {
1632 DPRINT1("Overflowing into kernel base not allowed\n");
1633 return STATUS_INVALID_PARAMETER_3;
1634 }
1635
1636 /* Check for invalid zero bits */
1637 if (((ULONG_PTR)SafeBaseAddress + SafeViewSize) > (0xFFFFFFFF >> ZeroBits)) // arch?
1638 {
1639 DPRINT1("Invalid zero bits\n");
1640 return STATUS_INVALID_PARAMETER_4;
1641 }
1642
1643 /* Reference the process */
1644 Status = ObReferenceObjectByHandle(ProcessHandle,
1645 PROCESS_VM_OPERATION,
1646 PsProcessType,
1647 PreviousMode,
1648 (PVOID*)&Process,
1649 NULL);
1650 if (!NT_SUCCESS(Status)) return Status;
1651
1652 /* Reference the section */
1653 Status = ObReferenceObjectByHandle(SectionHandle,
1654 DesiredAccess,
1655 MmSectionObjectType,
1656 PreviousMode,
1657 (PVOID*)&Section,
1658 NULL);
1659 if (!NT_SUCCESS(Status))
1660 {
1661 ObDereferenceObject(Process);
1662 return Status;
1663 }
1664
1665 /* Now do the actual mapping */
1666 Status = MmMapViewOfSection(Section,
1667 Process,
1668 &SafeBaseAddress,
1669 ZeroBits,
1670 CommitSize,
1671 &SafeSectionOffset,
1672 &SafeViewSize,
1673 InheritDisposition,
1674 AllocationType,
1675 Protect);
1676
1677 /* Check if this is an image for the current process */
1678 if ((Section->AllocationAttributes & SEC_IMAGE) &&
1679 (Process == PsGetCurrentProcess()) &&
1680 ((Status != STATUS_IMAGE_NOT_AT_BASE) ||
1681 (Status != STATUS_CONFLICTING_ADDRESSES)))
1682 {
1683 /* Notify the debugger */
1684 DbgkMapViewOfSection(Section,
1685 SafeBaseAddress,
1686 SafeSectionOffset.LowPart,
1687 SafeViewSize);
1688 }
1689
1690 /* Return data only on success */
1691 if (NT_SUCCESS(Status))
1692 {
1693 /* Enter SEH */
1694 _SEH2_TRY
1695 {
1696 /* Return parameters to user */
1697 *BaseAddress = SafeBaseAddress;
1698 *ViewSize = SafeViewSize;
1699 if (SectionOffset) *SectionOffset = SafeSectionOffset;
1700 }
1701 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1702 {
1703 /* Nothing to do */
1704 }
1705 _SEH2_END;
1706 }
1707
1708 /* Dereference all objects and return status */
1709 ObDereferenceObject(Section);
1710 ObDereferenceObject(Process);
1711 return Status;
1712 }
1713
1714 NTSTATUS
1715 NTAPI
1716 NtUnmapViewOfSection(IN HANDLE ProcessHandle,
1717 IN PVOID BaseAddress)
1718 {
1719 PEPROCESS Process;
1720 NTSTATUS Status;
1721 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1722
1723 /* Don't allowing mapping kernel views */
1724 if ((PreviousMode == UserMode) && (BaseAddress > MM_HIGHEST_USER_ADDRESS))
1725 {
1726 DPRINT1("Trying to unmap a kernel view\n");
1727 return STATUS_NOT_MAPPED_VIEW;
1728 }
1729
1730 /* Reference the process */
1731 Status = ObReferenceObjectByHandle(ProcessHandle,
1732 PROCESS_VM_OPERATION,
1733 PsProcessType,
1734 PreviousMode,
1735 (PVOID*)&Process,
1736 NULL);
1737 if (!NT_SUCCESS(Status)) return Status;
1738
1739 /* Unmap the view */
1740 Status = MmUnmapViewOfSection(Process, BaseAddress);
1741
1742 /* Dereference the process and return status */
1743 ObDereferenceObject(Process);
1744 return Status;
1745 }
1746
1747 NTSTATUS
1748 NTAPI
1749 NtExtendSection(IN HANDLE SectionHandle,
1750 IN OUT PLARGE_INTEGER NewMaximumSize)
1751 {
1752 LARGE_INTEGER SafeNewMaximumSize;
1753 PROS_SECTION_OBJECT Section;
1754 NTSTATUS Status;
1755 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1756
1757 /* Check for user-mode parameters */
1758 if (PreviousMode != KernelMode)
1759 {
1760 /* Enter SEH */
1761 _SEH2_TRY
1762 {
1763 /* Probe and capture the maximum size, it's both read and write */
1764 ProbeForWriteLargeInteger(NewMaximumSize);
1765 SafeNewMaximumSize = *NewMaximumSize;
1766 }
1767 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1768 {
1769 /* Return the exception code */
1770 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1771 }
1772 _SEH2_END;
1773 }
1774 else
1775 {
1776 /* Just read the size directly */
1777 SafeNewMaximumSize = *NewMaximumSize;
1778 }
1779
1780 /* Reference the section */
1781 Status = ObReferenceObjectByHandle(SectionHandle,
1782 SECTION_EXTEND_SIZE,
1783 MmSectionObjectType,
1784 PreviousMode,
1785 (PVOID*)&Section,
1786 NULL);
1787 if (!NT_SUCCESS(Status)) return Status;
1788
1789 /* Really this should go in MmExtendSection */
1790 if (!(Section->AllocationAttributes & SEC_FILE))
1791 {
1792 DPRINT1("Not extending a file\n");
1793 ObDereferenceObject(Section);
1794 return STATUS_SECTION_NOT_EXTENDED;
1795 }
1796
1797 /* FIXME: Do the work */
1798
1799 /* Dereference the section */
1800 ObDereferenceObject(Section);
1801
1802 /* Enter SEH */
1803 _SEH2_TRY
1804 {
1805 /* Write back the new size */
1806 *NewMaximumSize = SafeNewMaximumSize;
1807 }
1808 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1809 {
1810 /* Nothing to do */
1811 }
1812 _SEH2_END;
1813
1814 /* Return the status */
1815 return STATUS_NOT_IMPLEMENTED;
1816 }
1817
1818 /* PUBLIC FUNCTIONS ***********************************************************/
1819
1820 /*
1821 * @unimplemented
1822 */
1823 BOOLEAN
1824 NTAPI
1825 MmDisableModifiedWriteOfSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer)
1826 {
1827 UNIMPLEMENTED;
1828 return FALSE;
1829 }
1830
1831 /*
1832 * @unimplemented
1833 */
1834 BOOLEAN
1835 NTAPI
1836 MmForceSectionClosed(IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
1837 IN BOOLEAN DelayClose)
1838 {
1839 UNIMPLEMENTED;
1840 return FALSE;
1841 }
1842
1843 /*
1844 * @unimplemented
1845 */
1846 NTSTATUS
1847 NTAPI
1848 MmMapViewInSessionSpace(IN PVOID Section,
1849 OUT PVOID *MappedBase,
1850 IN OUT PSIZE_T ViewSize)
1851 {
1852 UNIMPLEMENTED;
1853 return STATUS_NOT_IMPLEMENTED;
1854 }
1855
1856 /*
1857 * @unimplemented
1858 */
1859 NTSTATUS
1860 NTAPI
1861 MmUnmapViewInSessionSpace(IN PVOID MappedBase)
1862 {
1863 UNIMPLEMENTED;
1864 return STATUS_NOT_IMPLEMENTED;
1865 }
1866
1867 /* EOF */