Status = MiSessionCommitPageTables(Base,
(PVOID)((ULONG_PTR)Base +
Buckets * MI_SYSTEM_VIEW_BUCKET_SIZE));
- NT_ASSERT(NT_SUCCESS(Status));
+ ASSERT(NT_SUCCESS(Status));
}
/* Create the actual prototype PTEs for this mapping */
ULONG QuotaCharge = 0, QuotaExcess = 0;
PMMPTE PointerPte, LastPte;
MMPTE TempPte;
+ ULONG Granularity = MM_VIRTMEM_GRANULARITY;
+
DPRINT("Mapping ARM3 data section\n");
/* Get the segment for this section */
Segment = ControlArea->Segment;
+#ifdef _M_IX86
+ /* ALlow being less restrictive on x86. */
+ if (AllocationType & MEM_DOS_LIM)
+ Granularity = PAGE_SIZE;
+#endif
+
/* One can only reserve a file-based mapping, not shared memory! */
if ((AllocationType & MEM_RESERVE) && !(ControlArea->FilePointer))
{
return STATUS_INVALID_PARAMETER_9;
}
- /* This flag determines alignment, but ARM3 does not yet support it */
- ASSERT((AllocationType & MEM_DOS_LIM) == 0);
-
/* First, increase the map count. No purging is supported yet */
Status = MiCheckPurgeAndUpMapCount(ControlArea, FALSE);
if (!NT_SUCCESS(Status)) return Status;
if (*BaseAddress != NULL)
{
/* Just align what the caller gave us */
- StartAddress = ROUND_UP((ULONG_PTR)*BaseAddress, _64K);
+ StartAddress = ALIGN_DOWN_BY((ULONG_PTR)*BaseAddress, Granularity);
}
else if (Section->Address.StartingVpn != 0)
{
&StartAddress,
ViewSizeInPages * PAGE_SIZE,
MAXULONG_PTR >> ZeroBits,
- MM_VIRTMEM_GRANULARITY,
+ Granularity,
AllocationType);
if (!NT_SUCCESS(Status))
{
if (AllocationAttributes & SEC_RESERVE) ControlArea->u.Flags.Reserve = 1;
if (AllocationAttributes & SEC_COMMIT) ControlArea->u.Flags.Commit = 1;
+ /* We just allocated it */
+ ControlArea->u.Flags.BeingCreated = 1;
+
/* The subsection follows, write the mask, PTE count and point back to the CA */
Subsection = (PSUBSECTION)(ControlArea + 1);
Subsection->ControlArea = ControlArea;
IN PMMPTE PointerPte,
IN ULONG ProtectionMask,
IN PMMPFN Pfn1,
- IN BOOLEAN CaptureDirtyBit)
+ IN BOOLEAN UpdateDirty)
{
MMPTE TempPte, PreviousPte;
KIRQL OldIrql;
//
// Windows updates the relevant PFN1 information, we currently don't.
//
- if (CaptureDirtyBit) DPRINT1("Warning, not handling dirty bit\n");
+ if (UpdateDirty && PreviousPte.u.Hard.Dirty)
+ {
+ if (!Pfn1->u3.e1.Modified)
+ {
+ DPRINT1("FIXME: Mark PFN as dirty\n");
+ }
+ }
//
// Not supported in ARM3
BOOLEAN FileLock = FALSE, KernelCall = FALSE;
KIRQL OldIrql;
PFILE_OBJECT File;
+ BOOLEAN UserRefIncremented = FALSE;
PVOID PreviousSectionPointer;
/* Make the same sanity checks that the Nt interface should've validated */
/* Write down that this CA is being created, and set it */
ControlArea->u.Flags.BeingCreated = TRUE;
+ ASSERT((AllocationAttributes & SEC_IMAGE) == 0);
PreviousSectionPointer = File->SectionObjectPointer;
File->SectionObjectPointer->DataSectionObject = ControlArea;
SectionPageProtection,
AllocationAttributes,
KernelCall);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Lock the PFN database while we play with the section pointers */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Reset the waiting-for-deletion event */
+ ASSERT(ControlArea->WaitingForDeletion == NULL);
+ ControlArea->WaitingForDeletion = NULL;
+
+ /* Set the file pointer NULL flag */
+ ASSERT(ControlArea->u.Flags.FilePointerNull == 0);
+ ControlArea->u.Flags.FilePointerNull = TRUE;
+
+ /* Delete the data section object */
+ ASSERT((AllocationAttributes & SEC_IMAGE) == 0);
+ File->SectionObjectPointer->DataSectionObject = NULL;
+
+ /* No longer being created */
+ ControlArea->u.Flags.BeingCreated = FALSE;
+
+ /* We can release the PFN lock now */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ /* Check if we locked and set the IRP */
+ if (FileLock)
+ {
+ /* Undo */
+ IoSetTopLevelIrp(NULL);
+ //FsRtlReleaseFile(File);
+ }
+
+ /* Free the control area and de-ref the file object */
+ ExFreePool(ControlArea);
+ ObDereferenceObject(File);
+
+ /* All done */
+ return Status;
+ }
+
+ /* On success, we expect this */
ASSERT(PreviousSectionPointer == File->SectionObjectPointer);
- ASSERT(NT_SUCCESS(Status));
/* Check if a maximum size was specified */
if (!InputMaximumSize->QuadPart)
/* Set the size here, and read the control area */
Section.SizeOfSection.QuadPart = NewSegment->SizeOfSegment;
ControlArea = NewSegment->ControlArea;
+
+ /* MiCreatePagingFileMap increments user references */
+ UserRefIncremented = TRUE;
}
/* Did we already have a segment? */
/* Check if this is a user-mode read-write non-image file mapping */
if (!(FileObject) &&
(SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) &&
- (ControlArea->u.Flags.Image == 0) &&
- (ControlArea->FilePointer != NULL))
+ !(ControlArea->u.Flags.Image) &&
+ (ControlArea->FilePointer))
{
/* Add a reference and set the flag */
- Section.u.Flags.UserWritable = 1;
- InterlockedIncrement((PLONG)&ControlArea->WritableUserReferences);
+ Section.u.Flags.UserWritable = TRUE;
+ InterlockedIncrement((volatile LONG*)&ControlArea->WritableUserReferences);
}
/* Check for image mappings or page file mappings */
- if ((ControlArea->u.Flags.Image == 1) || !(ControlArea->FilePointer))
+ if ((ControlArea->u.Flags.Image) || !(ControlArea->FilePointer))
{
/* Charge the segment size, and allocate a subsection */
PagedCharge = sizeof(SECTION) + NewSegment->TotalNumberOfPtes * sizeof(MMPTE);
PagedCharge,
NonPagedCharge,
(PVOID*)&NewSection);
- ASSERT(NT_SUCCESS(Status));
+ if (!NT_SUCCESS(Status))
+ {
+ /* Check if this is a user-mode read-write non-image file mapping */
+ if (!(FileObject) &&
+ (SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) &&
+ !(ControlArea->u.Flags.Image) &&
+ (ControlArea->FilePointer))
+ {
+ /* Remove a reference and check the flag */
+ ASSERT(Section.u.Flags.UserWritable == 1);
+ InterlockedDecrement((volatile LONG*)&ControlArea->WritableUserReferences);
+ }
+
+ /* Check if a user reference was added */
+ if (UserRefIncremented)
+ {
+ /* Acquire the PFN lock while we change counters */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Decrement the accounting counters */
+ ControlArea->NumberOfSectionReferences--;
+ ASSERT((LONG)ControlArea->NumberOfUserReferences > 0);
+ ControlArea->NumberOfUserReferences--;
+
+ /* Check if we should destroy the CA and release the lock */
+ MiCheckControlArea(ControlArea, OldIrql);
+ }
+
+ /* Return the failure code */
+ return Status;
+ }
+
+ /* NOTE: Past this point, all failures will be handled by Ob upon ref->0 */
/* Now copy the local section object from the stack into this new object */
RtlCopyMemory(NewSection, &Section, sizeof(SECTION));
ASSERT(KernelCall == FALSE);
NewSection->u.Flags.UserReference = TRUE;
- /* Migrate the attribute into a flag */
- if (AllocationAttributes & SEC_NO_CHANGE) NewSection->u.Flags.NoChange = TRUE;
-
- /* If R/W access is not requested, this might eventually become a CoW mapping */
- if (!(SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)))
- {
- NewSection->u.Flags.CopyOnWrite = TRUE;
- }
-
/* Is this a "based" allocation, in which all mappings are identical? */
if (AllocationAttributes & SEC_BASED)
{
- /* Convert the flag, and make sure the section isn't too big */
- NewSection->u.Flags.Based = TRUE;
- if ((ULONGLONG)NewSection->SizeOfSection.QuadPart >
- (ULONG_PTR)MmHighSectionBase)
- {
- DPRINT1("BASED section is too large\n");
- ObDereferenceObject(NewSection);
- return STATUS_NO_MEMORY;
- }
-
/* Lock the VAD tree during the search */
KeAcquireGuardedMutex(&MmSectionBasedMutex);
- /* Find an address top-down */
- Status = MiFindEmptyAddressRangeDownBasedTree(NewSection->SizeOfSection.LowPart,
- (ULONG_PTR)MmHighSectionBase,
- _64K,
- &MmSectionBasedRoot,
- &NewSection->Address.StartingVpn);
- ASSERT(NT_SUCCESS(Status));
+ /* Is it a brand new ControArea ? */
+ if (ControlArea->u.Flags.BeingCreated == 1)
+ {
+ ASSERT(ControlArea->u.Flags.Based == 1);
+ /* Then we must find a global address, top-down */
+ Status = MiFindEmptyAddressRangeDownBasedTree((SIZE_T)ControlArea->Segment->SizeOfSegment,
+ (ULONG_PTR)MmHighSectionBase,
+ _64K,
+ &MmSectionBasedRoot,
+ (ULONG_PTR*)&ControlArea->Segment->BasedAddress);
- /* Compute the ending address and insert it into the VAD tree */
- NewSection->Address.EndingVpn = NewSection->Address.StartingVpn +
- NewSection->SizeOfSection.LowPart -
- 1;
- MiInsertBasedSection(NewSection);
+ if (!NT_SUCCESS(Status))
+ {
+ /* No way to find a valid range. */
+ KeReleaseGuardedMutex(&MmSectionBasedMutex);
+ ControlArea->u.Flags.Based = 0;
+ NewSection->u.Flags.Based = 0;
+ ObDereferenceObject(NewSection);
+ return Status;
+ }
+
+ /* Compute the ending address and insert it into the VAD tree */
+ NewSection->Address.StartingVpn = (ULONG_PTR)ControlArea->Segment->BasedAddress;
+ NewSection->Address.EndingVpn = NewSection->Address.StartingVpn + NewSection->SizeOfSection.LowPart - 1;
+ MiInsertBasedSection(NewSection);
+ }
+ else
+ {
+ /* FIXME : Should we deny section creation if SEC_BASED is not set ? Can we have two different section objects on the same based address ? Investigate !*/
+ ASSERT(FALSE);
+ }
- /* Finally release the lock */
KeReleaseGuardedMutex(&MmSectionBasedMutex);
}
+ /* The control area is not being created anymore */
+ if (ControlArea->u.Flags.BeingCreated == 1)
+ {
+ /* Acquire the PFN lock while we set control area flags */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Take off the being created flag, and then release the lock */
+ ControlArea->u.Flags.BeingCreated = 0;
+ NewSection->u.Flags.BeingCreated = 0;
+
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ }
+
+ /* Migrate the attribute into a flag */
+ if (AllocationAttributes & SEC_NO_CHANGE) NewSection->u.Flags.NoChange = TRUE;
+
+ /* If R/W access is not requested, this might eventually become a CoW mapping */
+ if (!(SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)))
+ {
+ NewSection->u.Flags.CopyOnWrite = TRUE;
+ }
+
/* Write down if this was a kernel call */
ControlArea->u.Flags.WasPurged |= KernelCall;
ASSERT(ControlArea->u.Flags.WasPurged == FALSE);
ZeroBits,
AllocationType);
- /* Detatch if needed, then return status */
+ /* Detach if needed, then return status */
if (Attached) KeUnstackDetachProcess(&ApcState);
return Status;
}
SectionObject = (PSECTION)ObjectBody;
+ if (SectionObject->u.Flags.Based == 1)
+ {
+ /* Remove the node from the global section address tree */
+ KeAcquireGuardedMutex(&MmSectionBasedMutex);
+ MiRemoveNode(&SectionObject->Address, &MmSectionBasedRoot);
+ KeReleaseGuardedMutex(&MmSectionBasedMutex);
+ }
+
/* Lock the PFN database */
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
MiCheckControlArea(ControlArea, OldIrql);
}
+ULONG
+NTAPI
+MmDoesFileHaveUserWritableReferences(IN PSECTION_OBJECT_POINTERS SectionPointer)
+{
+ UNIMPLEMENTED;
+ return 0;
+}
+
/* SYSTEM CALLS ***************************************************************/
NTSTATUS
ACCESS_MASK DesiredAccess;
ULONG ProtectionMask;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
-
- /* Check for invalid zero bits */
- if (ZeroBits > 21) // per-arch?
- {
- DPRINT1("Invalid zero bits\n");
- return STATUS_INVALID_PARAMETER_4;
- }
+#ifdef _M_IX86
+ static const ULONG ValidAllocationType = (MEM_TOP_DOWN | MEM_LARGE_PAGES |
+ MEM_DOS_LIM | SEC_NO_CHANGE | MEM_RESERVE);
+#else
+ static const ULONG ValidAllocationType = (MEM_TOP_DOWN | MEM_LARGE_PAGES |
+ SEC_NO_CHANGE | MEM_RESERVE);
+#endif
/* Check for invalid inherit disposition */
if ((InheritDisposition > ViewUnmap) || (InheritDisposition < ViewShare))
}
/* Allow only valid allocation types */
- if ((AllocationType & ~(MEM_TOP_DOWN | MEM_LARGE_PAGES | MEM_DOS_LIM |
- SEC_NO_CHANGE | MEM_RESERVE)))
+ if (AllocationType & ~ValidAllocationType)
{
DPRINT1("Invalid allocation type\n");
return STATUS_INVALID_PARAMETER_9;
return STATUS_INVALID_PAGE_PROTECTION;
}
- /* Check for non-allocation-granularity-aligned BaseAddress */
- if (BaseAddress && (*BaseAddress != ALIGN_DOWN_POINTER_BY(*BaseAddress, MM_VIRTMEM_GRANULARITY)))
- {
- DPRINT("BaseAddress is not at 64-kilobyte address boundary.");
- return STATUS_MAPPED_ALIGNMENT;
- }
-
/* Now convert the protection mask into desired section access mask */
DesiredAccess = MmMakeSectionAccess[ProtectionMask & 0x7];
}
/* Check for invalid zero bits */
- if (((ULONG_PTR)SafeBaseAddress + SafeViewSize) > (0xFFFFFFFF >> ZeroBits)) // arch?
+ if (ZeroBits)
{
- DPRINT1("Invalid zero bits\n");
- return STATUS_INVALID_PARAMETER_4;
+ if (ZeroBits > MI_MAX_ZERO_BITS)
+ {
+ DPRINT1("Invalid zero bits\n");
+ return STATUS_INVALID_PARAMETER_4;
+ }
+
+ if ((((ULONG_PTR)SafeBaseAddress << ZeroBits) >> ZeroBits) != (ULONG_PTR)SafeBaseAddress)
+ {
+ DPRINT1("Invalid zero bits\n");
+ return STATUS_INVALID_PARAMETER_4;
+ }
+
+ if (((((ULONG_PTR)SafeBaseAddress + SafeViewSize) << ZeroBits) >> ZeroBits) != ((ULONG_PTR)SafeBaseAddress + SafeViewSize))
+ {
+ DPRINT1("Invalid zero bits\n");
+ return STATUS_INVALID_PARAMETER_4;
+ }
}
/* Reference the process */
return Status;
}
+ if (MiIsRosSectionObject(Section) &&
+ (Section->AllocationAttributes & SEC_PHYSICALMEMORY))
+ {
+ if (PreviousMode == UserMode &&
+ SafeSectionOffset.QuadPart + SafeViewSize > MmHighestPhysicalPage << PAGE_SHIFT)
+ {
+ DPRINT1("Denying map past highest physical page.\n");
+ ObDereferenceObject(Section);
+ ObDereferenceObject(Process);
+ return STATUS_INVALID_PARAMETER_6;
+ }
+ }
+ else if (!(AllocationType & MEM_DOS_LIM))
+ {
+ /* Check for non-allocation-granularity-aligned BaseAddress */
+ if (SafeBaseAddress != ALIGN_DOWN_POINTER_BY(SafeBaseAddress, MM_VIRTMEM_GRANULARITY))
+ {
+ DPRINT("BaseAddress is not at 64-kilobyte address boundary.\n");
+ ObDereferenceObject(Section);
+ ObDereferenceObject(Process);
+ return STATUS_MAPPED_ALIGNMENT;
+ }
+
+ /* Do the same for the section offset */
+ if (SafeSectionOffset.LowPart != ALIGN_DOWN_BY(SafeSectionOffset.LowPart, MM_VIRTMEM_GRANULARITY))
+ {
+ DPRINT("SectionOffset is not at 64-kilobyte address boundary.\n");
+ ObDereferenceObject(Section);
+ ObDereferenceObject(Process);
+ return STATUS_MAPPED_ALIGNMENT;
+ }
+ }
+
/* Now do the actual mapping */
Status = MmMapViewOfSection(Section,
Process,
if (NT_SUCCESS(Status))
{
/* Check if this is an image for the current process */
- if ((Section->AllocationAttributes & SEC_IMAGE) &&
+ if (MiIsRosSectionObject(Section) &&
+ (Section->AllocationAttributes & SEC_IMAGE) &&
(Process == PsGetCurrentProcess()) &&
(Status != STATUS_IMAGE_NOT_AT_BASE))
{