/// <summary> /// Adds a protection to the list of protections. /// </summary> /// <param name="address">Address of the protected region</param> /// <param name="size">Size of the protected region in bytes</param> /// <param name="permission">Memory permissions of the region</param> private void AddProtection(ulong address, ulong size, MemoryPermission permission) { ulong endAddress = address + size; var overlaps = Array.Empty <IntervalTreeNode <ulong, MemoryPermission> >(); int count; lock (_protections) { count = _protections.Get(address, endAddress, ref overlaps); if (count == 1 && overlaps[0].Start <= address && overlaps[0].End >= endAddress && overlaps[0].Value == permission) { return; } ulong startAddress = address; for (int index = 0; index < count; index++) { var protection = overlaps[index]; ulong protAddress = protection.Start; ulong protEndAddress = protection.End; MemoryPermission protPermission = protection.Value; _protections.Remove(protection); if (protection.Value == permission) { if (startAddress > protAddress) { startAddress = protAddress; } if (endAddress < protEndAddress) { endAddress = protEndAddress; } } else { if (startAddress > protAddress) { _protections.Add(protAddress, startAddress, protPermission); } if (endAddress < protEndAddress) { _protections.Add(endAddress, protEndAddress, protPermission); } } } _protections.Add(startAddress, endAddress, permission); } }
/// <summary> /// Reserves a range of the address space to be later mapped as shared memory views. /// </summary> /// <param name="address">Start address of the region to reserve</param> /// <param name="size">Size in bytes of the region to reserve</param> public void ReserveRange(ulong address, ulong size) { lock (_mappings) { _mappings.Add(address, address + size, ulong.MaxValue); } }
/// <summary> /// Unmaps the specified range of memory and marks it as mapped internally. /// </summary> /// <remarks> /// Since this marks the range as mapped, the expectation is that the range will be mapped after calling this method. /// </remarks> /// <param name="location">Memory address to unmap and mark as mapped</param> /// <param name="size">Size of the range in bytes</param> public void UnmapAndMarkRangeAsMapped(IntPtr location, IntPtr size) { ulong startAddress = (ulong)location; ulong unmapSize = (ulong)size; ulong endAddress = startAddress + unmapSize; var overlaps = Array.Empty <IntervalTreeNode <ulong, byte> >(); int count = 0; lock (_mappings) { count = _mappings.Get(startAddress, endAddress, ref overlaps); } for (int index = 0; index < count; index++) { var overlap = overlaps[index]; // Tree operations might modify the node start/end values, so save a copy before we modify the tree. ulong overlapStart = overlap.Start; ulong overlapEnd = overlap.End; ulong overlapValue = overlap.Value; _mappings.Remove(overlap); ulong unmapStart = Math.Max(overlapStart, startAddress); ulong unmapEnd = Math.Min(overlapEnd, endAddress); if (overlapStart < startAddress) { startAddress = overlapStart; } if (overlapEnd > endAddress) { endAddress = overlapEnd; } ulong currentAddress = unmapStart; while (currentAddress < unmapEnd) { WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)currentAddress, 2); currentAddress += PageSize; } } _mappings.Add(startAddress, endAddress, 0); }