1 /* $Id: section.c,v 1.31 2000/05/24 22:29:38 dwelch Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/section.c
6 * PURPOSE: Implements section objects
7 * PROGRAMMER: David Welch (welch@mcmail.com)
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.h>
15 #include <internal/mm.h>
16 #include <internal/ob.h>
17 #include <internal/io.h>
18 #include <internal/ps.h>
22 #include <internal/debug.h>
24 /* GLOBALS *******************************************************************/
26 POBJECT_TYPE EXPORTED MmSectionObjectType
= NULL
;
28 /* FUNCTIONS *****************************************************************/
30 VOID
MmLockSection(PSECTION_OBJECT Section
)
32 KeWaitForSingleObject(&Section
->Lock
,
39 VOID
MmUnlockSection(PSECTION_OBJECT Section
)
41 KeReleaseMutex(&Section
->Lock
, FALSE
);
44 VOID
MmSetPageEntrySection(PSECTION_OBJECT Section
,
48 PSECTION_PAGE_TABLE Table
;
49 ULONG DirectoryOffset
;
52 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
53 Table
= Section
->PageDirectory
.PageTables
[DirectoryOffset
];
57 Section
->PageDirectory
.PageTables
[DirectoryOffset
] =
58 ExAllocatePool(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
));
59 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
60 DPRINT("Table %x\n", Table
);
62 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
63 Table
->Pages
[TableOffset
] = Entry
;
66 PVOID
MmGetPageEntrySection(PSECTION_OBJECT Section
,
69 PSECTION_PAGE_TABLE Table
;
71 ULONG DirectoryOffset
;
74 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
76 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
77 Table
= Section
->PageDirectory
.PageTables
[DirectoryOffset
];
78 DPRINT("Table %x\n", Table
);
83 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
84 Entry
= Table
->Pages
[TableOffset
];
88 NTSTATUS
MmOldLoadPageForSection(PMADDRESS_SPACE AddressSpace
,
89 MEMORY_AREA
* MemoryArea
,
93 IO_STATUS_BLOCK IoStatus
;
98 PSECTION_OBJECT Section
;
100 DPRINT("MmOldLoadPageForSection(MemoryArea %x, Address %x)\n",
103 if (MmIsPagePresent(NULL
, Address
))
105 DPRINT("Page is already present\n");
106 return(STATUS_SUCCESS
);
109 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
110 Offset
.QuadPart
= (PAddress
- (ULONG
)MemoryArea
->BaseAddress
) +
111 MemoryArea
->Data
.SectionData
.ViewOffset
;
113 DPRINT("MemoryArea->BaseAddress %x\n", MemoryArea
->BaseAddress
);
114 DPRINT("MemoryArea->Data.SectionData.ViewOffset %x\n",
115 MemoryArea
->Data
.SectionData
.ViewOffset
);
116 DPRINT("Got offset %x\n", Offset
.QuadPart
);
118 Section
= MemoryArea
->Data
.SectionData
.Section
;
120 DPRINT("Section %x\n", Section
);
122 MmLockSection(Section
);
124 Mdl
= MmCreateMdl(NULL
, NULL
, PAGESIZE
);
125 MmBuildMdlFromPages(Mdl
);
126 Page
= MmGetMdlPageAddress(Mdl
, 0);
127 MmUnlockSection(Section
);
128 MmUnlockAddressSpace(AddressSpace
);
129 DPRINT("Reading file offset %x\n", Offset
.QuadPart
);
130 Status
= IoPageRead(MemoryArea
->Data
.SectionData
.Section
->FileObject
,
134 if (!NT_SUCCESS(Status
))
139 MmLockAddressSpace(AddressSpace
);
140 MmLockSection(Section
);
144 MemoryArea
->Attributes
,
146 MmUnlockSection(Section
);
148 return(STATUS_SUCCESS
);
152 NTSTATUS
MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
153 MEMORY_AREA
* MemoryArea
,
156 LARGE_INTEGER Offset
;
157 IO_STATUS_BLOCK IoStatus
;
162 PSECTION_OBJECT Section
;
165 DPRINT("MmSectionHandleFault(MemoryArea %x, Address %x)\n",
168 if (MmIsPagePresent(NULL
, Address
))
170 DPRINT("Page is already present\n");
171 return(STATUS_SUCCESS
);
174 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
175 Offset
.QuadPart
= (PAddress
- (ULONG
)MemoryArea
->BaseAddress
) +
176 MemoryArea
->Data
.SectionData
.ViewOffset
;
178 if ((MemoryArea
->Data
.SectionData
.ViewOffset
% PAGESIZE
) != 0)
180 return(MmOldLoadPageForSection(AddressSpace
, MemoryArea
, Address
));
183 DPRINT("MemoryArea->BaseAddress %x\n", MemoryArea
->BaseAddress
);
184 DPRINT("MemoryArea->Data.SectionData.ViewOffset %x\n",
185 MemoryArea
->Data
.SectionData
.ViewOffset
);
186 DPRINT("Got offset %x\n", Offset
.QuadPart
);
188 Section
= MemoryArea
->Data
.SectionData
.Section
;
190 DPRINT("Section %x\n", Section
);
192 MmLockSection(Section
);
194 Entry
= MmGetPageEntrySection(Section
, Offset
.u
.LowPart
);
196 DPRINT("Entry %x\n", Entry
);
200 Mdl
= MmCreateMdl(NULL
, NULL
, PAGESIZE
);
201 MmBuildMdlFromPages(Mdl
);
202 Page
= MmGetMdlPageAddress(Mdl
, 0);
203 MmUnlockSection(Section
);
204 MmUnlockAddressSpace(AddressSpace
);
205 DPRINT("Reading file offset %x\n", Offset
.QuadPart
);
206 Status
= IoPageRead(MemoryArea
->Data
.SectionData
.Section
->FileObject
,
210 if (!NT_SUCCESS(Status
))
215 MmLockAddressSpace(AddressSpace
);
216 MmLockSection(Section
);
218 Entry
= MmGetPageEntrySection(Section
, Offset
.QuadPart
);
222 MmSetPageEntrySection(Section
,
228 MmDereferencePage(Page
);
230 MmReferencePage(Page
);
236 MmReferencePage(Page
);
241 MemoryArea
->Attributes
,
243 MmUnlockSection(Section
);
245 return(STATUS_SUCCESS
);
248 VOID
MmpDeleteSection(PVOID ObjectBody
)
250 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
253 VOID
MmpCloseSection(PVOID ObjectBody
,
256 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
257 ObjectBody
, HandleCount
, ObGetReferenceCount(ObjectBody
));
260 NTSTATUS
MmpCreateSection(PVOID ObjectBody
,
263 POBJECT_ATTRIBUTES ObjectAttributes
)
267 DPRINT("MmpCreateDevice(ObjectBody %x, Parent %x, RemainingPath %S)\n",
268 ObjectBody
, Parent
, RemainingPath
);
270 if (RemainingPath
== NULL
)
272 return(STATUS_SUCCESS
);
275 if (wcschr(RemainingPath
+1, L
'\\') != NULL
)
277 return(STATUS_UNSUCCESSFUL
);
280 Status
= ObReferenceObjectByPointer(Parent
,
281 STANDARD_RIGHTS_REQUIRED
,
284 if (!NT_SUCCESS(Status
))
289 ObAddEntryDirectory(Parent
, ObjectBody
, RemainingPath
+1);
290 ObDereferenceObject(Parent
);
292 return(STATUS_SUCCESS
);
295 NTSTATUS
MmInitSectionImplementation(VOID
)
297 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
299 RtlInitUnicodeString(&MmSectionObjectType
->TypeName
, L
"Section");
301 MmSectionObjectType
->TotalObjects
= 0;
302 MmSectionObjectType
->TotalHandles
= 0;
303 MmSectionObjectType
->MaxObjects
= ULONG_MAX
;
304 MmSectionObjectType
->MaxHandles
= ULONG_MAX
;
305 MmSectionObjectType
->PagedPoolCharge
= 0;
306 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
307 MmSectionObjectType
->Dump
= NULL
;
308 MmSectionObjectType
->Open
= NULL
;
309 MmSectionObjectType
->Close
= MmpCloseSection
;
310 MmSectionObjectType
->Delete
= MmpDeleteSection
;
311 MmSectionObjectType
->Parse
= NULL
;
312 MmSectionObjectType
->Security
= NULL
;
313 MmSectionObjectType
->QueryName
= NULL
;
314 MmSectionObjectType
->OkayToClose
= NULL
;
315 MmSectionObjectType
->Create
= MmpCreateSection
;
317 return(STATUS_SUCCESS
);
321 /* FIXME: NtCS should call MmCS */
322 NTSTATUS STDCALL
NtCreateSection (OUT PHANDLE SectionHandle
,
323 IN ACCESS_MASK DesiredAccess
,
324 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
325 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
326 IN ULONG SectionPageProtection OPTIONAL
,
327 IN ULONG AllocationAttributes
,
328 IN HANDLE FileHandle OPTIONAL
)
330 * FUNCTION: Creates a section object.
332 * SectionHandle (OUT) = Caller supplied storage for the resulting
334 * DesiredAccess = Specifies the desired access to the section can be a
335 * combination of STANDARD_RIGHTS_REQUIRED |
336 * SECTION_QUERY | SECTION_MAP_WRITE |
337 * SECTION_MAP_READ | SECTION_MAP_EXECUTE.
338 * ObjectAttribute = Initialized attributes for the object can be used
339 * to create a named section
340 * MaxiumSize = Maximizes the size of the memory section. Must be
341 * non-NULL for a page-file backed section.
342 * If value specified for a mapped file and the file is
343 * not large enough, file will be extended.
344 * SectionPageProtection = Can be a combination of PAGE_READONLY |
345 * PAGE_READWRITE | PAGE_WRITEONLY |
347 * AllocationAttributes = can be a combination of SEC_IMAGE |
349 * FileHandle = Handle to a file to create a section mapped to a file
350 * instead of a memory backed section.
354 PSECTION_OBJECT Section
;
357 DPRINT("NtCreateSection()\n");
359 Section
= ObCreateObject(SectionHandle
,
362 MmSectionObjectType
);
363 DPRINT("SectionHandle %x\n", SectionHandle
);
366 return(STATUS_UNSUCCESSFUL
);
369 if (MaximumSize
!= NULL
)
371 Section
->MaximumSize
= *MaximumSize
;
375 Section
->MaximumSize
.QuadPart
= 0xffffffff;
377 Section
->SectionPageProtection
= SectionPageProtection
;
378 Section
->AllocateAttributes
= AllocationAttributes
;
379 InitializeListHead(&Section
->ViewListHead
);
380 KeInitializeSpinLock(&Section
->ViewListLock
);
381 KeInitializeMutex(&Section
->Lock
, 0);
382 memset(&Section
->PageDirectory
, 0, sizeof(Section
->PageDirectory
));
384 if (FileHandle
!= (HANDLE
)0xffffffff)
386 Status
= ObReferenceObjectByHandle(FileHandle
,
390 (PVOID
*)&Section
->FileObject
,
392 if (!NT_SUCCESS(Status
))
394 DPRINT("NtCreateSection() = %x\n",Status
);
395 ZwClose(SectionHandle
);
396 ObDereferenceObject(Section
);
402 Section
->FileObject
= NULL
;
405 DPRINT("NtCreateSection() = STATUS_SUCCESS\n");
406 ObDereferenceObject(Section
);
407 return(STATUS_SUCCESS
);
411 /**********************************************************************
429 NTSTATUS STDCALL
NtOpenSection(PHANDLE SectionHandle
,
430 ACCESS_MASK DesiredAccess
,
431 POBJECT_ATTRIBUTES ObjectAttributes
)
438 Status
= ObReferenceObjectByName(ObjectAttributes
->ObjectName
,
439 ObjectAttributes
->Attributes
,
446 if (!NT_SUCCESS(Status
))
451 Status
= ObCreateHandle(PsGetCurrentProcess(),
456 ObDereferenceObject(Object
);
461 /**********************************************************************
466 * Maps a view of a section into the virtual address space of a
471 * Handle of the section.
474 * Handle of the process.
477 * Desired base address (or NULL) on entry;
478 * Actual base address of the view on exit.
481 * Number of high order address bits that must be zero.
484 * Size in bytes of the initially committed section of
488 * Offset in bytes from the beginning of the section
489 * to the beginning of the view.
492 * Desired length of map (or zero to map all) on entry
493 * Actual length mapped on exit.
496 * Specified how the view is to be shared with
500 * Type of allocation for the pages.
503 * Protection for the committed region of the view.
508 NTSTATUS STDCALL
NtMapViewOfSection(HANDLE SectionHandle
,
509 HANDLE ProcessHandle
,
513 PLARGE_INTEGER SectionOffset
,
515 SECTION_INHERIT InheritDisposition
,
516 ULONG AllocationType
,
519 PSECTION_OBJECT Section
;
525 PMADDRESS_SPACE AddressSpace
;
527 DPRINT("NtMapViewOfSection(Section:%08lx, Process:%08lx,\n"
528 " Base:%08lx, ZeroBits:%08lx, CommitSize:%08lx,\n"
529 " SectionOffs:%08lx, *ViewSize:%08lx, InheritDisp:%08lx,\n"
530 " AllocType:%08lx, Protect:%08lx)\n",
531 SectionHandle
, ProcessHandle
, BaseAddress
, ZeroBits
,
532 CommitSize
, SectionOffset
, *ViewSize
, InheritDisposition
,
533 AllocationType
, Protect
);
535 DPRINT(" *Base:%08lx\n", *BaseAddress
);
537 Status
= ObReferenceObjectByHandle(SectionHandle
,
543 if (!(NT_SUCCESS(Status
)))
545 DPRINT("ObReference failed rc=%x\n",Status
);
549 DPRINT("Section %x\n",Section
);
550 MmLockSection(Section
);
552 Status
= ObReferenceObjectByHandle(ProcessHandle
,
553 PROCESS_VM_OPERATION
,
558 if (!NT_SUCCESS(Status
))
560 DPRINT("ObReferenceObjectByHandle(ProcessHandle, ...) failed (%x)\n",
562 MmUnlockSection(Section
);
563 ObDereferenceObject(Section
);
567 AddressSpace
= &Process
->Pcb
.AddressSpace
;
569 DPRINT("Process %x\n", Process
);
570 DPRINT("ViewSize %x\n",ViewSize
);
572 if (SectionOffset
== NULL
)
578 ViewOffset
= SectionOffset
->u
.LowPart
;
581 if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
583 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
586 DPRINT("Creating memory area\n");
587 MmLockAddressSpace(AddressSpace
);
588 Status
= MmCreateMemoryArea(Process
,
589 &Process
->Pcb
.AddressSpace
,
590 MEMORY_AREA_SECTION_VIEW_COMMIT
,
595 if (!NT_SUCCESS(Status
))
597 DPRINT("NtMapViewOfSection() = %x\n",Status
);
599 MmUnlockAddressSpace(AddressSpace
);
600 ObDereferenceObject(Process
);
601 MmUnlockSection(Section
);
602 ObDereferenceObject(Section
);
607 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
608 InsertTailList(&Section
->ViewListHead
,
609 &Result
->Data
.SectionData
.ViewListEntry
);
610 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
612 Result
->Data
.SectionData
.Section
= Section
;
613 Result
->Data
.SectionData
.ViewOffset
= ViewOffset
;
615 DPRINT("SectionOffset %x\n",SectionOffset
);
618 DPRINT("*BaseAddress %x\n",*BaseAddress
);
619 MmUnlockAddressSpace(AddressSpace
);
620 ObDereferenceObject(Process
);
621 MmUnlockSection(Section
);
623 DPRINT("NtMapViewOfSection() returning (Status %x)\n", STATUS_SUCCESS
);
624 return(STATUS_SUCCESS
);
627 NTSTATUS STDCALL
MmUnmapViewOfSection(PEPROCESS Process
,
628 PMEMORY_AREA MemoryArea
)
630 PSECTION_OBJECT Section
;
633 Section
= MemoryArea
->Data
.SectionData
.Section
;
635 DPRINT("MmUnmapViewOfSection(Section %x) SectionRC %d\n",
636 Section
, ObGetReferenceCount(Section
));
638 MmLockSection(Section
);
639 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
640 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
641 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
642 MmUnlockSection(Section
);
643 ObDereferenceObject(Section
);
645 return(STATUS_SUCCESS
);
648 /**********************************************************************
650 * NtUnmapViewOfSection
665 NTSTATUS STDCALL
NtUnmapViewOfSection (HANDLE ProcessHandle
,
670 PMEMORY_AREA MemoryArea
;
671 PMADDRESS_SPACE AddressSpace
;
673 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
674 ProcessHandle
, BaseAddress
);
676 DPRINT("Referencing process\n");
677 Status
= ObReferenceObjectByHandle(ProcessHandle
,
678 PROCESS_VM_OPERATION
,
683 if (!NT_SUCCESS(Status
))
685 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
689 AddressSpace
= &Process
->Pcb
.AddressSpace
;
691 DPRINT("Opening memory area Process %x BaseAddress %x\n",
692 Process
, BaseAddress
);
693 MmLockAddressSpace(AddressSpace
);
694 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
696 if (MemoryArea
== NULL
)
698 MmUnlockAddressSpace(AddressSpace
);
699 ObDereferenceObject(Process
);
700 return(STATUS_UNSUCCESSFUL
);
703 Status
= MmUnmapViewOfSection(Process
,
706 DPRINT("MmFreeMemoryArea()\n");
707 Status
= MmFreeMemoryArea(&Process
->Pcb
.AddressSpace
,
711 MmUnlockAddressSpace(AddressSpace
);
712 ObDereferenceObject(Process
);
718 NTSTATUS STDCALL
NtQuerySection (IN HANDLE SectionHandle
,
719 IN CINT SectionInformationClass
,
720 OUT PVOID SectionInformation
,
722 OUT PULONG ResultLength
)
724 * FUNCTION: Queries the information of a section object.
726 * SectionHandle = Handle to the section link object
727 * SectionInformationClass = Index to a certain information structure
728 * SectionInformation (OUT)= Caller supplies storage for resulting
730 * Length = Size of the supplied storage
731 * ResultLength = Data written
736 return(STATUS_UNSUCCESSFUL
);
740 NTSTATUS STDCALL
NtExtendSection(IN HANDLE SectionHandle
,
741 IN ULONG NewMaximumSize
)
747 /**********************************************************************
749 * MmAllocateSection@4
759 * Code taken from ntoskrnl/mm/special.c.
764 PVOID STDCALL
MmAllocateSection (IN ULONG Length
)
770 PMADDRESS_SPACE AddressSpace
;
772 DPRINT("MmAllocateSection(Length %x)\n",Length
);
774 AddressSpace
= MmGetKernelAddressSpace();
776 MmLockAddressSpace(AddressSpace
);
777 Status
= MmCreateMemoryArea (NULL
,
784 if (STATUS_SUCCESS
!= Status
)
788 DPRINT("Result %p\n",Result
);
789 for (i
= 0; (i
<= (Length
/ PAGESIZE
)); i
++)
792 (Result
+ (i
* PAGESIZE
)),
794 (ULONG
) MmAllocPage ());
796 MmUnlockAddressSpace(AddressSpace
);
797 return ((PVOID
)Result
);
801 /**********************************************************************
803 * MmMapViewOfSection@40
808 * FIXME: stack space allocated is 40 bytes, but nothing
809 * is known about what they are filled with.
837 MmCanFileBeTruncated (
838 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
839 IN PLARGE_INTEGER NewFileSize
849 MmDisableModifiedWriteOfSection (
859 MmFlushImageSection (
860 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
861 IN MMFLUSH_TYPE FlushType
870 MmForceSectionClosed (
882 MmMapViewInSystemSpace (
884 OUT PVOID
* MappedBase
,
889 return (STATUS_NOT_IMPLEMENTED
);
894 MmUnmapViewInSystemSpace (
899 return (STATUS_NOT_IMPLEMENTED
);
915 return (STATUS_NOT_IMPLEMENTED
);
919 /**********************************************************************
924 * Creates a section object.
927 * SectionObjiect (OUT)
928 * Caller supplied storage for the resulting pointer
929 * to a SECTION_BOJECT instance;
932 * Specifies the desired access to the section can be a
934 * STANDARD_RIGHTS_REQUIRED |
936 * SECTION_MAP_WRITE |
938 * SECTION_MAP_EXECUTE
940 * ObjectAttributes [OPTIONAL]
941 * Initialized attributes for the object can be used
942 * to create a named section;
945 * Maximizes the size of the memory section. Must be
946 * non-NULL for a page-file backed section.
947 * If value specified for a mapped file and the file is
948 * not large enough, file will be extended.
950 * SectionPageProtection
951 * Can be a combination of:
957 * AllocationAttributes
958 * Can be a combination of:
963 * Handle to a file to create a section mapped to a file
964 * instead of a memory backed section;
975 OUT PSECTION_OBJECT
* SectionObject
,
976 IN ACCESS_MASK DesiredAccess
,
977 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
978 IN PLARGE_INTEGER MaximumSize
,
979 IN ULONG SectionPageProtection
,
980 IN ULONG AllocationAttributes
,
981 IN HANDLE FileHandle OPTIONAL
,
982 IN PFILE_OBJECT File OPTIONAL
985 return (STATUS_NOT_IMPLEMENTED
);