_Must_inspect_result_
BOOLEAN
FxpIsAddressKnownToWdf(
    __in PVOID Address,
    __in PFX_DRIVER_GLOBALS FxDriverGlobals
    )
/*++

Routine Description:

    This routine will check the address to determine if it falls within the
    image of a WDF component (Library, Client driver or Class Extension).
    This is accomplished by traversing the WdfLdrGlobals.LoadedModuleList
    and comparing each image start/end address with Address.

Arguments:

    PVOID Address - The address to be checked, and it need not be currently
        paged in. In other words, it is NOT used in this routine as an
        address, but more as a simple scaler into a 4GB (x86) array.

        NOTE - Do not attempt to validatate Address, say via MmIsAddressValid(Address).
               Address's memory could be paged out, but Address is still valid.

    PFX_DRIVER_GLOBALS FxDriverGlobals - Driver's globals.

Return Value:

    TRUE indicates something was found, either library, client or both.
    FALSE indicates either not found or invalid parameters.

--*/
{

    if (NULL == Address || NULL == FxDriverGlobals) {
        return FALSE;
    }

    if (Address >= FxDriverGlobals->ImageAddress &&
        Address < WDF_PTR_ADD_OFFSET(FxDriverGlobals->ImageAddress,
                                     FxDriverGlobals->ImageSize)) {
        return TRUE;
    }

    return FALSE;
}
_Must_inspect_result_
NTSTATUS
FxpGetImageBase(
    __in  PDRIVER_OBJECT DriverObject,
    __out PVOID* ImageBase,
    __out PULONG ImageSize
    )
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    ULONG modulesSize = 0;
    AUX_MODULE_EXTENDED_INFO* modules = NULL;
    AUX_MODULE_EXTENDED_INFO* module;
    PVOID addressInImage = NULL;
    ULONG numberOfModules;
    ULONG i;

    //
    // Basic validation.
    //
    if (NULL == DriverObject || NULL == ImageBase || NULL == ImageSize) {
        status = STATUS_INVALID_PARAMETER;
        goto exit;
    }

    //
    // Get the address of a well known entry in the Image.
    //
    addressInImage = (PVOID) DriverObject->DriverStart;
    ASSERT(addressInImage != NULL);

    //
    // Initialize the AUX Kernel Library.
    //
    status = AuxKlibInitialize();
    if (!NT_SUCCESS(status)) {
        goto exit;
    }

    //
    // Get size of area needed for loaded modules.
    //
    status = AuxKlibQueryModuleInformation(&modulesSize,
                                           sizeof(AUX_MODULE_EXTENDED_INFO),
                                           NULL);

    if (!NT_SUCCESS(status) || (0 == modulesSize)) {
        goto exit;
    }

    numberOfModules = modulesSize / sizeof(AUX_MODULE_EXTENDED_INFO);

    //
    // Allocate returned-sized memory for the modules area.
    //
    modules = (AUX_MODULE_EXTENDED_INFO*) ExAllocatePoolWithTag(PagedPool,
                                                                modulesSize,
                                                                '30LW');
    if (NULL == modules) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto exit;
    }

    //
    // Request the modules array be filled with module information.
    //
    status = AuxKlibQueryModuleInformation(&modulesSize,
                                           sizeof(AUX_MODULE_EXTENDED_INFO),
                                           modules);

    if (!NT_SUCCESS(status)) {
        goto exit;
    }

    //
    // Traverse list, searching for the well known address in Image for which the
    // module's Image Base Address is in its range.
    //
    module = modules;

    for (i=0; i < numberOfModules; i++) {

        if (addressInImage >= module->BasicInfo.ImageBase &&
            addressInImage < WDF_PTR_ADD_OFFSET(module->BasicInfo.ImageBase,
                                                module->ImageSize)) {

            *ImageBase = module->BasicInfo.ImageBase;
            *ImageSize = module->ImageSize;

            status = STATUS_SUCCESS;
            goto exit;
        }
        module++;
    }

    status = STATUS_NOT_FOUND;

exit:

    if (modules != NULL) {
        ExFreePool(modules);
        modules = NULL;
    }

    return status;
}
_Must_inspect_result_
NTSTATUS
FxPkgPdo::Initialize(
    __in PWDFDEVICE_INIT DeviceInit
    )
