TimeSharedMemory.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. using System;
  2. using System.Runtime.CompilerServices;
  3. using System.Runtime.InteropServices;
  4. using System.Threading;
  5. using Ryujinx.HLE.HOS.Kernel.Memory;
  6. using Ryujinx.HLE.HOS.Kernel.Threading;
  7. using Ryujinx.HLE.HOS.Services.Time.Clock;
  8. using Ryujinx.HLE.HOS.Services.Time.Types;
  9. using Ryujinx.HLE.Utilities;
  10. namespace Ryujinx.HLE.HOS.Services.Time
  11. {
  12. class TimeSharedMemory
  13. {
  14. private Switch _device;
  15. private KSharedMemory _sharedMemory;
  16. private SharedMemoryStorage _timeSharedMemoryStorage;
  17. private int _timeSharedMemorySize;
  18. private const uint SteadyClockContextOffset = 0x00;
  19. private const uint LocalSystemClockContextOffset = 0x38;
  20. private const uint NetworkSystemClockContextOffset = 0x80;
  21. private const uint AutomaticCorrectionEnabledOffset = 0xC8;
  22. public void Initialize(Switch device, KSharedMemory sharedMemory, SharedMemoryStorage timeSharedMemoryStorage, int timeSharedMemorySize)
  23. {
  24. _device = device;
  25. _sharedMemory = sharedMemory;
  26. _timeSharedMemoryStorage = timeSharedMemoryStorage;
  27. _timeSharedMemorySize = timeSharedMemorySize;
  28. // Clean the shared memory
  29. timeSharedMemoryStorage.ZeroFill();
  30. }
  31. public KSharedMemory GetSharedMemory()
  32. {
  33. return _sharedMemory;
  34. }
  35. public void SetupStandardSteadyClock(KThread thread, UInt128 clockSourceId, TimeSpanType currentTimePoint)
  36. {
  37. TimeSpanType ticksTimeSpan;
  38. // As this may be called before the guest code, we support passing a null thread to make this api usable.
  39. if (thread == null)
  40. {
  41. ticksTimeSpan = TimeSpanType.FromSeconds(0);
  42. }
  43. else
  44. {
  45. ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
  46. }
  47. SteadyClockContext context = new SteadyClockContext
  48. {
  49. InternalOffset = (ulong)(currentTimePoint.NanoSeconds - ticksTimeSpan.NanoSeconds),
  50. ClockSourceId = clockSourceId
  51. };
  52. WriteObjectToSharedMemory(SteadyClockContextOffset, 4, context);
  53. }
  54. public void SetAutomaticCorrectionEnabled(bool isAutomaticCorrectionEnabled)
  55. {
  56. // We convert the bool to byte here as a bool in C# takes 4 bytes...
  57. WriteObjectToSharedMemory(AutomaticCorrectionEnabledOffset, 0, Convert.ToByte(isAutomaticCorrectionEnabled));
  58. }
  59. public void SetSteadyClockRawTimePoint(KThread thread, TimeSpanType currentTimePoint)
  60. {
  61. SteadyClockContext context = ReadObjectFromSharedMemory<SteadyClockContext>(SteadyClockContextOffset, 4);
  62. TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
  63. context.InternalOffset = (ulong)(currentTimePoint.NanoSeconds - ticksTimeSpan.NanoSeconds);
  64. WriteObjectToSharedMemory(SteadyClockContextOffset, 4, context);
  65. }
  66. public void UpdateLocalSystemClockContext(SystemClockContext context)
  67. {
  68. WriteObjectToSharedMemory(LocalSystemClockContextOffset, 4, context);
  69. }
  70. public void UpdateNetworkSystemClockContext(SystemClockContext context)
  71. {
  72. WriteObjectToSharedMemory(NetworkSystemClockContextOffset, 4, context);
  73. }
  74. private T ReadObjectFromSharedMemory<T>(ulong offset, ulong padding) where T : unmanaged
  75. {
  76. T result;
  77. uint index;
  78. uint possiblyNewIndex;
  79. do
  80. {
  81. index = _timeSharedMemoryStorage.GetRef<uint>(offset);
  82. ulong objectOffset = offset + 4 + padding + (ulong)((index & 1) * Unsafe.SizeOf<T>());
  83. result = _timeSharedMemoryStorage.GetRef<T>(objectOffset);
  84. Thread.MemoryBarrier();
  85. possiblyNewIndex = _device.Memory.Read<uint>(offset);
  86. } while (index != possiblyNewIndex);
  87. return result;
  88. }
  89. private void WriteObjectToSharedMemory<T>(ulong offset, ulong padding, T value) where T : unmanaged
  90. {
  91. uint newIndex = _timeSharedMemoryStorage.GetRef<uint>(offset) + 1;
  92. ulong objectOffset = offset + 4 + padding + (ulong)((newIndex & 1) * Unsafe.SizeOf<T>());
  93. _timeSharedMemoryStorage.GetRef<T>(objectOffset) = value;
  94. Thread.MemoryBarrier();
  95. _timeSharedMemoryStorage.GetRef<uint>(offset) = newIndex;
  96. }
  97. }
  98. }