Ejemplo n.º 1
0
        /// <summary>
        /// Checks if a buffer can be created within a given set of pages described by pageInfo
        /// satisfying the given size, minimum and maximum memory location.
        /// </summary>
        /// <param name="pageInfo">Contains the information about a singular memory page.</param>
        /// <param name="bufferSize">The size that a <see cref="MemoryBuffer"/> would occupy. Pre-aligned to page-size.</param>
        /// <param name="minimumPtr">The maximum pointer a <see cref="MemoryBuffer"/> can occupy.</param>
        /// <param name="maximumPtr">The minimum pointer a <see cref="MemoryBuffer"/> can occupy.</param>
        /// <returns>Zero if the operation fails; otherwise positive value.</returns>
        private IntPtr GetBufferPointerInPageRange(ref MEMORY_BASIC_INFORMATION pageInfo, int bufferSize, IntPtr minimumPtr, IntPtr maximumPtr)
        {
            // Fast return if page is not free.
            if (pageInfo.State != (uint)MEM_ALLOCATION_TYPE.MEM_FREE)
            {
                return(IntPtr.Zero);
            }

            // This is valid in both 32bit and 64bit Windows.
            // We can call GetSystemInfo to get this but that's a waste; these are constant for x86 and x64.
            int allocationGranularity = 65536;

            // Do not align page start/end to allocation granularity yet.
            // Align it when we map the possible buffer ranges in the pages.
            long pageStart = (long)pageInfo.BaseAddress;
            long pageEnd   = (long)pageInfo.BaseAddress + (long)pageInfo.RegionSize;

            // Get range for page and min-max region.
            var minMaxRange = new AddressRange((long)minimumPtr, (long)maximumPtr);
            var pageRange   = new AddressRange(pageStart, pageEnd);

            if (!pageRange.Overlaps(ref minMaxRange))
            {
                return(IntPtr.Zero);
            }

            /* Three possible cases here:
             * 1. Page fits entirely inside min-max range and is smaller.
             * 2. Min-max range is inside page (i.e. page is bigger than the range)
             * 3. Page and min-max intersect, e.g. first half of pages in end of min-max
             *    or second half of pages in start of min-max.
             *
             * Below we will build a set of possible buffer allocation ranges
             * and check if they satisfy our conditions.
             */

            /* Try placing range at start and end of page boundaries.
             * Since we are allocating in page boundaries, we must compare against Min-Max. */

            // Note: We are rounding page boundary addresses up/down, possibly beyond the original ends/starts of page.
            //       We need to validate that we are still in the bounds of the actual page itself.

            var allocPtrPageMaxAligned = Mathematics.RoundDown(pageRange.EndPointer - bufferSize, allocationGranularity);
            var allocRangePageMaxStart = new AddressRange(allocPtrPageMaxAligned, allocPtrPageMaxAligned + bufferSize);

            if (pageRange.Contains(ref allocRangePageMaxStart) && minMaxRange.Contains(ref allocRangePageMaxStart))
            {
                return((IntPtr)allocRangePageMaxStart.StartPointer);
            }

            var allocPtrPageMinAligned = Mathematics.RoundUp(pageRange.StartPointer, allocationGranularity);
            var allocRangePageMinStart = new AddressRange(allocPtrPageMinAligned, allocPtrPageMinAligned + bufferSize);

            if (pageRange.Contains(ref allocRangePageMinStart) && minMaxRange.Contains(ref allocRangePageMinStart))
            {
                return((IntPtr)allocRangePageMinStart.StartPointer);
            }

            /* Try placing range at start and end of given minimum-maximum.
             * Since we are allocating in Min-Max, we must compare against Page Boundaries. */

            // Note: Remember that rounding is dangerous and could potentially cause max and min to cross as usual,
            //       must check proposed page range against both given min-max and page memory range.

            var allocPtrMaxAligned = Mathematics.RoundDown((long)maximumPtr - bufferSize, allocationGranularity);
            var allocRangeMaxStart = new AddressRange(allocPtrMaxAligned, allocPtrMaxAligned + bufferSize);

            if (pageRange.Contains(ref allocRangeMaxStart) && minMaxRange.Contains(ref allocRangeMaxStart))
            {
                return((IntPtr)allocRangeMaxStart.StartPointer);
            }

            var allocPtrMinAligned = Mathematics.RoundUp((long)minimumPtr, allocationGranularity);
            var allocRangeMinStart = new AddressRange(allocPtrMinAligned, allocPtrMinAligned + bufferSize);

            if (pageRange.Contains(ref allocRangeMinStart) && minMaxRange.Contains(ref allocRangeMinStart))
            {
                return((IntPtr)allocRangeMinStart.StartPointer);
            }

            return(IntPtr.Zero);
        }