using System; using ProcessHacker.Common.Objects; using ProcessHacker.Native.Api; using ProcessHacker.Native.Objects; namespace ProcessHacker.Native.Memory { /// /// Represents an allocation of physical pages. /// public sealed class PhysicalPages : BaseObject { private ProcessHandle _processHandle; private int _count; private IntPtr[] _pfnArray; /// /// Allocates physical pages. /// /// The number of pages to allocate. public PhysicalPages(int pageCount) : this(pageCount, true) { } /// /// Allocates physical pages. /// /// /// The number of bytes to allocate, or the number of pages to allocate /// if is true. If a number of bytes is used, /// it will be rounded up to the system page size. /// /// Whether specifies bytes or pages. /// public PhysicalPages(int count, bool pages) : this(ProcessHandle.Current, count, pages) { } /// /// Allocates physical pages. /// /// The process to allocate the pages in. /// The number of pages to allocate. public PhysicalPages(ProcessHandle processHandle, int pageCount) : this(processHandle, pageCount, true) { } /// /// Allocates physical pages. /// /// The process to allocate the pages in. /// /// The number of bytes to allocate, or the number of pages to allocate /// if is true. If a number of bytes is used, /// it will be rounded up to the system page size. /// /// Whether specifies bytes or pages. /// public PhysicalPages(ProcessHandle processHandle, int count, bool pages) { if (pages) _count = count; else _count = Windows.BytesToPages(count); IntPtr pageCount = new IntPtr(_count); _pfnArray = new IntPtr[_count]; if (!Win32.AllocateUserPhysicalPages(processHandle, ref pageCount, _pfnArray)) Win32.Throw(); if (pageCount.ToInt32() != _count) throw new Exception("Could not allocate all pages."); _processHandle = processHandle; _processHandle.Reference(); } protected override void DisposeObject(bool disposing) { IntPtr freedPages = new IntPtr(_count); _processHandle.Dereference(); if (!Win32.FreeUserPhysicalPages(_processHandle, ref freedPages, _pfnArray)) Win32.Throw(); if (freedPages.ToInt32() != _count) throw new Exception("Could not free all pages."); } public PhysicalPagesMapping Map(MemoryProtection protection) { return this.Map(IntPtr.Zero, protection); } public PhysicalPagesMapping Map(IntPtr address, MemoryProtection protection) { // Reserve an address range. IntPtr allocAddress = ProcessHandle.Current.AllocateMemory( address, _count * Windows.PageSize, MemoryFlags.Reserve | MemoryFlags.Physical, protection ); // Map the physical memory into the address range. if (!Win32.MapUserPhysicalPages( allocAddress, new IntPtr(_count), _pfnArray )) Win32.Throw(); return new PhysicalPagesMapping(this, allocAddress); } internal void Unmap(IntPtr address) { // Unmap the physical memory from the address range. if (!Win32.MapUserPhysicalPages( address, new IntPtr(_count), null )) Win32.Throw(); ProcessHandle.Current.FreeMemory(address, 0, false); } } }