TimeSharedMemory.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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 ulong _timeSharedMemoryAddress;
  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, ulong timeSharedMemoryAddress, int timeSharedMemorySize)
  23. {
  24. _device = device;
  25. _sharedMemory = sharedMemory;
  26. _timeSharedMemoryAddress = timeSharedMemoryAddress;
  27. _timeSharedMemorySize = timeSharedMemorySize;
  28. // Clean the shared memory
  29. _device.Memory.ZeroFill(_timeSharedMemoryAddress, (ulong)_timeSharedMemorySize);
  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. ulong indexOffset = _timeSharedMemoryAddress + offset;
  77. T result;
  78. uint index;
  79. uint possiblyNewIndex;
  80. do
  81. {
  82. index = _device.Memory.Read<uint>(indexOffset);
  83. ulong objectOffset = indexOffset + 4 + padding + (ulong)((index & 1) * Unsafe.SizeOf<T>());
  84. result = _device.Memory.Read<T>(objectOffset);
  85. Thread.MemoryBarrier();
  86. possiblyNewIndex = _device.Memory.Read<uint>(indexOffset);
  87. } while (index != possiblyNewIndex);
  88. return result;
  89. }
  90. private void WriteObjectToSharedMemory<T>(ulong offset, ulong padding, T value) where T : unmanaged
  91. {
  92. ulong indexOffset = _timeSharedMemoryAddress + offset;
  93. uint newIndex = _device.Memory.Read<uint>(indexOffset) + 1;
  94. ulong objectOffset = indexOffset + 4 + padding + (ulong)((newIndex & 1) * Unsafe.SizeOf<T>());
  95. _device.Memory.Write(objectOffset, value);
  96. Thread.MemoryBarrier();
  97. _device.Memory.Write(indexOffset, newIndex);
  98. }
  99. }
  100. }