Logo Search packages:      
Sourcecode: virtualbox-ose version File versions

static int krdrFileMap ( PKRDR  pRdr,
void **  ppvBase,
KU32  cSegments,
PCKLDRSEG  paSegments,
KBOOL  fFixed 
) [static]

Todo:

Definition at line 551 of file kRdrFile.cpp.

References KRDRFILE::aPreps, KRDRFILEPREP::cb, KLDRSEG::cbFile, KLDRSEG::cbMapped, KRDRFILE::cPreps, KRDRFILE::File, KRDRFILEPREP::hSection, K_ELEMENTS, KLDR_ERR_ADDRESS_OVERFLOW, KRDR_ERR_TOO_MANY_MAPPINGS, krdrFileGenericMap(), krdrFileGetNtAllocProt(), krdrFileGetNtMapProt(), KSIZE, NIL_KLDRADDR, NULL, KLDRSEG::offFile, KRDROPS::pfnPageSize, KRDROPS::pfnSize, KRDR::pOps, KRDRFILEPREP::pv, and KLDRSEG::RVA.

{
    PKRDRFILE       pRdrFile = (PKRDRFILE)pRdr;
    PKRDRFILEPREP   pPrep = &pRdrFile->aPreps[pRdrFile->cPreps];
    KLDRSIZE        cbTotal;
    const KSIZE     cbPage = pRdr->pOps->pfnPageSize(pRdr);
    int             rc;
    KU32            i;

    if (pRdrFile->cPreps >= K_ELEMENTS(pRdrFile->aPreps))
        return KRDR_ERR_TOO_MANY_MAPPINGS;

    /*
     * Calc the total mapping space needed.
     */
    cbTotal = 0;
    for (i = 0; i < cSegments; i++)
    {
        KLDRSIZE uRVASegmentEnd;
        if (paSegments[i].RVA == NIL_KLDRADDR)
            continue;
        uRVASegmentEnd = paSegments[i].RVA + paSegments[i].cbMapped;
        if (cbTotal < uRVASegmentEnd)
            cbTotal = uRVASegmentEnd;
    }
    pPrep->cb = (KSIZE)cbTotal;
    if (pPrep->cb != cbTotal)
        return KLDR_ERR_ADDRESS_OVERFLOW;
    pPrep->cb = (pPrep->cb + (cbPage - 1)) & ~(cbPage- 1);

#if K_OS == K_OS_DARWIN \
 || K_OS == K_OS_FREEBSD \
 || K_OS == K_OS_LINUX \
 || K_OS == K_OS_NETBSD \
 || K_OS == K_OS_OPENBSD \
 || K_OS == K_OS_SOLARIS
    /** @todo */

#elif K_OS == K_OS_WINDOWS
    /*
     * The NT memory mapped file API sucks in a lot of ways. Unless you're actually
     * trying to map a PE image and the kernel can parse the file for it self, the
     * API just isn't up to scratch.
     *
     * Problems:
     *      1. Reserving memory for the views is risky because you can't reserve and
     *         map into the reserved space. So, other threads might grab the memory
     *         before we get to it.
     *      2. The page aligning of file offsets makes it impossible to map most
     *         executable images since these are commonly sector aligned.
     *      3. When mapping a read+execute file, its not possible to create section
     *         larger than the file since the section size is bound to the data file
     *         size. This wouldn't have been such a problem if it was possible to
     *         map views beyond the section restriction, i.e. have a file size and
     *         view size.
     *      4. Only x86 can map views at page granularity it seems, and that only
     *         using an undocument flag. The default granularity is 64KB.
     *      5. There is more crappyness here...
     *
     * So, first we'll have to check if we can the file using the crappy NT APIs.
     * Chances are we can't.
     */
    for (i = 0; i < cSegments; i++)
    {
        if (paSegments[i].RVA == NIL_KLDRADDR)
            continue;

        /* The file backing of the segments must be page aligned. */
        if (    paSegments[i].cbFile > 0
            &&  paSegments[i].offFile & (cbPage - 1))
            break;

        /* Only page alignment gaps between the file size and the mapping size. */
        if (    paSegments[i].cbFile > 0
            &&  (paSegments[i].cbFile & ~(cbPage - 1)) != (paSegments[i].cbMapped & ~(cbPage - 1)) )
            break;

        /* The mapping addresses of the segments must be page aligned.
         * Non-x86 will probably require 64KB alignment here. */
        if (paSegments[i].RVA & (cbPage - 1))
            break;

        /* If we do have to allocate the segment it's RVA must be 64KB aligned. */
        if (    paSegments[i].cbFile > 0
            &&  (paSegments[i].RVA & 0xffff))
            break;
    }
    /** @todo if this is a PE image, we might just try a SEC_IMAGE mapping. It'll work if the host and image machines matches. */
    if (i == cSegments)
    {
        /* WOW! it may work out! Incredible! */
        SIZE_T          ViewSize;
        LARGE_INTEGER   SectionOffset;
        LARGE_INTEGER   MaxiumSize;
        NTSTATUS        Status;
        PVOID           pv;

        MaxiumSize.QuadPart = pRdr->pOps->pfnSize(pRdr);
        if (MaxiumSize.QuadPart > (LONGLONG)cbTotal)
            MaxiumSize.QuadPart = cbTotal;

        Status = NtCreateSection(&pPrep->hSection,
                                 SECTION_MAP_EXECUTE | SECTION_MAP_READ,    /* desired access */
                                 NULL,                                      /* object attributes */
                                 &MaxiumSize,
                                 PAGE_EXECUTE_WRITECOPY,                    /* page attributes */
                                 SEC_COMMIT,                                /* section attributes */
                                 pRdrFile->File);
        if (!NT_SUCCESS(Status))
            return (int)Status;

        /*
         * Determin the base address.
         */
        if (fFixed)
            pPrep->pv = *ppvBase;
        else
        {
            pv = NULL;
            ViewSize = (KSIZE)cbTotal;

            Status = NtAllocateVirtualMemory(NtCurrentProcess(),
                                             &pv,
                                             0,                             /* ZeroBits */
                                             &ViewSize,
                                             MEM_RESERVE,
                                             PAGE_READONLY);
            if (NT_SUCCESS(Status))
            {
                pPrep->pv = *ppvBase = pv;
                ViewSize = 0;
                Status = NtFreeVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, MEM_RELEASE);
            }
            if (!NT_SUCCESS(Status))
            {
                NtClose(pPrep->hSection);
                return Status;
            }
        }

        /*
         * Map the segments.
         */
        for (i = 0; i < cSegments; i++)
        {
            ULONG fPageProt;

            if (paSegments[i].RVA == NIL_KLDRADDR)
                continue;

            pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
            if (paSegments[i].cbFile > 0)
            {
                SectionOffset.QuadPart = paSegments[i].offFile;
                ViewSize = paSegments[i].cbFile;
                fPageProt = krdrFileGetNtMapProt(paSegments[i].enmProt);
                /* STATUS_MAPPED_ALIGNMENT
                   STATUS_CONFLICTING_ADDRESSES
                   STATUS_INVALID_VIEW_SIZE */
                Status = NtMapViewOfSection(pPrep->hSection, NtCurrentProcess(),
                                            &pv,
                                            0,                                  /* ZeroBits */
                                            0,                                  /* CommitSize */
                                            &SectionOffset,                     /* SectionOffset */
                                            &ViewSize,
                                            ViewUnmap,
                                            MEM_DOS_LIM,                        /* AllocationType */
                                            fPageProt);
                /* do we have to zero anything? */
                if (    NT_SUCCESS(Status)
                    &&  0/*later*/)
                {
                    /*ULONG OldPageProt = 0;
                      NtProtectVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, , */
                }
            }
            else
            {
                ViewSize = paSegments[i].cbMapped;
                fPageProt = krdrFileGetNtAllocProt(paSegments[i].enmProt);
                Status = NtAllocateVirtualMemory(NtCurrentProcess(),
                                                 &pv,
                                                 0,                             /* ZeroBits */
                                                 &ViewSize,
                                                 MEM_COMMIT,
                                                 fPageProt);
            }
            if (!NT_SUCCESS(Status))
                break;
        }

        /*
         * On success, commit the mapping and return.
         */
        if (NT_SUCCESS(Status))
        {
            pRdrFile->cPreps++;
            return 0;
        }

        /* bail out and fall back on the generic code. */
        while (i-- > 0)
        {
            PVOID pv;

            if (paSegments[i].RVA == NIL_KLDRADDR)
                continue;

            pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
            if (paSegments[i].cbFile > 0)
                NtUnmapViewOfSection(NtCurrentProcess(), pv);
            else
                NtFreeVirtualMemory(NtCurrentProcess(), &pv, NULL, MEM_RELEASE);
        }
        NtClose(pPrep->hSection);
    }
    /* else: fall back to the generic code */
    pPrep->hSection = NULL;
#endif

    /*
     * Use the generic map emulation.
     */
    pPrep->pv = fFixed ? *ppvBase : NULL;
    rc = krdrFileGenericMap(pRdr, pPrep, cSegments, paSegments, fFixed);
    if (!rc)
    {
        *ppvBase = pPrep->pv;
        pRdrFile->cPreps++;
    }

    return rc;
}


Generated by  Doxygen 1.6.0   Back to index