// IShellPropSheetExt interface STDMETHODIMP CProppageUser::AddPages(LPFNADDPROPSHEETPAGE pAddPageProc, LPARAM lParam) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); TRACE(L"CProppageUser::AddPages()\n"); // Unpack the data pointer and create the property page. // Register clipboard format CLIPFORMAT cfDsObjectNames = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSOBJECTNAMES); ASSERT(cfDsObjectNames != 0); FORMATETC fmte = { cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM objMedium; HRESULT hr = m_spDataObj->GetData(&fmte, &objMedium); if (FAILED(hr)) { AfxMessageBox(_T("Failed to retrieve data from medium.")); return hr; } LPDSOBJECTNAMES pDsObjectNames; pDsObjectNames = (LPDSOBJECTNAMES)objMedium.hGlobal; if (pDsObjectNames->cItems < 1) { return ERROR_INVALID_DATA; } PWSTR pszObjADsPath = (PWSTR)BYTE_OFFSET(pDsObjectNames, pDsObjectNames->aObjects[0].offsetName); PWSTR pszClass = (PWSTR)BYTE_OFFSET(pDsObjectNames, pDsObjectNames->aObjects[0].offsetClass); TRACE(_T("Object path: %s, class: %s\n"), pszObjADsPath, pszClass); // Create/contact the notification object. HWND hNotifyObj; hr = ADsPropCreateNotifyObj(m_spDataObj, pszObjADsPath, &hNotifyObj); if (FAILED(hr)) { return hr; } CProppageUserUI* pProppageUI = new CProppageUserUI(hNotifyObj); pProppageUI->Init(pszObjADsPath, pszClass); ((PROPSHEETPAGE*)&pProppageUI->m_psp)->lParam = (LPARAM)pProppageUI; if (!(*pAddPageProc)(CreatePropertySheetPage((PROPSHEETPAGE*)&pProppageUI->m_psp), (LPARAM)lParam)) { delete pProppageUI; return E_FAIL; } return S_OK; }
/* * @implemented */ PVOID NTAPI MmAllocateContiguousMemorySpecifyCache(IN SIZE_T NumberOfBytes, IN PHYSICAL_ADDRESS LowestAcceptableAddress OPTIONAL, IN PHYSICAL_ADDRESS HighestAcceptableAddress, IN PHYSICAL_ADDRESS BoundaryAddressMultiple OPTIONAL, IN MEMORY_CACHING_TYPE CacheType OPTIONAL) { PFN_NUMBER LowestPfn, HighestPfn, BoundaryPfn; // // Verify count and cache type // ASSERT(NumberOfBytes != 0); ASSERT(CacheType <= MmWriteCombined); // // Convert the lowest address into a PFN // LowestPfn = (PFN_NUMBER)(LowestAcceptableAddress.QuadPart >> PAGE_SHIFT); if (BYTE_OFFSET(LowestAcceptableAddress.LowPart)) LowestPfn++; // // Convert and validate the boundary address into a PFN // if (BYTE_OFFSET(BoundaryAddressMultiple.LowPart)) return NULL; BoundaryPfn = (PFN_NUMBER)(BoundaryAddressMultiple.QuadPart >> PAGE_SHIFT); // // Convert the highest address into a PFN // HighestPfn = (PFN_NUMBER)(HighestAcceptableAddress.QuadPart >> PAGE_SHIFT); if (HighestPfn > MmHighestPhysicalPage) HighestPfn = MmHighestPhysicalPage; // // Validate the PFN bounds // if (LowestPfn > HighestPfn) return NULL; // // Let the contiguous memory allocator handle it // return MiAllocateContiguousMemory(NumberOfBytes, LowestPfn, HighestPfn, BoundaryPfn, CacheType); }
void gkUpdateMouseTarget(gkPanel* mainPanel){ gkPanel *oldMouseTarget, *p, *lastCommon; gkPoint pos = gkMousePosition; if(!mainPanel){ gkMouseTarget = 0; return; } oldMouseTarget = gkMouseTarget; gkMouseTarget = gkGetMouseTarget(mainPanel, pos, BYTE_OFFSET(mainPanel, mouseEnabled), BYTE_OFFSET(mainPanel, mouseChildren)); if(oldMouseTarget != gkMouseTarget){ gkMouseEvent enter, leave; enter.type = GK_ON_MOUSE_ENTER; enter.target = gkMouseTarget; enter.position = gkMousePosition; leave.type = GK_ON_MOUSE_LEAVE; leave.target = oldMouseTarget; leave.position = gkMousePosition; for(p = oldMouseTarget; p; p = p->parent) p->mouseOver = GK_FALSE; /* reset mouse over */ for(p = gkMouseTarget; p; p = p->parent) p->mouseOver = GK_TRUE; /* set mouse over to all panels under the mouse */ for(p = oldMouseTarget; p && !p->mouseOver; p = p->parent){ leave.currentTarget = p; gkDispatch(p, &leave); /* dispatch GK_ON_MOUSE_LEAVE */ } lastCommon = p; for(p = gkMouseTarget; p != 0 && p != lastCommon; p = p->parent){ enter.currentTarget = p; gkDispatch(p, &enter); /* dispatch GK_ON_MOUSE_ENTER */ } } }
// Creates a breakpoint object and fill out basic fields _Use_decl_annotations_ static std::unique_ptr<PatchInformation> SbppCreateBreakpoint(void* address) { auto info = std::make_unique<PatchInformation>(); auto reusable_info = SbppFindPatchByPage(address); if (reusable_info) { // Found an existing brekapoint object targetting the same page as this one. // re-use shadow pages. info->shadow_page_base_for_rw = reusable_info->shadow_page_base_for_rw; info->shadow_page_base_for_exec = reusable_info->shadow_page_base_for_exec; } else { // This breakpoint is for a page that is not currently set any breakpoint // (ie not shadowed). Creates shadow pages. info->shadow_page_base_for_rw = std::make_shared<Page>(); info->shadow_page_base_for_exec = std::make_shared<Page>(); auto page_base = PAGE_ALIGN(address); RtlCopyMemory(info->shadow_page_base_for_rw.get()->page, page_base, PAGE_SIZE); RtlCopyMemory(info->shadow_page_base_for_exec.get()->page, page_base, PAGE_SIZE); } info->patch_address = address; info->pa_base_for_rw = UtilPaFromVa(info->shadow_page_base_for_rw.get()->page); info->pa_base_for_exec = UtilPaFromVa(info->shadow_page_base_for_exec.get()->page); // Set an actual breakpoint (0xcc) onto the shadow page for EXEC SbppEmbedBreakpoint(info->shadow_page_base_for_exec.get()->page + BYTE_OFFSET(address)); return info; }
static rc_t vdb_dump_txt_ascii( p_dump_str s, const p_dump_src src, const p_col_def def ) { char *src_ptr = (char*)src->buf + BYTE_OFFSET( src->offset_in_bits ); return vds_append_fmt( s, src->number_of_elements, "%.*s", src->number_of_elements, src_ptr ); }
static void copy_bits(u_int8_t* src, /* Base pointer to source. */ size_t soffs, /* Bit offset for source relative to src. */ int sdir, /* Direction: 1 (forward) or -1 (backward). */ u_int8_t* dst, /* Base pointer to destination. */ size_t doffs, /* Bit offset for destination relative to dst. */ int ddir, /* Direction: 1 (forward) or -1 (backward). */ size_t n) /* Number of bits to copy. */ { u_int32_t lmask; u_int32_t rmask; u_int32_t count; u_int32_t deoffs; if (n == 0) { return; } src += sdir*BYTE_OFFSET(soffs); dst += ddir*BYTE_OFFSET(doffs); soffs = BIT_OFFSET(soffs); doffs = BIT_OFFSET(doffs); deoffs = BIT_OFFSET(doffs+n); lmask = (doffs) ? MAKE_MASK(8-doffs) : 0; rmask = (deoffs) ? (MAKE_MASK(deoffs)<<(8-deoffs)) : 0; /* * Take care of the case that all bits are in the same byte. */ if (doffs+n < 8) { /* All bits are in the same byte */ lmask = (lmask & rmask) ? (lmask & rmask) : (lmask | rmask); if (soffs == doffs) { *dst = MASK_BITS(*src,*dst,lmask); } else if (soffs > doffs) { u_int32_t bits = (*src << (soffs-doffs)); if (soffs+n > 8) { src += sdir; bits |= (*src >> (8-(soffs-doffs))); }
void vdt_move_to_value( void* dst, const p_dump_src src, const uint32_t n_bits ) { char *src_ptr = (char*)src->buf + BYTE_OFFSET(src->offset_in_bits); if ( BIT_OFFSET(src->offset_in_bits) == 0 ) { memmove( dst, src_ptr, vdt_bitlength_2_bytes( n_bits ) ); } else { bitcpy ( dst, 0, src_ptr, BIT_OFFSET(src->offset_in_bits), n_bits ); } }
/* * private void setField(Object o, Class declaringClass, Class type, * int slot, boolean noAccessCheck, Object value) * * When assigning into a primitive field we will automatically extract * the value from box types. */ static void Dalvik_java_lang_reflect_Field_setField(const u4* args, JValue* pResult) { // ignore thisPtr in args[0] Object* obj = (Object*) args[1]; ClassObject* declaringClass = (ClassObject*) args[2]; ClassObject* fieldType = (ClassObject*) args[3]; int slot = args[4]; bool noAccessCheck = (args[5] != 0); Object* valueObj = (Object*) args[6]; JValue* fieldPtr; JValue value; /* unwrap primitive, or verify object type */ if (!dvmUnwrapPrimitive(valueObj, fieldType, &value)) { dvmThrowException("Ljava/lang/IllegalArgumentException;", "invalid value for field"); RETURN_VOID(); } /* get a pointer to the field's data; performs access checks */ fieldPtr = getFieldDataAddr(obj, declaringClass, slot, true, noAccessCheck); if (fieldPtr == NULL) RETURN_VOID(); /* store 4 or 8 bytes */ if (fieldType->primitiveType == PRIM_LONG || fieldType->primitiveType == PRIM_DOUBLE) { fieldPtr->j = value.j; } else if (fieldType->primitiveType == PRIM_NOT) { if (slot < 0) { StaticField *sfield; sfield = (StaticField *)dvmSlotToField(declaringClass, slot); assert(fieldPtr == &sfield->value); dvmSetStaticFieldObject(sfield, value.l); } else { int offset = declaringClass->ifields[slot].byteOffset; assert(fieldPtr == (JValue *)BYTE_OFFSET(obj, offset)); dvmSetFieldObject(obj, offset, value.l); } } else { fieldPtr->i = value.i; } RETURN_VOID(); }
PVOID MmDbgTranslatePhysicalAddress ( IN PHYSICAL_ADDRESS PhysicalAddress ) /*++ Routine Description: ALPHA implementation specific: This routine maps the specified physical address and returns the virtual address which maps the physical address. The next call to MmDbgTranslatePhyiscalAddress removes the previous phyiscal address translation, hence on a single physical address can be examined at a time (can't cross page boundaries). Arguments: PhysicalAddress - Supplies the phyiscal address to map and translate. Return Value: The virtual address which corresponds to the phyiscal address. Environment: Kernel mode IRQL at DISPATCH_LEVEL or greater. --*/ { PVOID BaseAddress; LARGE_INTEGER LiTmp; BaseAddress = MiGetVirtualAddressMappedByPte (MmDebugPte); KiFlushSingleTb (TRUE, BaseAddress); *MmDebugPte = ValidKernelPte; LiTmp.QuadPart = PhysicalAddress.QuadPart >> PAGE_SHIFT; MmDebugPte->u.Hard.PageFrameNumber = LiTmp.LowPart; return (PVOID)((ULONG)BaseAddress + BYTE_OFFSET(PhysicalAddress.LowPart)); }
/* * @implemented */ VOID NTAPI IoBuildPartialMdl(IN PMDL SourceMdl, IN PMDL TargetMdl, IN PVOID VirtualAddress, IN ULONG Length) { PPFN_NUMBER TargetPages = (PPFN_NUMBER)(TargetMdl + 1); PPFN_NUMBER SourcePages = (PPFN_NUMBER)(SourceMdl + 1); ULONG Offset; ULONG FlagsMask = (MDL_IO_PAGE_READ | MDL_SOURCE_IS_NONPAGED_POOL | MDL_MAPPED_TO_SYSTEM_VA | MDL_IO_SPACE); /* Calculate the offset */ Offset = (ULONG)((ULONG_PTR)VirtualAddress - (ULONG_PTR)SourceMdl->StartVa) - SourceMdl->ByteOffset; /* Check if we don't have a length and calculate it */ if (!Length) Length = SourceMdl->ByteCount - Offset; /* Write the process, start VA and byte data */ TargetMdl->StartVa = (PVOID)PAGE_ROUND_DOWN(VirtualAddress); TargetMdl->Process = SourceMdl->Process; TargetMdl->ByteCount = Length; TargetMdl->ByteOffset = BYTE_OFFSET(VirtualAddress); /* Recalculate the length in pages */ Length = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, Length); /* Set the MDL Flags */ TargetMdl->MdlFlags &= (MDL_ALLOCATED_FIXED_SIZE | MDL_ALLOCATED_MUST_SUCCEED); TargetMdl->MdlFlags |= SourceMdl->MdlFlags & FlagsMask; TargetMdl->MdlFlags |= MDL_PARTIAL; /* Set the mapped VA */ TargetMdl->MappedSystemVa = (PCHAR)SourceMdl->MappedSystemVa + Offset; /* Now do the copy */ Offset = (ULONG)(((ULONG_PTR)TargetMdl->StartVa - (ULONG_PTR)SourceMdl->StartVa) >> PAGE_SHIFT); SourcePages += Offset; RtlCopyMemory(TargetPages, SourcePages, Length * sizeof(PFN_NUMBER)); }
void gkProcessMouseEvent(gkMouseEvent* mouseEvent){ gkPanel* current, *newFocusTarget = 0, *curFocusTarget = gkFocusPanel; gkMousePosition = mouseEvent->position; if(mouseEvent->type == GK_ON_MOUSE_DOWN){ newFocusTarget = gkGetMouseTarget(gkMainPanel, gkMousePosition, BYTE_OFFSET(gkMainPanel, keyboardEnabled), BYTE_OFFSET(gkMainPanel, keyboardChildren)); } if(gkMouseTarget){ mouseEvent->target = current = gkMouseTarget; do{ gkMatrix m = gkGlobalToLocal(current); mouseEvent->position = gkTransformPoint(gkMousePosition, &m); mouseEvent->currentTarget = current; }while(gkDispatch(current, mouseEvent) && (current = current->parent)); } if(newFocusTarget && curFocusTarget == gkFocusPanel){ gkSetFocus(newFocusTarget); } }
static rc_t vdb_dump_hex_ascii( p_dump_str s, const p_dump_src src, const p_col_def def ) { rc_t rc = 0; char *src_ptr = (char*)src->buf + BYTE_OFFSET( src->offset_in_bits ); char *tmp = malloc( src->number_of_elements * 4 ); if ( tmp != NULL ) { uint32_t i, dst = 0; for ( i = 0; i < src->number_of_elements && rc == 0; ++i ) rc = vdb_dump_hex_char( tmp, &dst, src_ptr[ i ] ); src_ptr[ dst ] = 0; if ( rc == 0 ) rc = vds_append_fmt( s, dst, "%.*s", dst, tmp ); } else rc = RC( rcVDB, rcNoTarg, rcConstructing, rcMemory, rcExhausted ); return rc; }
void StrokeMesh::bindVAO(Renderer_ptr& renderer) { // If we have a valid VAO, simply bind it. Done. if (_vaoValid) { glBindVertexArray(_vao); return; } ALWAYS_CHECK_GL("StrokeMesh::bindVAO().. about to initialize VAO"); // If we don't have a VAO, generate one. if (!_vao) { glGenVertexArrays(1, &_vao); if (!_vao) { cerr << "WARNING: glGenVertexArraysOES() failed in StrokeMesh::bindVAO" << endl; return; } } // Bind vertex attributes. glBindVertexArray(_vao); Stroke::Vertex v; // for offset/stride calculations. GLuint attrib = StrokeShader::POS_AND_NORM; _vertices->bindVertexAttrib(attrib, 4, GL_FLOAT, sizeof(v), 0); glEnableVertexAttribArray(attrib); attrib = StrokeShader::LENGTH_ETC; _vertices->bindVertexAttrib(attrib, 1, GL_FLOAT, sizeof(v), BYTE_OFFSET(v.x, v.length)); glEnableVertexAttribArray(attrib); // Bind indices. Stroke::indexBuffer(renderer, _triangleCount)->bind(); // Unbind buffer. Not sure why this is necessary, but the Apple example // does this. I suppose that if the bound buffer is always 0 for every VAO // that we create, then binding a VAO never needs to change the bound buffer. glBindBuffer(GL_ARRAY_BUFFER,0); // Check whether we were successful, and set validity accordingly. _vaoValid = ALWAYS_CHECK_GL("StrokeMesh::bindVAO()... failed to initialize VAO"); }
ARC_STATUS FloppyWrite ( IN ULONG FileId, IN PVOID Buffer, IN ULONG Length, OUT PULONG Count ) /*++ Routine Description: This function writes data to the floppy starting at the position specified in the file table. Arguments: FileId - Supplies the file table index. Buffer - Supplies a poiner to the buffer that contains the data to be written. Length - Supplies the number of bytes to be writtes. Count - Supplies a pointer to a variable that receives the number of bytes actually written. Return Value: The write completion status is returned. --*/ { ARC_STATUS ArcStatus; ULONG FrameNumber; ULONG Index; ULONG Limit; PMDL MdlAddress; UCHAR MdlBuffer[sizeof(MDL) + ((64 / 4) + 1) * sizeof(ULONG)]; ULONG NumberOfPages; ULONG Offset; PULONG PageFrame; ULONG Position; CHAR TempBuffer[SECTOR_SIZE + 32]; PCHAR TempPointer; // // If the requested size of the transfer is zero return ESUCCESS // if (Length==0) { return ESUCCESS; } // // If the current position is not at a sector boundary , then // read the first and/or last sector separately and copy the data. // Offset = BlFileTable[FileId].Position.LowPart & (SECTOR_SIZE - 1); if (Offset != 0) { // // Adjust position to the sector boundary, align the transfer address // and read that first sector. // BlFileTable[FileId].Position.LowPart -= Offset; TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1) & ~(KeGetDcacheFillSize() - 1)); ArcStatus = FloppyRead(FileId, TempPointer, SECTOR_SIZE, Count); // // If the transfer was not successful, then reset the position // and return the completion status. // if (ArcStatus != ESUCCESS) { BlFileTable[FileId].Position.LowPart += Offset; return ArcStatus; } else { // // Reset the position as it was before the read. // BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE; } // // If the length of write is less than the number of bytes from // the offset to the end of the sector, then copy only the number // of bytes required to fulfil the request. Otherwise copy to the end // of the sector and, read the remaining data. // if ((SECTOR_SIZE - Offset) > Length) { Limit = Offset + Length; } else { Limit = SECTOR_SIZE; } // // Merge the data from the specified buffer. // for (Index = Offset; Index < Limit; Index += 1) { *(TempPointer + Index) = *((PCHAR)Buffer)++; } // // Write the modified sector. // ArcStatus = FloppyWrite(FileId, TempPointer, SECTOR_SIZE, Count); if (ArcStatus != ESUCCESS) { return ArcStatus; } // // Adjust the current position and // Write the remaining part of the specified transfer. // BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE-Limit; Position = BlFileTable[FileId].Position.LowPart; ArcStatus = FloppyWrite(FileId, Buffer, Length - (Limit - Offset), Count); // // If the transfer was not successful, then reset the device // position and return the completion status. // if (ArcStatus != ESUCCESS) { BlFileTable[FileId].Position.LowPart = Position; return ArcStatus; } else { *Count = Length; return ESUCCESS; } } else { // // if the size of requested data is not a multiple of the sector // size then write the last sector separately. // if (Length & (SECTOR_SIZE - 1)) { // // Do the transfer of the complete sectors in the middle // Position = BlFileTable[FileId].Position.LowPart; ArcStatus = FloppyWrite(FileId, Buffer, Length & (~(SECTOR_SIZE - 1)), Count); // // If the transfer was not successful, then reset the device // position and return the completion status. // if (ArcStatus != ESUCCESS) { BlFileTable[FileId].Position.LowPart = Position; return ArcStatus; } // // Read the last sector and copy the requested data. // TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1) & ~(KeGetDcacheFillSize() - 1)); ArcStatus = FloppyRead(FileId, TempPointer, SECTOR_SIZE, Count); // // If the transfer was not successful return the completion status. // if (ArcStatus != ESUCCESS) { return ArcStatus; } // // Copy the data to the specified buffer. // (PCHAR)Buffer += Length & (~(SECTOR_SIZE - 1)); Limit = Length & (SECTOR_SIZE - 1); for (Index = 0; Index < Limit; Index += 1) { *(TempPointer + Index) = *((PCHAR)Buffer)++; } // // Adjust the position and write the data. // BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE; ArcStatus = FloppyWrite(FileId, TempPointer, SECTOR_SIZE, Count); // // Set the position for the requested transfer // BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE - Limit; *Count = Length; return ArcStatus; } else { // // Build the memory descriptor list. // MdlAddress = (PMDL)&MdlBuffer[0]; MdlAddress->Next = NULL; MdlAddress->Size = sizeof(MDL) + ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Length) * sizeof(ULONG); MdlAddress->StartVa = (PVOID)PAGE_ALIGN(Buffer); MdlAddress->ByteCount = Length; MdlAddress->ByteOffset = BYTE_OFFSET(Buffer); PageFrame = (PULONG)(MdlAddress + 1); FrameNumber = (((ULONG)MdlAddress->StartVa) & 0x1fffffff) >> PAGE_SHIFT; NumberOfPages = (MdlAddress->ByteCount + MdlAddress->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT; for (Index = 0; Index < NumberOfPages; Index += 1) { *PageFrame++ = FrameNumber++; } // // Flush I/O buffers and write to the boot device. // HalFlushIoBuffers(MdlAddress, FALSE, TRUE); ArcStatus = FloppyBootIO(MdlAddress, BlFileTable[FileId].Position.LowPart >> SECTOR_SHIFT, FileId, TRUE); if (ArcStatus == ESUCCESS) { BlFileTable[FileId].Position.LowPart += Length; *Count = Length; return ESUCCESS; } else { *Count = 0; return EIO; } } } }
NTSTATUS MiCcPutPagesInTransition ( IN PMI_READ_INFO MiReadInfo ) /*++ Routine Description: This routine allocates physical memory for the specified read-list and puts all the pages in transition (so collided faults from other threads for these same pages remain coherent). I/O for any pages not already resident are issued here. The caller must wait for their completion. Arguments: MiReadInfo - Supplies a pointer to the read-list. Return Value: STATUS_SUCCESS - all the pages were already resident, reference counts have been applied and no I/O needs to be waited for. STATUS_ISSUE_PAGING_IO - the I/O has been issued and the caller must wait. Various other failure status values indicate the operation failed. Environment: Kernel mode. PASSIVE_LEVEL. --*/ { NTSTATUS status; PMMPTE LocalPrototypePte; PVOID StartingVa; PFN_NUMBER MdlPages; KIRQL OldIrql; MMPTE PteContents; PFN_NUMBER PageFrameIndex; PFN_NUMBER ResidentAvailableCharge; PPFN_NUMBER IoPage; PPFN_NUMBER ApiPage; PPFN_NUMBER Page; PPFN_NUMBER DestinationPage; ULONG PageColor; PMMPTE PointerPte; PMMPTE *ProtoPteArray; PMMPTE *EndProtoPteArray; PFN_NUMBER DummyPage; PMDL Mdl; PMDL FreeMdl; PMMPFN PfnProto; PMMPFN Pfn1; PMMPFN DummyPfn1; ULONG i; PFN_NUMBER DummyTrim; ULONG NumberOfPagesNeedingIo; MMPTE TempPte; PMMPTE PointerPde; PEPROCESS CurrentProcess; PMMINPAGE_SUPPORT InPageSupport; PKPRCB Prcb; ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); MiReadInfo->DummyPagePfn = NULL; FreeMdl = NULL; CurrentProcess = PsGetCurrentProcess(); PfnProto = NULL; PointerPde = NULL; InPageSupport = MiReadInfo->InPageSupport; Mdl = MI_EXTRACT_PREFETCH_MDL (InPageSupport); ASSERT (Mdl == MiReadInfo->IoMdl); IoPage = (PPFN_NUMBER)(Mdl + 1); ApiPage = (PPFN_NUMBER)(MiReadInfo->ApiMdl + 1); StartingVa = (PVOID)((PCHAR)Mdl->StartVa + Mdl->ByteOffset); MdlPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES (StartingVa, Mdl->ByteCount); if (MdlPages + 1 > MAXUSHORT) { // // The PFN ReferenceCount for the dummy page could wrap, refuse the // request. // return STATUS_INSUFFICIENT_RESOURCES; } NumberOfPagesNeedingIo = 0; ProtoPteArray = (PMMPTE *)InPageSupport->BasePte; EndProtoPteArray = ProtoPteArray + MdlPages; ASSERT (*ProtoPteArray != NULL); LOCK_PFN (OldIrql); // // Ensure sufficient pages exist for the transfer plus the dummy page. // if (((SPFN_NUMBER)MdlPages > (SPFN_NUMBER)(MmAvailablePages - MM_HIGH_LIMIT)) || (MI_NONPAGEABLE_MEMORY_AVAILABLE() <= (SPFN_NUMBER)MdlPages)) { UNLOCK_PFN (OldIrql); return STATUS_INSUFFICIENT_RESOURCES; } // // Charge resident available immediately as the PFN lock may get released // and reacquired below before all the pages have been locked down. // Note the dummy page is immediately charged separately. // MI_DECREMENT_RESIDENT_AVAILABLE (MdlPages, MM_RESAVAIL_ALLOCATE_BUILDMDL); ResidentAvailableCharge = MdlPages; // // Allocate a dummy page to map discarded pages that aren't skipped. // DummyPage = MiRemoveAnyPage (0); Pfn1 = MI_PFN_ELEMENT (DummyPage); ASSERT (Pfn1->u2.ShareCount == 0); ASSERT (Pfn1->u3.e2.ReferenceCount == 0); MiInitializePfnForOtherProcess (DummyPage, MI_PF_DUMMY_PAGE_PTE, 0); // // Give the page a containing frame so MiIdentifyPfn won't crash. // Pfn1->u4.PteFrame = PsInitialSystemProcess->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT; // // Always bias the reference count by 1 and charge for this locked page // up front so the myriad increments and decrements don't get slowed // down with needless checking. // Pfn1->u3.e1.PrototypePte = 0; MI_ADD_LOCKED_PAGE_CHARGE (Pfn1); Pfn1->u3.e1.ReadInProgress = 1; MiReadInfo->DummyPagePfn = Pfn1; DummyPfn1 = Pfn1; DummyPfn1->u3.e2.ReferenceCount = (USHORT)(DummyPfn1->u3.e2.ReferenceCount + MdlPages); // // Properly initialize the inpage support block fields we overloaded. // InPageSupport->BasePte = *ProtoPteArray; // // Build the proper InPageSupport and MDL to describe this run. // for (; ProtoPteArray < EndProtoPteArray; ProtoPteArray += 1, IoPage += 1, ApiPage += 1) { // // Fill the MDL entry for this RLE. // PointerPte = *ProtoPteArray; ASSERT (PointerPte != NULL); // // The PointerPte better be inside a prototype PTE allocation // so that subsequent page trims update the correct PTEs. // ASSERT (((PointerPte >= (PMMPTE)MmPagedPoolStart) && (PointerPte <= (PMMPTE)MmPagedPoolEnd)) || ((PointerPte >= (PMMPTE)MmSpecialPoolStart) && (PointerPte <= (PMMPTE)MmSpecialPoolEnd))); // // Check the state of this prototype PTE now that the PFN lock is held. // If the page is not resident, the PTE must be put in transition with // read in progress before the PFN lock is released. // // // Lock page containing prototype PTEs in memory by // incrementing the reference count for the page. // Unlock any page locked earlier containing prototype PTEs if // the containing page is not the same for both. // if (PfnProto != NULL) { if (PointerPde != MiGetPteAddress (PointerPte)) { ASSERT (PfnProto->u3.e2.ReferenceCount > 1); MI_REMOVE_LOCKED_PAGE_CHARGE_AND_DECREF (PfnProto); PfnProto = NULL; } } if (PfnProto == NULL) { ASSERT (!MI_IS_PHYSICAL_ADDRESS (PointerPte)); PointerPde = MiGetPteAddress (PointerPte); if (PointerPde->u.Hard.Valid == 0) { MiMakeSystemAddressValidPfn (PointerPte, OldIrql); } PfnProto = MI_PFN_ELEMENT (PointerPde->u.Hard.PageFrameNumber); MI_ADD_LOCKED_PAGE_CHARGE (PfnProto); ASSERT (PfnProto->u3.e2.ReferenceCount > 1); } recheck: PteContents = *PointerPte; // LWFIX: are zero or dzero ptes possible here ? ASSERT (PteContents.u.Long != 0); if (PteContents.u.Hard.Valid == 1) { PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (&PteContents); Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); ASSERT (Pfn1->u3.e1.PrototypePte == 1); MI_ADD_LOCKED_PAGE_CHARGE (Pfn1); *ApiPage = PageFrameIndex; *IoPage = DummyPage; continue; } if ((PteContents.u.Soft.Prototype == 0) && (PteContents.u.Soft.Transition == 1)) { // // The page is in transition. If there is an inpage still in // progress, wait for it to complete. Reference the PFN and // then march on. // PageFrameIndex = MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (&PteContents); Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); ASSERT (Pfn1->u3.e1.PrototypePte == 1); if (Pfn1->u4.InPageError) { // // There was an in-page read error and there are other // threads colliding for this page, delay to let the // other threads complete and then retry. // UNLOCK_PFN (OldIrql); KeDelayExecutionThread (KernelMode, FALSE, (PLARGE_INTEGER)&MmHalfSecond); LOCK_PFN (OldIrql); goto recheck; } if (Pfn1->u3.e1.ReadInProgress) { // LWFIX - start with temp\aw.c } // // PTE refers to a normal transition PTE. // ASSERT ((SPFN_NUMBER)MmAvailablePages >= 0); if (MmAvailablePages == 0) { // // This can only happen if the system is utilizing a hardware // compression cache. This ensures that only a safe amount // of the compressed virtual cache is directly mapped so that // if the hardware gets into trouble, we can bail it out. // UNLOCK_PFN (OldIrql); KeDelayExecutionThread (KernelMode, FALSE, (PLARGE_INTEGER)&MmHalfSecond); LOCK_PFN (OldIrql); goto recheck; } // // The PFN reference count will be 1 already here if the // modified writer has begun a write of this page. Otherwise // it's ordinarily 0. // MI_ADD_LOCKED_PAGE_CHARGE_FOR_MODIFIED_PAGE (Pfn1); *IoPage = DummyPage; *ApiPage = PageFrameIndex; continue; } // LWFIX: need to handle protos that are now pagefile (or dzero) // backed - prefetching it from the file here would cause us to lose // the contents. Note this can happen for session-space images // as we back modified (ie: for relocation fixups or IAT // updated) portions from the pagefile. remove the assert below too. ASSERT (PteContents.u.Soft.Prototype == 1); if ((MmAvailablePages < MM_HIGH_LIMIT) && (MiEnsureAvailablePageOrWait (NULL, OldIrql))) { // // Had to wait so recheck all state. // goto recheck; } NumberOfPagesNeedingIo += 1; // // Allocate a physical page. // PageColor = MI_PAGE_COLOR_VA_PROCESS ( MiGetVirtualAddressMappedByPte (PointerPte), &CurrentProcess->NextPageColor); PageFrameIndex = MiRemoveAnyPage (PageColor); Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); ASSERT (Pfn1->u3.e2.ReferenceCount == 0); ASSERT (Pfn1->u2.ShareCount == 0); ASSERT (PointerPte->u.Hard.Valid == 0); // // Initialize read-in-progress PFN. // MiInitializePfn (PageFrameIndex, PointerPte, 0); // // These pieces of MiInitializePfn initialization are overridden // here as these pages are only going into prototype // transition and not into any page tables. // Pfn1->u3.e1.PrototypePte = 1; Pfn1->u2.ShareCount -= 1; ASSERT (Pfn1->u2.ShareCount == 0); Pfn1->u3.e1.PageLocation = ZeroedPageList; Pfn1->u3.e2.ReferenceCount -= 1; ASSERT (Pfn1->u3.e2.ReferenceCount == 0); MI_ADD_LOCKED_PAGE_CHARGE_FOR_MODIFIED_PAGE (Pfn1); // // Initialize the I/O specific fields. // Pfn1->u1.Event = &InPageSupport->Event; Pfn1->u3.e1.ReadInProgress = 1; ASSERT (Pfn1->u4.InPageError == 0); // // Increment the PFN reference count in the control area for // the subsection. // MiReadInfo->ControlArea->NumberOfPfnReferences += 1; // // Put the prototype PTE into the transition state. // MI_MAKE_TRANSITION_PTE (TempPte, PageFrameIndex, PointerPte->u.Soft.Protection, PointerPte); MI_WRITE_INVALID_PTE (PointerPte, TempPte); *IoPage = PageFrameIndex; *ApiPage = PageFrameIndex; } // // If all the pages were resident, dereference the dummy page references // now and notify our caller that I/O is not necessary. // if (NumberOfPagesNeedingIo == 0) { ASSERT (DummyPfn1->u3.e2.ReferenceCount > MdlPages); DummyPfn1->u3.e2.ReferenceCount = (USHORT)(DummyPfn1->u3.e2.ReferenceCount - MdlPages); // // Unlock page containing prototype PTEs. // if (PfnProto != NULL) { ASSERT (PfnProto->u3.e2.ReferenceCount > 1); MI_REMOVE_LOCKED_PAGE_CHARGE_AND_DECREF (PfnProto); } UNLOCK_PFN (OldIrql); // // Return the upfront resident available charge as the // individual charges have all been made at this point. // MI_INCREMENT_RESIDENT_AVAILABLE (ResidentAvailableCharge, MM_RESAVAIL_FREE_BUILDMDL_EXCESS); return STATUS_SUCCESS; } // // Carefully trim leading dummy pages. // Page = (PPFN_NUMBER)(Mdl + 1); DummyTrim = 0; for (i = 0; i < MdlPages - 1; i += 1) { if (*Page == DummyPage) { DummyTrim += 1; Page += 1; } else { break; } } if (DummyTrim != 0) { Mdl->Size = (USHORT)(Mdl->Size - (DummyTrim * sizeof(PFN_NUMBER))); Mdl->ByteCount -= (ULONG)(DummyTrim * PAGE_SIZE); ASSERT (Mdl->ByteCount != 0); InPageSupport->ReadOffset.QuadPart += (DummyTrim * PAGE_SIZE); DummyPfn1->u3.e2.ReferenceCount = (USHORT)(DummyPfn1->u3.e2.ReferenceCount - DummyTrim); // // Shuffle down the PFNs in the MDL. // Recalculate BasePte to adjust for the shuffle. // Pfn1 = MI_PFN_ELEMENT (*Page); ASSERT (Pfn1->PteAddress->u.Hard.Valid == 0); ASSERT ((Pfn1->PteAddress->u.Soft.Prototype == 0) && (Pfn1->PteAddress->u.Soft.Transition == 1)); InPageSupport->BasePte = Pfn1->PteAddress; DestinationPage = (PPFN_NUMBER)(Mdl + 1); do { *DestinationPage = *Page; DestinationPage += 1; Page += 1; i += 1; } while (i < MdlPages); MdlPages -= DummyTrim; } // // Carefully trim trailing dummy pages. // ASSERT (MdlPages != 0); Page = (PPFN_NUMBER)(Mdl + 1) + MdlPages - 1; if (*Page == DummyPage) { ASSERT (MdlPages >= 2); // // Trim the last page specially as it may be a partial page. // Mdl->Size -= sizeof(PFN_NUMBER); if (BYTE_OFFSET(Mdl->ByteCount) != 0) { Mdl->ByteCount &= ~(PAGE_SIZE - 1); } else { Mdl->ByteCount -= PAGE_SIZE; } ASSERT (Mdl->ByteCount != 0); DummyPfn1->u3.e2.ReferenceCount -= 1; // // Now trim any other trailing pages. // Page -= 1; DummyTrim = 0; while (Page != ((PPFN_NUMBER)(Mdl + 1))) { if (*Page != DummyPage) { break; } DummyTrim += 1; Page -= 1; } if (DummyTrim != 0) { ASSERT (Mdl->Size > (USHORT)(DummyTrim * sizeof(PFN_NUMBER))); Mdl->Size = (USHORT)(Mdl->Size - (DummyTrim * sizeof(PFN_NUMBER))); Mdl->ByteCount -= (ULONG)(DummyTrim * PAGE_SIZE); DummyPfn1->u3.e2.ReferenceCount = (USHORT)(DummyPfn1->u3.e2.ReferenceCount - DummyTrim); } ASSERT (MdlPages > DummyTrim + 1); MdlPages -= (DummyTrim + 1); #if DBG StartingVa = (PVOID)((PCHAR)Mdl->StartVa + Mdl->ByteOffset); ASSERT (MdlPages == ADDRESS_AND_SIZE_TO_SPAN_PAGES(StartingVa, Mdl->ByteCount)); #endif } // // If the MDL is not already embedded in the inpage block, see if its // final size qualifies it - if so, embed it now. // if ((Mdl != &InPageSupport->Mdl) && (Mdl->ByteCount <= (MM_MAXIMUM_READ_CLUSTER_SIZE + 1) * PAGE_SIZE)){ #if DBG RtlFillMemoryUlong (&InPageSupport->Page[0], (MM_MAXIMUM_READ_CLUSTER_SIZE+1) * sizeof (PFN_NUMBER), 0xf1f1f1f1); #endif RtlCopyMemory (&InPageSupport->Mdl, Mdl, Mdl->Size); FreeMdl = Mdl; Mdl = &InPageSupport->Mdl; ASSERT (((ULONG_PTR)Mdl & (sizeof(QUAD) - 1)) == 0); InPageSupport->u1.e1.PrefetchMdlHighBits = ((ULONG_PTR)Mdl >> 3); }
NTSTATUS MiCcPrepareReadInfo ( IN PMI_READ_INFO MiReadInfo ) /*++ Routine Description: This routine constructs MDLs that describe the pages in the argument read-list. The caller will then issue the I/O on return. Arguments: MiReadInfo - Supplies a pointer to the read-list. Return Value: Various NTSTATUS codes. Environment: Kernel mode, PASSIVE_LEVEL. --*/ { UINT64 PteOffset; NTSTATUS Status; PMMPTE ProtoPte; PMMPTE LastProto; PMMPTE *ProtoPteArray; PCONTROL_AREA ControlArea; PSUBSECTION Subsection; PMMINPAGE_SUPPORT InPageSupport; PMDL Mdl; PMDL IoMdl; PMDL ApiMdl; ULONG i; PFN_NUMBER NumberOfPages; ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); NumberOfPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES (MiReadInfo->FileOffset.LowPart, MiReadInfo->LengthInBytes); // // Translate the section object into the relevant control area. // ControlArea = (PCONTROL_AREA)MiReadInfo->FileObject->SectionObjectPointer->DataSectionObject; // // If the section is backed by a ROM, then there's no need to prefetch // anything as it would waste RAM. // if (ControlArea->u.Flags.Rom == 1) { return STATUS_NOT_SUPPORTED; } // // Initialize the internal Mi readlist. // MiReadInfo->ControlArea = ControlArea; // // Allocate and initialize an inpage support block for this run. // InPageSupport = MiGetInPageSupportBlock (MM_NOIRQL, &Status); if (InPageSupport == NULL) { ASSERT (!NT_SUCCESS (Status)); return Status; } MiReadInfo->InPageSupport = InPageSupport; // // Allocate and initialize an MDL to return to our caller. The actual // frame numbers are filled in when all the pages are reference counted. // ApiMdl = MmCreateMdl (NULL, NULL, NumberOfPages << PAGE_SHIFT); if (ApiMdl == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } ApiMdl->MdlFlags |= MDL_PAGES_LOCKED; MiReadInfo->ApiMdl = ApiMdl; // // Allocate and initialize an MDL to use for the actual transfer (if any). // IoMdl = MmCreateMdl (NULL, NULL, NumberOfPages << PAGE_SHIFT); if (IoMdl == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } MiReadInfo->IoMdl = IoMdl; Mdl = IoMdl; // // Make sure the section is really prefetchable - physical and // pagefile-backed sections are not. // if ((ControlArea->u.Flags.PhysicalMemory) || (ControlArea->u.Flags.Image == 1) || (ControlArea->FilePointer == NULL)) { return STATUS_INVALID_PARAMETER_1; } // // Start the read at the proper file offset. // InPageSupport->ReadOffset = MiReadInfo->FileOffset; ASSERT (BYTE_OFFSET (InPageSupport->ReadOffset.LowPart) == 0); InPageSupport->FilePointer = MiReadInfo->FileObject; // // Stash a pointer to the start of the prototype PTE array (the values // in the array are not contiguous as they may cross subsections) // in the inpage block so we can walk it quickly later when the pages // are put into transition. // ProtoPteArray = (PMMPTE *)(Mdl + 1); InPageSupport->BasePte = (PMMPTE) ProtoPteArray; // // Data (but not image) reads use the whole page and the filesystems // zero fill any remainder beyond valid data length so we don't // bother to handle this here. It is important to specify the // entire page where possible so the filesystem won't post this // which will hurt perf. LWFIX: must use CcZero to make this true. // ASSERT (((ULONG_PTR)Mdl & (sizeof(QUAD) - 1)) == 0); InPageSupport->u1.e1.PrefetchMdlHighBits = ((ULONG_PTR)Mdl >> 3); // // Initialize the prototype PTE pointers. // ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0); if (ControlArea->u.Flags.Rom == 0) { Subsection = (PSUBSECTION)(ControlArea + 1); } else { Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1); } #if DBG if (MiCcDebug & MI_CC_FORCE_PREFETCH) { MiRemoveUserPages (); } #endif // // Calculate the first prototype PTE address. // PteOffset = (UINT64)(MiReadInfo->FileOffset.QuadPart >> PAGE_SHIFT); // // Make sure the PTEs are not in the extended part of the segment. // while (TRUE) { // // A memory barrier is needed to read the subsection chains // in order to ensure the writes to the actual individual // subsection data structure fields are visible in correct // order. This avoids the need to acquire any stronger // synchronization (ie: PFN lock), thus yielding better // performance and pageability. // KeMemoryBarrier (); if (PteOffset < (UINT64) Subsection->PtesInSubsection) { break; } PteOffset -= Subsection->PtesInSubsection; Subsection = Subsection->NextSubsection; } Status = MiAddViewsForSectionWithPfn ((PMSUBSECTION) Subsection, Subsection->PtesInSubsection); if (!NT_SUCCESS (Status)) { return Status; } MiReadInfo->FirstReferencedSubsection = Subsection; MiReadInfo->LastReferencedSubsection = Subsection; ProtoPte = &Subsection->SubsectionBase[PteOffset]; LastProto = &Subsection->SubsectionBase[Subsection->PtesInSubsection]; for (i = 0; i < NumberOfPages; i += 1) { // // Calculate which PTE maps the given logical block offset. // // Always look forwards (as an optimization) in the subsection chain. // // A quick check is made first to avoid recalculations and loops where // possible. // if (ProtoPte >= LastProto) { // // Handle extended subsections. Increment the view count for // every subsection spanned by this request, creating prototype // PTEs if needed. // ASSERT (i != 0); Subsection = Subsection->NextSubsection; Status = MiAddViewsForSectionWithPfn ((PMSUBSECTION) Subsection, Subsection->PtesInSubsection); if (!NT_SUCCESS (Status)) { return Status; } MiReadInfo->LastReferencedSubsection = Subsection; ProtoPte = Subsection->SubsectionBase; LastProto = &Subsection->SubsectionBase[Subsection->PtesInSubsection]; } *ProtoPteArray = ProtoPte; ProtoPteArray += 1; ProtoPte += 1; } return STATUS_SUCCESS; }
/* * private void setField(Object o, Class declaringClass, Class type, * int slot, boolean noAccessCheck, Object value) * * When assigning into a primitive field we will automatically extract * the value from box types. */ static void Dalvik_java_lang_reflect_Field_setField(const u4* args, JValue* pResult) { // ignore thisPtr in args[0] Object* obj = (Object*) args[1]; ClassObject* declaringClass = (ClassObject*) args[2]; ClassObject* fieldType = (ClassObject*) args[3]; int slot = args[4]; bool noAccessCheck = (args[5] != 0); Object* valueObj = (Object*) args[6]; #ifdef WITH_TAINT_TRACKING /* rtaint = args[7] * thisPtr taint = args[8] * obj taint = args[9] * declaringClass taint = args[10] * fieldType taint = args[11] * slot taint = args[12] * noAccessCheck taint = args[13] */ u4 valueTaint = args[14]; #endif JValue* fieldPtr; JValue value; /* unwrap primitive, or verify object type */ if (!dvmUnwrapPrimitive(valueObj, fieldType, &value)) { dvmThrowException("Ljava/lang/IllegalArgumentException;", "invalid value for field"); RETURN_VOID(); } /* get a pointer to the field's data; performs access checks */ fieldPtr = getFieldDataAddr(obj, declaringClass, slot, true, noAccessCheck); if (fieldPtr == NULL) RETURN_VOID(); /* store 4 or 8 bytes */ if (fieldType->primitiveType == PRIM_LONG || fieldType->primitiveType == PRIM_DOUBLE) { fieldPtr->j = value.j; } else if (fieldType->primitiveType == PRIM_NOT) { if (slot < 0) { StaticField *sfield; sfield = (StaticField *)dvmSlotToField(declaringClass, slot); assert(fieldPtr == &sfield->value); dvmSetStaticFieldObject(sfield, value.l); } else { int offset = declaringClass->ifields[slot].byteOffset; assert(fieldPtr == (JValue *)BYTE_OFFSET(obj, offset)); dvmSetFieldObject(obj, offset, value.l); } } else { fieldPtr->i = value.i; } #ifdef WITH_TAINT_TRACKING /* If we got this far, we know the fields is okay to access and there * will not be a problem getting the field from the slot */ { Field* field = dvmSlotToField(declaringClass, slot); assert(field != NULL); if (dvmIsStaticField(field)) { StaticField* sfield = (StaticField*)field; dvmSetStaticFieldTaint(sfield, valueTaint); } else { /* Note, getFieldDataAddr() already checked that * obj is of type declaringClass, so no need to check here */ InstField* ifield = (InstField*)field; if (fieldType->primitiveType == PRIM_LONG || fieldType->primitiveType == PRIM_DOUBLE) { dvmSetFieldTaintWide(obj, ifield->byteOffset, valueTaint); } else { dvmSetFieldTaint(obj, ifield->byteOffset, valueTaint); } } } #endif RETURN_VOID(); }
PVOID NTAPI HalpMapPhysicalMemory64Vista(IN PHYSICAL_ADDRESS PhysicalAddress, IN PFN_COUNT PageCount, IN BOOLEAN FlushCurrentTLB) { PHARDWARE_PTE PointerPte; PFN_NUMBER UsedPages = 0; PVOID VirtualAddress, BaseAddress; /* Start at the current HAL heap base */ BaseAddress = HalpHeapStart; VirtualAddress = BaseAddress; /* Loop until we have all the pages required */ while (UsedPages < PageCount) { /* If this overflows past the HAL heap, it means there's no space */ if (VirtualAddress == NULL) return NULL; /* Get the PTE for this address */ PointerPte = HalAddressToPte(VirtualAddress); /* Go to the next page */ VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE); /* Check if the page is available */ if (PointerPte->Valid) { /* PTE has data, skip it and start with a new base address */ BaseAddress = VirtualAddress; UsedPages = 0; continue; } /* PTE is available, keep going on this run */ UsedPages++; } /* Take the base address of the page plus the actual offset in the address */ VirtualAddress = (PVOID)((ULONG_PTR)BaseAddress + BYTE_OFFSET(PhysicalAddress.LowPart)); /* If we are starting at the heap, move the heap */ if (BaseAddress == HalpHeapStart) { /* Past this allocation */ HalpHeapStart = (PVOID)((ULONG_PTR)BaseAddress + (PageCount * PAGE_SIZE)); } /* Loop pages that can be mapped */ while (UsedPages--) { /* Fill out the PTE */ PointerPte = HalAddressToPte(BaseAddress); PointerPte->PageFrameNumber = (PFN_NUMBER)(PhysicalAddress.QuadPart >> PAGE_SHIFT); PointerPte->Valid = 1; PointerPte->Write = 1; /* Move to the next address */ PhysicalAddress.QuadPart += PAGE_SIZE; BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PAGE_SIZE); } /* Flush the TLB and return the address */ if (FlushCurrentTLB) HalpFlushTLB(); return VirtualAddress; }
VOID HalpCopyBufferMap( IN PMDL Mdl, IN PTRANSLATION_ENTRY TranslationEntry, IN PVOID CurrentVa, IN ULONG Length, IN BOOLEAN WriteToDevice ) /*++ Routine Description: This routine copies the speicific data between the user's buffer and the map register buffer. First a the user buffer is mapped if necessary, then the data is copied. Finally the user buffer will be unmapped if neccessary. Arguments: Mdl - Pointer to the MDL that describes the pages of memory that are being read or written. TranslationEntry - The address of the base map register that has been allocated to the device driver for use in mapping the transfer. CurrentVa - Current virtual address in the buffer described by the MDL that the transfer is being done to or from. Length - The length of the transfer. This determines the number of map registers that need to be written to map the transfer. WriteToDevice - Boolean value that indicates whether this is a write to the device from memory (TRUE), or vice versa. Return Value: None. --*/ { PCCHAR bufferAddress; PCCHAR mapAddress; // // Get the system address of the MDL. // bufferAddress = MmGetSystemAddressForMdl(Mdl); // // Calculate the actual start of the buffer based on the system VA and // the current VA. // bufferAddress += (PCCHAR) CurrentVa - (PCCHAR) MmGetMdlVirtualAddress(Mdl); mapAddress = (PCCHAR) TranslationEntry->VirtualAddress + BYTE_OFFSET(CurrentVa); // // Copy the data between the user buffer and map buffer // if (WriteToDevice) { RtlMoveMemory( mapAddress, bufferAddress, Length); } else { RtlMoveMemory(bufferAddress, mapAddress, Length); } }
/* * @implemented */ PVOID NTAPI MmMapIoSpace(IN PHYSICAL_ADDRESS PhysicalAddress, IN SIZE_T NumberOfBytes, IN MEMORY_CACHING_TYPE CacheType) { PFN_NUMBER Pfn; PFN_COUNT PageCount; PMMPTE PointerPte; PVOID BaseAddress; MMPTE TempPte; PMMPFN Pfn1 = NULL; MI_PFN_CACHE_ATTRIBUTE CacheAttribute; BOOLEAN IsIoMapping; // // Must be called with a non-zero count // ASSERT(NumberOfBytes != 0); // // Make sure the upper bits are 0 if this system // can't describe more than 4 GB of physical memory. // FIXME: This doesn't respect PAE, but we currently don't // define a PAE build flag since there is no such build. // #if !defined(_M_AMD64) ASSERT(PhysicalAddress.HighPart == 0); #endif // // Normalize and validate the caching attributes // CacheType &= 0xFF; if (CacheType >= MmMaximumCacheType) return NULL; // // Calculate page count // PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(PhysicalAddress.LowPart, NumberOfBytes); // // Compute the PFN and check if it's a known I/O mapping // Also translate the cache attribute // Pfn = (PFN_NUMBER)(PhysicalAddress.QuadPart >> PAGE_SHIFT); Pfn1 = MiGetPfnEntry(Pfn); IsIoMapping = (Pfn1 == NULL) ? TRUE : FALSE; CacheAttribute = MiPlatformCacheAttributes[IsIoMapping][CacheType]; // // Now allocate system PTEs for the mapping, and get the VA // PointerPte = MiReserveSystemPtes(PageCount, SystemPteSpace); if (!PointerPte) return NULL; BaseAddress = MiPteToAddress(PointerPte); // // Check if this is uncached // if (CacheAttribute != MiCached) { // // Flush all caches // KeFlushEntireTb(TRUE, TRUE); KeInvalidateAllCaches(); } // // Now compute the VA offset // BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + BYTE_OFFSET(PhysicalAddress.LowPart)); // // Get the template and configure caching // TempPte = ValidKernelPte; switch (CacheAttribute) { case MiNonCached: // // Disable the cache // MI_PAGE_DISABLE_CACHE(&TempPte); MI_PAGE_WRITE_THROUGH(&TempPte); break; case MiCached: // // Leave defaults // break; case MiWriteCombined: // // We don't support write combining yet // ASSERT(FALSE); break; default: // // Should never happen // ASSERT(FALSE); break; } // // Sanity check and re-flush // Pfn = (PFN_NUMBER)(PhysicalAddress.QuadPart >> PAGE_SHIFT); ASSERT((Pfn1 == MiGetPfnEntry(Pfn)) || (Pfn1 == NULL)); KeFlushEntireTb(TRUE, TRUE); KeInvalidateAllCaches(); // // Do the mapping // do { // // Write the PFN // TempPte.u.Hard.PageFrameNumber = Pfn++; MI_WRITE_VALID_PTE(PointerPte++, TempPte); } while (--PageCount); // // We're done! // return BaseAddress; }
NTSTATUS MmAddPhysicalMemory ( IN PPHYSICAL_ADDRESS StartAddress, IN OUT PLARGE_INTEGER NumberOfBytes ) /*++ Routine Description: This routine adds the specified physical address range to the system. This includes initializing PFN database entries and adding it to the freelists. Arguments: StartAddress - Supplies the starting physical address. NumberOfBytes - Supplies a pointer to the number of bytes being added. If any bytes were added (ie: STATUS_SUCCESS is being returned), the actual amount is returned here. Return Value: NTSTATUS. Environment: Kernel mode. PASSIVE level. No locks held. --*/ { ULONG i; PMMPFN Pfn1; KIRQL OldIrql; LOGICAL Inserted; LOGICAL Updated; MMPTE TempPte; PMMPTE PointerPte; PMMPTE LastPte; PFN_NUMBER NumberOfPages; PFN_NUMBER start; PFN_NUMBER count; PFN_NUMBER StartPage; PFN_NUMBER EndPage; PFN_NUMBER PageFrameIndex; PFN_NUMBER Page; PFN_NUMBER LastPage; PFN_COUNT PagesNeeded; PPHYSICAL_MEMORY_DESCRIPTOR OldPhysicalMemoryBlock; PPHYSICAL_MEMORY_DESCRIPTOR NewPhysicalMemoryBlock; PPHYSICAL_MEMORY_RUN NewRun; LOGICAL PfnDatabaseIsPhysical; ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); ASSERT (BYTE_OFFSET(NumberOfBytes->LowPart) == 0); ASSERT (BYTE_OFFSET(StartAddress->LowPart) == 0); if (MI_IS_PHYSICAL_ADDRESS(MmPfnDatabase)) { // // The system must be configured for dynamic memory addition. This is // critical as only then is the database guaranteed to be non-sparse. // if (MmDynamicPfn == FALSE) { return STATUS_NOT_SUPPORTED; } PfnDatabaseIsPhysical = TRUE; } else { PfnDatabaseIsPhysical = FALSE; } StartPage = (PFN_NUMBER)(StartAddress->QuadPart >> PAGE_SHIFT); NumberOfPages = (PFN_NUMBER)(NumberOfBytes->QuadPart >> PAGE_SHIFT); EndPage = StartPage + NumberOfPages; if (EndPage - 1 > MmHighestPossiblePhysicalPage) { // // Truncate the request into something that can be mapped by the PFN // database. // EndPage = MmHighestPossiblePhysicalPage + 1; NumberOfPages = EndPage - StartPage; } // // The range cannot wrap. // if (StartPage >= EndPage) { return STATUS_INVALID_PARAMETER_1; } ExAcquireFastMutex (&MmDynamicMemoryMutex); i = (sizeof(PHYSICAL_MEMORY_DESCRIPTOR) + (sizeof(PHYSICAL_MEMORY_RUN) * (MmPhysicalMemoryBlock->NumberOfRuns + 1))); NewPhysicalMemoryBlock = ExAllocatePoolWithTag (NonPagedPool, i, ' mM'); if (NewPhysicalMemoryBlock == NULL) { ExReleaseFastMutex (&MmDynamicMemoryMutex); return STATUS_INSUFFICIENT_RESOURCES; } // // The range cannot overlap any ranges that are already present. // start = 0; LOCK_PFN (OldIrql); do { count = MmPhysicalMemoryBlock->Run[start].PageCount; Page = MmPhysicalMemoryBlock->Run[start].BasePage; if (count != 0) { LastPage = Page + count; if ((StartPage < Page) && (EndPage > Page)) { UNLOCK_PFN (OldIrql); ExReleaseFastMutex (&MmDynamicMemoryMutex); ExFreePool (NewPhysicalMemoryBlock); return STATUS_CONFLICTING_ADDRESSES; } if ((StartPage >= Page) && (StartPage < LastPage)) { UNLOCK_PFN (OldIrql); ExReleaseFastMutex (&MmDynamicMemoryMutex); ExFreePool (NewPhysicalMemoryBlock); return STATUS_CONFLICTING_ADDRESSES; } } start += 1; } while (start != MmPhysicalMemoryBlock->NumberOfRuns); // // Fill any gaps in the (sparse) PFN database needed for these pages, // unless the PFN database was physically allocated and completely // committed up front. // PagesNeeded = 0; if (PfnDatabaseIsPhysical == FALSE) { PointerPte = MiGetPteAddress (MI_PFN_ELEMENT(StartPage)); LastPte = MiGetPteAddress ((PCHAR)(MI_PFN_ELEMENT(EndPage)) - 1); while (PointerPte <= LastPte) { if (PointerPte->u.Hard.Valid == 0) { PagesNeeded += 1; } PointerPte += 1; } if (MmAvailablePages < PagesNeeded) { UNLOCK_PFN (OldIrql); ExReleaseFastMutex (&MmDynamicMemoryMutex); ExFreePool (NewPhysicalMemoryBlock); return STATUS_INSUFFICIENT_RESOURCES; } TempPte = ValidKernelPte; PointerPte = MiGetPteAddress (MI_PFN_ELEMENT(StartPage)); while (PointerPte <= LastPte) { if (PointerPte->u.Hard.Valid == 0) { PageFrameIndex = MiRemoveZeroPage(MI_GET_PAGE_COLOR_FROM_PTE (PointerPte)); MiInitializePfn (PageFrameIndex, PointerPte, 0); TempPte.u.Hard.PageFrameNumber = PageFrameIndex; *PointerPte = TempPte; } PointerPte += 1; } MmResidentAvailablePages -= PagesNeeded; } // // If the new range is adjacent to an existing range, just merge it into // the old block. Otherwise use the new block as a new entry will have to // be used. // NewPhysicalMemoryBlock->NumberOfRuns = MmPhysicalMemoryBlock->NumberOfRuns + 1; NewPhysicalMemoryBlock->NumberOfPages = MmPhysicalMemoryBlock->NumberOfPages + NumberOfPages; NewRun = &NewPhysicalMemoryBlock->Run[0]; start = 0; Inserted = FALSE; Updated = FALSE; do { Page = MmPhysicalMemoryBlock->Run[start].BasePage; count = MmPhysicalMemoryBlock->Run[start].PageCount; if (Inserted == FALSE) { // // Note overlaps into adjacent ranges were already checked above. // if (StartPage == Page + count) { MmPhysicalMemoryBlock->Run[start].PageCount += NumberOfPages; OldPhysicalMemoryBlock = NewPhysicalMemoryBlock; MmPhysicalMemoryBlock->NumberOfPages += NumberOfPages; // // Coalesce below and above to avoid leaving zero length gaps // as these gaps would prevent callers from removing ranges // the span them. // if (start + 1 < MmPhysicalMemoryBlock->NumberOfRuns) { start += 1; Page = MmPhysicalMemoryBlock->Run[start].BasePage; count = MmPhysicalMemoryBlock->Run[start].PageCount; if (StartPage + NumberOfPages == Page) { MmPhysicalMemoryBlock->Run[start - 1].PageCount += count; MmPhysicalMemoryBlock->NumberOfRuns -= 1; // // Copy any remaining entries. // if (start != MmPhysicalMemoryBlock->NumberOfRuns) { RtlMoveMemory (&MmPhysicalMemoryBlock->Run[start], &MmPhysicalMemoryBlock->Run[start + 1], (MmPhysicalMemoryBlock->NumberOfRuns - start) * sizeof (PHYSICAL_MEMORY_RUN)); } } } Updated = TRUE; break; } if (StartPage + NumberOfPages == Page) { MmPhysicalMemoryBlock->Run[start].BasePage = StartPage; MmPhysicalMemoryBlock->Run[start].PageCount += NumberOfPages; OldPhysicalMemoryBlock = NewPhysicalMemoryBlock; MmPhysicalMemoryBlock->NumberOfPages += NumberOfPages; Updated = TRUE; break; } if (StartPage + NumberOfPages <= Page) { if (start + 1 < MmPhysicalMemoryBlock->NumberOfRuns) { if (StartPage + NumberOfPages <= MmPhysicalMemoryBlock->Run[start + 1].BasePage) { // // Don't insert here - the new entry really belongs // (at least) one entry further down. // continue; } } NewRun->BasePage = StartPage; NewRun->PageCount = NumberOfPages; NewRun += 1; Inserted = TRUE; Updated = TRUE; } } *NewRun = MmPhysicalMemoryBlock->Run[start]; NewRun += 1; start += 1; } while (start != MmPhysicalMemoryBlock->NumberOfRuns); // // If the memory block has not been updated, then the new entry must // be added at the very end. // if (Updated == FALSE) { ASSERT (Inserted == FALSE); NewRun->BasePage = StartPage; NewRun->PageCount = NumberOfPages; Inserted = TRUE; } // // Repoint the MmPhysicalMemoryBlock at the new chunk, free the old after // releasing the PFN lock. // if (Inserted == TRUE) { OldPhysicalMemoryBlock = MmPhysicalMemoryBlock; MmPhysicalMemoryBlock = NewPhysicalMemoryBlock; } // // Note that the page directory (page parent entries on Win64) must be // filled in at system boot so that already-created processes do not fault // when referencing the new PFNs. // // // Walk through the memory descriptors and add pages to the // free list in the PFN database. // PageFrameIndex = StartPage; Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); if (EndPage - 1 > MmHighestPhysicalPage) { MmHighestPhysicalPage = EndPage - 1; } while (PageFrameIndex < EndPage) { ASSERT (Pfn1->u2.ShareCount == 0); ASSERT (Pfn1->u3.e2.ShortFlags == 0); ASSERT (Pfn1->u3.e2.ReferenceCount == 0); ASSERT64 (Pfn1->UsedPageTableEntries == 0); ASSERT (Pfn1->OriginalPte.u.Long == ZeroKernelPte.u.Long); ASSERT (Pfn1->PteFrame == 0); ASSERT ((Pfn1->PteAddress == PFN_REMOVED) || (Pfn1->PteAddress == (PMMPTE)(UINT_PTR)0)); // // Set the PTE address to the physical page for // virtual address alignment checking. // Pfn1->PteAddress = (PMMPTE)(PageFrameIndex << PTE_SHIFT); MiInsertPageInList (MmPageLocationList[FreePageList], PageFrameIndex); PageFrameIndex += 1; Pfn1 += 1; } MmResidentAvailablePages += NumberOfPages; MmNumberOfPhysicalPages += (PFN_COUNT)NumberOfPages; UNLOCK_PFN (OldIrql); // // Increase all commit limits to reflect the additional memory. // ExAcquireSpinLock (&MmChargeCommitmentLock, &OldIrql); MmTotalCommitLimit += NumberOfPages; MmTotalCommitLimitMaximum += NumberOfPages; MmTotalCommittedPages += PagesNeeded; ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql); ExReleaseFastMutex (&MmDynamicMemoryMutex); ExFreePool (OldPhysicalMemoryBlock); // // Indicate number of bytes actually added to our caller. // NumberOfBytes->QuadPart = (ULONGLONG)NumberOfPages * PAGE_SIZE; return STATUS_SUCCESS; }
NTSTATUS MmRemovePhysicalMemory ( IN PPHYSICAL_ADDRESS StartAddress, IN OUT PLARGE_INTEGER NumberOfBytes ) /*++ Routine Description: This routine attempts to remove the specified physical address range from the system. Arguments: StartAddress - Supplies the starting physical address. NumberOfBytes - Supplies a pointer to the number of bytes being removed. Return Value: NTSTATUS. Environment: Kernel mode. PASSIVE level. No locks held. --*/ { ULONG i; ULONG Additional; PFN_NUMBER Page; PFN_NUMBER LastPage; PFN_NUMBER OriginalLastPage; PFN_NUMBER start; PFN_NUMBER PagesReleased; PMMPFN Pfn1; PMMPFN StartPfn; PMMPFN EndPfn; KIRQL OldIrql; PFN_NUMBER StartPage; PFN_NUMBER EndPage; PFN_COUNT NumberOfPages; SPFN_NUMBER MaxPages; PFN_NUMBER PageFrameIndex; PFN_NUMBER RemovedPages; LOGICAL Inserted; NTSTATUS Status; PMMPTE PointerPte; PMMPTE EndPte; PVOID VirtualAddress; PPHYSICAL_MEMORY_DESCRIPTOR OldPhysicalMemoryBlock; PPHYSICAL_MEMORY_DESCRIPTOR NewPhysicalMemoryBlock; PPHYSICAL_MEMORY_RUN NewRun; LOGICAL PfnDatabaseIsPhysical; ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); ASSERT (BYTE_OFFSET(NumberOfBytes->LowPart) == 0); ASSERT (BYTE_OFFSET(StartAddress->LowPart) == 0); if (MI_IS_PHYSICAL_ADDRESS(MmPfnDatabase)) { // // The system must be configured for dynamic memory addition. This is // not strictly required to remove the memory, but it's better to check // for it now under the assumption that the administrator is probably // going to want to add this range of memory back in - better to give // the error now and refuse the removal than to refuse the addition // later. // if (MmDynamicPfn == FALSE) { return STATUS_NOT_SUPPORTED; } PfnDatabaseIsPhysical = TRUE; } else { PfnDatabaseIsPhysical = FALSE; } StartPage = (PFN_NUMBER)(StartAddress->QuadPart >> PAGE_SHIFT); NumberOfPages = (PFN_COUNT)(NumberOfBytes->QuadPart >> PAGE_SHIFT); EndPage = StartPage + NumberOfPages; if (EndPage - 1 > MmHighestPossiblePhysicalPage) { // // Truncate the request into something that can be mapped by the PFN // database. // EndPage = MmHighestPossiblePhysicalPage + 1; NumberOfPages = (PFN_COUNT)(EndPage - StartPage); } // // The range cannot wrap. // if (StartPage >= EndPage) { return STATUS_INVALID_PARAMETER_1; } StartPfn = MI_PFN_ELEMENT (StartPage); EndPfn = MI_PFN_ELEMENT (EndPage); ExAcquireFastMutex (&MmDynamicMemoryMutex); #if DBG MiDynmemData[0] += 1; #endif // // Decrease all commit limits to reflect the removed memory. // ExAcquireSpinLock (&MmChargeCommitmentLock, &OldIrql); ASSERT (MmTotalCommitLimit <= MmTotalCommitLimitMaximum); if ((NumberOfPages + 100 > MmTotalCommitLimit - MmTotalCommittedPages) || (MmTotalCommittedPages > MmTotalCommitLimit)) { #if DBG MiDynmemData[1] += 1; #endif ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql); ExReleaseFastMutex (&MmDynamicMemoryMutex); return STATUS_INSUFFICIENT_RESOURCES; } MmTotalCommitLimit -= NumberOfPages; MmTotalCommitLimitMaximum -= NumberOfPages; ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql); // // Check for outstanding promises that cannot be broken. // LOCK_PFN (OldIrql); MaxPages = MI_NONPAGABLE_MEMORY_AVAILABLE() - 100; if ((SPFN_NUMBER)NumberOfPages > MaxPages) { #if DBG MiDynmemData[2] += 1; #endif UNLOCK_PFN (OldIrql); Status = STATUS_INSUFFICIENT_RESOURCES; goto giveup2; } MmResidentAvailablePages -= NumberOfPages; MmNumberOfPhysicalPages -= NumberOfPages; // // The range must be contained in a single entry. It is permissible for // it to be part of a single entry, but it must not cross multiple entries. // Additional = (ULONG)-2; start = 0; do { Page = MmPhysicalMemoryBlock->Run[start].BasePage; LastPage = Page + MmPhysicalMemoryBlock->Run[start].PageCount; if ((StartPage >= Page) && (EndPage <= LastPage)) { if ((StartPage == Page) && (EndPage == LastPage)) { Additional = (ULONG)-1; } else if ((StartPage == Page) || (EndPage == LastPage)) { Additional = 0; } else { Additional = 1; } break; } start += 1; } while (start != MmPhysicalMemoryBlock->NumberOfRuns); if (Additional == (ULONG)-2) { #if DBG MiDynmemData[3] += 1; #endif MmResidentAvailablePages += NumberOfPages; MmNumberOfPhysicalPages += NumberOfPages; UNLOCK_PFN (OldIrql); Status = STATUS_CONFLICTING_ADDRESSES; goto giveup2; } for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) { Pfn1->u3.e1.RemovalRequested = 1; } // // The free and zero lists must be pruned now before releasing the PFN // lock otherwise if another thread allocates the page from these lists, // the allocation will clear the RemovalRequested flag forever. // RemovedPages = MiRemovePhysicalPages (StartPage, EndPage); if (RemovedPages != NumberOfPages) { #if DBG retry: #endif Pfn1 = StartPfn; InterlockedIncrement (&MiDelayPageFaults); for (i = 0; i < 5; i += 1) { UNLOCK_PFN (OldIrql); // // Attempt to move pages to the standby list. Note that only the // pages with RemovalRequested set are moved. // MiTrimRemovalPagesOnly = TRUE; MiEmptyAllWorkingSets (); MiTrimRemovalPagesOnly = FALSE; MiFlushAllPages (); KeDelayExecutionThread (KernelMode, FALSE, &MmHalfSecond); LOCK_PFN (OldIrql); RemovedPages += MiRemovePhysicalPages (StartPage, EndPage); if (RemovedPages == NumberOfPages) { break; } // // RemovedPages doesn't include pages that were freed directly to // the bad page list via MiDecrementReferenceCount. So use the above // check purely as an optimization - and walk here when necessary. // for ( ; Pfn1 < EndPfn; Pfn1 += 1) { if (Pfn1->u3.e1.PageLocation != BadPageList) { break; } } if (Pfn1 == EndPfn) { RemovedPages = NumberOfPages; break; } } InterlockedDecrement (&MiDelayPageFaults); } if (RemovedPages != NumberOfPages) { #if DBG MiDynmemData[4] += 1; if (MiShowStuckPages != 0) { RemovedPages = 0; for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) { if (Pfn1->u3.e1.PageLocation != BadPageList) { RemovedPages += 1; } } ASSERT (RemovedPages != 0); DbgPrint("MmRemovePhysicalMemory : could not get %d of %d pages\n", RemovedPages, NumberOfPages); if (MiShowStuckPages & 0x2) { ULONG PfnsPrinted; ULONG EnoughShown; PMMPFN FirstPfn; PFN_COUNT PfnCount; PfnCount = 0; PfnsPrinted = 0; EnoughShown = 100; if (MiShowStuckPages & 0x4) { EnoughShown = (ULONG)-1; } DbgPrint("Stuck PFN list: "); for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) { if (Pfn1->u3.e1.PageLocation != BadPageList) { if (PfnCount == 0) { FirstPfn = Pfn1; } PfnCount += 1; } else { if (PfnCount != 0) { DbgPrint("%x -> %x ; ", FirstPfn - MmPfnDatabase, (FirstPfn - MmPfnDatabase) + PfnCount - 1); PfnsPrinted += 1; if (PfnsPrinted == EnoughShown) { break; } PfnCount = 0; } } } if (PfnCount != 0) { DbgPrint("%x -> %x ; ", FirstPfn - MmPfnDatabase, (FirstPfn - MmPfnDatabase) + PfnCount - 1); } DbgPrint("\n"); } if (MiShowStuckPages & 0x8) { DbgBreakPoint (); } if (MiShowStuckPages & 0x10) { goto retry; } } #endif UNLOCK_PFN (OldIrql); Status = STATUS_NO_MEMORY; goto giveup; } #if DBG for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) { ASSERT (Pfn1->u3.e1.PageLocation == BadPageList); } #endif // // All the pages in the range have been removed. Update the physical // memory blocks and other associated housekeeping. // if (Additional == 0) { // // The range can be split off from an end of an existing chunk so no // pool growth or shrinkage is required. // NewPhysicalMemoryBlock = MmPhysicalMemoryBlock; OldPhysicalMemoryBlock = NULL; } else { // // The range cannot be split off from an end of an existing chunk so // pool growth or shrinkage is required. // UNLOCK_PFN (OldIrql); i = (sizeof(PHYSICAL_MEMORY_DESCRIPTOR) + (sizeof(PHYSICAL_MEMORY_RUN) * (MmPhysicalMemoryBlock->NumberOfRuns + Additional))); NewPhysicalMemoryBlock = ExAllocatePoolWithTag (NonPagedPool, i, ' mM'); if (NewPhysicalMemoryBlock == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; #if DBG MiDynmemData[5] += 1; #endif goto giveup; } OldPhysicalMemoryBlock = MmPhysicalMemoryBlock; RtlZeroMemory (NewPhysicalMemoryBlock, i); LOCK_PFN (OldIrql); } // // Remove or split the requested range from the existing memory block. // NewPhysicalMemoryBlock->NumberOfRuns = MmPhysicalMemoryBlock->NumberOfRuns + Additional; NewPhysicalMemoryBlock->NumberOfPages = MmPhysicalMemoryBlock->NumberOfPages - NumberOfPages; NewRun = &NewPhysicalMemoryBlock->Run[0]; start = 0; Inserted = FALSE; do { Page = MmPhysicalMemoryBlock->Run[start].BasePage; LastPage = Page + MmPhysicalMemoryBlock->Run[start].PageCount; if (Inserted == FALSE) { if ((StartPage >= Page) && (EndPage <= LastPage)) { if ((StartPage == Page) && (EndPage == LastPage)) { ASSERT (Additional == -1); start += 1; continue; } else if ((StartPage == Page) || (EndPage == LastPage)) { ASSERT (Additional == 0); if (StartPage == Page) { MmPhysicalMemoryBlock->Run[start].BasePage += NumberOfPages; } MmPhysicalMemoryBlock->Run[start].PageCount -= NumberOfPages; } else { ASSERT (Additional == 1); OriginalLastPage = LastPage; MmPhysicalMemoryBlock->Run[start].PageCount = StartPage - MmPhysicalMemoryBlock->Run[start].BasePage; *NewRun = MmPhysicalMemoryBlock->Run[start]; NewRun += 1; NewRun->BasePage = EndPage; NewRun->PageCount = OriginalLastPage - EndPage; NewRun += 1; start += 1; continue; } Inserted = TRUE; } } *NewRun = MmPhysicalMemoryBlock->Run[start]; NewRun += 1; start += 1; } while (start != MmPhysicalMemoryBlock->NumberOfRuns); // // Repoint the MmPhysicalMemoryBlock at the new chunk. // Free the old block after releasing the PFN lock. // MmPhysicalMemoryBlock = NewPhysicalMemoryBlock; if (EndPage - 1 == MmHighestPhysicalPage) { MmHighestPhysicalPage = StartPage - 1; } // // Throw away all the removed pages that are currently enqueued. // for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) { ASSERT (Pfn1->u3.e1.PageLocation == BadPageList); ASSERT (Pfn1->u3.e1.RemovalRequested == 1); MiUnlinkPageFromList (Pfn1); ASSERT (Pfn1->u1.Flink == 0); ASSERT (Pfn1->u2.Blink == 0); ASSERT (Pfn1->u3.e2.ReferenceCount == 0); ASSERT64 (Pfn1->UsedPageTableEntries == 0); Pfn1->PteAddress = PFN_REMOVED; Pfn1->u3.e2.ShortFlags = 0; Pfn1->OriginalPte.u.Long = ZeroKernelPte.u.Long; Pfn1->PteFrame = 0; } // // Now that the removed pages have been discarded, eliminate the PFN // entries that mapped them. Straddling entries left over from an // adjacent earlier removal are not collapsed at this point. // // PagesReleased = 0; if (PfnDatabaseIsPhysical == FALSE) { VirtualAddress = (PVOID)ROUND_TO_PAGES(MI_PFN_ELEMENT(StartPage)); PointerPte = MiGetPteAddress (VirtualAddress); EndPte = MiGetPteAddress (PAGE_ALIGN(MI_PFN_ELEMENT(EndPage))); while (PointerPte < EndPte) { PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); ASSERT (Pfn1->u2.ShareCount == 1); ASSERT (Pfn1->u3.e2.ReferenceCount == 1); Pfn1->u2.ShareCount = 0; MI_SET_PFN_DELETED (Pfn1); #if DBG Pfn1->u3.e1.PageLocation = StandbyPageList; #endif //DBG MiDecrementReferenceCount (PageFrameIndex); KeFlushSingleTb (VirtualAddress, TRUE, TRUE, (PHARDWARE_PTE)PointerPte, ZeroKernelPte.u.Flush); PagesReleased += 1; PointerPte += 1; VirtualAddress = (PVOID)((PCHAR)VirtualAddress + PAGE_SIZE); } MmResidentAvailablePages += PagesReleased; } #if DBG MiDynmemData[6] += 1; #endif UNLOCK_PFN (OldIrql); if (PagesReleased != 0) { MiReturnCommitment (PagesReleased); } ExReleaseFastMutex (&MmDynamicMemoryMutex); if (OldPhysicalMemoryBlock != NULL) { ExFreePool (OldPhysicalMemoryBlock); } NumberOfBytes->QuadPart = (ULONGLONG)NumberOfPages * PAGE_SIZE; return STATUS_SUCCESS; giveup: // // All the pages in the range were not obtained. Back everything out. // PageFrameIndex = StartPage; Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); LOCK_PFN (OldIrql); while (PageFrameIndex < EndPage) { ASSERT (Pfn1->u3.e1.RemovalRequested == 1); Pfn1->u3.e1.RemovalRequested = 0; if ((Pfn1->u3.e1.PageLocation == BadPageList) && (Pfn1->u3.e1.ParityError == 0)) { MiUnlinkPageFromList (Pfn1); MiInsertPageInList (MmPageLocationList[FreePageList], PageFrameIndex); } Pfn1 += 1; PageFrameIndex += 1; } MmResidentAvailablePages += NumberOfPages; MmNumberOfPhysicalPages += NumberOfPages; UNLOCK_PFN (OldIrql); giveup2: ExAcquireSpinLock (&MmChargeCommitmentLock, &OldIrql); MmTotalCommitLimit += NumberOfPages; MmTotalCommitLimitMaximum += NumberOfPages; ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql); ExReleaseFastMutex (&MmDynamicMemoryMutex); return Status; }
// Checks if #BP is caused by the read write copy page. If so, that breakpoint // is set by a guest and not the VMM and should be delivered to a guest. _Use_decl_annotations_ static bool SbppIsShadowBreakpoint( const PatchInformation& info) { auto address = info.shadow_page_base_for_rw.get()->page + BYTE_OFFSET(info.patch_address); return (*address != 0xcc); }
PVOID MmDbgTranslatePhysicalAddress ( IN PHYSICAL_ADDRESS PhysicalAddress ) /*++ Routine Description: MIPS implementation specific: This routine maps the specified physical address and returns the virtual address which maps the physical address. The next call to MmDbgTranslatePhyiscalAddress removes the previous phyiscal address translation, hence on a single physical address can be examined at a time (can't cross page boundaries). Arguments: PhysicalAddress - Supplies the phyiscal address to map and translate. Return Value: The virtual address which corresponds to the phyiscal address. NULL if the physical address was bogus. Environment: Kernel mode IRQL at DISPATCH_LEVEL or greater. --*/ { PVOID BaseAddress; PMMPTE BasePte; PMMPFN Pfn1; ULONG Page; BasePte = MmDebugPte + (MM_NUMBER_OF_COLORS - 1); BasePte = (PMMPTE)((ULONG)BasePte & ~(MM_COLOR_MASK << PTE_SHIFT)); Page = (ULONG)(PhysicalAddress.QuadPart >> PAGE_SHIFT); if ((Page > (LONGLONG)MmHighestPhysicalPage) || (Page < (LONGLONG)MmLowestPhysicalPage)) { return NULL; } Pfn1 = MI_PFN_ELEMENT (Page); if (!MmIsAddressValid (Pfn1)) { return NULL; } BasePte = BasePte + Pfn1->u3.e1.PageColor; BaseAddress = MiGetVirtualAddressMappedByPte (BasePte); KiFlushSingleTb (TRUE, BaseAddress); *BasePte = ValidKernelPte; BasePte->u.Hard.PageFrameNumber = Page; return (PVOID)((ULONG)BaseAddress + BYTE_OFFSET(PhysicalAddress.LowPart)); }