/*++

Routine Description:

    Do initialization that might fail here.

Arguemnts:

    DeviceInit - the structure the driver passed in with initialization data

Returns:

    NTSTATUS

--*/
{
    NTSTATUS status;
    size_t cbLength, cbStrLength;
    PWSTR pCur;
    PdoInit* pPdo;

    status = FxPkgPnp::Initialize(DeviceInit);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    cbLength = 0;

    //
    // Compute the total number of bytes required for all strings and then
    // make one allocation and remember pointers w/in the string so we can
    // retrieve them individually later.
    //
    pPdo = &DeviceInit->Pdo;
    cbLength += FxCalculateTotalStringSize(&pPdo->HardwareIDs);
    cbLength += FxCalculateTotalStringSize(&pPdo->CompatibleIDs);

    if (pPdo->DeviceID != NULL) {
        cbLength += pPdo->DeviceID->ByteLength(TRUE);
    }
    if (pPdo->InstanceID != NULL) {
        cbLength += pPdo->InstanceID->ByteLength(TRUE);
    }
    if (pPdo->ContainerID != NULL) {
        cbLength += pPdo->ContainerID->ByteLength(TRUE);
    }

    m_IDsAllocation = (PWSTR) FxPoolAllocate(GetDriverGlobals(),
                                             PagedPool,
                                             cbLength);

    if (m_IDsAllocation == NULL) {
        status = STATUS_INSUFFICIENT_RESOURCES;

        DoTraceLevelMessage(
            GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
            "DeviceInit %p could not allocate string for device IDs "
            "(length %I64d), %!STATUS!", DeviceInit, cbLength, status);

        return status;
    }

    pCur = m_IDsAllocation;

    m_HardwareIDs = pCur;
    pCur = FxCopyMultiSz(m_HardwareIDs, &pPdo->HardwareIDs);

    m_CompatibleIDs = pCur;
    pCur = FxCopyMultiSz(m_CompatibleIDs, &pPdo->CompatibleIDs);

    if (pPdo->DeviceID != NULL) {
        m_DeviceID = pCur;

        //
        // Copy the bytes and then null terminate the buffer
        //
        cbStrLength = pPdo->DeviceID->ByteLength(FALSE);

        RtlCopyMemory(m_DeviceID,
                      pPdo->DeviceID->Buffer(),
                      cbStrLength);

        m_DeviceID[cbStrLength / sizeof(WCHAR)] = UNICODE_NULL;

        pCur = (PWSTR) WDF_PTR_ADD_OFFSET(m_DeviceID,
                                          cbStrLength + sizeof(UNICODE_NULL));
    }

    if (pPdo->InstanceID != NULL) {
        m_InstanceID = pCur;

        //
        // Copy the bytes and then null terminate the buffer
        //
        cbStrLength = pPdo->InstanceID->ByteLength(FALSE);

        RtlCopyMemory(m_InstanceID,
                      pPdo->InstanceID->Buffer(),
                      cbStrLength);

        m_InstanceID[cbStrLength / sizeof(WCHAR)] = UNICODE_NULL;

        pCur = (PWSTR) WDF_PTR_ADD_OFFSET(m_InstanceID,
                                          cbStrLength + sizeof(UNICODE_NULL));
    }
    
    if (pPdo->ContainerID != NULL) {
        m_ContainerID = pCur;

        //
        // Copy the bytes and then null terminate the buffer
        //
        cbStrLength = pPdo->ContainerID->ByteLength(FALSE);

        RtlCopyMemory(m_ContainerID,
                      pPdo->ContainerID->Buffer(),
                      cbStrLength);

        m_ContainerID[cbStrLength / sizeof(WCHAR)] = UNICODE_NULL;
    }

    m_Static = pPdo->Static;

    if (m_Static) {
        //
        // Statically enumerated children do not support reenumeration requests
        // from the stack on top of them.
        //

        //
        // The only way we can have static children is if an FDO enumerates them.
        //





        Mx::MxAssert(m_Device->m_ParentDevice->IsFdo());
        m_OwningChildList = m_Device->m_ParentDevice->GetFdoPkg()->m_StaticDeviceList;

        m_OwningChildList->ADDREF(this);
    }
    else {
        m_Description = pPdo->DescriptionEntry;

        m_OwningChildList = m_Description->GetParentList();
        m_OwningChildList->ADDREF(this);
    }

    return STATUS_SUCCESS;
}