Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygensection.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: ntoskrnl/mm/ARM3/sectopm.c 00005 * PURPOSE: ARM Memory Manager Section Support 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 */ 00008 00009 /* INCLUDES *******************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 #define MODULE_INVOLVED_IN_ARM3 00016 #include "../ARM3/miarm.h" 00017 00018 /* GLOBALS ********************************************************************/ 00019 00020 ACCESS_MASK MmMakeSectionAccess[8] = 00021 { 00022 SECTION_MAP_READ, 00023 SECTION_MAP_READ, 00024 SECTION_MAP_EXECUTE, 00025 SECTION_MAP_EXECUTE | SECTION_MAP_READ, 00026 SECTION_MAP_WRITE, 00027 SECTION_MAP_READ, 00028 SECTION_MAP_EXECUTE | SECTION_MAP_WRITE, 00029 SECTION_MAP_EXECUTE | SECTION_MAP_READ 00030 }; 00031 00032 ACCESS_MASK MmMakeFileAccess[8] = 00033 { 00034 FILE_READ_DATA, 00035 FILE_READ_DATA, 00036 FILE_EXECUTE, 00037 FILE_EXECUTE | FILE_READ_DATA, 00038 FILE_WRITE_DATA | FILE_READ_DATA, 00039 FILE_READ_DATA, 00040 FILE_EXECUTE | FILE_WRITE_DATA | FILE_READ_DATA, 00041 FILE_EXECUTE | FILE_READ_DATA 00042 }; 00043 00044 CHAR MmUserProtectionToMask1[16] = 00045 { 00046 0, 00047 MM_NOACCESS, 00048 MM_READONLY, 00049 (CHAR)MM_INVALID_PROTECTION, 00050 MM_READWRITE, 00051 (CHAR)MM_INVALID_PROTECTION, 00052 (CHAR)MM_INVALID_PROTECTION, 00053 (CHAR)MM_INVALID_PROTECTION, 00054 MM_WRITECOPY, 00055 (CHAR)MM_INVALID_PROTECTION, 00056 (CHAR)MM_INVALID_PROTECTION, 00057 (CHAR)MM_INVALID_PROTECTION, 00058 (CHAR)MM_INVALID_PROTECTION, 00059 (CHAR)MM_INVALID_PROTECTION, 00060 (CHAR)MM_INVALID_PROTECTION, 00061 (CHAR)MM_INVALID_PROTECTION 00062 }; 00063 00064 CHAR MmUserProtectionToMask2[16] = 00065 { 00066 0, 00067 MM_EXECUTE, 00068 MM_EXECUTE_READ, 00069 (CHAR)MM_INVALID_PROTECTION, 00070 MM_EXECUTE_READWRITE, 00071 (CHAR)MM_INVALID_PROTECTION, 00072 (CHAR)MM_INVALID_PROTECTION, 00073 (CHAR)MM_INVALID_PROTECTION, 00074 MM_EXECUTE_WRITECOPY, 00075 (CHAR)MM_INVALID_PROTECTION, 00076 (CHAR)MM_INVALID_PROTECTION, 00077 (CHAR)MM_INVALID_PROTECTION, 00078 (CHAR)MM_INVALID_PROTECTION, 00079 (CHAR)MM_INVALID_PROTECTION, 00080 (CHAR)MM_INVALID_PROTECTION, 00081 (CHAR)MM_INVALID_PROTECTION 00082 }; 00083 00084 MMSESSION MmSession; 00085 KGUARDED_MUTEX MmSectionCommitMutex; 00086 MM_AVL_TABLE MmSectionBasedRoot; 00087 KGUARDED_MUTEX MmSectionBasedMutex; 00088 PVOID MmHighSectionBase; 00089 00090 /* PRIVATE FUNCTIONS **********************************************************/ 00091 00092 ACCESS_MASK 00093 NTAPI 00094 MiArm3GetCorrectFileAccessMask(IN ACCESS_MASK SectionPageProtection) 00095 { 00096 ULONG ProtectionMask; 00097 00098 /* Calculate the protection mask and make sure it's valid */ 00099 ProtectionMask = MiMakeProtectionMask(SectionPageProtection); 00100 if (ProtectionMask == MM_INVALID_PROTECTION) 00101 { 00102 DPRINT1("Invalid protection mask\n"); 00103 return STATUS_INVALID_PAGE_PROTECTION; 00104 } 00105 00106 /* Now convert it to the required file access */ 00107 return MmMakeFileAccess[ProtectionMask & 0x7]; 00108 } 00109 00110 ULONG 00111 NTAPI 00112 MiMakeProtectionMask(IN ULONG Protect) 00113 { 00114 ULONG Mask1, Mask2, ProtectMask; 00115 00116 /* PAGE_EXECUTE_WRITECOMBINE is theoretically the maximum */ 00117 if (Protect >= (PAGE_WRITECOMBINE * 2)) return MM_INVALID_PROTECTION; 00118 00119 /* 00120 * Windows API protection mask can be understood as two bitfields, differing 00121 * by whether or not execute rights are being requested 00122 */ 00123 Mask1 = Protect & 0xF; 00124 Mask2 = (Protect >> 4) & 0xF; 00125 00126 /* Check which field is there */ 00127 if (!Mask1) 00128 { 00129 /* Mask2 must be there, use it to determine the PTE protection */ 00130 if (!Mask2) return MM_INVALID_PROTECTION; 00131 ProtectMask = MmUserProtectionToMask2[Mask2]; 00132 } 00133 else 00134 { 00135 /* Mask2 should not be there, use Mask1 to determine the PTE mask */ 00136 if (Mask2) return MM_INVALID_PROTECTION; 00137 ProtectMask = MmUserProtectionToMask1[Mask1]; 00138 } 00139 00140 /* Make sure the final mask is a valid one */ 00141 if (ProtectMask == MM_INVALID_PROTECTION) return MM_INVALID_PROTECTION; 00142 00143 /* Check for PAGE_GUARD option */ 00144 if (Protect & PAGE_GUARD) 00145 { 00146 /* It's not valid on no-access, nocache, or writecombine pages */ 00147 if ((ProtectMask == MM_NOACCESS) || 00148 (Protect & (PAGE_NOCACHE | PAGE_WRITECOMBINE))) 00149 { 00150 /* Fail such requests */ 00151 return MM_INVALID_PROTECTION; 00152 } 00153 00154 /* This actually turns on guard page in this scenario! */ 00155 ProtectMask |= MM_DECOMMIT; 00156 } 00157 00158 /* Check for nocache option */ 00159 if (Protect & PAGE_NOCACHE) 00160 { 00161 /* The earlier check should've eliminated this possibility */ 00162 ASSERT((Protect & PAGE_GUARD) == 0); 00163 00164 /* Check for no-access page or write combine page */ 00165 if ((ProtectMask == MM_NOACCESS) || (Protect & PAGE_WRITECOMBINE)) 00166 { 00167 /* Such a request is invalid */ 00168 return MM_INVALID_PROTECTION; 00169 } 00170 00171 /* Add the PTE flag */ 00172 ProtectMask |= MM_NOCACHE; 00173 } 00174 00175 /* Check for write combine option */ 00176 if (Protect & PAGE_WRITECOMBINE) 00177 { 00178 /* The two earlier scenarios should've caught this */ 00179 ASSERT((Protect & (PAGE_GUARD | PAGE_NOACCESS)) == 0); 00180 00181 /* Don't allow on no-access pages */ 00182 if (ProtectMask == MM_NOACCESS) return MM_INVALID_PROTECTION; 00183 00184 /* This actually turns on write-combine in this scenario! */ 00185 ProtectMask |= MM_NOACCESS; 00186 } 00187 00188 /* Return the final MM PTE protection mask */ 00189 return ProtectMask; 00190 } 00191 00192 BOOLEAN 00193 NTAPI 00194 MiInitializeSystemSpaceMap(IN PVOID InputSession OPTIONAL) 00195 { 00196 SIZE_T AllocSize, BitmapSize; 00197 PMMSESSION Session; 00198 00199 /* For now, always use the global session */ 00200 ASSERT(InputSession == NULL); 00201 Session = &MmSession; 00202 00203 /* Initialize the system space lock */ 00204 Session->SystemSpaceViewLockPointer = &Session->SystemSpaceViewLock; 00205 KeInitializeGuardedMutex(Session->SystemSpaceViewLockPointer); 00206 00207 /* Set the start address */ 00208 Session->SystemSpaceViewStart = MiSystemViewStart; 00209 00210 /* Create a bitmap to describe system space */ 00211 BitmapSize = sizeof(RTL_BITMAP) + ((((MmSystemViewSize / MI_SYSTEM_VIEW_BUCKET_SIZE) + 31) / 32) * sizeof(ULONG)); 00212 Session->SystemSpaceBitMap = ExAllocatePoolWithTag(NonPagedPool, 00213 BitmapSize, 00214 TAG_MM); 00215 ASSERT(Session->SystemSpaceBitMap); 00216 RtlInitializeBitMap(Session->SystemSpaceBitMap, 00217 (PULONG)(Session->SystemSpaceBitMap + 1), 00218 (ULONG)(MmSystemViewSize / MI_SYSTEM_VIEW_BUCKET_SIZE)); 00219 00220 /* Set system space fully empty to begin with */ 00221 RtlClearAllBits(Session->SystemSpaceBitMap); 00222 00223 /* Set default hash flags */ 00224 Session->SystemSpaceHashSize = 31; 00225 Session->SystemSpaceHashKey = Session->SystemSpaceHashSize - 1; 00226 Session->SystemSpaceHashEntries = 0; 00227 00228 /* Calculate how much space for the hash views we'll need */ 00229 AllocSize = sizeof(MMVIEW) * Session->SystemSpaceHashSize; 00230 ASSERT(AllocSize < PAGE_SIZE); 00231 00232 /* Allocate and zero the view table */ 00233 Session->SystemSpaceViewTable = ExAllocatePoolWithTag(NonPagedPool, 00234 AllocSize, 00235 TAG_MM); 00236 ASSERT(Session->SystemSpaceViewTable != NULL); 00237 RtlZeroMemory(Session->SystemSpaceViewTable, AllocSize); 00238 00239 /* Success */ 00240 return TRUE; 00241 } 00242 00243 PVOID 00244 NTAPI 00245 MiInsertInSystemSpace(IN PMMSESSION Session, 00246 IN ULONG Buckets, 00247 IN PCONTROL_AREA ControlArea) 00248 { 00249 PVOID Base; 00250 ULONG Entry, Hash, i, HashSize; 00251 PMMVIEW OldTable; 00252 PAGED_CODE(); 00253 00254 /* Only global mappings supported for now */ 00255 ASSERT(Session == &MmSession); 00256 00257 /* Stay within 4GB */ 00258 ASSERT(Buckets < MI_SYSTEM_VIEW_BUCKET_SIZE); 00259 00260 /* Lock system space */ 00261 KeAcquireGuardedMutex(Session->SystemSpaceViewLockPointer); 00262 00263 /* Check if we're going to exhaust hash entries */ 00264 if ((Session->SystemSpaceHashEntries + 8) > Session->SystemSpaceHashSize) 00265 { 00266 /* Double the hash size */ 00267 HashSize = Session->SystemSpaceHashSize * 2; 00268 00269 /* Save the old table and allocate a new one */ 00270 OldTable = Session->SystemSpaceViewTable; 00271 Session->SystemSpaceViewTable = ExAllocatePoolWithTag(NonPagedPool, 00272 HashSize * 00273 sizeof(MMVIEW), 00274 ' mM'); 00275 if (!Session->SystemSpaceViewTable) 00276 { 00277 /* Failed to allocate a new table, keep the old one for now */ 00278 Session->SystemSpaceViewTable = OldTable; 00279 } 00280 else 00281 { 00282 /* Clear the new table and set the new ahsh and key */ 00283 RtlZeroMemory(Session->SystemSpaceViewTable, HashSize * sizeof(MMVIEW)); 00284 Session->SystemSpaceHashSize = HashSize; 00285 Session->SystemSpaceHashKey = Session->SystemSpaceHashSize - 1; 00286 00287 /* Loop the old table */ 00288 for (i = 0; i < Session->SystemSpaceHashSize / 2; i++) 00289 { 00290 /* Check if the entry was valid */ 00291 if (OldTable[i].Entry) 00292 { 00293 /* Re-hash the old entry and search for space in the new table */ 00294 Hash = (OldTable[i].Entry >> 16) % Session->SystemSpaceHashKey; 00295 while (Session->SystemSpaceViewTable[Hash].Entry) 00296 { 00297 /* Loop back at the beginning if we had an overflow */ 00298 if (++Hash >= Session->SystemSpaceHashSize) Hash = 0; 00299 } 00300 00301 /* Write the old entry in the new table */ 00302 Session->SystemSpaceViewTable[Hash] = OldTable[i]; 00303 } 00304 } 00305 00306 /* Free the old table */ 00307 ExFreePool(OldTable); 00308 } 00309 } 00310 00311 /* Check if we ran out */ 00312 if (Session->SystemSpaceHashEntries == Session->SystemSpaceHashSize) 00313 { 00314 DPRINT1("Ran out of system view hash entries\n"); 00315 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 00316 return NULL; 00317 } 00318 00319 /* Find space where to map this view */ 00320 i = RtlFindClearBitsAndSet(Session->SystemSpaceBitMap, Buckets, 0); 00321 if (i == 0xFFFFFFFF) 00322 { 00323 /* Out of space, fail */ 00324 Session->BitmapFailures++; 00325 DPRINT1("Out of system view space\n"); 00326 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 00327 return NULL; 00328 } 00329 00330 /* Compute the base address */ 00331 Base = (PVOID)((ULONG_PTR)Session->SystemSpaceViewStart + (i * MI_SYSTEM_VIEW_BUCKET_SIZE)); 00332 00333 /* Get the hash entry for this allocation */ 00334 Entry = ((ULONG_PTR)Base & ~(MI_SYSTEM_VIEW_BUCKET_SIZE - 1)) + Buckets; 00335 Hash = (Entry >> 16) % Session->SystemSpaceHashKey; 00336 00337 /* Loop hash entries until a free one is found */ 00338 while (Session->SystemSpaceViewTable[Hash].Entry) 00339 { 00340 /* Unless we overflow, in which case loop back at hash o */ 00341 if (++Hash >= Session->SystemSpaceHashSize) Hash = 0; 00342 } 00343 00344 /* Add this entry into the hash table */ 00345 Session->SystemSpaceViewTable[Hash].Entry = Entry; 00346 Session->SystemSpaceViewTable[Hash].ControlArea = ControlArea; 00347 00348 /* Hash entry found, increment total and return the base address */ 00349 Session->SystemSpaceHashEntries++; 00350 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 00351 return Base; 00352 } 00353 00354 NTSTATUS 00355 NTAPI 00356 MiAddMappedPtes(IN PMMPTE FirstPte, 00357 IN PFN_NUMBER PteCount, 00358 IN PCONTROL_AREA ControlArea) 00359 { 00360 MMPTE TempPte; 00361 PMMPTE PointerPte, ProtoPte, LastProtoPte, LastPte; 00362 PSUBSECTION Subsection; 00363 00364 /* ARM3 doesn't support this yet */ 00365 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 00366 ASSERT(ControlArea->u.Flags.Rom == 0); 00367 ASSERT(ControlArea->FilePointer == NULL); 00368 00369 /* Sanity checks */ 00370 ASSERT(PteCount != 0); 00371 ASSERT(ControlArea->NumberOfMappedViews >= 1); 00372 ASSERT(ControlArea->NumberOfUserReferences >= 1); 00373 ASSERT(ControlArea->NumberOfSectionReferences != 0); 00374 ASSERT(ControlArea->u.Flags.BeingCreated == 0); 00375 ASSERT(ControlArea->u.Flags.BeingDeleted == 0); 00376 ASSERT(ControlArea->u.Flags.BeingPurged == 0); 00377 00378 /* Get the PTEs for the actual mapping */ 00379 PointerPte = FirstPte; 00380 LastPte = FirstPte + PteCount; 00381 00382 /* Get the prototype PTEs that desribe the section mapping in the subsection */ 00383 Subsection = (PSUBSECTION)(ControlArea + 1); 00384 ProtoPte = Subsection->SubsectionBase; 00385 LastProtoPte = &Subsection->SubsectionBase[Subsection->PtesInSubsection]; 00386 00387 /* Loop the PTEs for the mapping */ 00388 while (PointerPte < LastPte) 00389 { 00390 /* We may have run out of prototype PTEs in this subsection */ 00391 if (ProtoPte >= LastProtoPte) 00392 { 00393 /* But we don't handle this yet */ 00394 ASSERT(FALSE); 00395 } 00396 00397 /* The PTE should be completely clear */ 00398 ASSERT(PointerPte->u.Long == 0); 00399 00400 /* Build the prototype PTE and write it */ 00401 MI_MAKE_PROTOTYPE_PTE(&TempPte, ProtoPte); 00402 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 00403 00404 /* Keep going */ 00405 PointerPte++; 00406 ProtoPte++; 00407 } 00408 00409 /* No failure path */ 00410 return STATUS_SUCCESS; 00411 } 00412 00413 VOID 00414 NTAPI 00415 MiFillSystemPageDirectory(IN PVOID Base, 00416 IN SIZE_T NumberOfBytes) 00417 { 00418 PMMPDE PointerPde, LastPde, SystemMapPde; 00419 MMPDE TempPde; 00420 PFN_NUMBER PageFrameIndex, ParentPage; 00421 KIRQL OldIrql; 00422 PAGED_CODE(); 00423 00424 /* Find the PDEs needed for this mapping */ 00425 PointerPde = MiAddressToPde(Base); 00426 LastPde = MiAddressToPde((PVOID)((ULONG_PTR)Base + NumberOfBytes - 1)); 00427 00428 #if (_MI_PAGING_LEVELS == 2) 00429 /* Find the system double-mapped PDE that describes this mapping */ 00430 SystemMapPde = &MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)]; 00431 #else 00432 /* We don't have a double mapping */ 00433 SystemMapPde = PointerPde; 00434 #endif 00435 00436 /* Use the PDE template and loop the PDEs */ 00437 TempPde = ValidKernelPde; 00438 while (PointerPde <= LastPde) 00439 { 00440 /* Lock the PFN database */ 00441 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00442 00443 /* Check if we don't already have this PDE mapped */ 00444 if (SystemMapPde->u.Hard.Valid == 0) 00445 { 00446 /* Grab a page for it */ 00447 MI_SET_USAGE(MI_USAGE_PAGE_TABLE); 00448 MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName); 00449 PageFrameIndex = MiRemoveZeroPage(MI_GET_NEXT_COLOR()); 00450 ASSERT(PageFrameIndex); 00451 TempPde.u.Hard.PageFrameNumber = PageFrameIndex; 00452 00453 #if (_MI_PAGING_LEVELS == 2) 00454 ParentPage = MmSystemPageDirectory[(PointerPde - MiAddressToPde(NULL)) / PDE_COUNT]; 00455 #else 00456 ParentPage = MiPdeToPpe(PointerPde)->u.Hard.PageFrameNumber; 00457 #endif 00458 /* Initialize its PFN entry, with the parent system page directory page table */ 00459 MiInitializePfnForOtherProcess(PageFrameIndex, 00460 (PMMPTE)PointerPde, 00461 ParentPage); 00462 00463 /* Make the system PDE entry valid */ 00464 MI_WRITE_VALID_PDE(SystemMapPde, TempPde); 00465 00466 /* The system PDE entry might be the PDE itself, so check for this */ 00467 if (PointerPde->u.Hard.Valid == 0) 00468 { 00469 /* It's different, so make the real PDE valid too */ 00470 MI_WRITE_VALID_PDE(PointerPde, TempPde); 00471 } 00472 } 00473 00474 /* Release the lock and keep going with the next PDE */ 00475 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 00476 SystemMapPde++; 00477 PointerPde++; 00478 } 00479 } 00480 00481 NTSTATUS 00482 NTAPI 00483 MiCheckPurgeAndUpMapCount(IN PCONTROL_AREA ControlArea, 00484 IN BOOLEAN FailIfSystemViews) 00485 { 00486 KIRQL OldIrql; 00487 00488 /* Flag not yet supported */ 00489 ASSERT(FailIfSystemViews == FALSE); 00490 00491 /* Lock the PFN database */ 00492 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00493 00494 /* State not yet supported */ 00495 ASSERT(ControlArea->u.Flags.BeingPurged == 0); 00496 00497 /* Increase the reference counts */ 00498 ControlArea->NumberOfMappedViews++; 00499 ControlArea->NumberOfUserReferences++; 00500 ASSERT(ControlArea->NumberOfSectionReferences != 0); 00501 00502 /* Release the PFN lock and return success */ 00503 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 00504 return STATUS_SUCCESS; 00505 } 00506 00507 PSUBSECTION 00508 NTAPI 00509 MiLocateSubsection(IN PMMVAD Vad, 00510 IN ULONG_PTR Vpn) 00511 { 00512 PSUBSECTION Subsection; 00513 PCONTROL_AREA ControlArea; 00514 ULONG_PTR PteOffset; 00515 00516 /* Get the control area */ 00517 ControlArea = Vad->ControlArea; 00518 ASSERT(ControlArea->u.Flags.Rom == 0); 00519 ASSERT(ControlArea->u.Flags.Image == 0); 00520 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 00521 00522 /* Get the subsection */ 00523 Subsection = (PSUBSECTION)(ControlArea + 1); 00524 00525 /* We only support single-subsection segments */ 00526 ASSERT(Subsection->SubsectionBase != NULL); 00527 ASSERT(Vad->FirstPrototypePte >= Subsection->SubsectionBase); 00528 ASSERT(Vad->FirstPrototypePte < &Subsection->SubsectionBase[Subsection->PtesInSubsection]); 00529 00530 /* Compute the PTE offset */ 00531 PteOffset = Vpn - Vad->StartingVpn; 00532 PteOffset += Vad->FirstPrototypePte - Subsection->SubsectionBase; 00533 00534 /* Again, we only support single-subsection segments */ 00535 ASSERT(PteOffset < 0xF0000000); 00536 ASSERT(PteOffset < Subsection->PtesInSubsection); 00537 00538 /* Return the subsection */ 00539 return Subsection; 00540 } 00541 00542 VOID 00543 NTAPI 00544 MiSegmentDelete(IN PSEGMENT Segment) 00545 { 00546 PCONTROL_AREA ControlArea; 00547 SEGMENT_FLAGS SegmentFlags; 00548 PSUBSECTION Subsection; 00549 PMMPTE PointerPte, LastPte, PteForProto; 00550 MMPTE TempPte; 00551 KIRQL OldIrql; 00552 00553 /* Capture data */ 00554 SegmentFlags = Segment->SegmentFlags; 00555 ControlArea = Segment->ControlArea; 00556 00557 /* Make sure control area is on the right delete path */ 00558 ASSERT(ControlArea->u.Flags.BeingDeleted == 1); 00559 ASSERT(ControlArea->WritableUserReferences == 0); 00560 00561 /* These things are not supported yet */ 00562 ASSERT(ControlArea->DereferenceList.Flink == NULL); 00563 ASSERT(!(ControlArea->u.Flags.Image) & !(ControlArea->u.Flags.File)); 00564 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 00565 ASSERT(ControlArea->u.Flags.Rom == 0); 00566 00567 /* Get the subsection and PTEs for this segment */ 00568 Subsection = (PSUBSECTION)(ControlArea + 1); 00569 PointerPte = Subsection->SubsectionBase; 00570 LastPte = PointerPte + Segment->NonExtendedPtes; 00571 00572 /* Lock the PFN database */ 00573 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00574 00575 /* Check if the master PTE is invalid */ 00576 PteForProto = MiAddressToPte(PointerPte); 00577 if (!PteForProto->u.Hard.Valid) 00578 { 00579 /* Fault it in */ 00580 MiMakeSystemAddressValidPfn(PointerPte, OldIrql); 00581 } 00582 00583 /* Loop all the segment PTEs */ 00584 while (PointerPte < LastPte) 00585 { 00586 /* Check if it's time to switch master PTEs if we passed a PDE boundary */ 00587 if (!((ULONG_PTR)PointerPte & (PD_SIZE - 1)) && 00588 (PointerPte != Subsection->SubsectionBase)) 00589 { 00590 /* Check if the master PTE is invalid */ 00591 PteForProto = MiAddressToPte(PointerPte); 00592 if (!PteForProto->u.Hard.Valid) 00593 { 00594 /* Fault it in */ 00595 MiMakeSystemAddressValidPfn(PointerPte, OldIrql); 00596 } 00597 } 00598 00599 /* This should be a prototype PTE */ 00600 TempPte = *PointerPte; 00601 ASSERT(SegmentFlags.LargePages == 0); 00602 ASSERT(TempPte.u.Hard.Valid == 0); 00603 ASSERT(TempPte.u.Soft.Prototype == 1); 00604 00605 /* Zero the PTE and keep going */ 00606 PointerPte->u.Long = 0; 00607 PointerPte++; 00608 } 00609 00610 /* Release the PFN lock */ 00611 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 00612 00613 /* Free the structures */ 00614 ExFreePool(ControlArea); 00615 ExFreePool(Segment); 00616 } 00617 00618 VOID 00619 NTAPI 00620 MiCheckControlArea(IN PCONTROL_AREA ControlArea, 00621 IN KIRQL OldIrql) 00622 { 00623 BOOLEAN DeleteSegment = FALSE; 00624 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 00625 00626 /* Check if this is the last reference or view */ 00627 if (!(ControlArea->NumberOfMappedViews) && 00628 !(ControlArea->NumberOfSectionReferences)) 00629 { 00630 /* There should be no more user references either */ 00631 ASSERT(ControlArea->NumberOfUserReferences == 0); 00632 00633 /* Not yet supported */ 00634 ASSERT(ControlArea->FilePointer == NULL); 00635 00636 /* The control area is being destroyed */ 00637 ControlArea->u.Flags.BeingDeleted = TRUE; 00638 DeleteSegment = TRUE; 00639 } 00640 00641 /* Release the PFN lock */ 00642 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 00643 00644 /* Delete the segment if needed */ 00645 if (DeleteSegment) 00646 { 00647 /* No more user write references at all */ 00648 ASSERT(ControlArea->WritableUserReferences == 0); 00649 MiSegmentDelete(ControlArea->Segment); 00650 } 00651 } 00652 00653 VOID 00654 NTAPI 00655 MiRemoveMappedView(IN PEPROCESS CurrentProcess, 00656 IN PMMVAD Vad) 00657 { 00658 KIRQL OldIrql; 00659 PCONTROL_AREA ControlArea; 00660 00661 /* Get the control area */ 00662 ControlArea = Vad->ControlArea; 00663 00664 /* We only support non-extendable, non-image, pagefile-backed regular sections */ 00665 ASSERT(Vad->u.VadFlags.VadType == VadNone); 00666 ASSERT(Vad->u2.VadFlags2.ExtendableFile == FALSE); 00667 ASSERT(ControlArea); 00668 ASSERT(ControlArea->FilePointer == NULL); 00669 00670 /* Delete the actual virtual memory pages */ 00671 MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT, 00672 (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1), 00673 Vad); 00674 00675 /* Release the working set */ 00676 MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); 00677 00678 /* Lock the PFN database */ 00679 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00680 00681 /* Remove references */ 00682 ControlArea->NumberOfMappedViews--; 00683 ControlArea->NumberOfUserReferences--; 00684 00685 /* Check if it should be destroyed */ 00686 MiCheckControlArea(ControlArea, OldIrql); 00687 } 00688 00689 NTSTATUS 00690 NTAPI 00691 MiUnmapViewOfSection(IN PEPROCESS Process, 00692 IN PVOID BaseAddress, 00693 IN ULONG Flags) 00694 { 00695 PMEMORY_AREA MemoryArea; 00696 BOOLEAN Attached = FALSE; 00697 KAPC_STATE ApcState; 00698 PMMVAD Vad; 00699 PVOID DbgBase = NULL; 00700 SIZE_T RegionSize; 00701 NTSTATUS Status; 00702 PAGED_CODE(); 00703 00704 /* Check for Mm Region */ 00705 MemoryArea = MmLocateMemoryAreaByAddress(&Process->Vm, BaseAddress); 00706 if ((MemoryArea) && (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3)) 00707 { 00708 /* Call Mm API */ 00709 return MiRosUnmapViewOfSection(Process, BaseAddress, Flags); 00710 } 00711 00712 /* Check if we should attach to the process */ 00713 if (PsGetCurrentProcess() != Process) 00714 { 00715 /* The process is different, do an attach */ 00716 KeStackAttachProcess(&Process->Pcb, &ApcState); 00717 Attached = TRUE; 00718 } 00719 00720 /* Check if we need to lock the address space */ 00721 if (!Flags) MmLockAddressSpace(&Process->Vm); 00722 00723 /* Check if the process is already daed */ 00724 if (Process->VmDeleted) 00725 { 00726 /* Fail the call */ 00727 DPRINT1("Process died!\n"); 00728 if (!Flags) MmUnlockAddressSpace(&Process->Vm); 00729 Status = STATUS_PROCESS_IS_TERMINATING; 00730 goto Quickie; 00731 } 00732 00733 /* Find the VAD for the address and make sure it's a section VAD */ 00734 Vad = MiLocateAddress(BaseAddress); 00735 if (!(Vad) || (Vad->u.VadFlags.PrivateMemory)) 00736 { 00737 /* Couldn't find it, or invalid VAD, fail */ 00738 DPRINT1("No VAD or invalid VAD\n"); 00739 if (!Flags) MmUnlockAddressSpace(&Process->Vm); 00740 Status = STATUS_NOT_MAPPED_VIEW; 00741 goto Quickie; 00742 } 00743 00744 /* We should be attached */ 00745 ASSERT(Process == PsGetCurrentProcess()); 00746 00747 /* We need the base address for the debugger message on image-backed VADs */ 00748 if (Vad->u.VadFlags.VadType == VadImageMap) 00749 { 00750 DbgBase = (PVOID)(Vad->StartingVpn >> PAGE_SHIFT); 00751 } 00752 00753 /* Compute the size of the VAD region */ 00754 RegionSize = PAGE_SIZE + ((Vad->EndingVpn - Vad->StartingVpn) << PAGE_SHIFT); 00755 00756 /* For SEC_NO_CHANGE sections, we need some extra checks */ 00757 if (Vad->u.VadFlags.NoChange == 1) 00758 { 00759 DPRINT1("Unmapping SEC_NO_CHANGE. Should validate if allowed!\n"); 00760 } 00761 00762 /* Not currently supported */ 00763 ASSERT(Vad->u.VadFlags.VadType != VadRotatePhysical); 00764 00765 /* FIXME: Remove VAD charges */ 00766 00767 /* Lock the working set */ 00768 MiLockWorkingSet(PsGetCurrentThread(), &Process->Vm); 00769 00770 /* Remove the VAD */ 00771 ASSERT(Process->VadRoot.NumberGenericTableElements >= 1); 00772 MiRemoveNode((PMMADDRESS_NODE)Vad, &Process->VadRoot); 00773 00774 /* Remove the PTEs for this view */ 00775 MiRemoveMappedView(Process, Vad); 00776 00777 /* FIXME: Remove commitment */ 00778 00779 /* Update performance counter and release the lock */ 00780 Process->VirtualSize -= RegionSize; 00781 if (!Flags) MmUnlockAddressSpace(&Process->Vm); 00782 00783 /* Destroy the VAD and return success */ 00784 ExFreePool(Vad); 00785 Status = STATUS_SUCCESS; 00786 00787 /* Failure and success case -- send debugger message, detach, and return */ 00788 Quickie: 00789 if (DbgBase) DbgkUnMapViewOfSection(DbgBase); 00790 if (Attached) KeUnstackDetachProcess(&ApcState); 00791 return Status; 00792 } 00793 00794 NTSTATUS 00795 NTAPI 00796 MiMapViewInSystemSpace(IN PVOID Section, 00797 IN PMMSESSION Session, 00798 OUT PVOID *MappedBase, 00799 IN OUT PSIZE_T ViewSize) 00800 { 00801 PVOID Base; 00802 PCONTROL_AREA ControlArea; 00803 ULONG Buckets, SectionSize; 00804 NTSTATUS Status; 00805 PAGED_CODE(); 00806 00807 /* Only global mappings for now */ 00808 ASSERT(Session == &MmSession); 00809 00810 /* Get the control area, check for any flags ARM3 doesn't yet support */ 00811 ControlArea = ((PSECTION)Section)->Segment->ControlArea; 00812 ASSERT(ControlArea->u.Flags.Image == 0); 00813 ASSERT(ControlArea->FilePointer == NULL); 00814 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 00815 ASSERT(ControlArea->u.Flags.Rom == 0); 00816 ASSERT(ControlArea->u.Flags.WasPurged == 0); 00817 00818 /* Increase the reference and map count on the control area, no purges yet */ 00819 Status = MiCheckPurgeAndUpMapCount(ControlArea, FALSE); 00820 ASSERT(NT_SUCCESS(Status)); 00821 00822 /* Get the section size at creation time */ 00823 SectionSize = ((PSECTION)Section)->SizeOfSection.LowPart; 00824 00825 /* If the caller didn't specify a view size, assume the whole section */ 00826 if (!(*ViewSize)) *ViewSize = SectionSize; 00827 00828 /* Check if the caller wanted a larger section than the view */ 00829 if (*ViewSize > SectionSize) 00830 { 00831 /* We should probably fail. FIXME TODO */ 00832 ASSERT(FALSE); 00833 } 00834 00835 /* Get the number of 64K buckets required for this mapping */ 00836 Buckets = (ULONG)(*ViewSize / MI_SYSTEM_VIEW_BUCKET_SIZE); 00837 if (*ViewSize & (MI_SYSTEM_VIEW_BUCKET_SIZE - 1)) Buckets++; 00838 00839 /* Check if the view is more than 4GB large */ 00840 if (Buckets >= MI_SYSTEM_VIEW_BUCKET_SIZE) 00841 { 00842 /* We should probably fail */ 00843 ASSERT(FALSE); 00844 } 00845 00846 /* Insert this view into system space and get a base address for it */ 00847 Base = MiInsertInSystemSpace(Session, Buckets, ControlArea); 00848 ASSERT(Base); 00849 00850 /* Create the PDEs needed for this mapping, and double-map them if needed */ 00851 MiFillSystemPageDirectory(Base, Buckets * MI_SYSTEM_VIEW_BUCKET_SIZE); 00852 00853 /* Create the actual prototype PTEs for this mapping */ 00854 Status = MiAddMappedPtes(MiAddressToPte(Base), 00855 BYTES_TO_PAGES(*ViewSize), 00856 ControlArea); 00857 ASSERT(NT_SUCCESS(Status)); 00858 00859 /* Return the base adress of the mapping and success */ 00860 *MappedBase = Base; 00861 return STATUS_SUCCESS; 00862 } 00863 00864 NTSTATUS 00865 NTAPI 00866 MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea, 00867 IN PEPROCESS Process, 00868 IN PVOID *BaseAddress, 00869 IN PLARGE_INTEGER SectionOffset, 00870 IN PSIZE_T ViewSize, 00871 IN PSECTION Section, 00872 IN SECTION_INHERIT InheritDisposition, 00873 IN ULONG ProtectionMask, 00874 IN SIZE_T CommitSize, 00875 IN ULONG_PTR ZeroBits, 00876 IN ULONG AllocationType) 00877 { 00878 PMMVAD_LONG Vad; 00879 PETHREAD Thread = PsGetCurrentThread(); 00880 ULONG_PTR StartAddress, EndingAddress; 00881 PSUBSECTION Subsection; 00882 PSEGMENT Segment; 00883 PFN_NUMBER PteOffset; 00884 NTSTATUS Status; 00885 ULONG QuotaCharge = 0, QuotaExcess = 0; 00886 PMMPTE PointerPte, LastPte; 00887 MMPTE TempPte; 00888 00889 /* Get the segment for this section */ 00890 Segment = ControlArea->Segment; 00891 00892 /* One can only reserve a file-based mapping, not shared memory! */ 00893 if ((AllocationType & MEM_RESERVE) && !(ControlArea->FilePointer)) 00894 { 00895 return STATUS_INVALID_PARAMETER_9; 00896 } 00897 00898 /* This flag determines alignment, but ARM3 does not yet support it */ 00899 ASSERT((AllocationType & MEM_DOS_LIM) == 0); 00900 00901 /* First, increase the map count. No purging is supported yet */ 00902 Status = MiCheckPurgeAndUpMapCount(ControlArea, FALSE); 00903 if (!NT_SUCCESS(Status)) return Status; 00904 00905 /* Check if the caller specified the view size */ 00906 if (!(*ViewSize)) 00907 { 00908 /* The caller did not, so pick a 64K aligned view size based on the offset */ 00909 SectionOffset->LowPart &= ~(_64K - 1); 00910 *ViewSize = (SIZE_T)(Section->SizeOfSection.QuadPart - SectionOffset->QuadPart); 00911 } 00912 else 00913 { 00914 /* A size was specified, align it to a 64K boundary */ 00915 *ViewSize += SectionOffset->LowPart & (_64K - 1); 00916 00917 /* Align the offset as well to make this an aligned map */ 00918 SectionOffset->LowPart &= ~((ULONG)_64K - 1); 00919 } 00920 00921 /* We must be dealing with a 64KB aligned offset. This is a Windows ASSERT */ 00922 ASSERT((SectionOffset->LowPart & ((ULONG)_64K - 1)) == 0); 00923 00924 /* It's illegal to try to map more than 2GB */ 00925 /* FIXME: Should dereference the control area */ 00926 if (*ViewSize >= 0x80000000) return STATUS_INVALID_VIEW_SIZE; 00927 00928 /* Windows ASSERTs for this flag */ 00929 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 00930 00931 /* Get the subsection. We don't support LARGE_CONTROL_AREA in ARM3 */ 00932 ASSERT(ControlArea->u.Flags.Rom == 0); 00933 Subsection = (PSUBSECTION)(ControlArea + 1); 00934 00935 /* Sections with extended segments are not supported in ARM3 */ 00936 ASSERT(Segment->SegmentFlags.TotalNumberOfPtes4132 == 0); 00937 00938 /* Within this section, figure out which PTEs will describe the view */ 00939 PteOffset = (PFN_NUMBER)(SectionOffset->QuadPart >> PAGE_SHIFT); 00940 00941 /* The offset must be in this segment's PTE chunk and it must be valid. Windows ASSERTs */ 00942 ASSERT(PteOffset < Segment->TotalNumberOfPtes); 00943 ASSERT(((SectionOffset->QuadPart + *ViewSize + PAGE_SIZE - 1) >> PAGE_SHIFT) >= PteOffset); 00944 00945 /* In ARM3, only one subsection is used for now. It must contain these PTEs */ 00946 ASSERT(PteOffset < Subsection->PtesInSubsection); 00947 00948 /* In ARM3, only page-file backed sections (shared memory) are supported now */ 00949 ASSERT(ControlArea->FilePointer == NULL); 00950 00951 /* Windows ASSERTs for this too -- there must be a subsection base address */ 00952 ASSERT(Subsection->SubsectionBase != NULL); 00953 00954 /* Compute how much commit space the segment will take */ 00955 if ((CommitSize) && (Segment->NumberOfCommittedPages < Segment->TotalNumberOfPtes)) 00956 { 00957 PointerPte = &Subsection->SubsectionBase[PteOffset]; 00958 LastPte = PointerPte + BYTES_TO_PAGES(CommitSize); 00959 QuotaCharge = (ULONG)(LastPte - PointerPte); 00960 } 00961 00962 /* ARM3 does not currently support large pages */ 00963 ASSERT(Segment->SegmentFlags.LargePages == 0); 00964 00965 /* Did the caller specify an address? */ 00966 if (!(*BaseAddress) && !(Section->Address.StartingVpn)) 00967 { 00968 /* ARM3 does not support these flags yet */ 00969 ASSERT(Process->VmTopDown == 0); 00970 ASSERT(ZeroBits == 0); 00971 00972 /* Which way should we search? */ 00973 if (AllocationType & MEM_TOP_DOWN) 00974 { 00975 /* No, find an address top-down */ 00976 Status = MiFindEmptyAddressRangeDownTree(*ViewSize, 00977 (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS, 00978 _64K, 00979 &Process->VadRoot, 00980 &StartAddress, 00981 (PMMADDRESS_NODE*)&Process->VadFreeHint); 00982 ASSERT(NT_SUCCESS(Status)); 00983 } 00984 else 00985 { 00986 /* No, find an address bottom-up */ 00987 Status = MiFindEmptyAddressRangeInTree(*ViewSize, 00988 _64K, 00989 &Process->VadRoot, 00990 (PMMADDRESS_NODE*)&Process->VadFreeHint, 00991 &StartAddress); 00992 ASSERT(NT_SUCCESS(Status)); 00993 } 00994 00995 /* Get the ending address, which is the last piece we need for the VAD */ 00996 EndingAddress = (StartAddress + *ViewSize - 1) | (PAGE_SIZE - 1); 00997 } 00998 else 00999 { 01000 /* Is it SEC_BASED, or did the caller manually specify an address? */ 01001 if (!(*BaseAddress)) 01002 { 01003 /* It is a SEC_BASED mapping, use the address that was generated */ 01004 StartAddress = Section->Address.StartingVpn + SectionOffset->LowPart; 01005 DPRINT("BASED: 0x%p\n", StartAddress); 01006 } 01007 else 01008 { 01009 /* Just align what the caller gave us */ 01010 StartAddress = ROUND_UP((ULONG_PTR)*BaseAddress, _64K); 01011 } 01012 01013 /* Get the ending address, which is the last piece we need for the VAD */ 01014 EndingAddress = (StartAddress + *ViewSize - 1) | (PAGE_SIZE - 1); 01015 01016 /* Make sure it doesn't conflict with an existing allocation */ 01017 if (MiCheckForConflictingNode(StartAddress >> PAGE_SHIFT, 01018 EndingAddress >> PAGE_SHIFT, 01019 &Process->VadRoot)) 01020 { 01021 DPRINT1("Conflict with SEC_BASED or manually based section!\n"); 01022 return STATUS_CONFLICTING_ADDRESSES; // FIXME: CA Leak 01023 } 01024 } 01025 01026 /* A VAD can now be allocated. Do so and zero it out */ 01027 /* FIXME: we are allocating a LONG VAD for ReactOS compatibility only */ 01028 ASSERT((AllocationType & MEM_RESERVE) == 0); /* ARM3 does not support this */ 01029 Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), 'ldaV'); 01030 if (!Vad) return STATUS_INSUFFICIENT_RESOURCES; /* FIXME: CA Leak */ 01031 RtlZeroMemory(Vad, sizeof(MMVAD_LONG)); 01032 Vad->u4.Banked = (PVOID)0xDEADBABE; 01033 01034 /* Write all the data required in the VAD for handling a fault */ 01035 Vad->StartingVpn = StartAddress >> PAGE_SHIFT; 01036 Vad->EndingVpn = EndingAddress >> PAGE_SHIFT; 01037 Vad->ControlArea = ControlArea; 01038 Vad->u.VadFlags.Protection = ProtectionMask; 01039 Vad->u2.VadFlags2.FileOffset = (ULONG)(SectionOffset->QuadPart >> 16); 01040 Vad->u2.VadFlags2.Inherit = (InheritDisposition == ViewShare); 01041 if ((AllocationType & SEC_NO_CHANGE) || (Section->u.Flags.NoChange)) 01042 { 01043 /* This isn't really implemented yet, but handle setting the flag */ 01044 Vad->u.VadFlags.NoChange = 1; 01045 Vad->u2.VadFlags2.SecNoChange = 1; 01046 } 01047 01048 /* Finally, write down the first and last prototype PTE */ 01049 Vad->FirstPrototypePte = &Subsection->SubsectionBase[PteOffset]; 01050 PteOffset += (Vad->EndingVpn - Vad->StartingVpn); 01051 ASSERT(PteOffset < Subsection->PtesInSubsection); 01052 Vad->LastContiguousPte = &Subsection->SubsectionBase[PteOffset]; 01053 01054 /* Make sure the prototype PTE ranges make sense, this is a Windows ASSERT */ 01055 ASSERT(Vad->FirstPrototypePte <= Vad->LastContiguousPte); 01056 01057 /* FIXME: Should setup VAD bitmap */ 01058 Status = STATUS_SUCCESS; 01059 01060 /* Pretend as if we own the working set */ 01061 MiLockProcessWorkingSet(Process, Thread); 01062 01063 /* Insert the VAD */ 01064 MiInsertVad((PMMVAD)Vad, Process); 01065 01066 /* Release the working set */ 01067 MiUnlockProcessWorkingSet(Process, Thread); 01068 01069 /* Windows stores this for accounting purposes, do so as well */ 01070 if (!Segment->u2.FirstMappedVa) Segment->u2.FirstMappedVa = (PVOID)StartAddress; 01071 01072 /* Check if anything was committed */ 01073 if (QuotaCharge) 01074 { 01075 /* Set the start and end PTE addresses, and pick the template PTE */ 01076 PointerPte = Vad->FirstPrototypePte; 01077 LastPte = PointerPte + BYTES_TO_PAGES(CommitSize); 01078 TempPte = Segment->SegmentPteTemplate; 01079 01080 /* Acquire the commit lock and loop all prototype PTEs to be committed */ 01081 KeAcquireGuardedMutexUnsafe(&MmSectionCommitMutex); 01082 while (PointerPte < LastPte) 01083 { 01084 /* Make sure the PTE is already invalid */ 01085 if (PointerPte->u.Long == 0) 01086 { 01087 /* And write the invalid PTE */ 01088 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 01089 } 01090 else 01091 { 01092 /* The PTE is valid, so skip it */ 01093 QuotaExcess++; 01094 } 01095 01096 /* Move to the next PTE */ 01097 PointerPte++; 01098 } 01099 01100 /* Now check how many pages exactly we committed, and update accounting */ 01101 ASSERT(QuotaCharge >= QuotaExcess); 01102 QuotaCharge -= QuotaExcess; 01103 Segment->NumberOfCommittedPages += QuotaCharge; 01104 ASSERT(Segment->NumberOfCommittedPages <= Segment->TotalNumberOfPtes); 01105 01106 /* Now that we're done, release the lock */ 01107 KeReleaseGuardedMutexUnsafe(&MmSectionCommitMutex); 01108 } 01109 01110 /* Finally, let the caller know where, and for what size, the view was mapped */ 01111 *ViewSize = (ULONG_PTR)EndingAddress - (ULONG_PTR)StartAddress + 1; 01112 *BaseAddress = (PVOID)StartAddress; 01113 DPRINT("Start and region: 0x%p, 0x%p\n", *BaseAddress, *ViewSize); 01114 return STATUS_SUCCESS; 01115 } 01116 01117 NTSTATUS 01118 NTAPI 01119 MiCreatePagingFileMap(OUT PSEGMENT *Segment, 01120 IN PSIZE_T MaximumSize, 01121 IN ULONG ProtectionMask, 01122 IN ULONG AllocationAttributes) 01123 { 01124 SIZE_T SizeLimit; 01125 PFN_COUNT PteCount; 01126 PMMPTE PointerPte; 01127 MMPTE TempPte; 01128 PCONTROL_AREA ControlArea; 01129 PSEGMENT NewSegment; 01130 PSUBSECTION Subsection; 01131 PAGED_CODE(); 01132 01133 /* No large pages in ARM3 yet */ 01134 ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0); 01135 01136 /* Pagefile-backed sections need a known size */ 01137 if (!(*MaximumSize)) return STATUS_INVALID_PARAMETER_4; 01138 01139 /* Calculate the maximum size possible, given the Prototype PTEs we'll need */ 01140 SizeLimit = MAXULONG_PTR - sizeof(SEGMENT); 01141 SizeLimit /= sizeof(MMPTE); 01142 SizeLimit <<= PAGE_SHIFT; 01143 01144 /* Fail if this size is too big */ 01145 if (*MaximumSize > SizeLimit) return STATUS_SECTION_TOO_BIG; 01146 01147 /* Calculate how many Prototype PTEs will be needed */ 01148 PteCount = (PFN_COUNT)((*MaximumSize + PAGE_SIZE - 1) >> PAGE_SHIFT); 01149 01150 /* For commited memory, we must have a valid protection mask */ 01151 if (AllocationAttributes & SEC_COMMIT) ASSERT(ProtectionMask != 0); 01152 01153 /* The segment contains all the Prototype PTEs, allocate it in paged pool */ 01154 NewSegment = ExAllocatePoolWithTag(PagedPool, 01155 sizeof(SEGMENT) + 01156 sizeof(MMPTE) * (PteCount - 1), 01157 'tSmM'); 01158 ASSERT(NewSegment); 01159 *Segment = NewSegment; 01160 01161 /* Now allocate the control area, which has the subsection structure */ 01162 ControlArea = ExAllocatePoolWithTag(NonPagedPool, 01163 sizeof(CONTROL_AREA) + sizeof(SUBSECTION), 01164 'tCmM'); 01165 ASSERT(ControlArea); 01166 01167 /* And zero it out, filling the basic segmnet pointer and reference fields */ 01168 RtlZeroMemory(ControlArea, sizeof(CONTROL_AREA) + sizeof(SUBSECTION)); 01169 ControlArea->Segment = NewSegment; 01170 ControlArea->NumberOfSectionReferences = 1; 01171 ControlArea->NumberOfUserReferences = 1; 01172 01173 /* Convert allocation attributes to control area flags */ 01174 if (AllocationAttributes & SEC_BASED) ControlArea->u.Flags.Based = 1; 01175 if (AllocationAttributes & SEC_RESERVE) ControlArea->u.Flags.Reserve = 1; 01176 if (AllocationAttributes & SEC_COMMIT) ControlArea->u.Flags.Commit = 1; 01177 01178 /* The subsection follows, write the mask, PTE count and point back to the CA */ 01179 Subsection = (PSUBSECTION)(ControlArea + 1); 01180 Subsection->ControlArea = ControlArea; 01181 Subsection->PtesInSubsection = PteCount; 01182 Subsection->u.SubsectionFlags.Protection = ProtectionMask; 01183 01184 /* Zero out the segment's prototype PTEs, and link it with the control area */ 01185 PointerPte = &NewSegment->ThePtes[0]; 01186 RtlZeroMemory(NewSegment, sizeof(SEGMENT)); 01187 NewSegment->PrototypePte = PointerPte; 01188 NewSegment->ControlArea = ControlArea; 01189 01190 /* Save some extra accounting data for the segment as well */ 01191 NewSegment->u1.CreatingProcess = PsGetCurrentProcess(); 01192 NewSegment->SizeOfSegment = PteCount * PAGE_SIZE; 01193 NewSegment->TotalNumberOfPtes = PteCount; 01194 NewSegment->NonExtendedPtes = PteCount; 01195 01196 /* The subsection's base address is the first Prototype PTE in the segment */ 01197 Subsection->SubsectionBase = PointerPte; 01198 01199 /* Start with an empty PTE, unless this is a commit operation */ 01200 TempPte.u.Long = 0; 01201 if (AllocationAttributes & SEC_COMMIT) 01202 { 01203 /* In which case, write down the protection mask in the Prototype PTEs */ 01204 TempPte.u.Soft.Protection = ProtectionMask; 01205 01206 /* For accounting, also mark these pages as being committed */ 01207 NewSegment->NumberOfCommittedPages = PteCount; 01208 } 01209 01210 /* The template PTE itself for the segment should also have the mask set */ 01211 NewSegment->SegmentPteTemplate.u.Soft.Protection = ProtectionMask; 01212 01213 /* Write out the prototype PTEs, for now they're simply demand zero */ 01214 #ifdef _WIN64 01215 RtlFillMemoryUlonglong(PointerPte, PteCount * sizeof(MMPTE), TempPte.u.Long); 01216 #else 01217 RtlFillMemoryUlong(PointerPte, PteCount * sizeof(MMPTE), TempPte.u.Long); 01218 #endif 01219 return STATUS_SUCCESS; 01220 } 01221 01222 PFILE_OBJECT 01223 NTAPI 01224 MmGetFileObjectForSection(IN PVOID SectionObject) 01225 { 01226 PSECTION_OBJECT Section; 01227 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); 01228 ASSERT(SectionObject != NULL); 01229 01230 /* Check if it's an ARM3, or ReactOS section */ 01231 if (MiIsRosSectionObject(SectionObject) == FALSE) 01232 { 01233 /* Return the file pointer stored in the control area */ 01234 Section = SectionObject; 01235 return Section->Segment->ControlArea->FilePointer; 01236 } 01237 01238 /* Return the file object */ 01239 return ((PROS_SECTION_OBJECT)SectionObject)->FileObject; 01240 } 01241 01242 NTSTATUS 01243 NTAPI 01244 MmGetFileNameForFileObject(IN PFILE_OBJECT FileObject, 01245 OUT POBJECT_NAME_INFORMATION *ModuleName) 01246 { 01247 POBJECT_NAME_INFORMATION ObjectNameInfo; 01248 NTSTATUS Status; 01249 ULONG ReturnLength; 01250 01251 /* Allocate memory for our structure */ 01252 ObjectNameInfo = ExAllocatePoolWithTag(PagedPool, 1024, TAG_MM); 01253 if (!ObjectNameInfo) return STATUS_NO_MEMORY; 01254 01255 /* Query the name */ 01256 Status = ObQueryNameString(FileObject, 01257 ObjectNameInfo, 01258 1024, 01259 &ReturnLength); 01260 if (!NT_SUCCESS(Status)) 01261 { 01262 /* Failed, free memory */ 01263 DPRINT1("Name query failed\n"); 01264 ExFreePoolWithTag(ObjectNameInfo, TAG_MM); 01265 *ModuleName = NULL; 01266 return Status; 01267 } 01268 01269 /* Success */ 01270 *ModuleName = ObjectNameInfo; 01271 return STATUS_SUCCESS; 01272 } 01273 01274 NTSTATUS 01275 NTAPI 01276 MmGetFileNameForSection(IN PVOID Section, 01277 OUT POBJECT_NAME_INFORMATION *ModuleName) 01278 { 01279 PFILE_OBJECT FileObject; 01280 01281 /* Make sure it's an image section */ 01282 if (MiIsRosSectionObject(Section) == FALSE) 01283 { 01284 /* Check ARM3 Section flag */ 01285 if (((PSECTION)Section)->u.Flags.Image == 0) 01286 { 01287 /* It's not, fail */ 01288 DPRINT1("Not an image section\n"); 01289 return STATUS_SECTION_NOT_IMAGE; 01290 } 01291 } 01292 else if (!(((PROS_SECTION_OBJECT)Section)->AllocationAttributes & SEC_IMAGE)) 01293 { 01294 /* It's not, fail */ 01295 DPRINT1("Not an image section\n"); 01296 return STATUS_SECTION_NOT_IMAGE; 01297 } 01298 01299 /* Get the file object */ 01300 FileObject = MmGetFileObjectForSection(Section); 01301 return MmGetFileNameForFileObject(FileObject, ModuleName); 01302 } 01303 01304 NTSTATUS 01305 NTAPI 01306 MmGetFileNameForAddress(IN PVOID Address, 01307 OUT PUNICODE_STRING ModuleName) 01308 { 01309 PVOID Section; 01310 PMEMORY_AREA MemoryArea; 01311 POBJECT_NAME_INFORMATION ModuleNameInformation; 01312 PVOID AddressSpace; 01313 NTSTATUS Status; 01314 PFILE_OBJECT FileObject = NULL; 01315 PMMVAD Vad; 01316 PCONTROL_AREA ControlArea; 01317 01318 /* Lock address space */ 01319 AddressSpace = MmGetCurrentAddressSpace(); 01320 MmLockAddressSpace(AddressSpace); 01321 01322 /* Locate the memory area for the process by address */ 01323 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address); 01324 if (!MemoryArea) 01325 { 01326 /* Fail, the address does not exist */ 01327 InvalidAddress: 01328 DPRINT1("Invalid address\n"); 01329 MmUnlockAddressSpace(AddressSpace); 01330 return STATUS_INVALID_ADDRESS; 01331 } 01332 01333 /* Check if it's a section view (RosMm section) or ARM3 section */ 01334 if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) 01335 { 01336 /* Get the section pointer to the SECTION_OBJECT */ 01337 Section = MemoryArea->Data.SectionData.Section; 01338 01339 /* Unlock address space */ 01340 MmUnlockAddressSpace(AddressSpace); 01341 01342 /* Get the filename of the section */ 01343 Status = MmGetFileNameForSection(Section, &ModuleNameInformation); 01344 } 01345 else if (MemoryArea->Type == MEMORY_AREA_OWNED_BY_ARM3) 01346 { 01347 /* Get the VAD */ 01348 Vad = MiLocateAddress(Address); 01349 if (!Vad) goto InvalidAddress; 01350 01351 /* Make sure it's not a VM VAD */ 01352 if (Vad->u.VadFlags.PrivateMemory == 1) 01353 { 01354 NotSection: 01355 DPRINT1("Address is not a section\n"); 01356 MmUnlockAddressSpace(AddressSpace); 01357 return STATUS_SECTION_NOT_IMAGE; 01358 } 01359 01360 /* Get the control area */ 01361 ControlArea = Vad->ControlArea; 01362 if (!(ControlArea) || !(ControlArea->u.Flags.Image)) goto NotSection; 01363 01364 /* Get the file object */ 01365 FileObject = ControlArea->FilePointer; 01366 ASSERT(FileObject != NULL); 01367 ObReferenceObject(FileObject); 01368 01369 /* Unlock address space */ 01370 MmUnlockAddressSpace(AddressSpace); 01371 01372 /* Get the filename of the file object */ 01373 Status = MmGetFileNameForFileObject(FileObject, &ModuleNameInformation); 01374 01375 /* Dereference it */ 01376 ObDereferenceObject(FileObject); 01377 } 01378 else 01379 { 01380 /* Trying to access virtual memory or something */ 01381 goto InvalidAddress; 01382 } 01383 01384 /* Check if we were able to get the file object name */ 01385 if (NT_SUCCESS(Status)) 01386 { 01387 /* Init modulename */ 01388 RtlCreateUnicodeString(ModuleName, 01389 ModuleNameInformation->Name.Buffer); 01390 01391 /* Free temp taged buffer from MmGetFileNameForFileObject() */ 01392 ExFreePoolWithTag(ModuleNameInformation, TAG_MM); 01393 DPRINT("Found ModuleName %S by address %p\n", ModuleName->Buffer, Address); 01394 } 01395 01396 /* Return status */ 01397 return Status; 01398 } 01399 01400 NTSTATUS 01401 NTAPI 01402 MiQueryMemorySectionName(IN HANDLE ProcessHandle, 01403 IN PVOID BaseAddress, 01404 OUT PVOID MemoryInformation, 01405 IN SIZE_T MemoryInformationLength, 01406 OUT PSIZE_T ReturnLength) 01407 { 01408 PEPROCESS Process; 01409 NTSTATUS Status; 01410 WCHAR ModuleFileNameBuffer[MAX_PATH] = {0}; 01411 UNICODE_STRING ModuleFileName; 01412 PMEMORY_SECTION_NAME SectionName = NULL; 01413 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 01414 01415 Status = ObReferenceObjectByHandle(ProcessHandle, 01416 PROCESS_QUERY_INFORMATION, 01417 NULL, 01418 PreviousMode, 01419 (PVOID*)(&Process), 01420 NULL); 01421 01422 if (!NT_SUCCESS(Status)) 01423 { 01424 DPRINT("MiQueryMemorySectionName: ObReferenceObjectByHandle returned %x\n",Status); 01425 return Status; 01426 } 01427 01428 RtlInitEmptyUnicodeString(&ModuleFileName, ModuleFileNameBuffer, sizeof(ModuleFileNameBuffer)); 01429 Status = MmGetFileNameForAddress(BaseAddress, &ModuleFileName); 01430 01431 if (NT_SUCCESS(Status)) 01432 { 01433 SectionName = MemoryInformation; 01434 if (PreviousMode != KernelMode) 01435 { 01436 _SEH2_TRY 01437 { 01438 RtlInitUnicodeString(&SectionName->SectionFileName, SectionName->NameBuffer); 01439 SectionName->SectionFileName.MaximumLength = (USHORT)MemoryInformationLength; 01440 RtlCopyUnicodeString(&SectionName->SectionFileName, &ModuleFileName); 01441 01442 if (ReturnLength) *ReturnLength = ModuleFileName.Length; 01443 01444 } 01445 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 01446 { 01447 Status = _SEH2_GetExceptionCode(); 01448 } 01449 _SEH2_END; 01450 } 01451 else 01452 { 01453 RtlInitUnicodeString(&SectionName->SectionFileName, SectionName->NameBuffer); 01454 SectionName->SectionFileName.MaximumLength = (USHORT)MemoryInformationLength; 01455 RtlCopyUnicodeString(&SectionName->SectionFileName, &ModuleFileName); 01456 01457 if (ReturnLength) *ReturnLength = ModuleFileName.Length; 01458 01459 } 01460 } 01461 ObDereferenceObject(Process); 01462 return Status; 01463 } 01464 01465 VOID 01466 NTAPI 01467 MiFlushTbAndCapture(IN PMMVAD FoundVad, 01468 IN PMMPTE PointerPte, 01469 IN ULONG ProtectionMask, 01470 IN PMMPFN Pfn1, 01471 IN BOOLEAN CaptureDirtyBit) 01472 { 01473 MMPTE TempPte, PreviousPte; 01474 KIRQL OldIrql; 01475 01476 // 01477 // User for sanity checking later on 01478 // 01479 PreviousPte = *PointerPte; 01480 01481 // 01482 // Build the PTE and acquire the PFN lock 01483 // 01484 MI_MAKE_HARDWARE_PTE_USER(&TempPte, 01485 PointerPte, 01486 ProtectionMask, 01487 PreviousPte.u.Hard.PageFrameNumber); 01488 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 01489 01490 // 01491 // We don't support I/O mappings in this path yet, and only cached memory 01492 // 01493 ASSERT(Pfn1 != NULL); 01494 ASSERT(Pfn1->u3.e1.CacheAttribute == MiCached); 01495 ASSERT((ProtectionMask & (MM_NOCACHE | MM_NOACCESS)) == 0); 01496 01497 // 01498 // Write the new PTE, making sure we are only changing the bits 01499 // 01500 ASSERT(PointerPte->u.Hard.Valid == 1); 01501 ASSERT(TempPte.u.Hard.Valid == 1); 01502 ASSERT(PointerPte->u.Hard.PageFrameNumber == TempPte.u.Hard.PageFrameNumber); 01503 *PointerPte = TempPte; 01504 01505 // 01506 // Flush the TLB 01507 // 01508 ASSERT(PreviousPte.u.Hard.Valid == 1); 01509 KeFlushCurrentTb(); 01510 ASSERT(PreviousPte.u.Hard.Valid == 1); 01511 01512 // 01513 // Windows updates the relevant PFN1 information, we currently don't. 01514 // 01515 if (CaptureDirtyBit) DPRINT1("Warning, not handling dirty bit\n"); 01516 01517 // 01518 // Not supported in ARM3 01519 // 01520 ASSERT(FoundVad->u.VadFlags.VadType != VadWriteWatch); 01521 01522 // 01523 // Release the PFN lock, we are done 01524 // 01525 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 01526 } 01527 01528 // 01529 // NOTE: This function gets a lot more complicated if we want Copy-on-Write support 01530 // 01531 NTSTATUS 01532 NTAPI 01533 MiSetProtectionOnSection(IN PEPROCESS Process, 01534 IN PMMVAD FoundVad, 01535 IN PVOID StartingAddress, 01536 IN PVOID EndingAddress, 01537 IN ULONG NewProtect, 01538 OUT PULONG CapturedOldProtect, 01539 IN ULONG DontCharge, 01540 OUT PULONG Locked) 01541 { 01542 PMMPTE PointerPte, LastPte; 01543 MMPTE TempPte, PteContents; 01544 PMMPDE PointerPde; 01545 PMMPFN Pfn1; 01546 ULONG ProtectionMask, QuotaCharge = 0; 01547 PUSHORT UsedPageTableEntries; 01548 //PETHREAD Thread = PsGetCurrentThread(); 01549 PAGED_CODE(); 01550 01551 // 01552 // Tell caller nothing is being locked 01553 // 01554 *Locked = FALSE; 01555 01556 // 01557 // This function should only be used for section VADs. Windows ASSERT */ 01558 // 01559 ASSERT(FoundVad->u.VadFlags.PrivateMemory == 0); 01560 01561 // 01562 // We don't support these features in ARM3 01563 // 01564 ASSERT(FoundVad->u.VadFlags.VadType != VadImageMap); 01565 ASSERT(FoundVad->u2.VadFlags2.CopyOnWrite == 0); 01566 01567 // 01568 // Convert and validate the protection mask 01569 // 01570 ProtectionMask = MiMakeProtectionMask(NewProtect); 01571 if (ProtectionMask == MM_INVALID_PROTECTION) 01572 { 01573 DPRINT1("Invalid section protect\n"); 01574 return STATUS_INVALID_PAGE_PROTECTION; 01575 } 01576 01577 // 01578 // Get the PTE and PDE for the address, as well as the final PTE 01579 // 01580 //MiLockProcessWorkingSet(Thread, Process); 01581 PointerPde = MiAddressToPde(StartingAddress); 01582 PointerPte = MiAddressToPte(StartingAddress); 01583 LastPte = MiAddressToPte(EndingAddress); 01584 01585 // 01586 // Make the PDE valid, and check the status of the first PTE 01587 // 01588 MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL); 01589 if (PointerPte->u.Long) 01590 { 01591 // 01592 // Not supported in ARM3 01593 // 01594 ASSERT(FoundVad->u.VadFlags.VadType != VadRotatePhysical); 01595 01596 // 01597 // Capture the page protection and make the PDE valid 01598 // 01599 *CapturedOldProtect = MiGetPageProtection(PointerPte); 01600 MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL); 01601 } 01602 else 01603 { 01604 // 01605 // Only pagefile-backed section VADs are supported for now 01606 // 01607 ASSERT(FoundVad->u.VadFlags.VadType != VadImageMap); 01608 01609 // 01610 // Grab the old protection from the VAD itself 01611 // 01612 *CapturedOldProtect = MmProtectToValue[FoundVad->u.VadFlags.Protection]; 01613 } 01614 01615 // 01616 // Loop all the PTEs now 01617 // 01618 MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL); 01619 while (PointerPte <= LastPte) 01620 { 01621 // 01622 // Check if we've crossed a PDE boundary and make the new PDE valid too 01623 // 01624 if ((((ULONG_PTR)PointerPte) & (SYSTEM_PD_SIZE - 1)) == 0) 01625 { 01626 PointerPde = MiAddressToPte(PointerPte); 01627 MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL); 01628 } 01629 01630 // 01631 // Capture the PTE and see what we're dealing with 01632 // 01633 PteContents = *PointerPte; 01634 if (PteContents.u.Long == 0) 01635 { 01636 // 01637 // This used to be a zero PTE and it no longer is, so we must add a 01638 // reference to the pagetable. 01639 // 01640 UsedPageTableEntries = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(MiPteToAddress(PointerPte))]; 01641 (*UsedPageTableEntries)++; 01642 ASSERT((*UsedPageTableEntries) <= PTE_COUNT); 01643 01644 // 01645 // Create the demand-zero prototype PTE 01646 // 01647 TempPte = PrototypePte; 01648 TempPte.u.Soft.Protection = ProtectionMask; 01649 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 01650 } 01651 else if (PteContents.u.Hard.Valid == 1) 01652 { 01653 // 01654 // Get the PFN entry 01655 // 01656 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents)); 01657 01658 // 01659 // We don't support these yet 01660 // 01661 ASSERT((NewProtect & (PAGE_NOACCESS | PAGE_GUARD)) == 0); 01662 ASSERT(Pfn1->u3.e1.PrototypePte == 0); 01663 01664 // 01665 // Write the protection mask and write it with a TLB flush 01666 // 01667 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask; 01668 MiFlushTbAndCapture(FoundVad, 01669 PointerPte, 01670 ProtectionMask, 01671 Pfn1, 01672 TRUE); 01673 } 01674 else 01675 { 01676 // 01677 // We don't support these cases yet 01678 // 01679 ASSERT(PteContents.u.Soft.Prototype == 0); 01680 ASSERT(PteContents.u.Soft.Transition == 0); 01681 01682 // 01683 // The PTE is already demand-zero, just update the protection mask 01684 // 01685 PointerPte->u.Soft.Protection = ProtectionMask; 01686 } 01687 01688 PointerPte++; 01689 } 01690 01691 // 01692 // Unlock the working set and update quota charges if needed, then return 01693 // 01694 //MiUnlockProcessWorkingSet(Thread, Process); 01695 if ((QuotaCharge > 0) && (!DontCharge)) 01696 { 01697 FoundVad->u.VadFlags.CommitCharge -= QuotaCharge; 01698 Process->CommitCharge -= QuotaCharge; 01699 } 01700 return STATUS_SUCCESS; 01701 } 01702 01703 VOID 01704 NTAPI 01705 MiRemoveMappedPtes(IN PVOID BaseAddress, 01706 IN ULONG NumberOfPtes, 01707 IN PCONTROL_AREA ControlArea, 01708 IN PMMSUPPORT Ws) 01709 { 01710 PMMPTE PointerPte, FirstPte; 01711 PMMPDE PointerPde, SystemMapPde; 01712 PMMPFN Pfn1, Pfn2; 01713 MMPTE PteContents; 01714 KIRQL OldIrql; 01715 DPRINT("Removing mapped view at: 0x%p\n", BaseAddress); 01716 01717 /* Get the PTE and loop each one */ 01718 PointerPte = MiAddressToPte(BaseAddress); 01719 FirstPte = PointerPte; 01720 while (NumberOfPtes) 01721 { 01722 /* Check if the PTE is already valid */ 01723 PteContents = *PointerPte; 01724 if (PteContents.u.Hard.Valid == 1) 01725 { 01726 /* Get the PFN entry */ 01727 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents)); 01728 01729 /* Get the PTE */ 01730 PointerPde = MiAddressToPte(PointerPte); 01731 01732 /* Lock the PFN database and make sure this isn't a mapped file */ 01733 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 01734 ASSERT(((Pfn1->u3.e1.PrototypePte) && (Pfn1->OriginalPte.u.Soft.Prototype)) == 0); 01735 01736 /* FIXME: Dirty bit management */ 01737 01738 /* Was the PDE invalid */ 01739 if (PointerPde->u.Long == 0) 01740 { 01741 #if (_MI_PAGING_LEVELS == 2) 01742 /* Find the system double-mapped PDE that describes this mapping */ 01743 SystemMapPde = &MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)]; 01744 01745 /* Make it valid */ 01746 ASSERT(SystemMapPde->u.Hard.Valid == 1); 01747 MI_WRITE_VALID_PDE(PointerPde, *SystemMapPde); 01748 #else 01749 ASSERT(FALSE); 01750 #endif 01751 } 01752 01753 /* Dereference the PDE and the PTE */ 01754 Pfn2 = MiGetPfnEntry(PFN_FROM_PTE(PointerPde)); 01755 //MiDecrementShareCount(Pfn2, PFN_FROM_PTE(PointerPde)); 01756 MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&PteContents)); 01757 01758 /* Release the PFN lock */ 01759 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 01760 } 01761 else 01762 { 01763 /* Windows ASSERT */ 01764 ASSERT((PteContents.u.Long == 0) || (PteContents.u.Soft.Prototype == 1)); 01765 01766 /* But not handled in ARM3 */ 01767 ASSERT(PteContents.u.Soft.Prototype == 0); 01768 } 01769 01770 /* Make the PTE into a zero PTE */ 01771 PointerPte->u.Long = 0; 01772 01773 /* Move to the next PTE */ 01774 PointerPte++; 01775 NumberOfPtes--; 01776 } 01777 01778 /* Flush the TLB */ 01779 KeFlushCurrentTb(); 01780 01781 /* Acquire the PFN lock */ 01782 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 01783 01784 /* Decrement the accounting counters */ 01785 ControlArea->NumberOfUserReferences--; 01786 ControlArea->NumberOfMappedViews--; 01787 01788 /* Check if we should destroy the CA and release the lock */ 01789 MiCheckControlArea(ControlArea, OldIrql); 01790 } 01791 01792 ULONG 01793 NTAPI 01794 MiRemoveFromSystemSpace(IN PMMSESSION Session, 01795 IN PVOID Base, 01796 OUT PCONTROL_AREA *ControlArea) 01797 { 01798 ULONG Hash, Size, Count = 0; 01799 ULONG_PTR Entry; 01800 PAGED_CODE(); 01801 01802 /* Compute the hash for this entry and loop trying to find it */ 01803 Entry = (ULONG_PTR)Base >> 16; 01804 Hash = Entry % Session->SystemSpaceHashKey; 01805 while ((Session->SystemSpaceViewTable[Hash].Entry >> 16) != Entry) 01806 { 01807 /* Check if we overflew past the end of the hash table */ 01808 if (++Hash >= Session->SystemSpaceHashSize) 01809 { 01810 /* Reset the hash to zero and keep searching from the bottom */ 01811 Hash = 0; 01812 if (++Count == 2) 01813 { 01814 /* But if we overflew twice, then this is not a real mapping */ 01815 KeBugCheckEx(0xD7, //DRIVER_UNMAPPING_INVALID_VIEW, 01816 (ULONG_PTR)Base, 01817 1, 01818 0, 01819 0); 01820 } 01821 } 01822 } 01823 01824 /* One less entry */ 01825 Session->SystemSpaceHashEntries--; 01826 01827 /* Extract the size and clear the entry */ 01828 Size = Session->SystemSpaceViewTable[Hash].Entry & 0xFFFF; 01829 Session->SystemSpaceViewTable[Hash].Entry = 0; 01830 01831 /* Return the control area and the size */ 01832 *ControlArea = Session->SystemSpaceViewTable[Hash].ControlArea; 01833 return Size; 01834 } 01835 01836 NTSTATUS 01837 NTAPI 01838 MiUnmapViewInSystemSpace(IN PMMSESSION Session, 01839 IN PVOID MappedBase) 01840 { 01841 ULONG Size; 01842 PCONTROL_AREA ControlArea; 01843 PAGED_CODE(); 01844 01845 /* Only global mappings supported for now */ 01846 ASSERT(Session == &MmSession); 01847 01848 /* Remove this mapping */ 01849 KeAcquireGuardedMutex(Session->SystemSpaceViewLockPointer); 01850 Size = MiRemoveFromSystemSpace(Session, MappedBase, &ControlArea); 01851 01852 /* Clear the bits for this mapping */ 01853 RtlClearBits(Session->SystemSpaceBitMap, 01854 (ULONG)(((ULONG_PTR)MappedBase - (ULONG_PTR)Session->SystemSpaceViewStart) >> 16), 01855 Size); 01856 01857 /* Convert the size from a bit size into the actual size */ 01858 Size = Size * (_64K >> PAGE_SHIFT); 01859 01860 /* Remove the PTEs now */ 01861 MiRemoveMappedPtes(MappedBase, Size, ControlArea, NULL); 01862 KeReleaseGuardedMutex(Session->SystemSpaceViewLockPointer); 01863 01864 /* Return success */ 01865 return STATUS_SUCCESS; 01866 } 01867 01868 /* PUBLIC FUNCTIONS ***********************************************************/ 01869 01870 /* 01871 * @implemented 01872 */ 01873 NTSTATUS 01874 NTAPI 01875 MmCreateArm3Section(OUT PVOID *SectionObject, 01876 IN ACCESS_MASK DesiredAccess, 01877 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 01878 IN PLARGE_INTEGER InputMaximumSize, 01879 IN ULONG SectionPageProtection, 01880 IN ULONG AllocationAttributes, 01881 IN HANDLE FileHandle OPTIONAL, 01882 IN PFILE_OBJECT FileObject OPTIONAL) 01883 { 01884 SECTION Section; 01885 PSECTION NewSection; 01886 PSUBSECTION Subsection; 01887 PSEGMENT NewSegment; 01888 NTSTATUS Status; 01889 PCONTROL_AREA ControlArea; 01890 ULONG ProtectionMask; 01891 01892 /* ARM3 does not yet support this */ 01893 ASSERT(FileHandle == NULL); 01894 ASSERT(FileObject == NULL); 01895 ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0); 01896 01897 /* Make the same sanity checks that the Nt interface should've validated */ 01898 ASSERT((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED | 01899 SEC_LARGE_PAGES | SEC_IMAGE | SEC_NOCACHE | 01900 SEC_NO_CHANGE)) == 0); 01901 ASSERT((AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_IMAGE)) != 0); 01902 ASSERT(!((AllocationAttributes & SEC_IMAGE) && 01903 (AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | 01904 SEC_NOCACHE | SEC_NO_CHANGE)))); 01905 ASSERT(!((AllocationAttributes & SEC_COMMIT) && (AllocationAttributes & SEC_RESERVE))); 01906 ASSERT(!((SectionPageProtection & PAGE_NOCACHE) || 01907 (SectionPageProtection & PAGE_WRITECOMBINE) || 01908 (SectionPageProtection & PAGE_GUARD) || 01909 (SectionPageProtection & PAGE_NOACCESS))); 01910 01911 /* Convert section flag to page flag */ 01912 if (AllocationAttributes & SEC_NOCACHE) SectionPageProtection |= PAGE_NOCACHE; 01913 01914 /* Check to make sure the protection is correct. Nt* does this already */ 01915 ProtectionMask = MiMakeProtectionMask(SectionPageProtection); 01916 if (ProtectionMask == MM_INVALID_PROTECTION) return STATUS_INVALID_PAGE_PROTECTION; 01917 01918 /* A handle must be supplied with SEC_IMAGE, and this is the no-handle path */ 01919 if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION; 01920 01921 /* So this must be a pagefile-backed section, create the mappings needed */ 01922 Status = MiCreatePagingFileMap(&NewSegment, 01923 (PSIZE_T)InputMaximumSize, 01924 ProtectionMask, 01925 AllocationAttributes); 01926 ASSERT(NT_SUCCESS(Status)); 01927 ASSERT(NewSegment != NULL); 01928 01929 /* Set the initial section object data */ 01930 Section.InitialPageProtection = SectionPageProtection; 01931 Section.SizeOfSection.QuadPart = NewSegment->SizeOfSegment; 01932 Section.Segment = NewSegment; 01933 01934 /* THe mapping created a control area and segment, save the flags */ 01935 ControlArea = NewSegment->ControlArea; 01936 Section.u.LongFlags = ControlArea->u.LongFlags; 01937 01938 /* ARM3 cannot support these right now, make sure they're not being set */ 01939 ASSERT(ControlArea->u.Flags.Image == 0); 01940 ASSERT(ControlArea->FilePointer == NULL); 01941 ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0); 01942 ASSERT(ControlArea->u.Flags.Rom == 0); 01943 ASSERT(ControlArea->u.Flags.WasPurged == 0); 01944 01945 /* A pagefile-backed mapping only has one subsection, and this is all ARM3 supports */ 01946 Subsection = (PSUBSECTION)(ControlArea + 1); 01947 ASSERT(Subsection->NextSubsection == NULL); 01948 01949 /* Create the actual section object, with enough space for the prototype PTEs */ 01950 Status = ObCreateObject(ExGetPreviousMode(), 01951 MmSectionObjectType, 01952 ObjectAttributes, 01953 ExGetPreviousMode(), 01954 NULL, 01955 sizeof(SECTION), 01956 sizeof(SECTION) + 01957 NewSegment->TotalNumberOfPtes * sizeof(MMPTE), 01958 sizeof(CONTROL_AREA) + sizeof(SUBSECTION), 01959 (PVOID*)&NewSection); 01960 ASSERT(NT_SUCCESS(Status)); 01961 01962 /* Now copy the local section object from the stack into this new object */ 01963 RtlCopyMemory(NewSection, &Section, sizeof(SECTION)); 01964 NewSection->Address.StartingVpn = 0; 01965 NewSection->u.Flags.UserReference = TRUE; 01966 01967 /* Migrate the attribute into a flag */ 01968 if (AllocationAttributes & SEC_NO_CHANGE) NewSection->u.Flags.NoChange = TRUE; 01969 01970 /* If R/W access is not requested, this might eventually become a CoW mapping */ 01971 if (!(SectionPageProtection & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE))) 01972 { 01973 NewSection->u.Flags.CopyOnWrite = TRUE; 01974 } 01975 01976 /* Is this a "based" allocation, in which all mappings are identical? */ 01977 if (AllocationAttributes & SEC_BASED) 01978 { 01979 /* Convert the flag, and make sure the section isn't too big */ 01980 NewSection->u.Flags.Based = TRUE; 01981 if ((ULONGLONG)NewSection->SizeOfSection.QuadPart > 01982 (ULONG_PTR)MmHighSectionBase) 01983 { 01984 DPRINT1("BASED section is too large\n"); 01985 ObDereferenceObject(NewSection); 01986 return STATUS_NO_MEMORY; 01987 } 01988 01989 /* Lock the VAD tree during the search */ 01990 KeAcquireGuardedMutex(&MmSectionBasedMutex); 01991 01992 /* Find an address top-down */ 01993 Status = MiFindEmptyAddressRangeDownBasedTree(NewSection->SizeOfSection.LowPart, 01994 (ULONG_PTR)MmHighSectionBase, 01995 _64K, 01996 &MmSectionBasedRoot, 01997 &NewSection->Address.StartingVpn); 01998 ASSERT(NT_SUCCESS(Status)); 01999 02000 /* Compute the ending address and insert it into the VAD tree */ 02001 NewSection->Address.EndingVpn = NewSection->Address.StartingVpn + 02002 NewSection->SizeOfSection.LowPart - 02003 1; 02004 MiInsertBasedSection(NewSection); 02005 02006 /* Finally release the lock */ 02007 KeReleaseGuardedMutex(&MmSectionBasedMutex); 02008 } 02009 02010 /* Return the object and the creation status */ 02011 *SectionObject = (PVOID)NewSection; 02012 return Status; 02013 } 02014 02015 /* 02016 * @implemented 02017 */ 02018 NTSTATUS 02019 NTAPI 02020 MmMapViewOfArm3Section(IN PVOID SectionObject, 02021 IN PEPROCESS Process, 02022 IN OUT PVOID *BaseAddress, 02023 IN ULONG_PTR ZeroBits, 02024 IN SIZE_T CommitSize, 02025 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, 02026 IN OUT PSIZE_T ViewSize, 02027 IN SECTION_INHERIT InheritDisposition, 02028 IN ULONG AllocationType, 02029 IN ULONG Protect) 02030 { 02031 KAPC_STATE ApcState; 02032 BOOLEAN Attached = FALSE; 02033 PSECTION Section; 02034 PCONTROL_AREA ControlArea; 02035 ULONG ProtectionMask; 02036 NTSTATUS Status; 02037 PAGED_CODE(); 02038 02039 /* Force PAGE_READWRITE for everything, for now */ 02040 Protect = PAGE_READWRITE; 02041 02042 /* Get the segment and control area */ 02043 Section = (PSECTION)SectionObject; 02044 ControlArea = Section->Segment->ControlArea; 02045 02046 /* These flags/states are not yet supported by ARM3 */ 02047 ASSERT(Section->u.Flags.Image == 0); 02048 ASSERT(Section->u.Flags.NoCache == 0); 02049 ASSERT(Section->u.Flags.WriteCombined == 0); 02050 ASSERT((AllocationType & MEM_RESERVE) == 0); 02051 ASSERT(ControlArea->u.Flags.PhysicalMemory == 0); 02052 02053 #if 0 02054 /* FIXME: Check if the mapping protection is compatible with the create */ 02055 if (!MiIsProtectionCompatible(Section->InitialPageProtection, Protect)) 02056 { 02057 DPRINT1("Mapping protection is incompatible\n"); 02058 return STATUS_SECTION_PROTECTION; 02059 } 02060 #endif 02061 02062 /* Check if the offset and size would cause an overflow */ 02063 if (((ULONG64)SectionOffset->QuadPart + *ViewSize) < 02064 (ULONG64)SectionOffset->QuadPart) 02065 { 02066 DPRINT1("Section offset overflows\n"); 02067 return STATUS_INVALID_VIEW_SIZE; 02068 } 02069 02070 /* Check if the offset and size are bigger than the section itself */ 02071 if (((ULONG64)SectionOffset->QuadPart + *ViewSize) > 02072 (ULONG64)Section->SizeOfSection.QuadPart) 02073 { 02074 DPRINT1("Section offset is larger than section\n"); 02075 return STATUS_INVALID_VIEW_SIZE; 02076 } 02077 02078 /* Check if the caller did not specify a view size */ 02079 if (!(*ViewSize)) 02080 { 02081 /* Compute it for the caller */ 02082 *ViewSize = (SIZE_T)(Section->SizeOfSection.QuadPart - SectionOffset->QuadPart); 02083 02084 /* Check if it's larger than 4GB or overflows into kernel-mode */ 02085 if ((*ViewSize > 0xFFFFFFFF) || 02086 (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)*BaseAddress) < *ViewSize)) 02087 { 02088 DPRINT1("Section view won't fit\n"); 02089 return STATUS_INVALID_VIEW_SIZE; 02090 } 02091 } 02092 02093 /* Check if the commit size is larger than the view size */ 02094 if (CommitSize > *ViewSize) 02095 { 02096 DPRINT1("Attempting to commit more than the view itself\n"); 02097 return STATUS_INVALID_PARAMETER_5; 02098 } 02099 02100 /* Check if the view size is larger than the section */ 02101 if (*ViewSize > (ULONG64)Section->SizeOfSection.QuadPart) 02102 { 02103 DPRINT1("The view is larger than the section\n"); 02104 return STATUS_INVALID_VIEW_SIZE; 02105 } 02106 02107 /* Compute and validate the protection mask */ 02108 ProtectionMask = MiMakeProtectionMask(Protect); 02109 if (ProtectionMask == MM_INVALID_PROTECTION) 02110 { 02111 DPRINT1("The protection is invalid\n"); 02112 return STATUS_INVALID_PAGE_PROTECTION; 02113 } 02114 02115 /* We only handle pagefile-backed sections, which cannot be writecombined */ 02116 if (Protect & PAGE_WRITECOMBINE) 02117 { 02118 DPRINT1("Cannot write combine a pagefile-backed section\n"); 02119 return STATUS_INVALID_PARAMETER_10; 02120 } 02121 02122 /* Start by attaching to the current process if needed */ 02123 if (PsGetCurrentProcess() != Process) 02124 { 02125 KeStackAttachProcess(&Process->Pcb, &ApcState); 02126 Attached = TRUE; 02127 } 02128 02129 /* Lock the address space and make sure the process is alive */ 02130 MmLockAddressSpace(&Process->Vm); 02131 if (!Process->VmDeleted) 02132 { 02133 /* Do the actual mapping */ 02134 DPRINT("Mapping ARM3 data section\n"); 02135 Status = MiMapViewOfDataSection(ControlArea, 02136 Process, 02137 BaseAddress, 02138 SectionOffset, 02139 ViewSize, 02140 Section, 02141 InheritDisposition, 02142 ProtectionMask, 02143 CommitSize, 02144 ZeroBits, 02145 AllocationType); 02146 } 02147 else 02148 { 02149 /* The process is being terminated, fail */ 02150 DPRINT1("The process is dying\n"); 02151 Status = STATUS_PROCESS_IS_TERMINATING; 02152 } 02153 02154 /* Unlock the address space and detatch if needed, then return status */ 02155 MmUnlockAddressSpace(&Process->Vm); 02156 if (Attached) KeUnstackDetachProcess(&ApcState); 02157 return Status; 02158 } 02159 02160 /* 02161 * @unimplemented 02162 */ 02163 BOOLEAN 02164 NTAPI 02165 MmDisableModifiedWriteOfSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer) 02166 { 02167 UNIMPLEMENTED; 02168 return FALSE; 02169 } 02170 02171 /* 02172 * @unimplemented 02173 */ 02174 BOOLEAN 02175 NTAPI 02176 MmForceSectionClosed(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, 02177 IN BOOLEAN DelayClose) 02178 { 02179 UNIMPLEMENTED; 02180 return FALSE; 02181 } 02182 02183 /* 02184 * @unimplemented 02185 */ 02186 NTSTATUS 02187 NTAPI 02188 MmMapViewInSessionSpace(IN PVOID Section, 02189 OUT PVOID *MappedBase, 02190 IN OUT PSIZE_T ViewSize) 02191 { 02192 UNIMPLEMENTED; 02193 return STATUS_NOT_IMPLEMENTED; 02194 } 02195 02196 /* 02197 * @unimplemented 02198 */ 02199 NTSTATUS 02200 NTAPI 02201 MmUnmapViewInSessionSpace(IN PVOID MappedBase) 02202 { 02203 UNIMPLEMENTED; 02204 return STATUS_NOT_IMPLEMENTED; 02205 } 02206 02207 /* 02208 * @implemented 02209 */ 02210 NTSTATUS 02211 NTAPI 02212 MmUnmapViewOfSection(IN PEPROCESS Process, 02213 IN PVOID BaseAddress) 02214 { 02215 return MiUnmapViewOfSection(Process, BaseAddress, 0); 02216 } 02217 02218 /* 02219 * @implemented 02220 */ 02221 NTSTATUS 02222 NTAPI 02223 MmUnmapViewInSystemSpace(IN PVOID MappedBase) 02224 { 02225 PMEMORY_AREA MemoryArea; 02226 PAGED_CODE(); 02227 02228 /* Was this mapped by RosMm? */ 02229 MemoryArea = MmLocateMemoryAreaByAddress(MmGetKernelAddressSpace(), MappedBase); 02230 if ((MemoryArea) && (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3)) 02231 { 02232 return MiRosUnmapViewInSystemSpace(MappedBase); 02233 } 02234 02235 /* It was not, call the ARM3 routine */ 02236 return MiUnmapViewInSystemSpace(&MmSession, MappedBase); 02237 } 02238 02239 /* SYSTEM CALLS ***************************************************************/ 02240 02241 NTSTATUS 02242 NTAPI 02243 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage, 02244 IN PVOID File2MappedAsFile) 02245 { 02246 PVOID AddressSpace; 02247 PMEMORY_AREA MemoryArea1, MemoryArea2; 02248 PROS_SECTION_OBJECT Section1, Section2; 02249 02250 /* Lock address space */ 02251 AddressSpace = MmGetCurrentAddressSpace(); 02252 MmLockAddressSpace(AddressSpace); 02253 02254 /* Locate the memory area for the process by address */ 02255 MemoryArea1 = MmLocateMemoryAreaByAddress(AddressSpace, File1MappedAsAnImage); 02256 if (!MemoryArea1) 02257 { 02258 /* Fail, the address does not exist */ 02259 MmUnlockAddressSpace(AddressSpace); 02260 return STATUS_INVALID_ADDRESS; 02261 } 02262 02263 /* Check if it's a section view (RosMm section) or ARM3 section */ 02264 if (MemoryArea1->Type != MEMORY_AREA_SECTION_VIEW) 02265 { 02266 /* Fail, the address is not a section */ 02267 MmUnlockAddressSpace(AddressSpace); 02268 return STATUS_CONFLICTING_ADDRESSES; 02269 } 02270 02271 /* Get the section pointer to the SECTION_OBJECT */ 02272 Section1 = MemoryArea1->Data.SectionData.Section; 02273 if (Section1->FileObject == NULL) 02274 { 02275 MmUnlockAddressSpace(AddressSpace); 02276 return STATUS_CONFLICTING_ADDRESSES; 02277 } 02278 02279 /* Locate the memory area for the process by address */ 02280 MemoryArea2 = MmLocateMemoryAreaByAddress(AddressSpace, File2MappedAsFile); 02281 if (!MemoryArea2) 02282 { 02283 /* Fail, the address does not exist */ 02284 MmUnlockAddressSpace(AddressSpace); 02285 return STATUS_INVALID_ADDRESS; 02286 } 02287 02288 /* Check if it's a section view (RosMm section) or ARM3 section */ 02289 if (MemoryArea2->Type != MEMORY_AREA_SECTION_VIEW) 02290 { 02291 /* Fail, the address is not a section */ 02292 MmUnlockAddressSpace(AddressSpace); 02293 return STATUS_CONFLICTING_ADDRESSES; 02294 } 02295 02296 /* Get the section pointer to the SECTION_OBJECT */ 02297 Section2 = MemoryArea2->Data.SectionData.Section; 02298 if (Section2->FileObject == NULL) 02299 { 02300 MmUnlockAddressSpace(AddressSpace); 02301 return STATUS_CONFLICTING_ADDRESSES; 02302 } 02303 02304 /* The shared cache map seems to be the same if both of these are equal */ 02305 if (Section1->FileObject->SectionObjectPointer->SharedCacheMap == 02306 Section2->FileObject->SectionObjectPointer->SharedCacheMap) 02307 { 02308 MmUnlockAddressSpace(AddressSpace); 02309 return STATUS_SUCCESS; 02310 } 02311 02312 /* Unlock address space */ 02313 MmUnlockAddressSpace(AddressSpace); 02314 return STATUS_NOT_SAME_DEVICE; 02315 } 02316 02317 /* 02318 * @implemented 02319 */ 02320 NTSTATUS 02321 NTAPI 02322 NtCreateSection(OUT PHANDLE SectionHandle, 02323 IN ACCESS_MASK DesiredAccess, 02324 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 02325 IN PLARGE_INTEGER MaximumSize OPTIONAL, 02326 IN ULONG SectionPageProtection OPTIONAL, 02327 IN ULONG AllocationAttributes, 02328 IN HANDLE FileHandle OPTIONAL) 02329 { 02330 LARGE_INTEGER SafeMaximumSize; 02331 PVOID SectionObject; 02332 HANDLE Handle; 02333 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 02334 NTSTATUS Status; 02335 PAGED_CODE(); 02336 02337 /* Check for non-existing flags */ 02338 if ((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED | 02339 SEC_LARGE_PAGES | SEC_IMAGE | SEC_NOCACHE | 02340 SEC_NO_CHANGE))) 02341 { 02342 if (!(AllocationAttributes & 1)) 02343 { 02344 DPRINT1("Bogus allocation attribute: %lx\n", AllocationAttributes); 02345 return STATUS_INVALID_PARAMETER_6; 02346 } 02347 } 02348 02349 /* Check for no allocation type */ 02350 if (!(AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_IMAGE))) 02351 { 02352 DPRINT1("Missing allocation type in allocation attributes\n"); 02353 return STATUS_INVALID_PARAMETER_6; 02354 } 02355 02356 /* Check for image allocation with invalid attributes */ 02357 if ((AllocationAttributes & SEC_IMAGE) && 02358 (AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_LARGE_PAGES | 02359 SEC_NOCACHE | SEC_NO_CHANGE))) 02360 { 02361 DPRINT1("Image allocation with invalid attributes\n"); 02362 return STATUS_INVALID_PARAMETER_6; 02363 } 02364 02365 /* Check for allocation type is both commit and reserve */ 02366 if ((AllocationAttributes & SEC_COMMIT) && (AllocationAttributes & SEC_RESERVE)) 02367 { 02368 DPRINT1("Commit and reserve in the same time\n"); 02369 return STATUS_INVALID_PARAMETER_6; 02370 } 02371 02372 /* Now check for valid protection */ 02373 if ((SectionPageProtection & PAGE_NOCACHE) || 02374 (SectionPageProtection & PAGE_WRITECOMBINE) || 02375 (SectionPageProtection & PAGE_GUARD) || 02376 (SectionPageProtection & PAGE_NOACCESS)) 02377 { 02378 DPRINT1("Sections don't support these protections\n"); 02379 return STATUS_INVALID_PAGE_PROTECTION; 02380 } 02381 02382 /* Use a maximum size of zero, if none was specified */ 02383 SafeMaximumSize.QuadPart = 0; 02384 02385 /* Check for user-mode caller */ 02386 if (PreviousMode != KernelMode) 02387 { 02388 /* Enter SEH */ 02389 _SEH2_TRY 02390 { 02391 /* Safely check user-mode parameters */ 02392 if (MaximumSize) SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize); 02393 MaximumSize = &SafeMaximumSize; 02394 ProbeForWriteHandle(SectionHandle); 02395 } 02396 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 02397 { 02398 /* Return the exception code */ 02399 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 02400 } 02401 _SEH2_END; 02402 } 02403 else if (!MaximumSize) MaximumSize = &SafeMaximumSize; 02404 02405 /* Check that MaximumSize is valid if backed by paging file */ 02406 if ((!FileHandle) && (!MaximumSize->QuadPart)) 02407 return STATUS_INVALID_PARAMETER_4; 02408 02409 /* Create the section */ 02410 Status = MmCreateSection(&SectionObject, 02411 DesiredAccess, 02412 ObjectAttributes, 02413 MaximumSize, 02414 SectionPageProtection, 02415 AllocationAttributes, 02416 FileHandle, 02417 NULL); 02418 if (!NT_SUCCESS(Status)) return Status; 02419 02420 /* FIXME: Should zero last page for a file mapping */ 02421 02422 /* Now insert the object */ 02423 Status = ObInsertObject(SectionObject, 02424 NULL, 02425 DesiredAccess, 02426 0, 02427 NULL, 02428 &Handle); 02429 if (NT_SUCCESS(Status)) 02430 { 02431 /* Enter SEH */ 02432 _SEH2_TRY 02433 { 02434 /* Return the handle safely */ 02435 *SectionHandle = Handle; 02436 } 02437 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 02438 { 02439 /* Nothing here */ 02440 } 02441 _SEH2_END; 02442 } 02443 02444 /* Return the status */ 02445 return Status; 02446 } 02447 02448 NTSTATUS 02449 NTAPI 02450 NtOpenSection(OUT PHANDLE SectionHandle, 02451 IN ACCESS_MASK DesiredAccess, 02452 IN POBJECT_ATTRIBUTES ObjectAttributes) 02453 { 02454 HANDLE Handle; 02455 NTSTATUS Status; 02456 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 02457 PAGED_CODE(); 02458 02459 /* Check for user-mode caller */ 02460 if (PreviousMode != KernelMode) 02461 { 02462 /* Enter SEH */ 02463 _SEH2_TRY 02464 { 02465 /* Safely check user-mode parameters */ 02466 ProbeForWriteHandle(SectionHandle); 02467 } 02468 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 02469 { 02470 /* Return the exception code */ 02471 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 02472 } 02473 _SEH2_END; 02474 } 02475 02476 /* Try opening the object */ 02477 Status = ObOpenObjectByName(ObjectAttributes, 02478 MmSectionObjectType, 02479 PreviousMode, 02480 NULL, 02481 DesiredAccess, 02482 NULL, 02483 &Handle); 02484 02485 /* Enter SEH */ 02486 _SEH2_TRY 02487 { 02488 /* Return the handle safely */ 02489 *SectionHandle = Handle; 02490 } 02491 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 02492 { 02493 /* Nothing here */ 02494 } 02495 _SEH2_END; 02496 02497 /* Return the status */ 02498 return Status; 02499 } 02500 02501 NTSTATUS 02502 NTAPI 02503 NtMapViewOfSection(IN HANDLE SectionHandle, 02504 IN HANDLE ProcessHandle, 02505 IN OUT PVOID* BaseAddress, 02506 IN ULONG_PTR ZeroBits, 02507 IN SIZE_T CommitSize, 02508 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, 02509 IN OUT PSIZE_T ViewSize, 02510 IN SECTION_INHERIT InheritDisposition, 02511 IN ULONG AllocationType, 02512 IN ULONG Protect) 02513 { 02514 PVOID SafeBaseAddress; 02515 LARGE_INTEGER SafeSectionOffset; 02516 SIZE_T SafeViewSize; 02517 PROS_SECTION_OBJECT Section; 02518 PEPROCESS Process; 02519 NTSTATUS Status; 02520 ACCESS_MASK DesiredAccess; 02521 ULONG ProtectionMask; 02522 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 02523 02524 /* Check for invalid zero bits */ 02525 if (ZeroBits > 21) // per-arch? 02526 { 02527 DPRINT1("Invalid zero bits\n"); 02528 return STATUS_INVALID_PARAMETER_4; 02529 } 02530 02531 /* Check for invalid inherit disposition */ 02532 if ((InheritDisposition > ViewUnmap) || (InheritDisposition < ViewShare)) 02533 { 02534 DPRINT1("Invalid inherit disposition\n"); 02535 return STATUS_INVALID_PARAMETER_8; 02536 } 02537 02538 /* Allow only valid allocation types */ 02539 if ((AllocationType & ~(MEM_TOP_DOWN | MEM_LARGE_PAGES | MEM_DOS_LIM | 02540 SEC_NO_CHANGE | MEM_RESERVE))) 02541 { 02542 DPRINT1("Invalid allocation type\n"); 02543 return STATUS_INVALID_PARAMETER_9; 02544 } 02545 02546 /* Convert the protection mask, and validate it */ 02547 ProtectionMask = MiMakeProtectionMask(Protect); 02548 if (ProtectionMask == MM_INVALID_PROTECTION) 02549 { 02550 DPRINT1("Invalid page protection\n"); 02551 return STATUS_INVALID_PAGE_PROTECTION; 02552 } 02553 02554 /* Now convert the protection mask into desired section access mask */ 02555 DesiredAccess = MmMakeSectionAccess[ProtectionMask & 0x7]; 02556 02557 /* Assume no section offset */ 02558 SafeSectionOffset.QuadPart = 0; 02559 02560 /* Enter SEH */ 02561 _SEH2_TRY 02562 { 02563 /* Check for unsafe parameters */ 02564 if (PreviousMode != KernelMode) 02565 { 02566 /* Probe the parameters */ 02567 ProbeForWritePointer(BaseAddress); 02568 ProbeForWriteSize_t(ViewSize); 02569 } 02570 02571 /* Check if a section offset was given */ 02572 if (SectionOffset) 02573 { 02574 /* Check for unsafe parameters and capture section offset */ 02575 if (PreviousMode != KernelMode) ProbeForWriteLargeInteger(SectionOffset); 02576 SafeSectionOffset = *SectionOffset; 02577 } 02578 02579 /* Capture the other parameters */ 02580 SafeBaseAddress = *BaseAddress; 02581 SafeViewSize = *ViewSize; 02582 } 02583 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 02584 { 02585 /* Return the exception code */ 02586 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 02587 } 02588 _SEH2_END; 02589 02590 /* Check for kernel-mode address */ 02591 if (SafeBaseAddress > MM_HIGHEST_VAD_ADDRESS) 02592 { 02593 DPRINT1("Kernel base not allowed\n"); 02594 return STATUS_INVALID_PARAMETER_3; 02595 } 02596 02597 /* Check for range entering kernel-mode */ 02598 if (((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS - (ULONG_PTR)SafeBaseAddress) < SafeViewSize) 02599 { 02600 DPRINT1("Overflowing into kernel base not allowed\n"); 02601 return STATUS_INVALID_PARAMETER_3; 02602 } 02603 02604 /* Check for invalid zero bits */ 02605 if (((ULONG_PTR)SafeBaseAddress + SafeViewSize) > (0xFFFFFFFF >> ZeroBits)) // arch? 02606 { 02607 DPRINT1("Invalid zero bits\n"); 02608 return STATUS_INVALID_PARAMETER_4; 02609 } 02610 02611 /* Reference the process */ 02612 Status = ObReferenceObjectByHandle(ProcessHandle, 02613 PROCESS_VM_OPERATION, 02614 PsProcessType, 02615 PreviousMode, 02616 (PVOID*)&Process, 02617 NULL); 02618 if (!NT_SUCCESS(Status)) return Status; 02619 02620 /* Reference the section */ 02621 Status = ObReferenceObjectByHandle(SectionHandle, 02622 DesiredAccess, 02623 MmSectionObjectType, 02624 PreviousMode, 02625 (PVOID*)&Section, 02626 NULL); 02627 if (!NT_SUCCESS(Status)) 02628 { 02629 ObDereferenceObject(Process); 02630 return Status; 02631 } 02632 02633 /* Now do the actual mapping */ 02634 Status = MmMapViewOfSection(Section, 02635 Process, 02636 &SafeBaseAddress, 02637 ZeroBits, 02638 CommitSize, 02639 &SafeSectionOffset, 02640 &SafeViewSize, 02641 InheritDisposition, 02642 AllocationType, 02643 Protect); 02644 02645 /* Return data only on success */ 02646 if (NT_SUCCESS(Status)) 02647 { 02648 /* Check if this is an image for the current process */ 02649 if ((Section->AllocationAttributes & SEC_IMAGE) && 02650 (Process == PsGetCurrentProcess()) && 02651 (Status != STATUS_IMAGE_NOT_AT_BASE)) 02652 { 02653 /* Notify the debugger */ 02654 DbgkMapViewOfSection(Section, 02655 SafeBaseAddress, 02656 SafeSectionOffset.LowPart, 02657 SafeViewSize); 02658 } 02659 02660 /* Enter SEH */ 02661 _SEH2_TRY 02662 { 02663 /* Return parameters to user */ 02664 *BaseAddress = SafeBaseAddress; 02665 *ViewSize = SafeViewSize; 02666 if (SectionOffset) *SectionOffset = SafeSectionOffset; 02667 } 02668 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 02669 { 02670 /* Nothing to do */ 02671 } 02672 _SEH2_END; 02673 } 02674 02675 /* Dereference all objects and return status */ 02676 ObDereferenceObject(Section); 02677 ObDereferenceObject(Process); 02678 return Status; 02679 } 02680 02681 NTSTATUS 02682 NTAPI 02683 NtUnmapViewOfSection(IN HANDLE ProcessHandle, 02684 IN PVOID BaseAddress) 02685 { 02686 PEPROCESS Process; 02687 NTSTATUS Status; 02688 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 02689 02690 /* Don't allowing mapping kernel views */ 02691 if ((PreviousMode == UserMode) && (BaseAddress > MM_HIGHEST_USER_ADDRESS)) 02692 { 02693 DPRINT1("Trying to unmap a kernel view\n"); 02694 return STATUS_NOT_MAPPED_VIEW; 02695 } 02696 02697 /* Reference the process */ 02698 Status = ObReferenceObjectByHandle(ProcessHandle, 02699 PROCESS_VM_OPERATION, 02700 PsProcessType, 02701 PreviousMode, 02702 (PVOID*)&Process, 02703 NULL); 02704 if (!NT_SUCCESS(Status)) return Status; 02705 02706 /* Unmap the view */ 02707 Status = MiUnmapViewOfSection(Process, BaseAddress, 0); 02708 02709 /* Dereference the process and return status */ 02710 ObDereferenceObject(Process); 02711 return Status; 02712 } 02713 02714 NTSTATUS 02715 NTAPI 02716 NtExtendSection(IN HANDLE SectionHandle, 02717 IN OUT PLARGE_INTEGER NewMaximumSize) 02718 { 02719 LARGE_INTEGER SafeNewMaximumSize; 02720 PROS_SECTION_OBJECT Section; 02721 NTSTATUS Status; 02722 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 02723 02724 /* Check for user-mode parameters */ 02725 if (PreviousMode != KernelMode) 02726 { 02727 /* Enter SEH */ 02728 _SEH2_TRY 02729 { 02730 /* Probe and capture the maximum size, it's both read and write */ 02731 ProbeForWriteLargeInteger(NewMaximumSize); 02732 SafeNewMaximumSize = *NewMaximumSize; 02733 } 02734 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 02735 { 02736 /* Return the exception code */ 02737 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 02738 } 02739 _SEH2_END; 02740 } 02741 else 02742 { 02743 /* Just read the size directly */ 02744 SafeNewMaximumSize = *NewMaximumSize; 02745 } 02746 02747 /* Reference the section */ 02748 Status = ObReferenceObjectByHandle(SectionHandle, 02749 SECTION_EXTEND_SIZE, 02750 MmSectionObjectType, 02751 PreviousMode, 02752 (PVOID*)&Section, 02753 NULL); 02754 if (!NT_SUCCESS(Status)) return Status; 02755 02756 /* Really this should go in MmExtendSection */ 02757 if (!(Section->AllocationAttributes & SEC_FILE)) 02758 { 02759 DPRINT1("Not extending a file\n"); 02760 ObDereferenceObject(Section); 02761 return STATUS_SECTION_NOT_EXTENDED; 02762 } 02763 02764 /* FIXME: Do the work */ 02765 02766 /* Dereference the section */ 02767 ObDereferenceObject(Section); 02768 02769 /* Enter SEH */ 02770 _SEH2_TRY 02771 { 02772 /* Write back the new size */ 02773 *NewMaximumSize = SafeNewMaximumSize; 02774 } 02775 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 02776 { 02777 /* Nothing to do */ 02778 } 02779 _SEH2_END; 02780 02781 /* Return the status */ 02782 return STATUS_NOT_IMPLEMENTED; 02783 } 02784 02785 /* EOF */ Generated on Sun May 27 2012 04:37:36 for ReactOS by
1.7.6.1
|