MemoryManagementUnix.cs 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. using Mono.Unix.Native;
  2. using System;
  3. using System.Collections.Concurrent;
  4. namespace Ryujinx.Memory
  5. {
  6. static class MemoryManagementUnix
  7. {
  8. private static readonly ConcurrentDictionary<IntPtr, ulong> _allocations = new ConcurrentDictionary<IntPtr, ulong>();
  9. public static IntPtr Allocate(ulong size)
  10. {
  11. return AllocateInternal(size, MmapProts.PROT_READ | MmapProts.PROT_WRITE);
  12. }
  13. public static IntPtr Reserve(ulong size)
  14. {
  15. return AllocateInternal(size, MmapProts.PROT_NONE);
  16. }
  17. private static IntPtr AllocateInternal(ulong size, MmapProts prot)
  18. {
  19. const MmapFlags flags = MmapFlags.MAP_PRIVATE | MmapFlags.MAP_ANONYMOUS;
  20. IntPtr ptr = Syscall.mmap(IntPtr.Zero, size, prot, flags, -1, 0);
  21. if (ptr == new IntPtr(-1L))
  22. {
  23. throw new OutOfMemoryException();
  24. }
  25. if (!_allocations.TryAdd(ptr, size))
  26. {
  27. // This should be impossible, kernel shouldn't return an already mapped address.
  28. throw new InvalidOperationException();
  29. }
  30. return ptr;
  31. }
  32. public static bool Commit(IntPtr address, ulong size)
  33. {
  34. return Syscall.mprotect(address, size, MmapProts.PROT_READ | MmapProts.PROT_WRITE) == 0;
  35. }
  36. public static bool Reprotect(IntPtr address, ulong size, MemoryPermission permission)
  37. {
  38. return Syscall.mprotect(address, size, GetProtection(permission)) == 0;
  39. }
  40. private static MmapProts GetProtection(MemoryPermission permission)
  41. {
  42. return permission switch
  43. {
  44. MemoryPermission.None => MmapProts.PROT_NONE,
  45. MemoryPermission.Read => MmapProts.PROT_READ,
  46. MemoryPermission.ReadAndWrite => MmapProts.PROT_READ | MmapProts.PROT_WRITE,
  47. MemoryPermission.ReadAndExecute => MmapProts.PROT_READ | MmapProts.PROT_EXEC,
  48. MemoryPermission.ReadWriteExecute => MmapProts.PROT_READ | MmapProts.PROT_WRITE | MmapProts.PROT_EXEC,
  49. MemoryPermission.Execute => MmapProts.PROT_EXEC,
  50. _ => throw new MemoryProtectionException(permission)
  51. };
  52. }
  53. public static bool Free(IntPtr address)
  54. {
  55. if (_allocations.TryRemove(address, out ulong size))
  56. {
  57. return Syscall.munmap(address, size) == 0;
  58. }
  59. return false;
  60. }
  61. }
  62. }