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