// 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;
}
Example #2
0
/*
 * @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);
}
Example #3
0
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 */
		}
	}
}
Example #4
0
// 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;
}
Example #5
0
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 );

}
Example #6
0
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)));
	    }
Example #7
0
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();
}
Example #9
0
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));
}
Example #10
0
/*
 * @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));
}
Example #11
0
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);
	}
}
Example #12
0
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;
}
Example #13
0
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");
}
Example #14
0
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;
            }
        }
    }
}
Example #15
0
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);
    }
Example #16
0
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();
}
Example #18
0
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;
}
Example #19
0
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);

    }

}
Example #20
0
/*
 * @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;
}
Example #21
0
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;
}
Example #22
0
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;
}
Example #23
0
// 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);
}
Example #24
0
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));
}