/* Blocking function to acquire zeroed pages from the balancer. Upon entry: Required->Amount: Number of pages to acquire Required->Consumer: consumer to charge the page to Upon return: Required->Pages[0..Amount]: Allocated pages. The function fails unless all requested pages can be allocated. */ NTSTATUS NTAPI MiGetOnePage(PMMSUPPORT AddressSpace, PMEMORY_AREA MemoryArea, PMM_REQUIRED_RESOURCES Required) { ULONG i; NTSTATUS Status = STATUS_SUCCESS; for (i = 0; i < Required->Amount; i++) { DPRINTC("MiGetOnePage(%s:%d)\n", Required->File, Required->Line); Status = MmRequestPageMemoryConsumer(Required->Consumer, TRUE, &Required->Page[i]); if (!NT_SUCCESS(Status)) { while (i > 0) { MmReleasePageMemoryConsumer(Required->Consumer, Required->Page[i-1]); i--; } return Status; } } return Status; }
ULONG_PTR NTAPI _MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset, const char *file, int line) { LARGE_INTEGER FileOffset; ULONG_PTR PageIndex, Result; PCACHE_SECTION_PAGE_TABLE PageTable; ASSERT(Segment->Locked); FileOffset.QuadPart = ROUND_DOWN(Offset->QuadPart, ENTRIES_PER_ELEMENT * PAGE_SIZE); PageTable = MiSectionPageTableGet(&Segment->PageTable, &FileOffset); if (!PageTable) return 0; PageIndex = (ULONG_PTR)((Offset->QuadPart - PageTable->FileOffset.QuadPart) / PAGE_SIZE); Result = PageTable->PageEntries[PageIndex]; #if 0 DPRINTC ("MiGetPageEntrySectionSegment(%p,%08x%08x) => %x %s:%d\n", Segment, FileOffset.u.HighPart, FileOffset.u.LowPart + PageIndex * PAGE_SIZE, Result, file, line); #endif return Result; }
NTSTATUS NTAPI MmNotPresentFaultCacheSection(KPROCESSOR_MODE Mode, ULONG_PTR Address, BOOLEAN FromMdl) { PETHREAD Thread; PMMSUPPORT AddressSpace; NTSTATUS Status; Address &= ~(PAGE_SIZE - 1); DPRINT("MmNotPresentFault(Mode %d, Address %Ix)\n", Mode, Address); Thread = PsGetCurrentThread(); if (KeGetCurrentIrql() >= DISPATCH_LEVEL) { DPRINT1("Page fault at high IRQL %u, address %Ix\n", KeGetCurrentIrql(), Address); ASSERT(FALSE); return STATUS_UNSUCCESSFUL; } /* Find the memory area for the faulting address */ if (Address >= (ULONG_PTR)MmSystemRangeStart) { /* Check permissions */ if (Mode != KernelMode) { DPRINTC("Address: %x\n", Address); return STATUS_ACCESS_VIOLATION; } AddressSpace = MmGetKernelAddressSpace(); } else { AddressSpace = &PsGetCurrentProcess()->Vm; } Thread->ActiveFaultCount++; Status = MmNotPresentFaultCacheSectionInner(Mode, AddressSpace, Address, FromMdl, Thread); Thread->ActiveFaultCount--; ASSERT(Status != STATUS_UNSUCCESSFUL); ASSERT(Status != STATUS_INVALID_PARAMETER); DPRINT("MmAccessFault %p:%Ix -> %x\n", MmGetAddressSpaceOwner(AddressSpace), Address, Status); return Status; }
static void ftt_detect_pad_statistics(struct ftt_charger_device *ftt_pdev) { u32 count; ftt_pdev->ftt_detect_pad_statistics_count[ftt_pdev->detect_pad]++; ftt_pdev->ftt_detect_pad_statistics_total++; DPRINT(FTT_LOG_PAD_DETECT_TEST, "####################### STATISTICS #######################\n"); DPRINT(FTT_LOG_PAD_DETECT_TEST, "STATISTICS : "); for (count = 1;count < FTT_PAD_TYPE_MAX;count++) { if (ftt_pdev->ftt_detect_pad_statistics_count[count] != 0) { DPRINTC(FTT_LOG_PAD_DETECT_TEST, "%d=%u(%u%%), ", count, ftt_pdev->ftt_detect_pad_statistics_count[count], ftt_pdev->ftt_detect_pad_statistics_count[count]*100/ftt_pdev->ftt_detect_pad_statistics_total); } } DPRINTC(FTT_LOG_PAD_DETECT_TEST, "total=%u\n", ftt_pdev->ftt_detect_pad_statistics_total); DPRINT(FTT_LOG_PAD_DETECT_TEST, "##########################################################\n"); }
SServerConfigs * serverConfigInit(SircConfig *generic_configs) { SServerConfigs *_this; DPRINTC(PrintComp_IrcCfg,"Initializing server configs. Upperlayer struct at %p",generic_configs); MAZZERT(NULL!=generic_configs,"NULL arg given to serverConfigInit()"); _this=malloc(sizeof(SServerConfigs)); if(NULL==_this) { PPRINTC(PrintComp_IrcCfg,"Alloc failed at serverConfigInit()"); return NULL; } memset(_this,0,sizeof(SServerConfigs)); _this->generic_configs=generic_configs; _this->type=EcfgStructType_server; _this->ServerConfigsCfgAdd=&ServerConfigsCfgAdd; _this->serverEventConfAdd=&serverEventConfAdd; DPRINTC(PrintComp_IrcCfg,"serverConfigInit - server config struct initialized at %p",_this); return _this; }
static int ServerConfigsCfgAdd(SServerConfigs *_this,SmbotPseudoxmlTag* serverRootTag) { size_t servernamelen; int allocd_channels; int allocd_events; SmbotPseudoxmlTag *temptag; //SmbotPseudoxmlTag *chantag; /* Sanity checks */ MAZZERT(NULL!=_this && NULL!=serverRootTag,"NULL ptr given to ServerConfigsCfgAdd()"); MAZZERT( !strcmp(serverRootTag->name, "server"),"tag which type is not 'server' given to ServerConfigsCfgAdd() as root tag!"); MAZZERT( serverRootTag->valuetype==EmbotPseudoxmlType_char,"Unsupported type for server tag!"); MAZZERT( (int)serverRootTag->size > 0,"Zero or negative server name lenght!"); servernamelen=strlen(serverRootTag->value); if(servernamelen>=sizeof(_this->domain)) { EPRINTC(PrintComp_IrcCfg,"Too long server domain given! Max lenght %u chars",sizeof(_this->domain)); return -1; } /* Fill server name */ memcpy(_this->domain,serverRootTag->value,servernamelen+1); if(NULL==serverRootTag->subtags) { WPRINTC(PrintComp_IrcCfg,"No channels. users or other configs given for server %s",_this->domain); } /* Loop through the subtags && set values */ DPRINTC(PrintComp_IrcCfg,"Tags preparsed => starting to fill channel structs"); allocd_channels=10; allocd_events=10; _this->channels=malloc(allocd_channels*sizeof(SChannelConfigs *)); _this->events=malloc(allocd_events*sizeof(SServerEvents *)); if(NULL==_this->channels || NULL == _this->events) { PPRINTC(PrintComp_IrcCfg,"malloc failed, out of mem??"); return -1; } temptag=serverRootTag->subtags; for(;NULL!=temptag;) { if(!strcmp(temptag->name,"channel")) { DPRINTC(PrintComp_IrcCfg,"Found channel for server %s",_this->domain); /* Depth 1 channel tag parsing */ if(allocd_channels<=_this->amntofchannels) { DPRINTC(PrintComp_IrcCfg, "Channel %d, but allocated only %d slots => reallocking to %d slots", _this->amntofchannels+1, allocd_channels, allocd_channels+10 ); allocd_channels+=10; _this->channels=realloc(_this->channels,sizeof(SChannelConfigs *)*allocd_channels); if(NULL==_this->channels) { PPRINTC(PrintComp_IrcCfg,"Realloc failed while allocating space for channel specific configs!"); return -1; } } DPRINTC(PrintComp_IrcCfg,"Initializing channel[%d] for server %s",_this->amntofchannels,_this->domain); _this->channels[_this->amntofchannels]=channelConfigInit(_this); if(NULL==_this->channels[_this->amntofchannels]) { PPRINTC(PrintComp_IrcCfg,"ChannelCfgInit FAILED"); return -1; } if(0!=_this->channels[_this->amntofchannels]->ChannelConfigsCfgAdd(_this->channels[_this->amntofchannels],temptag)) { EPRINTC(PrintComp_IrcCfg,"Final parsing for channel %s configs FAILED!",(char *)temptag->value); return -1; } DPRINTC(PrintComp_IrcCfg, "Channel %s at index[%d] adding successfull for server %s", _this->channels[_this->amntofchannels]->chan, _this->amntofchannels, _this->domain ); DPRINTC(PrintComp_IrcCfg,"Channel configs successfully parsed for channel %s",(char *)temptag->value); _this->amntofchannels++; } else if(!strcmp(temptag->name,"port")) { DPRINTC(PrintComp_IrcCfg,"Port tag for server %s found, processing...",_this->domain); if(temptag->valuetype!=EmbotPseudoxmlType_16bit) { WPRINTC(PrintComp_IrcCfg,"Port tag for server %s is not expected type '16bit'",_this->domain); } /* TODO: Add function / macro to do this conversion safely */ if(EmbotPseudoxmlType_8bit==temptag->valuetype || EmbotPseudoxmlType_char==temptag->valuetype) _this->port=*(unsigned char *)temptag->value; else if(EmbotPseudoxmlType_16bit==temptag->valuetype) _this->port=*(unsigned short *)temptag->value; else if(EmbotPseudoxmlType_32bit == temptag->valuetype) _this->port=(unsigned short int)*(unsigned int *)temptag->value; else if(EmbotPseudoxmlType_64bit == temptag->valuetype) _this->port=(unsigned short int)*(unsigned long long int *)temptag->value; } else if(!strcmp(temptag->name,"user")) { DPRINTC(PrintComp_IrcCfg,"Found user for server %s, adding..",_this->domain); if(_this->generic_configs->ircUserConfAdd(_this,temptag)) { EPRINTC(PrintComp_IrcCfg,"User adding for server %s FAILED",_this->domain); return -1; } DPRINTC(PrintComp_IrcCfg, "User at index %d (nick=%s) added to server %s", _this->useramnt-1, _this->users[_this->useramnt-1]->nick, _this->domain ); // _this->useramnt++; } else if(!strcmp(temptag->name,"event")) { if(allocd_events<=_this->amntofevents) { DPRINTC(PrintComp_IrcCfg, "Event %d, but allocated only %d slots => reallocking to %d slots", _this->amntofevents+1, allocd_events, allocd_events+10 ); allocd_events+=10; _this->events=realloc(_this->events,sizeof(SServerEvents *)*allocd_events); if(NULL==_this->events) { PPRINTC(PrintComp_IrcCfg,"Realloc failed while allocating space for event specific configs!"); return -1; } } if(_this->serverEventConfAdd(_this,temptag)) { EPRINTC(PrintComp_IrcCfg,"Event adding for server %s FAILED",_this->domain); return -1; } } else if(!strcmp(temptag->name,"botnick")) { if(temptag->subtags!=NULL) { EPRINTC(PrintComp_IrcCfg,"tag botnick should be closed!"); return -1; } if(temptag->valuetype!=EmbotPseudoxmlType_char) { EPRINTC(PrintComp_IrcCfg,"tag botnick has bad valuetype, should be EmbotPseudoxmlType_char!"); return -1; } if( (int)temptag->size <= 0 || temptag->size>sizeof(Tircnick)) { EPRINTC(PrintComp_IrcCfg,"Zero or negative bot name lenght!"); return -1; } memcpy(_this->mynick,temptag->value,sizeof(Tircnick)); } /* else if(!strcmp(temptag->name,"ADD HERE OTHER ALLOWED TAGS AT SERVER LEVEL") */ else { EPRINTC(PrintComp_IrcCfg,"Unknown server config %s given! - ignoring",temptag->name); } temptag=temptag->next; } /* Check that compulsory tags are given */ if(0==_this->port) { WPRINTC(PrintComp_IrcCfg,"No port given for server %s => assuming 6667",_this->domain); _this->port=6667; } if('\0'==_this->generic_configs->mynick[0] && '\0'==_this->mynick[0]) { WPRINTC(PrintComp_IrcCfg,"No generic or server specific nickname given when server %s seems to be configured!",_this->domain); DPRINTC(PrintComp_IrcCfg,"This is not fatal, since nothing says the 'botnick' cannot be given after server specific stuff"); } return 0; }
NTSTATUS NTAPI MmNotPresentFaultCacheSectionInner(KPROCESSOR_MODE Mode, PMMSUPPORT AddressSpace, ULONG_PTR Address, BOOLEAN FromMdl, PETHREAD Thread) { BOOLEAN Locked = FromMdl; PMEMORY_AREA MemoryArea; MM_REQUIRED_RESOURCES Resources = { 0 }; WORK_QUEUE_WITH_CONTEXT Context; NTSTATUS Status = STATUS_SUCCESS; RtlZeroMemory(&Context, sizeof(WORK_QUEUE_WITH_CONTEXT)); if (!FromMdl) { MmLockAddressSpace(AddressSpace); } /* Call the memory area specific fault handler */ do { MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address); if (MemoryArea == NULL || MemoryArea->DeleteInProgress) { Status = STATUS_ACCESS_VIOLATION; if (MemoryArea) { DPRINT1("Type %x DIP %x\n", MemoryArea->Type, MemoryArea->DeleteInProgress); } else { DPRINT1("No memory area\n"); } DPRINT1("Process %p, Address %Ix\n", MmGetAddressSpaceOwner(AddressSpace), Address); break; } DPRINTC("Type %x (%p -> %08Ix -> %p) in %p\n", MemoryArea->Type, MemoryArea->StartingAddress, Address, MemoryArea->EndingAddress, PsGetCurrentThread()); Resources.DoAcquisition = NULL; // Note: fault handlers are called with address space locked // We return STATUS_MORE_PROCESSING_REQUIRED if anything is needed Status = MmNotPresentFaultCachePage(AddressSpace, MemoryArea, (PVOID)Address, Locked, &Resources); if (!FromMdl) { MmUnlockAddressSpace(AddressSpace); } if (Status == STATUS_SUCCESS) { ; // Nothing } else if (Status == STATUS_SUCCESS + 1) { /* Wait page ... */ DPRINT("Waiting for %Ix\n", Address); MiWaitForPageEvent(MmGetAddressSpaceOwner(AddressSpace), Address); DPRINT("Done waiting for %Ix\n", Address); Status = STATUS_MM_RESTART_OPERATION; } else if (Status == STATUS_MM_RESTART_OPERATION) { /* Clean slate */ DPRINT("Clear resource\n"); RtlZeroMemory(&Resources, sizeof(Resources)); } else if (Status == STATUS_MORE_PROCESSING_REQUIRED) { if (Thread->ActiveFaultCount > 2) { DPRINTC("Already fault handling ... going to work item (%Ix)\n", Address); Context.AddressSpace = AddressSpace; Context.MemoryArea = MemoryArea; Context.Required = &Resources; KeInitializeEvent(&Context.Wait, NotificationEvent, FALSE); ExInitializeWorkItem(&Context.WorkItem, (PWORKER_THREAD_ROUTINE)MmpFaultWorker, &Context); DPRINT("Queue work item\n"); ExQueueWorkItem(&Context.WorkItem, DelayedWorkQueue); DPRINT("Wait\n"); KeWaitForSingleObject(&Context.Wait, 0, KernelMode, FALSE, NULL); Status = Context.Status; DPRINTC("Status %x\n", Status); } else { DPRINT("DoAcquisition %p\n", Resources.DoAcquisition); Status = Resources.DoAcquisition(AddressSpace, MemoryArea, &Resources); DPRINT("DoAcquisition %p -> %x\n", Resources.DoAcquisition, Status); } if (NT_SUCCESS(Status)) { Status = STATUS_MM_RESTART_OPERATION; } } else if (NT_SUCCESS(Status)) { ASSERT(FALSE); } if (!FromMdl) { MmLockAddressSpace(AddressSpace); } } while (Status == STATUS_MM_RESTART_OPERATION); DPRINTC("Completed page fault handling: %p:%Ix %x\n", MmGetAddressSpaceOwner(AddressSpace), Address, Status); if (!FromMdl) { MmUnlockAddressSpace(AddressSpace); } MiSetPageEvent(MmGetAddressSpaceOwner(AddressSpace), Address); DPRINT("Done %x\n", Status); return Status; }
NTSTATUS NTAPI MiCowCacheSectionPage ( _In_ PMMSUPPORT AddressSpace, _In_ PMEMORY_AREA MemoryArea, _In_ PVOID Address, _In_ BOOLEAN Locked, _Inout_ PMM_REQUIRED_RESOURCES Required) { PMM_SECTION_SEGMENT Segment; PFN_NUMBER NewPage, OldPage; NTSTATUS Status; PVOID PAddress; LARGE_INTEGER Offset; PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); DPRINT("MmAccessFaultSectionView(%p, %p, %p, %u)\n", AddressSpace, MemoryArea, Address, Locked); Segment = MemoryArea->Data.SectionData.Segment; /* Lock the segment */ MmLockSectionSegment(Segment); /* Find the offset of the page */ PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE); Offset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress + MemoryArea->Data.SectionData.ViewOffset.QuadPart; if (!Segment->WriteCopy /*&& !MemoryArea->Data.SectionData.WriteCopyView*/ || Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED) { #if 0 if (Region->Protect == PAGE_READWRITE || Region->Protect == PAGE_EXECUTE_READWRITE) #endif { ULONG_PTR Entry; DPRINTC("setting non-cow page %p %p:%p offset %I64x (%Ix) to writable\n", Segment, Process, PAddress, Offset.QuadPart, MmGetPfnForProcess(Process, Address)); if (Segment->FileObject) { DPRINTC("file %wZ\n", &Segment->FileObject->FileName); } Entry = MmGetPageEntrySectionSegment(Segment, &Offset); DPRINT("Entry %x\n", Entry); if (Entry && !IS_SWAP_FROM_SSE(Entry) && PFN_FROM_SSE(Entry) == MmGetPfnForProcess(Process, Address)) { MmSetPageEntrySectionSegment(Segment, &Offset, DIRTY_SSE(Entry)); } MmSetPageProtect(Process, PAddress, PAGE_READWRITE); MmSetDirtyPage(Process, PAddress); MmUnlockSectionSegment(Segment); DPRINT("Done\n"); return STATUS_SUCCESS; } #if 0 else { DPRINT("Not supposed to be writable\n"); MmUnlockSectionSegment(Segment); return STATUS_ACCESS_VIOLATION; } #endif } if (!Required->Page[0]) { SWAPENTRY SwapEntry; if (MmIsPageSwapEntry(Process, Address)) { MmGetPageFileMapping(Process, Address, &SwapEntry); MmUnlockSectionSegment(Segment); if (SwapEntry == MM_WAIT_ENTRY) return STATUS_SUCCESS + 1; // Wait ... somebody else is getting it right now else return STATUS_SUCCESS; // Nonwait swap entry ... handle elsewhere } /* Call out to acquire a page to copy to. We'll be re-called when * the page has been allocated. */ Required->Page[1] = MmGetPfnForProcess(Process, Address); Required->Consumer = MC_CACHE; Required->Amount = 1; Required->File = __FILE__; Required->Line = __LINE__; Required->DoAcquisition = MiGetOnePage; MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY); MmUnlockSectionSegment(Segment); return STATUS_MORE_PROCESSING_REQUIRED; } NewPage = Required->Page[0]; OldPage = Required->Page[1]; DPRINT("Allocated page %x\n", NewPage); /* Unshare the old page */ MmDeleteRmap(OldPage, Process, PAddress); /* Copy the old page */ DPRINT("Copying\n"); MiCopyPageToPage(NewPage, OldPage); /* Set the PTE to point to the new page */ Status = MmCreateVirtualMapping(Process, Address, PAGE_READWRITE, &NewPage, 1); if (!NT_SUCCESS(Status)) { DPRINT1("MmCreateVirtualMapping failed, not out of memory\n"); ASSERT(FALSE); MmUnlockSectionSegment(Segment); return Status; } MmInsertRmap(NewPage, Process, PAddress); MmReleasePageMemoryConsumer(MC_CACHE, OldPage); MmUnlockSectionSegment(Segment); DPRINT("Address 0x%p\n", Address); return STATUS_SUCCESS; }
NTSTATUS NTAPI MmNotPresentFaultCachePage ( _In_ PMMSUPPORT AddressSpace, _In_ MEMORY_AREA* MemoryArea, _In_ PVOID Address, _In_ BOOLEAN Locked, _Inout_ PMM_REQUIRED_RESOURCES Required) { NTSTATUS Status; PVOID PAddress; ULONG Consumer; PMM_SECTION_SEGMENT Segment; LARGE_INTEGER FileOffset, TotalOffset; ULONG_PTR Entry; ULONG Attributes; PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); KIRQL OldIrql; DPRINT("Not Present: %p %p (%p-%p)\n", AddressSpace, Address, MemoryArea->StartingAddress, MemoryArea->EndingAddress); /* * There is a window between taking the page fault and locking the * address space when another thread could load the page so we check * that. */ if (MmIsPagePresent(Process, Address)) { DPRINT("Done\n"); return STATUS_SUCCESS; } PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE); TotalOffset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress; Segment = MemoryArea->Data.SectionData.Segment; TotalOffset.QuadPart += MemoryArea->Data.SectionData.ViewOffset.QuadPart; FileOffset = TotalOffset; //Consumer = (Segment->Flags & MM_DATAFILE_SEGMENT) ? MC_CACHE : MC_USER; Consumer = MC_CACHE; if (Segment->FileObject) { DPRINT("FileName %wZ\n", &Segment->FileObject->FileName); } DPRINT("Total Offset %08x%08x\n", TotalOffset.HighPart, TotalOffset.LowPart); /* Lock the segment */ MmLockSectionSegment(Segment); /* Get the entry corresponding to the offset within the section */ Entry = MmGetPageEntrySectionSegment(Segment, &TotalOffset); Attributes = PAGE_READONLY; if (Required->State && Required->Page[0]) { DPRINT("Have file and page, set page %x in section @ %x #\n", Required->Page[0], TotalOffset.LowPart); if (Required->SwapEntry) MmSetSavedSwapEntryPage(Required->Page[0], Required->SwapEntry); if (Required->State & 2) { DPRINT("Set in section @ %x\n", TotalOffset.LowPart); Status = MmSetPageEntrySectionSegment(Segment, &TotalOffset, Entry = MAKE_PFN_SSE(Required->Page[0])); if (!NT_SUCCESS(Status)) { MmReleasePageMemoryConsumer(MC_CACHE, Required->Page[0]); } MmUnlockSectionSegment(Segment); MiSetPageEvent(Process, Address); DPRINT("Status %x\n", Status); return STATUS_MM_RESTART_OPERATION; } else { DPRINT("Set %x in address space @ %p\n", Required->Page[0], Address); Status = MmCreateVirtualMapping(Process, Address, Attributes, Required->Page, 1); if (NT_SUCCESS(Status)) { MmInsertRmap(Required->Page[0], Process, Address); } else { /* Drop the reference for our address space ... */ MmReleasePageMemoryConsumer(MC_CACHE, Required->Page[0]); } MmUnlockSectionSegment(Segment); DPRINTC("XXX Set Event %x\n", Status); MiSetPageEvent(Process, Address); DPRINT("Status %x\n", Status); return Status; } } else if (MM_IS_WAIT_PTE(Entry)) { // Whenever MM_WAIT_ENTRY is required as a swap entry, we need to // ask the fault handler to wait until we should continue. Rathern // than recopy this boilerplate code everywhere, we just ask them // to wait. MmUnlockSectionSegment(Segment); return STATUS_SUCCESS + 1; } else if (Entry) { PFN_NUMBER Page = PFN_FROM_SSE(Entry); DPRINT("Take reference to page %x #\n", Page); if (MiGetPfnEntry(Page) == NULL) { DPRINT1("Found no PFN entry for page 0x%x in page entry 0x%x (segment: 0x%p, offset: %08x%08x)\n", Page, Entry, Segment, TotalOffset.HighPart, TotalOffset.LowPart); KeBugCheck(CACHE_MANAGER); } OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); MmReferencePage(Page); KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); Status = MmCreateVirtualMapping(Process, Address, Attributes, &Page, 1); if (NT_SUCCESS(Status)) { MmInsertRmap(Page, Process, Address); } DPRINT("XXX Set Event %x\n", Status); MiSetPageEvent(Process, Address); MmUnlockSectionSegment(Segment); DPRINT("Status %x\n", Status); return Status; } else { DPRINT("Get page into section\n"); /* * If the entry is zero (and it can't change because we have * locked the segment) then we need to load the page. */ //DPRINT1("Read from file %08x %wZ\n", FileOffset.LowPart, &Section->FileObject->FileName); Required->State = 2; Required->Context = Segment->FileObject; Required->Consumer = Consumer; Required->FileOffset = FileOffset; Required->Amount = PAGE_SIZE; Required->DoAcquisition = MiReadFilePage; MmSetPageEntrySectionSegment(Segment, &TotalOffset, MAKE_SWAP_SSE(MM_WAIT_ENTRY)); MmUnlockSectionSegment(Segment); return STATUS_MORE_PROCESSING_REQUIRED; } ASSERT(FALSE); return STATUS_ACCESS_VIOLATION; }
NTSTATUS NTAPI MmpPageOutPhysicalAddress(PFN_NUMBER Page) { BOOLEAN ProcRef = FALSE, PageDirty; PFN_NUMBER SectionPage = 0; PMM_RMAP_ENTRY entry; PMM_SECTION_SEGMENT Segment = NULL; LARGE_INTEGER FileOffset; PMEMORY_AREA MemoryArea; PMMSUPPORT AddressSpace = NULL; BOOLEAN Dirty = FALSE; PVOID Address = NULL; PEPROCESS Process = NULL; NTSTATUS Status = STATUS_SUCCESS; MM_REQUIRED_RESOURCES Resources = { 0 }; DPRINTC("Page out %x (ref ct %x)\n", Page, MmGetReferenceCountPage(Page)); ExAcquireFastMutex(&MiGlobalPageOperation); if ((Segment = MmGetSectionAssociation(Page, &FileOffset))) { DPRINTC("Withdrawing page (%x) %p:%x\n", Page, Segment, FileOffset.LowPart); SectionPage = MmWithdrawSectionPage(Segment, &FileOffset, &Dirty); DPRINTC("SectionPage %x\n", SectionPage); if (SectionPage == MM_WAIT_ENTRY || SectionPage == 0) { DPRINT1("In progress page out %x\n", SectionPage); ExReleaseFastMutex(&MiGlobalPageOperation); return STATUS_UNSUCCESSFUL; } else { ASSERT(SectionPage == Page); } Resources.State = Dirty ? 1 : 0; } else { DPRINT("No segment association for %x\n", Page); } Dirty = MmIsDirtyPageRmap(Page); DPRINTC("Trying to unmap all instances of %x\n", Page); ExAcquireFastMutex(&RmapListLock); entry = MmGetRmapListHeadPage(Page); // Entry and Segment might be null here in the case that the page // is new and is in the process of being swapped in if (!entry && !Segment) { Status = STATUS_UNSUCCESSFUL; DPRINT1("Page %x is in transit\n", Page); ExReleaseFastMutex(&RmapListLock); goto bail; } while (entry != NULL && NT_SUCCESS(Status)) { Process = entry->Process; Address = entry->Address; DPRINTC("Process %p Address %p Page %x\n", Process, Address, Page); if (RMAP_IS_SEGMENT(Address)) { entry = entry->Next; continue; } if (Process && Address < MmSystemRangeStart) { /* Make sure we don't try to page out part of an exiting process */ if (PspIsProcessExiting(Process)) { DPRINT("bail\n"); ExReleaseFastMutex(&RmapListLock); goto bail; } ObReferenceObject(Process); ProcRef = TRUE; AddressSpace = &Process->Vm; } else { AddressSpace = MmGetKernelAddressSpace(); } ExReleaseFastMutex(&RmapListLock); RtlZeroMemory(&Resources, sizeof(Resources)); if ((((ULONG_PTR)Address) & 0xFFF) != 0) { KeBugCheck(MEMORY_MANAGEMENT); } do { MmLockAddressSpace(AddressSpace); MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address); if (MemoryArea == NULL || MemoryArea->DeleteInProgress) { Status = STATUS_UNSUCCESSFUL; MmUnlockAddressSpace(AddressSpace); DPRINTC("bail\n"); goto bail; } DPRINTC("Type %x (%p -> %p)\n", MemoryArea->Type, MemoryArea->StartingAddress, MemoryArea->EndingAddress); Resources.DoAcquisition = NULL; Resources.Page[0] = Page; ASSERT(KeGetCurrentIrql() <= APC_LEVEL); DPRINT("%p:%p, page %x %x\n", Process, Address, Page, Resources.Page[0]); PageDirty = FALSE; Status = MmPageOutCacheSection(AddressSpace, MemoryArea, Address, &PageDirty, &Resources); Dirty |= PageDirty; DPRINT("%x\n", Status); ASSERT(KeGetCurrentIrql() <= APC_LEVEL); MmUnlockAddressSpace(AddressSpace); if (Status == STATUS_SUCCESS + 1) { // Wait page ... the other guy has it, so we'll just fail for now DPRINT1("Wait entry ... can't continue\n"); Status = STATUS_UNSUCCESSFUL; goto bail; } else if (Status == STATUS_MORE_PROCESSING_REQUIRED) { DPRINTC("DoAcquisition %p\n", Resources.DoAcquisition); Status = Resources.DoAcquisition(AddressSpace, MemoryArea, &Resources); DPRINTC("Status %x\n", Status); if (!NT_SUCCESS(Status)) { DPRINT1("bail\n"); goto bail; } else { Status = STATUS_MM_RESTART_OPERATION; } } } while (Status == STATUS_MM_RESTART_OPERATION); if (ProcRef) { ObDereferenceObject(Process); ProcRef = FALSE; } ExAcquireFastMutex(&RmapListLock); ASSERT(!MM_IS_WAIT_PTE(MmGetPfnForProcess(Process, Address))); entry = MmGetRmapListHeadPage(Page); DPRINTC("Entry %p\n", entry); } ExReleaseFastMutex(&RmapListLock); bail: DPRINTC("BAIL %x\n", Status); if (Segment) { ULONG RefCount; DPRINTC("About to finalize section page %x (%p:%x) Status %x %s\n", Page, Segment, FileOffset.LowPart, Status, Dirty ? "dirty" : "clean"); if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = MmFinalizeSectionPageOut(Segment, &FileOffset, Page, Dirty))) { DPRINTC("Failed to page out %x, replacing %x at %x in segment %x\n", SectionPage, FileOffset.LowPart, Segment); MmLockSectionSegment(Segment); MmSetPageEntrySectionSegment(Segment, &FileOffset, Dirty ? MAKE_PFN_SSE(Page) : DIRTY_SSE(MAKE_PFN_SSE(Page))); MmUnlockSectionSegment(Segment); } /* Alas, we had the last reference */ if ((RefCount = InterlockedDecrementUL(&Segment->ReferenceCount)) == 0) MmFinalizeSegment(Segment); } if (ProcRef) { DPRINTC("Dereferencing process...\n"); ObDereferenceObject(Process); } ExReleaseFastMutex(&MiGlobalPageOperation); DPRINTC("%s %x %x\n", NT_SUCCESS(Status) ? "Evicted" : "Spared", Page, Status); return NT_SUCCESS(Status) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; }
NTSTATUS NTAPI MiReadFilePage(PMMSUPPORT AddressSpace, PMEMORY_AREA MemoryArea, PMM_REQUIRED_RESOURCES RequiredResources) { PFILE_OBJECT FileObject = RequiredResources->Context; PPFN_NUMBER Page = &RequiredResources->Page[RequiredResources->Offset]; PLARGE_INTEGER FileOffset = &RequiredResources->FileOffset; NTSTATUS Status; PVOID PageBuf = NULL; KEVENT Event; IO_STATUS_BLOCK IOSB; UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)]; PMDL Mdl = (PMDL)MdlBase; KIRQL OldIrql; DPRINTC("Pulling page %I64x from %wZ to %Ix\n", FileOffset->QuadPart, &FileObject->FileName, *Page); Status = MmRequestPageMemoryConsumer(RequiredResources->Consumer, TRUE, Page); if (!NT_SUCCESS(Status)) { DPRINT1("Status: %x\n", Status); return Status; } MmInitializeMdl(Mdl, NULL, PAGE_SIZE); MmBuildMdlFromPages(Mdl, Page); Mdl->MdlFlags |= MDL_PAGES_LOCKED; KeInitializeEvent(&Event, NotificationEvent, FALSE); Status = IoPageRead(FileObject, Mdl, FileOffset, &Event, &IOSB); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IOSB.Status; } if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) { MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); } PageBuf = MiMapPageInHyperSpace(PsGetCurrentProcess(), *Page, &OldIrql); if (!PageBuf) { MmReleasePageMemoryConsumer(RequiredResources->Consumer, *Page); return STATUS_NO_MEMORY; } RtlZeroMemory((PCHAR)PageBuf+RequiredResources->Amount, PAGE_SIZE-RequiredResources->Amount); MiUnmapPageInHyperSpace(PsGetCurrentProcess(), PageBuf, OldIrql); DPRINT("Read Status %x (Page %x)\n", Status, *Page); if (!NT_SUCCESS(Status)) { MmReleasePageMemoryConsumer(RequiredResources->Consumer, *Page); DPRINT("Status: %x\n", Status); return Status; } return STATUS_SUCCESS; }